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 143#if defined(HAVE_MACH_MACH_H) && !defined(__GNU__) 144#include <mach/mach.h> 145#endif 146 147// Some LLVM programs such as bugpoint produce core files as a normal part of 148// their operation. To prevent the disk from filling up, this function 149// does what's necessary to prevent their generation. 150void Process::PreventCoreFiles() { 151#if HAVE_SETRLIMIT 152 struct rlimit rlim; 153 rlim.rlim_cur = rlim.rlim_max = 0; 154 setrlimit(RLIMIT_CORE, &rlim); 155#endif 156 157#if defined(HAVE_MACH_MACH_H) && !defined(__GNU__) 158 // Disable crash reporting on Mac OS X 10.0-10.4 159 160 // get information about the original set of exception ports for the task 161 mach_msg_type_number_t Count = 0; 162 exception_mask_t OriginalMasks[EXC_TYPES_COUNT]; 163 exception_port_t OriginalPorts[EXC_TYPES_COUNT]; 164 exception_behavior_t OriginalBehaviors[EXC_TYPES_COUNT]; 165 thread_state_flavor_t OriginalFlavors[EXC_TYPES_COUNT]; 166 kern_return_t err = 167 task_get_exception_ports(mach_task_self(), EXC_MASK_ALL, OriginalMasks, 168 &Count, OriginalPorts, OriginalBehaviors, 169 OriginalFlavors); 170 if (err == KERN_SUCCESS) { 171 // replace each with MACH_PORT_NULL. 172 for (unsigned i = 0; i != Count; ++i) 173 task_set_exception_ports(mach_task_self(), OriginalMasks[i], 174 MACH_PORT_NULL, OriginalBehaviors[i], 175 OriginalFlavors[i]); 176 } 177 178 // Disable crash reporting on Mac OS X 10.5 179 signal(SIGABRT, _exit); 180 signal(SIGILL, _exit); 181 signal(SIGFPE, _exit); 182 signal(SIGSEGV, _exit); 183 signal(SIGBUS, _exit); 184#endif 185} 186 187bool Process::StandardInIsUserInput() { 188 return FileDescriptorIsDisplayed(STDIN_FILENO); 189} 190 191bool Process::StandardOutIsDisplayed() { 192 return FileDescriptorIsDisplayed(STDOUT_FILENO); 193} 194 195bool Process::StandardErrIsDisplayed() { 196 return FileDescriptorIsDisplayed(STDERR_FILENO); 197} 198 199bool Process::FileDescriptorIsDisplayed(int fd) { 200#if HAVE_ISATTY 201 return isatty(fd); 202#else 203 // If we don't have isatty, just return false. 204 return false; 205#endif 206} 207 208static unsigned getColumns(int FileID) { 209 // If COLUMNS is defined in the environment, wrap to that many columns. 210 if (const char *ColumnsStr = std::getenv("COLUMNS")) { 211 int Columns = std::atoi(ColumnsStr); 212 if (Columns > 0) 213 return Columns; 214 } 215 216 unsigned Columns = 0; 217 218#if defined(HAVE_SYS_IOCTL_H) && defined(HAVE_TERMIOS_H) 219 // Try to determine the width of the terminal. 220 struct winsize ws; 221 if (ioctl(FileID, TIOCGWINSZ, &ws) == 0) 222 Columns = ws.ws_col; 223#endif 224 225 return Columns; 226} 227 228unsigned Process::StandardOutColumns() { 229 if (!StandardOutIsDisplayed()) 230 return 0; 231 232 return getColumns(1); 233} 234 235unsigned Process::StandardErrColumns() { 236 if (!StandardErrIsDisplayed()) 237 return 0; 238 239 return getColumns(2); 240} 241 242#ifdef HAVE_TERMINFO 243// We manually declare these two extern functions because finding the correct 244// headers from various terminfo, curses, or other sources is harder than 245// writing their specs down. 246extern "C" int setupterm(char *term, int filedes, int *errret); 247extern "C" int tigetnum(char *capname); 248#endif 249 250static bool terminalHasColors(int fd) { 251#ifdef HAVE_TERMINFO 252 // First, acquire a global lock because these C routines are thread hostile. 253 static sys::Mutex M; 254 MutexGuard G(M); 255 256 int errret = 0; 257 if (setupterm((char *)0, fd, &errret) != 0) 258 // Regardless of why, if we can't get terminfo, we shouldn't try to print 259 // colors. 260 return false; 261 262 // Test whether the terminal as set up supports color output. How to do this 263 // isn't entirely obvious. We can use the curses routine 'has_colors' but it 264 // would be nice to avoid a dependency on curses proper when we can make do 265 // with a minimal terminfo parsing library. Also, we don't really care whether 266 // the terminal supports the curses-specific color changing routines, merely 267 // if it will interpret ANSI color escape codes in a reasonable way. Thus, the 268 // strategy here is just to query the baseline colors capability and if it 269 // supports colors at all to assume it will translate the escape codes into 270 // whatever range of colors it does support. We can add more detailed tests 271 // here if users report them as necessary. 272 // 273 // The 'tigetnum' routine returns -2 or -1 on errors, and might return 0 if 274 // the terminfo says that no colors are supported. 275 if (tigetnum(const_cast<char *>("colors")) > 0) 276 return true; 277#endif 278 279 // Otherwise, be conservative. 280 return false; 281} 282 283bool Process::FileDescriptorHasColors(int fd) { 284 // A file descriptor has colors if it is displayed and the terminal has 285 // colors. 286 return FileDescriptorIsDisplayed(fd) && terminalHasColors(fd); 287} 288 289bool Process::StandardOutHasColors() { 290 return FileDescriptorHasColors(STDOUT_FILENO); 291} 292 293bool Process::StandardErrHasColors() { 294 return FileDescriptorHasColors(STDERR_FILENO); 295} 296 297bool Process::ColorNeedsFlush() { 298 // No, we use ANSI escape sequences. 299 return false; 300} 301 302#define COLOR(FGBG, CODE, BOLD) "\033[0;" BOLD FGBG CODE "m" 303 304#define ALLCOLORS(FGBG,BOLD) {\ 305 COLOR(FGBG, "0", BOLD),\ 306 COLOR(FGBG, "1", BOLD),\ 307 COLOR(FGBG, "2", BOLD),\ 308 COLOR(FGBG, "3", BOLD),\ 309 COLOR(FGBG, "4", BOLD),\ 310 COLOR(FGBG, "5", BOLD),\ 311 COLOR(FGBG, "6", BOLD),\ 312 COLOR(FGBG, "7", BOLD)\ 313 } 314 315static const char colorcodes[2][2][8][10] = { 316 { ALLCOLORS("3",""), ALLCOLORS("3","1;") }, 317 { ALLCOLORS("4",""), ALLCOLORS("4","1;") } 318}; 319 320const char *Process::OutputColor(char code, bool bold, bool bg) { 321 return colorcodes[bg?1:0][bold?1:0][code&7]; 322} 323 324const char *Process::OutputBold(bool bg) { 325 return "\033[1m"; 326} 327 328const char *Process::OutputReverse() { 329 return "\033[7m"; 330} 331 332const char *Process::ResetColor() { 333 return "\033[0m"; 334} 335 336#if !defined(HAVE_ARC4RANDOM) 337static unsigned GetRandomNumberSeed() { 338 // Attempt to get the initial seed from /dev/urandom, if possible. 339 if (FILE *RandomSource = ::fopen("/dev/urandom", "r")) { 340 unsigned seed; 341 int count = ::fread((void *)&seed, sizeof(seed), 1, RandomSource); 342 ::fclose(RandomSource); 343 344 // Return the seed if the read was successful. 345 if (count == 1) 346 return seed; 347 } 348 349 // Otherwise, swizzle the current time and the process ID to form a reasonable 350 // seed. 351 TimeValue Now = TimeValue::now(); 352 return hash_combine(Now.seconds(), Now.nanoseconds(), ::getpid()); 353} 354#endif 355 356unsigned llvm::sys::Process::GetRandomNumber() { 357#if defined(HAVE_ARC4RANDOM) 358 return arc4random(); 359#else 360 static int x = (::srand(GetRandomNumberSeed()), 0); 361 (void)x; 362 return ::rand(); 363#endif 364} 365