1218885Sdim//===- Unix/Process.cpp - Unix Process Implementation --------- -*- C++ -*-===// 2218885Sdim// 3218885Sdim// The LLVM Compiler Infrastructure 4218885Sdim// 5218885Sdim// This file is distributed under the University of Illinois Open Source 6218885Sdim// License. See LICENSE.TXT for details. 7218885Sdim// 8218885Sdim//===----------------------------------------------------------------------===// 9218885Sdim// 10218885Sdim// This file provides the generic Unix implementation of the Process class. 11218885Sdim// 12218885Sdim//===----------------------------------------------------------------------===// 13218885Sdim 14218885Sdim#include "Unix.h" 15239462Sdim#include "llvm/ADT/Hashing.h" 16239462Sdim#include "llvm/Support/TimeValue.h" 17218885Sdim#ifdef HAVE_SYS_TIME_H 18218885Sdim#include <sys/time.h> 19218885Sdim#endif 20218885Sdim#ifdef HAVE_SYS_RESOURCE_H 21218885Sdim#include <sys/resource.h> 22218885Sdim#endif 23239462Sdim// DragonFlyBSD, OpenBSD, and Bitrig have deprecated <malloc.h> for 24239462Sdim// <stdlib.h> instead. Unix.h includes this for us already. 25239462Sdim#if defined(HAVE_MALLOC_H) && !defined(__DragonFly__) && \ 26239462Sdim !defined(__OpenBSD__) && !defined(__Bitrig__) 27218885Sdim#include <malloc.h> 28218885Sdim#endif 29218885Sdim#ifdef HAVE_MALLOC_MALLOC_H 30218885Sdim#include <malloc/malloc.h> 31218885Sdim#endif 32218885Sdim#ifdef HAVE_SYS_IOCTL_H 33218885Sdim# include <sys/ioctl.h> 34218885Sdim#endif 35218885Sdim#ifdef HAVE_TERMIOS_H 36218885Sdim# include <termios.h> 37218885Sdim#endif 38218885Sdim 39218885Sdim//===----------------------------------------------------------------------===// 40218885Sdim//=== WARNING: Implementation here must contain only generic UNIX code that 41218885Sdim//=== is guaranteed to work on *all* UNIX variants. 42218885Sdim//===----------------------------------------------------------------------===// 43218885Sdim 44218885Sdimusing namespace llvm; 45218885Sdimusing namespace sys; 46218885Sdim 47249423Sdim 48249423Sdimprocess::id_type self_process::get_id() { 49249423Sdim return getpid(); 50249423Sdim} 51249423Sdim 52249423Sdimstatic std::pair<TimeValue, TimeValue> getRUsageTimes() { 53249423Sdim#if defined(HAVE_GETRUSAGE) 54249423Sdim struct rusage RU; 55249423Sdim ::getrusage(RUSAGE_SELF, &RU); 56249423Sdim return std::make_pair( 57249423Sdim TimeValue( 58249423Sdim static_cast<TimeValue::SecondsType>(RU.ru_utime.tv_sec), 59249423Sdim static_cast<TimeValue::NanoSecondsType>( 60249423Sdim RU.ru_utime.tv_usec * TimeValue::NANOSECONDS_PER_MICROSECOND)), 61249423Sdim TimeValue( 62249423Sdim static_cast<TimeValue::SecondsType>(RU.ru_stime.tv_sec), 63249423Sdim static_cast<TimeValue::NanoSecondsType>( 64249423Sdim RU.ru_stime.tv_usec * TimeValue::NANOSECONDS_PER_MICROSECOND))); 65249423Sdim#else 66249423Sdim#warning Cannot get usage times on this platform 67249423Sdim return std::make_pair(TimeValue(), TimeValue()); 68249423Sdim#endif 69249423Sdim} 70249423Sdim 71249423SdimTimeValue self_process::get_user_time() const { 72249423Sdim#if _POSIX_TIMERS > 0 && _POSIX_CPUTIME > 0 73249423Sdim // Try to get a high resolution CPU timer. 74249423Sdim struct timespec TS; 75249423Sdim if (::clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &TS) == 0) 76249423Sdim return TimeValue(static_cast<TimeValue::SecondsType>(TS.tv_sec), 77249423Sdim static_cast<TimeValue::NanoSecondsType>(TS.tv_nsec)); 78249423Sdim#endif 79249423Sdim 80249423Sdim // Otherwise fall back to rusage based timing. 81249423Sdim return getRUsageTimes().first; 82249423Sdim} 83249423Sdim 84249423SdimTimeValue self_process::get_system_time() const { 85249423Sdim // We can only collect system time by inspecting the results of getrusage. 86249423Sdim return getRUsageTimes().second; 87249423Sdim} 88249423Sdim 89249423Sdimstatic unsigned getPageSize() { 90218885Sdim#if defined(__CYGWIN__) 91218885Sdim // On Cygwin, getpagesize() returns 64k but the page size for the purposes of 92218885Sdim // memory protection and mmap() is 4k. 93218885Sdim // See http://www.cygwin.com/ml/cygwin/2009-01/threads.html#00492 94218885Sdim const int page_size = 0x1000; 95218885Sdim#elif defined(HAVE_GETPAGESIZE) 96218885Sdim const int page_size = ::getpagesize(); 97218885Sdim#elif defined(HAVE_SYSCONF) 98218885Sdim long page_size = ::sysconf(_SC_PAGE_SIZE); 99218885Sdim#else 100218885Sdim#warning Cannot get the page size on this machine 101218885Sdim#endif 102218885Sdim return static_cast<unsigned>(page_size); 103218885Sdim} 104218885Sdim 105249423Sdim// This constructor guaranteed to be run exactly once on a single thread, and 106249423Sdim// sets up various process invariants that can be queried cheaply from then on. 107249423Sdimself_process::self_process() : PageSize(getPageSize()) { 108249423Sdim} 109249423Sdim 110249423Sdim 111218885Sdimsize_t Process::GetMallocUsage() { 112218885Sdim#if defined(HAVE_MALLINFO) 113218885Sdim struct mallinfo mi; 114218885Sdim mi = ::mallinfo(); 115218885Sdim return mi.uordblks; 116218885Sdim#elif defined(HAVE_MALLOC_ZONE_STATISTICS) && defined(HAVE_MALLOC_MALLOC_H) 117218885Sdim malloc_statistics_t Stats; 118218885Sdim malloc_zone_statistics(malloc_default_zone(), &Stats); 119218885Sdim return Stats.size_in_use; // darwin 120218885Sdim#elif defined(HAVE_SBRK) 121218885Sdim // Note this is only an approximation and more closely resembles 122218885Sdim // the value returned by mallinfo in the arena field. 123218885Sdim static char *StartOfMemory = reinterpret_cast<char*>(::sbrk(0)); 124218885Sdim char *EndOfMemory = (char*)sbrk(0); 125218885Sdim if (EndOfMemory != ((char*)-1) && StartOfMemory != ((char*)-1)) 126218885Sdim return EndOfMemory - StartOfMemory; 127218885Sdim else 128218885Sdim return 0; 129218885Sdim#else 130218885Sdim#warning Cannot get malloc info on this platform 131218885Sdim return 0; 132218885Sdim#endif 133218885Sdim} 134218885Sdim 135249423Sdimvoid Process::GetTimeUsage(TimeValue &elapsed, TimeValue &user_time, 136249423Sdim TimeValue &sys_time) { 137218885Sdim elapsed = TimeValue::now(); 138249423Sdim llvm::tie(user_time, sys_time) = getRUsageTimes(); 139218885Sdim} 140218885Sdim 141218885Sdimint Process::GetCurrentUserId() { 142218885Sdim return getuid(); 143218885Sdim} 144218885Sdim 145218885Sdimint Process::GetCurrentGroupId() { 146218885Sdim return getgid(); 147218885Sdim} 148218885Sdim 149234353Sdim#if defined(HAVE_MACH_MACH_H) && !defined(__GNU__) 150218885Sdim#include <mach/mach.h> 151218885Sdim#endif 152218885Sdim 153218885Sdim// Some LLVM programs such as bugpoint produce core files as a normal part of 154218885Sdim// their operation. To prevent the disk from filling up, this function 155218885Sdim// does what's necessary to prevent their generation. 156218885Sdimvoid Process::PreventCoreFiles() { 157218885Sdim#if HAVE_SETRLIMIT 158218885Sdim struct rlimit rlim; 159218885Sdim rlim.rlim_cur = rlim.rlim_max = 0; 160218885Sdim setrlimit(RLIMIT_CORE, &rlim); 161218885Sdim#endif 162218885Sdim 163234353Sdim#if defined(HAVE_MACH_MACH_H) && !defined(__GNU__) 164218885Sdim // Disable crash reporting on Mac OS X 10.0-10.4 165218885Sdim 166218885Sdim // get information about the original set of exception ports for the task 167218885Sdim mach_msg_type_number_t Count = 0; 168218885Sdim exception_mask_t OriginalMasks[EXC_TYPES_COUNT]; 169218885Sdim exception_port_t OriginalPorts[EXC_TYPES_COUNT]; 170218885Sdim exception_behavior_t OriginalBehaviors[EXC_TYPES_COUNT]; 171218885Sdim thread_state_flavor_t OriginalFlavors[EXC_TYPES_COUNT]; 172218885Sdim kern_return_t err = 173218885Sdim task_get_exception_ports(mach_task_self(), EXC_MASK_ALL, OriginalMasks, 174218885Sdim &Count, OriginalPorts, OriginalBehaviors, 175218885Sdim OriginalFlavors); 176218885Sdim if (err == KERN_SUCCESS) { 177218885Sdim // replace each with MACH_PORT_NULL. 178218885Sdim for (unsigned i = 0; i != Count; ++i) 179218885Sdim task_set_exception_ports(mach_task_self(), OriginalMasks[i], 180218885Sdim MACH_PORT_NULL, OriginalBehaviors[i], 181218885Sdim OriginalFlavors[i]); 182218885Sdim } 183218885Sdim 184218885Sdim // Disable crash reporting on Mac OS X 10.5 185218885Sdim signal(SIGABRT, _exit); 186218885Sdim signal(SIGILL, _exit); 187218885Sdim signal(SIGFPE, _exit); 188218885Sdim signal(SIGSEGV, _exit); 189218885Sdim signal(SIGBUS, _exit); 190218885Sdim#endif 191218885Sdim} 192218885Sdim 193218885Sdimbool Process::StandardInIsUserInput() { 194218885Sdim return FileDescriptorIsDisplayed(STDIN_FILENO); 195218885Sdim} 196218885Sdim 197218885Sdimbool Process::StandardOutIsDisplayed() { 198218885Sdim return FileDescriptorIsDisplayed(STDOUT_FILENO); 199218885Sdim} 200218885Sdim 201218885Sdimbool Process::StandardErrIsDisplayed() { 202218885Sdim return FileDescriptorIsDisplayed(STDERR_FILENO); 203218885Sdim} 204218885Sdim 205218885Sdimbool Process::FileDescriptorIsDisplayed(int fd) { 206218885Sdim#if HAVE_ISATTY 207218885Sdim return isatty(fd); 208218885Sdim#else 209218885Sdim // If we don't have isatty, just return false. 210218885Sdim return false; 211218885Sdim#endif 212218885Sdim} 213218885Sdim 214218885Sdimstatic unsigned getColumns(int FileID) { 215218885Sdim // If COLUMNS is defined in the environment, wrap to that many columns. 216218885Sdim if (const char *ColumnsStr = std::getenv("COLUMNS")) { 217218885Sdim int Columns = std::atoi(ColumnsStr); 218218885Sdim if (Columns > 0) 219218885Sdim return Columns; 220218885Sdim } 221218885Sdim 222218885Sdim unsigned Columns = 0; 223218885Sdim 224218885Sdim#if defined(HAVE_SYS_IOCTL_H) && defined(HAVE_TERMIOS_H) 225218885Sdim // Try to determine the width of the terminal. 226218885Sdim struct winsize ws; 227249423Sdim // Zero-fill ws to avoid a false positive from MemorySanitizer. 228249423Sdim memset(&ws, 0, sizeof(ws)); 229218885Sdim if (ioctl(FileID, TIOCGWINSZ, &ws) == 0) 230218885Sdim Columns = ws.ws_col; 231218885Sdim#endif 232218885Sdim 233218885Sdim return Columns; 234218885Sdim} 235218885Sdim 236218885Sdimunsigned Process::StandardOutColumns() { 237218885Sdim if (!StandardOutIsDisplayed()) 238218885Sdim return 0; 239218885Sdim 240218885Sdim return getColumns(1); 241218885Sdim} 242218885Sdim 243218885Sdimunsigned Process::StandardErrColumns() { 244218885Sdim if (!StandardErrIsDisplayed()) 245218885Sdim return 0; 246218885Sdim 247218885Sdim return getColumns(2); 248218885Sdim} 249218885Sdim 250218885Sdimstatic bool terminalHasColors() { 251218885Sdim if (const char *term = std::getenv("TERM")) { 252218885Sdim // Most modern terminals support ANSI escape sequences for colors. 253218885Sdim // We could check terminfo, or have a list of known terms that support 254218885Sdim // colors, but that would be overkill. 255218885Sdim // The user can always ask for no colors by setting TERM to dumb, or 256218885Sdim // using a commandline flag. 257218885Sdim return strcmp(term, "dumb") != 0; 258218885Sdim } 259218885Sdim return false; 260218885Sdim} 261218885Sdim 262239462Sdimbool Process::FileDescriptorHasColors(int fd) { 263239462Sdim // A file descriptor has colors if it is displayed and the terminal has 264239462Sdim // colors. 265239462Sdim return FileDescriptorIsDisplayed(fd) && terminalHasColors(); 266239462Sdim} 267239462Sdim 268218885Sdimbool Process::StandardOutHasColors() { 269239462Sdim return FileDescriptorHasColors(STDOUT_FILENO); 270218885Sdim} 271218885Sdim 272218885Sdimbool Process::StandardErrHasColors() { 273239462Sdim return FileDescriptorHasColors(STDERR_FILENO); 274218885Sdim} 275218885Sdim 276218885Sdimbool Process::ColorNeedsFlush() { 277218885Sdim // No, we use ANSI escape sequences. 278218885Sdim return false; 279218885Sdim} 280218885Sdim 281218885Sdim#define COLOR(FGBG, CODE, BOLD) "\033[0;" BOLD FGBG CODE "m" 282218885Sdim 283218885Sdim#define ALLCOLORS(FGBG,BOLD) {\ 284218885Sdim COLOR(FGBG, "0", BOLD),\ 285218885Sdim COLOR(FGBG, "1", BOLD),\ 286218885Sdim COLOR(FGBG, "2", BOLD),\ 287218885Sdim COLOR(FGBG, "3", BOLD),\ 288218885Sdim COLOR(FGBG, "4", BOLD),\ 289218885Sdim COLOR(FGBG, "5", BOLD),\ 290218885Sdim COLOR(FGBG, "6", BOLD),\ 291218885Sdim COLOR(FGBG, "7", BOLD)\ 292218885Sdim } 293218885Sdim 294218885Sdimstatic const char colorcodes[2][2][8][10] = { 295218885Sdim { ALLCOLORS("3",""), ALLCOLORS("3","1;") }, 296218885Sdim { ALLCOLORS("4",""), ALLCOLORS("4","1;") } 297218885Sdim}; 298218885Sdim 299218885Sdimconst char *Process::OutputColor(char code, bool bold, bool bg) { 300218885Sdim return colorcodes[bg?1:0][bold?1:0][code&7]; 301218885Sdim} 302218885Sdim 303218885Sdimconst char *Process::OutputBold(bool bg) { 304218885Sdim return "\033[1m"; 305218885Sdim} 306218885Sdim 307234982Sdimconst char *Process::OutputReverse() { 308234982Sdim return "\033[7m"; 309234982Sdim} 310234982Sdim 311218885Sdimconst char *Process::ResetColor() { 312218885Sdim return "\033[0m"; 313218885Sdim} 314239462Sdim 315239462Sdim#if !defined(HAVE_ARC4RANDOM) 316239462Sdimstatic unsigned GetRandomNumberSeed() { 317239462Sdim // Attempt to get the initial seed from /dev/urandom, if possible. 318239462Sdim if (FILE *RandomSource = ::fopen("/dev/urandom", "r")) { 319239462Sdim unsigned seed; 320239462Sdim int count = ::fread((void *)&seed, sizeof(seed), 1, RandomSource); 321239462Sdim ::fclose(RandomSource); 322239462Sdim 323239462Sdim // Return the seed if the read was successful. 324239462Sdim if (count == 1) 325239462Sdim return seed; 326239462Sdim } 327239462Sdim 328239462Sdim // Otherwise, swizzle the current time and the process ID to form a reasonable 329239462Sdim // seed. 330249423Sdim TimeValue Now = TimeValue::now(); 331239462Sdim return hash_combine(Now.seconds(), Now.nanoseconds(), ::getpid()); 332239462Sdim} 333239462Sdim#endif 334239462Sdim 335239462Sdimunsigned llvm::sys::Process::GetRandomNumber() { 336239462Sdim#if defined(HAVE_ARC4RANDOM) 337239462Sdim return arc4random(); 338239462Sdim#else 339239462Sdim static int x = (::srand(GetRandomNumberSeed()), 0); 340239462Sdim (void)x; 341239462Sdim return ::rand(); 342239462Sdim#endif 343239462Sdim} 344