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/TimeValue.h" 17#ifdef HAVE_SYS_TIME_H 18#include <sys/time.h> 19#endif 20#ifdef HAVE_SYS_RESOURCE_H 21#include <sys/resource.h> 22#endif 23// DragonFlyBSD, OpenBSD, and Bitrig have deprecated <malloc.h> for 24// <stdlib.h> instead. Unix.h includes this for us already. 25#if defined(HAVE_MALLOC_H) && !defined(__DragonFly__) && \ 26 !defined(__OpenBSD__) && !defined(__Bitrig__) 27#include <malloc.h> 28#endif 29#ifdef HAVE_MALLOC_MALLOC_H 30#include <malloc/malloc.h> 31#endif 32#ifdef HAVE_SYS_IOCTL_H 33# include <sys/ioctl.h> 34#endif 35#ifdef HAVE_TERMIOS_H 36# include <termios.h> 37#endif 38 39//===----------------------------------------------------------------------===// 40//=== WARNING: Implementation here must contain only generic UNIX code that 41//=== is guaranteed to work on *all* UNIX variants. 42//===----------------------------------------------------------------------===// 43 44using namespace llvm; 45using namespace sys; 46 47 48process::id_type self_process::get_id() { 49 return getpid(); 50} 51 52static std::pair<TimeValue, TimeValue> getRUsageTimes() { 53#if defined(HAVE_GETRUSAGE) 54 struct rusage RU; 55 ::getrusage(RUSAGE_SELF, &RU); 56 return std::make_pair( 57 TimeValue( 58 static_cast<TimeValue::SecondsType>(RU.ru_utime.tv_sec), 59 static_cast<TimeValue::NanoSecondsType>( 60 RU.ru_utime.tv_usec * TimeValue::NANOSECONDS_PER_MICROSECOND)), 61 TimeValue( 62 static_cast<TimeValue::SecondsType>(RU.ru_stime.tv_sec), 63 static_cast<TimeValue::NanoSecondsType>( 64 RU.ru_stime.tv_usec * TimeValue::NANOSECONDS_PER_MICROSECOND))); 65#else 66#warning Cannot get usage times on this platform 67 return std::make_pair(TimeValue(), TimeValue()); 68#endif 69} 70 71TimeValue self_process::get_user_time() const { 72#if _POSIX_TIMERS > 0 && _POSIX_CPUTIME > 0 73 // Try to get a high resolution CPU timer. 74 struct timespec TS; 75 if (::clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &TS) == 0) 76 return TimeValue(static_cast<TimeValue::SecondsType>(TS.tv_sec), 77 static_cast<TimeValue::NanoSecondsType>(TS.tv_nsec)); 78#endif 79 80 // Otherwise fall back to rusage based timing. 81 return getRUsageTimes().first; 82} 83 84TimeValue self_process::get_system_time() const { 85 // We can only collect system time by inspecting the results of getrusage. 86 return getRUsageTimes().second; 87} 88 89static unsigned getPageSize() { 90#if defined(__CYGWIN__) 91 // On Cygwin, getpagesize() returns 64k but the page size for the purposes of 92 // memory protection and mmap() is 4k. 93 // See http://www.cygwin.com/ml/cygwin/2009-01/threads.html#00492 94 const int page_size = 0x1000; 95#elif defined(HAVE_GETPAGESIZE) 96 const int page_size = ::getpagesize(); 97#elif defined(HAVE_SYSCONF) 98 long page_size = ::sysconf(_SC_PAGE_SIZE); 99#else 100#warning Cannot get the page size on this machine 101#endif 102 return static_cast<unsigned>(page_size); 103} 104 105// This constructor guaranteed to be run exactly once on a single thread, and 106// sets up various process invariants that can be queried cheaply from then on. 107self_process::self_process() : PageSize(getPageSize()) { 108} 109 110 111size_t Process::GetMallocUsage() { 112#if defined(HAVE_MALLINFO) 113 struct mallinfo mi; 114 mi = ::mallinfo(); 115 return mi.uordblks; 116#elif defined(HAVE_MALLOC_ZONE_STATISTICS) && defined(HAVE_MALLOC_MALLOC_H) 117 malloc_statistics_t Stats; 118 malloc_zone_statistics(malloc_default_zone(), &Stats); 119 return Stats.size_in_use; // darwin 120#elif defined(HAVE_SBRK) 121 // Note this is only an approximation and more closely resembles 122 // the value returned by mallinfo in the arena field. 123 static char *StartOfMemory = reinterpret_cast<char*>(::sbrk(0)); 124 char *EndOfMemory = (char*)sbrk(0); 125 if (EndOfMemory != ((char*)-1) && StartOfMemory != ((char*)-1)) 126 return EndOfMemory - StartOfMemory; 127 else 128 return 0; 129#else 130#warning Cannot get malloc info on this platform 131 return 0; 132#endif 133} 134 135void Process::GetTimeUsage(TimeValue &elapsed, TimeValue &user_time, 136 TimeValue &sys_time) { 137 elapsed = TimeValue::now(); 138 llvm::tie(user_time, sys_time) = getRUsageTimes(); 139} 140 141int Process::GetCurrentUserId() { 142 return getuid(); 143} 144 145int Process::GetCurrentGroupId() { 146 return getgid(); 147} 148 149#if defined(HAVE_MACH_MACH_H) && !defined(__GNU__) 150#include <mach/mach.h> 151#endif 152 153// Some LLVM programs such as bugpoint produce core files as a normal part of 154// their operation. To prevent the disk from filling up, this function 155// does what's necessary to prevent their generation. 156void Process::PreventCoreFiles() { 157#if HAVE_SETRLIMIT 158 struct rlimit rlim; 159 rlim.rlim_cur = rlim.rlim_max = 0; 160 setrlimit(RLIMIT_CORE, &rlim); 161#endif 162 163#if defined(HAVE_MACH_MACH_H) && !defined(__GNU__) 164 // Disable crash reporting on Mac OS X 10.0-10.4 165 166 // get information about the original set of exception ports for the task 167 mach_msg_type_number_t Count = 0; 168 exception_mask_t OriginalMasks[EXC_TYPES_COUNT]; 169 exception_port_t OriginalPorts[EXC_TYPES_COUNT]; 170 exception_behavior_t OriginalBehaviors[EXC_TYPES_COUNT]; 171 thread_state_flavor_t OriginalFlavors[EXC_TYPES_COUNT]; 172 kern_return_t err = 173 task_get_exception_ports(mach_task_self(), EXC_MASK_ALL, OriginalMasks, 174 &Count, OriginalPorts, OriginalBehaviors, 175 OriginalFlavors); 176 if (err == KERN_SUCCESS) { 177 // replace each with MACH_PORT_NULL. 178 for (unsigned i = 0; i != Count; ++i) 179 task_set_exception_ports(mach_task_self(), OriginalMasks[i], 180 MACH_PORT_NULL, OriginalBehaviors[i], 181 OriginalFlavors[i]); 182 } 183 184 // Disable crash reporting on Mac OS X 10.5 185 signal(SIGABRT, _exit); 186 signal(SIGILL, _exit); 187 signal(SIGFPE, _exit); 188 signal(SIGSEGV, _exit); 189 signal(SIGBUS, _exit); 190#endif 191} 192 193bool Process::StandardInIsUserInput() { 194 return FileDescriptorIsDisplayed(STDIN_FILENO); 195} 196 197bool Process::StandardOutIsDisplayed() { 198 return FileDescriptorIsDisplayed(STDOUT_FILENO); 199} 200 201bool Process::StandardErrIsDisplayed() { 202 return FileDescriptorIsDisplayed(STDERR_FILENO); 203} 204 205bool Process::FileDescriptorIsDisplayed(int fd) { 206#if HAVE_ISATTY 207 return isatty(fd); 208#else 209 // If we don't have isatty, just return false. 210 return false; 211#endif 212} 213 214static unsigned getColumns(int FileID) { 215 // If COLUMNS is defined in the environment, wrap to that many columns. 216 if (const char *ColumnsStr = std::getenv("COLUMNS")) { 217 int Columns = std::atoi(ColumnsStr); 218 if (Columns > 0) 219 return Columns; 220 } 221 222 unsigned Columns = 0; 223 224#if defined(HAVE_SYS_IOCTL_H) && defined(HAVE_TERMIOS_H) 225 // Try to determine the width of the terminal. 226 struct winsize ws; 227 // Zero-fill ws to avoid a false positive from MemorySanitizer. 228 memset(&ws, 0, sizeof(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 250static bool terminalHasColors() { 251 if (const char *term = std::getenv("TERM")) { 252 // Most modern terminals support ANSI escape sequences for colors. 253 // We could check terminfo, or have a list of known terms that support 254 // colors, but that would be overkill. 255 // The user can always ask for no colors by setting TERM to dumb, or 256 // using a commandline flag. 257 return strcmp(term, "dumb") != 0; 258 } 259 return false; 260} 261 262bool Process::FileDescriptorHasColors(int fd) { 263 // A file descriptor has colors if it is displayed and the terminal has 264 // colors. 265 return FileDescriptorIsDisplayed(fd) && terminalHasColors(); 266} 267 268bool Process::StandardOutHasColors() { 269 return FileDescriptorHasColors(STDOUT_FILENO); 270} 271 272bool Process::StandardErrHasColors() { 273 return FileDescriptorHasColors(STDERR_FILENO); 274} 275 276bool Process::ColorNeedsFlush() { 277 // No, we use ANSI escape sequences. 278 return false; 279} 280 281#define COLOR(FGBG, CODE, BOLD) "\033[0;" BOLD FGBG CODE "m" 282 283#define ALLCOLORS(FGBG,BOLD) {\ 284 COLOR(FGBG, "0", BOLD),\ 285 COLOR(FGBG, "1", BOLD),\ 286 COLOR(FGBG, "2", BOLD),\ 287 COLOR(FGBG, "3", BOLD),\ 288 COLOR(FGBG, "4", BOLD),\ 289 COLOR(FGBG, "5", BOLD),\ 290 COLOR(FGBG, "6", BOLD),\ 291 COLOR(FGBG, "7", BOLD)\ 292 } 293 294static const char colorcodes[2][2][8][10] = { 295 { ALLCOLORS("3",""), ALLCOLORS("3","1;") }, 296 { ALLCOLORS("4",""), ALLCOLORS("4","1;") } 297}; 298 299const char *Process::OutputColor(char code, bool bold, bool bg) { 300 return colorcodes[bg?1:0][bold?1:0][code&7]; 301} 302 303const char *Process::OutputBold(bool bg) { 304 return "\033[1m"; 305} 306 307const char *Process::OutputReverse() { 308 return "\033[7m"; 309} 310 311const char *Process::ResetColor() { 312 return "\033[0m"; 313} 314 315#if !defined(HAVE_ARC4RANDOM) 316static unsigned GetRandomNumberSeed() { 317 // Attempt to get the initial seed from /dev/urandom, if possible. 318 if (FILE *RandomSource = ::fopen("/dev/urandom", "r")) { 319 unsigned seed; 320 int count = ::fread((void *)&seed, sizeof(seed), 1, RandomSource); 321 ::fclose(RandomSource); 322 323 // Return the seed if the read was successful. 324 if (count == 1) 325 return seed; 326 } 327 328 // Otherwise, swizzle the current time and the process ID to form a reasonable 329 // seed. 330 TimeValue Now = TimeValue::now(); 331 return hash_combine(Now.seconds(), Now.nanoseconds(), ::getpid()); 332} 333#endif 334 335unsigned llvm::sys::Process::GetRandomNumber() { 336#if defined(HAVE_ARC4RANDOM) 337 return arc4random(); 338#else 339 static int x = (::srand(GetRandomNumberSeed()), 0); 340 (void)x; 341 return ::rand(); 342#endif 343} 344