Home | History | Annotate | Download | only in Unix
      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