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 // See if we can use curses to detect information about a terminal when 42 // connected to one. 43 #ifdef HAVE_CURSES 44 # if defined(HAVE_CURSES_H) 45 # include <curses.h> 46 # elif defined(HAVE_NCURSES_H) 47 # include <ncurses.h> 48 # elif defined(HAVE_NCURSESW_H) 49 # include <ncursesw.h> 50 # elif defined(HAVE_NCURSES_CURSES_H) 51 # include <ncurses/curses.h> 52 # elif defined(HAVE_NCURSESW_CURSES_H) 53 # include <ncursesw/curses.h> 54 # else 55 # error Have a curses library but unable to find a curses header! 56 # endif 57 # include <term.h> 58 #endif 59 60 //===----------------------------------------------------------------------===// 61 //=== WARNING: Implementation here must contain only generic UNIX code that 62 //=== is guaranteed to work on *all* UNIX variants. 63 //===----------------------------------------------------------------------===// 64 65 using namespace llvm; 66 using namespace sys; 67 68 69 process::id_type self_process::get_id() { 70 return getpid(); 71 } 72 73 static std::pair<TimeValue, TimeValue> getRUsageTimes() { 74 #if defined(HAVE_GETRUSAGE) 75 struct rusage RU; 76 ::getrusage(RUSAGE_SELF, &RU); 77 return std::make_pair( 78 TimeValue( 79 static_cast<TimeValue::SecondsType>(RU.ru_utime.tv_sec), 80 static_cast<TimeValue::NanoSecondsType>( 81 RU.ru_utime.tv_usec * TimeValue::NANOSECONDS_PER_MICROSECOND)), 82 TimeValue( 83 static_cast<TimeValue::SecondsType>(RU.ru_stime.tv_sec), 84 static_cast<TimeValue::NanoSecondsType>( 85 RU.ru_stime.tv_usec * TimeValue::NANOSECONDS_PER_MICROSECOND))); 86 #else 87 #warning Cannot get usage times on this platform 88 return std::make_pair(TimeValue(), TimeValue()); 89 #endif 90 } 91 92 TimeValue self_process::get_user_time() const { 93 #if _POSIX_TIMERS > 0 && _POSIX_CPUTIME > 0 94 // Try to get a high resolution CPU timer. 95 struct timespec TS; 96 if (::clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &TS) == 0) 97 return TimeValue(static_cast<TimeValue::SecondsType>(TS.tv_sec), 98 static_cast<TimeValue::NanoSecondsType>(TS.tv_nsec)); 99 #endif 100 101 // Otherwise fall back to rusage based timing. 102 return getRUsageTimes().first; 103 } 104 105 TimeValue self_process::get_system_time() const { 106 // We can only collect system time by inspecting the results of getrusage. 107 return getRUsageTimes().second; 108 } 109 110 static unsigned getPageSize() { 111 #if defined(__CYGWIN__) 112 // On Cygwin, getpagesize() returns 64k but the page size for the purposes of 113 // memory protection and mmap() is 4k. 114 // See http://www.cygwin.com/ml/cygwin/2009-01/threads.html#00492 115 const int page_size = 0x1000; 116 #elif defined(HAVE_GETPAGESIZE) 117 const int page_size = ::getpagesize(); 118 #elif defined(HAVE_SYSCONF) 119 long page_size = ::sysconf(_SC_PAGE_SIZE); 120 #else 121 #warning Cannot get the page size on this machine 122 #endif 123 return static_cast<unsigned>(page_size); 124 } 125 126 // This constructor guaranteed to be run exactly once on a single thread, and 127 // sets up various process invariants that can be queried cheaply from then on. 128 self_process::self_process() : PageSize(getPageSize()) { 129 } 130 131 132 size_t Process::GetMallocUsage() { 133 #if defined(HAVE_MALLINFO) 134 struct mallinfo mi; 135 mi = ::mallinfo(); 136 return mi.uordblks; 137 #elif defined(HAVE_MALLOC_ZONE_STATISTICS) && defined(HAVE_MALLOC_MALLOC_H) 138 malloc_statistics_t Stats; 139 malloc_zone_statistics(malloc_default_zone(), &Stats); 140 return Stats.size_in_use; // darwin 141 #elif defined(HAVE_SBRK) 142 // Note this is only an approximation and more closely resembles 143 // the value returned by mallinfo in the arena field. 144 static char *StartOfMemory = reinterpret_cast<char*>(::sbrk(0)); 145 char *EndOfMemory = (char*)sbrk(0); 146 if (EndOfMemory != ((char*)-1) && StartOfMemory != ((char*)-1)) 147 return EndOfMemory - StartOfMemory; 148 else 149 return 0; 150 #else 151 #warning Cannot get malloc info on this platform 152 return 0; 153 #endif 154 } 155 156 void Process::GetTimeUsage(TimeValue &elapsed, TimeValue &user_time, 157 TimeValue &sys_time) { 158 elapsed = TimeValue::now(); 159 llvm::tie(user_time, sys_time) = getRUsageTimes(); 160 } 161 162 int Process::GetCurrentUserId() { 163 return getuid(); 164 } 165 166 int Process::GetCurrentGroupId() { 167 return getgid(); 168 } 169 170 #if defined(HAVE_MACH_MACH_H) && !defined(__GNU__) 171 #include <mach/mach.h> 172 #endif 173 174 // Some LLVM programs such as bugpoint produce core files as a normal part of 175 // their operation. To prevent the disk from filling up, this function 176 // does what's necessary to prevent their generation. 177 void Process::PreventCoreFiles() { 178 #if HAVE_SETRLIMIT 179 struct rlimit rlim; 180 rlim.rlim_cur = rlim.rlim_max = 0; 181 setrlimit(RLIMIT_CORE, &rlim); 182 #endif 183 184 #if defined(HAVE_MACH_MACH_H) && !defined(__GNU__) 185 // Disable crash reporting on Mac OS X 10.0-10.4 186 187 // get information about the original set of exception ports for the task 188 mach_msg_type_number_t Count = 0; 189 exception_mask_t OriginalMasks[EXC_TYPES_COUNT]; 190 exception_port_t OriginalPorts[EXC_TYPES_COUNT]; 191 exception_behavior_t OriginalBehaviors[EXC_TYPES_COUNT]; 192 thread_state_flavor_t OriginalFlavors[EXC_TYPES_COUNT]; 193 kern_return_t err = 194 task_get_exception_ports(mach_task_self(), EXC_MASK_ALL, OriginalMasks, 195 &Count, OriginalPorts, OriginalBehaviors, 196 OriginalFlavors); 197 if (err == KERN_SUCCESS) { 198 // replace each with MACH_PORT_NULL. 199 for (unsigned i = 0; i != Count; ++i) 200 task_set_exception_ports(mach_task_self(), OriginalMasks[i], 201 MACH_PORT_NULL, OriginalBehaviors[i], 202 OriginalFlavors[i]); 203 } 204 205 // Disable crash reporting on Mac OS X 10.5 206 signal(SIGABRT, _exit); 207 signal(SIGILL, _exit); 208 signal(SIGFPE, _exit); 209 signal(SIGSEGV, _exit); 210 signal(SIGBUS, _exit); 211 #endif 212 } 213 214 bool Process::StandardInIsUserInput() { 215 return FileDescriptorIsDisplayed(STDIN_FILENO); 216 } 217 218 bool Process::StandardOutIsDisplayed() { 219 return FileDescriptorIsDisplayed(STDOUT_FILENO); 220 } 221 222 bool Process::StandardErrIsDisplayed() { 223 return FileDescriptorIsDisplayed(STDERR_FILENO); 224 } 225 226 bool Process::FileDescriptorIsDisplayed(int fd) { 227 #if HAVE_ISATTY 228 return isatty(fd); 229 #else 230 // If we don't have isatty, just return false. 231 return false; 232 #endif 233 } 234 235 static unsigned getColumns(int FileID) { 236 // If COLUMNS is defined in the environment, wrap to that many columns. 237 if (const char *ColumnsStr = std::getenv("COLUMNS")) { 238 int Columns = std::atoi(ColumnsStr); 239 if (Columns > 0) 240 return Columns; 241 } 242 243 unsigned Columns = 0; 244 245 #if defined(HAVE_SYS_IOCTL_H) && defined(HAVE_TERMIOS_H) 246 // Try to determine the width of the terminal. 247 struct winsize ws; 248 if (ioctl(FileID, TIOCGWINSZ, &ws) == 0) 249 Columns = ws.ws_col; 250 #endif 251 252 return Columns; 253 } 254 255 unsigned Process::StandardOutColumns() { 256 if (!StandardOutIsDisplayed()) 257 return 0; 258 259 return getColumns(1); 260 } 261 262 unsigned Process::StandardErrColumns() { 263 if (!StandardErrIsDisplayed()) 264 return 0; 265 266 return getColumns(2); 267 } 268 269 static bool terminalHasColors(int fd) { 270 #ifdef HAVE_CURSES 271 // First, acquire a global lock because the curses C routines are thread 272 // hostile. 273 static sys::Mutex M; 274 MutexGuard G(M); 275 276 int errret = 0; 277 if (setupterm((char *)0, fd, &errret) != OK) 278 // Regardless of why, if we can't get terminfo, we shouldn't try to print 279 // colors. 280 return false; 281 282 // Test whether the terminal as set up supports color output. 283 if (has_colors() == TRUE) 284 return true; 285 #endif 286 287 // Otherwise, be conservative. 288 return false; 289 } 290 291 bool 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 297 bool Process::StandardOutHasColors() { 298 return FileDescriptorHasColors(STDOUT_FILENO); 299 } 300 301 bool Process::StandardErrHasColors() { 302 return FileDescriptorHasColors(STDERR_FILENO); 303 } 304 305 bool 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 323 static const char colorcodes[2][2][8][10] = { 324 { ALLCOLORS("3",""), ALLCOLORS("3","1;") }, 325 { ALLCOLORS("4",""), ALLCOLORS("4","1;") } 326 }; 327 328 const char *Process::OutputColor(char code, bool bold, bool bg) { 329 return colorcodes[bg?1:0][bold?1:0][code&7]; 330 } 331 332 const char *Process::OutputBold(bool bg) { 333 return "\033[1m"; 334 } 335 336 const char *Process::OutputReverse() { 337 return "\033[7m"; 338 } 339 340 const char *Process::ResetColor() { 341 return "\033[0m"; 342 } 343 344 #if !defined(HAVE_ARC4RANDOM) 345 static 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 364 unsigned 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