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 91// On Cygwin, getpagesize() returns 64k(AllocationGranularity) and 92// offset in mmap(3) should be aligned to the AllocationGranularity. 93static unsigned getPageSize() { 94#if defined(HAVE_GETPAGESIZE) 95 const int page_size = ::getpagesize(); 96#elif defined(HAVE_SYSCONF) 97 long page_size = ::sysconf(_SC_PAGE_SIZE); 98#else 99#warning Cannot get the page size on this machine 100#endif 101 return static_cast<unsigned>(page_size); 102} 103 104// This constructor guaranteed to be run exactly once on a single thread, and 105// sets up various process invariants that can be queried cheaply from then on. 106self_process::self_process() : PageSize(getPageSize()) { 107} 108 109 110size_t Process::GetMallocUsage() { 111#if defined(HAVE_MALLINFO) 112 struct mallinfo mi; 113 mi = ::mallinfo(); 114 return mi.uordblks; 115#elif defined(HAVE_MALLOC_ZONE_STATISTICS) && defined(HAVE_MALLOC_MALLOC_H) 116 malloc_statistics_t Stats; 117 malloc_zone_statistics(malloc_default_zone(), &Stats); 118 return Stats.size_in_use; // darwin 119#elif defined(HAVE_SBRK) 120 // Note this is only an approximation and more closely resembles 121 // the value returned by mallinfo in the arena field. 122 static char *StartOfMemory = reinterpret_cast<char*>(::sbrk(0)); 123 char *EndOfMemory = (char*)sbrk(0); 124 if (EndOfMemory != ((char*)-1) && StartOfMemory != ((char*)-1)) 125 return EndOfMemory - StartOfMemory; 126 else 127 return 0; 128#else 129#warning Cannot get malloc info on this platform 130 return 0; 131#endif 132} 133 134void Process::GetTimeUsage(TimeValue &elapsed, TimeValue &user_time, 135 TimeValue &sys_time) { 136 elapsed = TimeValue::now(); 137 llvm::tie(user_time, sys_time) = getRUsageTimes(); 138} 139 140#if defined(HAVE_MACH_MACH_H) && !defined(__GNU__) 141#include <mach/mach.h> 142#endif 143 144// Some LLVM programs such as bugpoint produce core files as a normal part of 145// their operation. To prevent the disk from filling up, this function 146// does what's necessary to prevent their generation. 147void Process::PreventCoreFiles() { 148#if HAVE_SETRLIMIT 149 struct rlimit rlim; 150 rlim.rlim_cur = rlim.rlim_max = 0; 151 setrlimit(RLIMIT_CORE, &rlim); 152#endif 153 154#if defined(HAVE_MACH_MACH_H) && !defined(__GNU__) 155 // Disable crash reporting on Mac OS X 10.0-10.4 156 157 // get information about the original set of exception ports for the task 158 mach_msg_type_number_t Count = 0; 159 exception_mask_t OriginalMasks[EXC_TYPES_COUNT]; 160 exception_port_t OriginalPorts[EXC_TYPES_COUNT]; 161 exception_behavior_t OriginalBehaviors[EXC_TYPES_COUNT]; 162 thread_state_flavor_t OriginalFlavors[EXC_TYPES_COUNT]; 163 kern_return_t err = 164 task_get_exception_ports(mach_task_self(), EXC_MASK_ALL, OriginalMasks, 165 &Count, OriginalPorts, OriginalBehaviors, 166 OriginalFlavors); 167 if (err == KERN_SUCCESS) { 168 // replace each with MACH_PORT_NULL. 169 for (unsigned i = 0; i != Count; ++i) 170 task_set_exception_ports(mach_task_self(), OriginalMasks[i], 171 MACH_PORT_NULL, OriginalBehaviors[i], 172 OriginalFlavors[i]); 173 } 174 175 // Disable crash reporting on Mac OS X 10.5 176 signal(SIGABRT, _exit); 177 signal(SIGILL, _exit); 178 signal(SIGFPE, _exit); 179 signal(SIGSEGV, _exit); 180 signal(SIGBUS, _exit); 181#endif 182} 183 184bool Process::StandardInIsUserInput() { 185 return FileDescriptorIsDisplayed(STDIN_FILENO); 186} 187 188bool Process::StandardOutIsDisplayed() { 189 return FileDescriptorIsDisplayed(STDOUT_FILENO); 190} 191 192bool Process::StandardErrIsDisplayed() { 193 return FileDescriptorIsDisplayed(STDERR_FILENO); 194} 195 196bool Process::FileDescriptorIsDisplayed(int fd) { 197#if HAVE_ISATTY 198 return isatty(fd); 199#else 200 // If we don't have isatty, just return false. 201 return false; 202#endif 203} 204 205static unsigned getColumns(int FileID) { 206 // If COLUMNS is defined in the environment, wrap to that many columns. 207 if (const char *ColumnsStr = std::getenv("COLUMNS")) { 208 int Columns = std::atoi(ColumnsStr); 209 if (Columns > 0) 210 return Columns; 211 } 212 213 unsigned Columns = 0; 214 215#if defined(HAVE_SYS_IOCTL_H) && defined(HAVE_TERMIOS_H) 216 // Try to determine the width of the terminal. 217 struct winsize ws; 218 if (ioctl(FileID, TIOCGWINSZ, &ws) == 0) 219 Columns = ws.ws_col; 220#endif 221 222 return Columns; 223} 224 225unsigned Process::StandardOutColumns() { 226 if (!StandardOutIsDisplayed()) 227 return 0; 228 229 return getColumns(1); 230} 231 232unsigned Process::StandardErrColumns() { 233 if (!StandardErrIsDisplayed()) 234 return 0; 235 236 return getColumns(2); 237} 238 239#ifdef HAVE_TERMINFO 240// We manually declare these extern functions because finding the correct 241// headers from various terminfo, curses, or other sources is harder than 242// writing their specs down. 243extern "C" int setupterm(char *term, int filedes, int *errret); 244extern "C" struct term *set_curterm(struct term *termp); 245extern "C" int del_curterm(struct term *termp); 246extern "C" int tigetnum(char *capname); 247#endif 248 249static bool terminalHasColors(int fd) { 250#ifdef HAVE_TERMINFO 251 // First, acquire a global lock because these C routines are thread hostile. 252 static sys::Mutex M; 253 MutexGuard G(M); 254 255 int errret = 0; 256 if (setupterm((char *)0, fd, &errret) != 0) 257 // Regardless of why, if we can't get terminfo, we shouldn't try to print 258 // colors. 259 return false; 260 261 // Test whether the terminal as set up supports color output. How to do this 262 // isn't entirely obvious. We can use the curses routine 'has_colors' but it 263 // would be nice to avoid a dependency on curses proper when we can make do 264 // with a minimal terminfo parsing library. Also, we don't really care whether 265 // the terminal supports the curses-specific color changing routines, merely 266 // if it will interpret ANSI color escape codes in a reasonable way. Thus, the 267 // strategy here is just to query the baseline colors capability and if it 268 // supports colors at all to assume it will translate the escape codes into 269 // whatever range of colors it does support. We can add more detailed tests 270 // here if users report them as necessary. 271 // 272 // The 'tigetnum' routine returns -2 or -1 on errors, and might return 0 if 273 // the terminfo says that no colors are supported. 274 bool HasColors = tigetnum(const_cast<char *>("colors")) > 0; 275 276 // Now extract the structure allocated by setupterm and free its memory 277 // through a really silly dance. 278 struct term *termp = set_curterm((struct term *)0); 279 (void)del_curterm(termp); // Drop any errors here. 280 281 // Return true if we found a color capabilities for the current terminal. 282 if (HasColors) 283 return true; 284#endif 285 286 // Otherwise, be conservative. 287 return false; 288} 289 290bool Process::FileDescriptorHasColors(int fd) { 291 // A file descriptor has colors if it is displayed and the terminal has 292 // colors. 293 return FileDescriptorIsDisplayed(fd) && terminalHasColors(fd); 294} 295 296bool Process::StandardOutHasColors() { 297 return FileDescriptorHasColors(STDOUT_FILENO); 298} 299 300bool Process::StandardErrHasColors() { 301 return FileDescriptorHasColors(STDERR_FILENO); 302} 303 304bool Process::ColorNeedsFlush() { 305 // No, we use ANSI escape sequences. 306 return false; 307} 308 309#define COLOR(FGBG, CODE, BOLD) "\033[0;" BOLD FGBG CODE "m" 310 311#define ALLCOLORS(FGBG,BOLD) {\ 312 COLOR(FGBG, "0", BOLD),\ 313 COLOR(FGBG, "1", BOLD),\ 314 COLOR(FGBG, "2", BOLD),\ 315 COLOR(FGBG, "3", BOLD),\ 316 COLOR(FGBG, "4", BOLD),\ 317 COLOR(FGBG, "5", BOLD),\ 318 COLOR(FGBG, "6", BOLD),\ 319 COLOR(FGBG, "7", BOLD)\ 320 } 321 322static const char colorcodes[2][2][8][10] = { 323 { ALLCOLORS("3",""), ALLCOLORS("3","1;") }, 324 { ALLCOLORS("4",""), ALLCOLORS("4","1;") } 325}; 326 327const char *Process::OutputColor(char code, bool bold, bool bg) { 328 return colorcodes[bg?1:0][bold?1:0][code&7]; 329} 330 331const char *Process::OutputBold(bool bg) { 332 return "\033[1m"; 333} 334 335const char *Process::OutputReverse() { 336 return "\033[7m"; 337} 338 339const char *Process::ResetColor() { 340 return "\033[0m"; 341} 342 343#if !defined(HAVE_ARC4RANDOM) 344static unsigned GetRandomNumberSeed() { 345 // Attempt to get the initial seed from /dev/urandom, if possible. 346 if (FILE *RandomSource = ::fopen("/dev/urandom", "r")) { 347 unsigned seed; 348 int count = ::fread((void *)&seed, sizeof(seed), 1, RandomSource); 349 ::fclose(RandomSource); 350 351 // Return the seed if the read was successful. 352 if (count == 1) 353 return seed; 354 } 355 356 // Otherwise, swizzle the current time and the process ID to form a reasonable 357 // seed. 358 TimeValue Now = TimeValue::now(); 359 return hash_combine(Now.seconds(), Now.nanoseconds(), ::getpid()); 360} 361#endif 362 363unsigned llvm::sys::Process::GetRandomNumber() { 364#if defined(HAVE_ARC4RANDOM) 365 return arc4random(); 366#else 367 static int x = (::srand(GetRandomNumberSeed()), 0); 368 (void)x; 369 return ::rand(); 370#endif 371} 372