1//===- Unix/Process.cpp - Unix Process Implementation --------- -*- C++ -*-===// 2// 3// The LLVM Compiler Infrastructure 4// 5// This file is distributed under the University of Illinois Open Source 6// License. See LICENSE.TXT for details. 7// 8//===----------------------------------------------------------------------===// 9// 10// This file provides the generic Unix implementation of the Process class. 11// 12//===----------------------------------------------------------------------===// 13 14#include "Unix.h" 15#include "llvm/ADT/Hashing.h" 16#include "llvm/Support/Mutex.h" 17#include "llvm/Support/MutexGuard.h" 18#include "llvm/Support/TimeValue.h" 19#ifdef HAVE_SYS_TIME_H 20#include <sys/time.h> 21#endif 22#ifdef HAVE_SYS_RESOURCE_H 23#include <sys/resource.h> 24#endif 25// DragonFlyBSD, OpenBSD, and Bitrig have deprecated <malloc.h> for 26// <stdlib.h> instead. Unix.h includes this for us already. 27#if defined(HAVE_MALLOC_H) && !defined(__DragonFly__) && \ 28 !defined(__OpenBSD__) && !defined(__Bitrig__) 29#include <malloc.h> 30#endif 31#ifdef HAVE_MALLOC_MALLOC_H 32#include <malloc/malloc.h> 33#endif 34#ifdef HAVE_SYS_IOCTL_H 35# include <sys/ioctl.h> 36#endif 37#ifdef HAVE_TERMIOS_H 38# include <termios.h> 39#endif 40 41//===----------------------------------------------------------------------===// 42//=== WARNING: Implementation here must contain only generic UNIX code that 43//=== is guaranteed to work on *all* UNIX variants. 44//===----------------------------------------------------------------------===// 45 46using namespace llvm; 47using namespace sys; 48 49 50process::id_type self_process::get_id() { 51 return getpid(); 52} 53 54static std::pair<TimeValue, TimeValue> getRUsageTimes() { 55#if defined(HAVE_GETRUSAGE) 56 struct rusage RU; 57 ::getrusage(RUSAGE_SELF, &RU); 58 return std::make_pair( 59 TimeValue( 60 static_cast<TimeValue::SecondsType>(RU.ru_utime.tv_sec), 61 static_cast<TimeValue::NanoSecondsType>( 62 RU.ru_utime.tv_usec * TimeValue::NANOSECONDS_PER_MICROSECOND)), 63 TimeValue( 64 static_cast<TimeValue::SecondsType>(RU.ru_stime.tv_sec), 65 static_cast<TimeValue::NanoSecondsType>( 66 RU.ru_stime.tv_usec * TimeValue::NANOSECONDS_PER_MICROSECOND))); 67#else 68#warning Cannot get usage times on this platform 69 return std::make_pair(TimeValue(), TimeValue()); 70#endif 71} 72 73TimeValue self_process::get_user_time() const { 74#if _POSIX_TIMERS > 0 && _POSIX_CPUTIME > 0 75 // Try to get a high resolution CPU timer. 76 struct timespec TS; 77 if (::clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &TS) == 0) 78 return TimeValue(static_cast<TimeValue::SecondsType>(TS.tv_sec), 79 static_cast<TimeValue::NanoSecondsType>(TS.tv_nsec)); 80#endif 81 82 // Otherwise fall back to rusage based timing. 83 return getRUsageTimes().first; 84} 85 86TimeValue self_process::get_system_time() const { 87 // We can only collect system time by inspecting the results of getrusage. 88 return getRUsageTimes().second; 89} 90 91static unsigned getPageSize() { 92#if defined(__CYGWIN__) 93 // On Cygwin, getpagesize() returns 64k but the page size for the purposes of 94 // memory protection and mmap() is 4k. 95 // See http://www.cygwin.com/ml/cygwin/2009-01/threads.html#00492 96 const int page_size = 0x1000; 97#elif defined(HAVE_GETPAGESIZE) 98 const int page_size = ::getpagesize(); 99#elif defined(HAVE_SYSCONF) 100 long page_size = ::sysconf(_SC_PAGE_SIZE); 101#else 102#warning Cannot get the page size on this machine 103#endif 104 return static_cast<unsigned>(page_size); 105} 106 107// This constructor guaranteed to be run exactly once on a single thread, and 108// sets up various process invariants that can be queried cheaply from then on. 109self_process::self_process() : PageSize(getPageSize()) { 110} 111 112 113size_t Process::GetMallocUsage() { 114#if defined(HAVE_MALLINFO) 115 struct mallinfo mi; 116 mi = ::mallinfo(); 117 return mi.uordblks; 118#elif defined(HAVE_MALLOC_ZONE_STATISTICS) && defined(HAVE_MALLOC_MALLOC_H) 119 malloc_statistics_t Stats; 120 malloc_zone_statistics(malloc_default_zone(), &Stats); 121 return Stats.size_in_use; // darwin 122#elif defined(HAVE_SBRK) 123 // Note this is only an approximation and more closely resembles 124 // the value returned by mallinfo in the arena field. 125 static char *StartOfMemory = reinterpret_cast<char*>(::sbrk(0)); 126 char *EndOfMemory = (char*)sbrk(0); 127 if (EndOfMemory != ((char*)-1) && StartOfMemory != ((char*)-1)) 128 return EndOfMemory - StartOfMemory; 129 else 130 return 0; 131#else 132#warning Cannot get malloc info on this platform 133 return 0; 134#endif 135} 136 137void Process::GetTimeUsage(TimeValue &elapsed, TimeValue &user_time, 138 TimeValue &sys_time) { 139 elapsed = TimeValue::now(); 140 llvm::tie(user_time, sys_time) = getRUsageTimes(); 141} 142 143int Process::GetCurrentUserId() { 144 return getuid(); 145} 146 147int Process::GetCurrentGroupId() { 148 return getgid(); 149} 150 151#if defined(HAVE_MACH_MACH_H) && !defined(__GNU__) 152#include <mach/mach.h> 153#endif 154 155// Some LLVM programs such as bugpoint produce core files as a normal part of 156// their operation. To prevent the disk from filling up, this function 157// does what's necessary to prevent their generation. 158void Process::PreventCoreFiles() { 159#if HAVE_SETRLIMIT 160 struct rlimit rlim; 161 rlim.rlim_cur = rlim.rlim_max = 0; 162 setrlimit(RLIMIT_CORE, &rlim); 163#endif 164 165#if defined(HAVE_MACH_MACH_H) && !defined(__GNU__) 166 // Disable crash reporting on Mac OS X 10.0-10.4 167 168 // get information about the original set of exception ports for the task 169 mach_msg_type_number_t Count = 0; 170 exception_mask_t OriginalMasks[EXC_TYPES_COUNT]; 171 exception_port_t OriginalPorts[EXC_TYPES_COUNT]; 172 exception_behavior_t OriginalBehaviors[EXC_TYPES_COUNT]; 173 thread_state_flavor_t OriginalFlavors[EXC_TYPES_COUNT]; 174 kern_return_t err = 175 task_get_exception_ports(mach_task_self(), EXC_MASK_ALL, OriginalMasks, 176 &Count, OriginalPorts, OriginalBehaviors, 177 OriginalFlavors); 178 if (err == KERN_SUCCESS) { 179 // replace each with MACH_PORT_NULL. 180 for (unsigned i = 0; i != Count; ++i) 181 task_set_exception_ports(mach_task_self(), OriginalMasks[i], 182 MACH_PORT_NULL, OriginalBehaviors[i], 183 OriginalFlavors[i]); 184 } 185 186 // Disable crash reporting on Mac OS X 10.5 187 signal(SIGABRT, _exit); 188 signal(SIGILL, _exit); 189 signal(SIGFPE, _exit); 190 signal(SIGSEGV, _exit); 191 signal(SIGBUS, _exit); 192#endif 193} 194 195bool Process::StandardInIsUserInput() { 196 return FileDescriptorIsDisplayed(STDIN_FILENO); 197} 198 199bool Process::StandardOutIsDisplayed() { 200 return FileDescriptorIsDisplayed(STDOUT_FILENO); 201} 202 203bool Process::StandardErrIsDisplayed() { 204 return FileDescriptorIsDisplayed(STDERR_FILENO); 205} 206 207bool Process::FileDescriptorIsDisplayed(int fd) { 208#if HAVE_ISATTY 209 return isatty(fd); 210#else 211 // If we don't have isatty, just return false. 212 return false; 213#endif 214} 215 216static unsigned getColumns(int FileID) { 217 // If COLUMNS is defined in the environment, wrap to that many columns. 218 if (const char *ColumnsStr = std::getenv("COLUMNS")) { 219 int Columns = std::atoi(ColumnsStr); 220 if (Columns > 0) 221 return Columns; 222 } 223 224 unsigned Columns = 0; 225 226#if defined(HAVE_SYS_IOCTL_H) && defined(HAVE_TERMIOS_H) 227 // Try to determine the width of the terminal. 228 struct winsize ws; 229 if (ioctl(FileID, TIOCGWINSZ, &ws) == 0) 230 Columns = ws.ws_col; 231#endif 232 233 return Columns; 234} 235 236unsigned Process::StandardOutColumns() { 237 if (!StandardOutIsDisplayed()) 238 return 0; 239 240 return getColumns(1); 241} 242 243unsigned Process::StandardErrColumns() { 244 if (!StandardErrIsDisplayed()) 245 return 0; 246 247 return getColumns(2); 248} 249 250#ifdef HAVE_TERMINFO 251// We manually declare these two extern functions because finding the correct 252// headers from various terminfo, curses, or other sources is harder than 253// writing their specs down. 254extern "C" int setupterm(char *term, int filedes, int *errret); 255extern "C" int tigetnum(char *capname); 256#endif 257 258static bool terminalHasColors(int fd) { 259#ifdef HAVE_TERMINFO 260 // First, acquire a global lock because these C routines are thread hostile. 261 static sys::Mutex M; 262 MutexGuard G(M); 263 264 int errret = 0; 265 if (setupterm((char *)0, fd, &errret) != 0) 266 // Regardless of why, if we can't get terminfo, we shouldn't try to print 267 // colors. 268 return false; 269 270 // Test whether the terminal as set up supports color output. How to do this 271 // isn't entirely obvious. We can use the curses routine 'has_colors' but it 272 // would be nice to avoid a dependency on curses proper when we can make do 273 // with a minimal terminfo parsing library. Also, we don't really care whether 274 // the terminal supports the curses-specific color changing routines, merely 275 // if it will interpret ANSI color escape codes in a reasonable way. Thus, the 276 // strategy here is just to query the baseline colors capability and if it 277 // supports colors at all to assume it will translate the escape codes into 278 // whatever range of colors it does support. We can add more detailed tests 279 // here if users report them as necessary. 280 // 281 // The 'tigetnum' routine returns -2 or -1 on errors, and might return 0 if 282 // the terminfo says that no colors are supported. 283 if (tigetnum(const_cast<char *>("colors")) > 0) 284 return true; 285#endif 286 287 // Otherwise, be conservative. 288 return false; 289} 290 291bool Process::FileDescriptorHasColors(int fd) { 292 // A file descriptor has colors if it is displayed and the terminal has 293 // colors. 294 return FileDescriptorIsDisplayed(fd) && terminalHasColors(fd); 295} 296 297bool Process::StandardOutHasColors() { 298 return FileDescriptorHasColors(STDOUT_FILENO); 299} 300 301bool Process::StandardErrHasColors() { 302 return FileDescriptorHasColors(STDERR_FILENO); 303} 304 305bool Process::ColorNeedsFlush() { 306 // No, we use ANSI escape sequences. 307 return false; 308} 309 310#define COLOR(FGBG, CODE, BOLD) "\033[0;" BOLD FGBG CODE "m" 311 312#define ALLCOLORS(FGBG,BOLD) {\ 313 COLOR(FGBG, "0", BOLD),\ 314 COLOR(FGBG, "1", BOLD),\ 315 COLOR(FGBG, "2", BOLD),\ 316 COLOR(FGBG, "3", BOLD),\ 317 COLOR(FGBG, "4", BOLD),\ 318 COLOR(FGBG, "5", BOLD),\ 319 COLOR(FGBG, "6", BOLD),\ 320 COLOR(FGBG, "7", BOLD)\ 321 } 322 323static const char colorcodes[2][2][8][10] = { 324 { ALLCOLORS("3",""), ALLCOLORS("3","1;") }, 325 { ALLCOLORS("4",""), ALLCOLORS("4","1;") } 326}; 327 328const char *Process::OutputColor(char code, bool bold, bool bg) { 329 return colorcodes[bg?1:0][bold?1:0][code&7]; 330} 331 332const char *Process::OutputBold(bool bg) { 333 return "\033[1m"; 334} 335 336const char *Process::OutputReverse() { 337 return "\033[7m"; 338} 339 340const char *Process::ResetColor() { 341 return "\033[0m"; 342} 343 344#if !defined(HAVE_ARC4RANDOM) 345static unsigned GetRandomNumberSeed() { 346 // Attempt to get the initial seed from /dev/urandom, if possible. 347 if (FILE *RandomSource = ::fopen("/dev/urandom", "r")) { 348 unsigned seed; 349 int count = ::fread((void *)&seed, sizeof(seed), 1, RandomSource); 350 ::fclose(RandomSource); 351 352 // Return the seed if the read was successful. 353 if (count == 1) 354 return seed; 355 } 356 357 // Otherwise, swizzle the current time and the process ID to form a reasonable 358 // seed. 359 TimeValue Now = TimeValue::now(); 360 return hash_combine(Now.seconds(), Now.nanoseconds(), ::getpid()); 361} 362#endif 363 364unsigned llvm::sys::Process::GetRandomNumber() { 365#if defined(HAVE_ARC4RANDOM) 366 return arc4random(); 367#else 368 static int x = (::srand(GetRandomNumberSeed()), 0); 369 (void)x; 370 return ::rand(); 371#endif 372} 373