Process.inc revision 239462
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 47218885Sdimunsigned 48218885SdimProcess::GetPageSize() 49218885Sdim{ 50218885Sdim#if defined(__CYGWIN__) 51218885Sdim // On Cygwin, getpagesize() returns 64k but the page size for the purposes of 52218885Sdim // memory protection and mmap() is 4k. 53218885Sdim // See http://www.cygwin.com/ml/cygwin/2009-01/threads.html#00492 54218885Sdim const int page_size = 0x1000; 55218885Sdim#elif defined(HAVE_GETPAGESIZE) 56218885Sdim const int page_size = ::getpagesize(); 57218885Sdim#elif defined(HAVE_SYSCONF) 58218885Sdim long page_size = ::sysconf(_SC_PAGE_SIZE); 59218885Sdim#else 60218885Sdim#warning Cannot get the page size on this machine 61218885Sdim#endif 62218885Sdim return static_cast<unsigned>(page_size); 63218885Sdim} 64218885Sdim 65218885Sdimsize_t Process::GetMallocUsage() { 66218885Sdim#if defined(HAVE_MALLINFO) 67218885Sdim struct mallinfo mi; 68218885Sdim mi = ::mallinfo(); 69218885Sdim return mi.uordblks; 70218885Sdim#elif defined(HAVE_MALLOC_ZONE_STATISTICS) && defined(HAVE_MALLOC_MALLOC_H) 71218885Sdim malloc_statistics_t Stats; 72218885Sdim malloc_zone_statistics(malloc_default_zone(), &Stats); 73218885Sdim return Stats.size_in_use; // darwin 74218885Sdim#elif defined(HAVE_SBRK) 75218885Sdim // Note this is only an approximation and more closely resembles 76218885Sdim // the value returned by mallinfo in the arena field. 77218885Sdim static char *StartOfMemory = reinterpret_cast<char*>(::sbrk(0)); 78218885Sdim char *EndOfMemory = (char*)sbrk(0); 79218885Sdim if (EndOfMemory != ((char*)-1) && StartOfMemory != ((char*)-1)) 80218885Sdim return EndOfMemory - StartOfMemory; 81218885Sdim else 82218885Sdim return 0; 83218885Sdim#else 84218885Sdim#warning Cannot get malloc info on this platform 85218885Sdim return 0; 86218885Sdim#endif 87218885Sdim} 88218885Sdim 89218885Sdimsize_t 90218885SdimProcess::GetTotalMemoryUsage() 91218885Sdim{ 92218885Sdim#if defined(HAVE_MALLINFO) 93218885Sdim struct mallinfo mi = ::mallinfo(); 94218885Sdim return mi.uordblks + mi.hblkhd; 95218885Sdim#elif defined(HAVE_MALLOC_ZONE_STATISTICS) && defined(HAVE_MALLOC_MALLOC_H) 96218885Sdim malloc_statistics_t Stats; 97218885Sdim malloc_zone_statistics(malloc_default_zone(), &Stats); 98218885Sdim return Stats.size_allocated; // darwin 99218885Sdim#elif defined(HAVE_GETRUSAGE) && !defined(__HAIKU__) 100218885Sdim struct rusage usage; 101218885Sdim ::getrusage(RUSAGE_SELF, &usage); 102218885Sdim return usage.ru_maxrss; 103218885Sdim#else 104218885Sdim#warning Cannot get total memory size on this platform 105218885Sdim return 0; 106218885Sdim#endif 107218885Sdim} 108218885Sdim 109218885Sdimvoid 110218885SdimProcess::GetTimeUsage(TimeValue& elapsed, TimeValue& user_time, 111218885Sdim TimeValue& sys_time) 112218885Sdim{ 113218885Sdim elapsed = TimeValue::now(); 114218885Sdim#if defined(HAVE_GETRUSAGE) 115218885Sdim struct rusage usage; 116218885Sdim ::getrusage(RUSAGE_SELF, &usage); 117218885Sdim user_time = TimeValue( 118218885Sdim static_cast<TimeValue::SecondsType>( usage.ru_utime.tv_sec ), 119218885Sdim static_cast<TimeValue::NanoSecondsType>( usage.ru_utime.tv_usec * 120218885Sdim TimeValue::NANOSECONDS_PER_MICROSECOND ) ); 121218885Sdim sys_time = TimeValue( 122218885Sdim static_cast<TimeValue::SecondsType>( usage.ru_stime.tv_sec ), 123218885Sdim static_cast<TimeValue::NanoSecondsType>( usage.ru_stime.tv_usec * 124218885Sdim TimeValue::NANOSECONDS_PER_MICROSECOND ) ); 125218885Sdim#else 126218885Sdim#warning Cannot get usage times on this platform 127218885Sdim user_time.seconds(0); 128218885Sdim user_time.microseconds(0); 129218885Sdim sys_time.seconds(0); 130218885Sdim sys_time.microseconds(0); 131218885Sdim#endif 132218885Sdim} 133218885Sdim 134218885Sdimint Process::GetCurrentUserId() { 135218885Sdim return getuid(); 136218885Sdim} 137218885Sdim 138218885Sdimint Process::GetCurrentGroupId() { 139218885Sdim return getgid(); 140218885Sdim} 141218885Sdim 142234353Sdim#if defined(HAVE_MACH_MACH_H) && !defined(__GNU__) 143218885Sdim#include <mach/mach.h> 144218885Sdim#endif 145218885Sdim 146218885Sdim// Some LLVM programs such as bugpoint produce core files as a normal part of 147218885Sdim// their operation. To prevent the disk from filling up, this function 148218885Sdim// does what's necessary to prevent their generation. 149218885Sdimvoid Process::PreventCoreFiles() { 150218885Sdim#if HAVE_SETRLIMIT 151218885Sdim struct rlimit rlim; 152218885Sdim rlim.rlim_cur = rlim.rlim_max = 0; 153218885Sdim setrlimit(RLIMIT_CORE, &rlim); 154218885Sdim#endif 155218885Sdim 156234353Sdim#if defined(HAVE_MACH_MACH_H) && !defined(__GNU__) 157218885Sdim // Disable crash reporting on Mac OS X 10.0-10.4 158218885Sdim 159218885Sdim // get information about the original set of exception ports for the task 160218885Sdim mach_msg_type_number_t Count = 0; 161218885Sdim exception_mask_t OriginalMasks[EXC_TYPES_COUNT]; 162218885Sdim exception_port_t OriginalPorts[EXC_TYPES_COUNT]; 163218885Sdim exception_behavior_t OriginalBehaviors[EXC_TYPES_COUNT]; 164218885Sdim thread_state_flavor_t OriginalFlavors[EXC_TYPES_COUNT]; 165218885Sdim kern_return_t err = 166218885Sdim task_get_exception_ports(mach_task_self(), EXC_MASK_ALL, OriginalMasks, 167218885Sdim &Count, OriginalPorts, OriginalBehaviors, 168218885Sdim OriginalFlavors); 169218885Sdim if (err == KERN_SUCCESS) { 170218885Sdim // replace each with MACH_PORT_NULL. 171218885Sdim for (unsigned i = 0; i != Count; ++i) 172218885Sdim task_set_exception_ports(mach_task_self(), OriginalMasks[i], 173218885Sdim MACH_PORT_NULL, OriginalBehaviors[i], 174218885Sdim OriginalFlavors[i]); 175218885Sdim } 176218885Sdim 177218885Sdim // Disable crash reporting on Mac OS X 10.5 178218885Sdim signal(SIGABRT, _exit); 179218885Sdim signal(SIGILL, _exit); 180218885Sdim signal(SIGFPE, _exit); 181218885Sdim signal(SIGSEGV, _exit); 182218885Sdim signal(SIGBUS, _exit); 183218885Sdim#endif 184218885Sdim} 185218885Sdim 186218885Sdimbool Process::StandardInIsUserInput() { 187218885Sdim return FileDescriptorIsDisplayed(STDIN_FILENO); 188218885Sdim} 189218885Sdim 190218885Sdimbool Process::StandardOutIsDisplayed() { 191218885Sdim return FileDescriptorIsDisplayed(STDOUT_FILENO); 192218885Sdim} 193218885Sdim 194218885Sdimbool Process::StandardErrIsDisplayed() { 195218885Sdim return FileDescriptorIsDisplayed(STDERR_FILENO); 196218885Sdim} 197218885Sdim 198218885Sdimbool Process::FileDescriptorIsDisplayed(int fd) { 199218885Sdim#if HAVE_ISATTY 200218885Sdim return isatty(fd); 201218885Sdim#else 202218885Sdim // If we don't have isatty, just return false. 203218885Sdim return false; 204218885Sdim#endif 205218885Sdim} 206218885Sdim 207218885Sdimstatic unsigned getColumns(int FileID) { 208218885Sdim // If COLUMNS is defined in the environment, wrap to that many columns. 209218885Sdim if (const char *ColumnsStr = std::getenv("COLUMNS")) { 210218885Sdim int Columns = std::atoi(ColumnsStr); 211218885Sdim if (Columns > 0) 212218885Sdim return Columns; 213218885Sdim } 214218885Sdim 215218885Sdim unsigned Columns = 0; 216218885Sdim 217218885Sdim#if defined(HAVE_SYS_IOCTL_H) && defined(HAVE_TERMIOS_H) 218218885Sdim // Try to determine the width of the terminal. 219218885Sdim struct winsize ws; 220218885Sdim if (ioctl(FileID, TIOCGWINSZ, &ws) == 0) 221218885Sdim Columns = ws.ws_col; 222218885Sdim#endif 223218885Sdim 224218885Sdim return Columns; 225218885Sdim} 226218885Sdim 227218885Sdimunsigned Process::StandardOutColumns() { 228218885Sdim if (!StandardOutIsDisplayed()) 229218885Sdim return 0; 230218885Sdim 231218885Sdim return getColumns(1); 232218885Sdim} 233218885Sdim 234218885Sdimunsigned Process::StandardErrColumns() { 235218885Sdim if (!StandardErrIsDisplayed()) 236218885Sdim return 0; 237218885Sdim 238218885Sdim return getColumns(2); 239218885Sdim} 240218885Sdim 241218885Sdimstatic bool terminalHasColors() { 242218885Sdim if (const char *term = std::getenv("TERM")) { 243218885Sdim // Most modern terminals support ANSI escape sequences for colors. 244218885Sdim // We could check terminfo, or have a list of known terms that support 245218885Sdim // colors, but that would be overkill. 246218885Sdim // The user can always ask for no colors by setting TERM to dumb, or 247218885Sdim // using a commandline flag. 248218885Sdim return strcmp(term, "dumb") != 0; 249218885Sdim } 250218885Sdim return false; 251218885Sdim} 252218885Sdim 253239462Sdimbool Process::FileDescriptorHasColors(int fd) { 254239462Sdim // A file descriptor has colors if it is displayed and the terminal has 255239462Sdim // colors. 256239462Sdim return FileDescriptorIsDisplayed(fd) && terminalHasColors(); 257239462Sdim} 258239462Sdim 259218885Sdimbool Process::StandardOutHasColors() { 260239462Sdim return FileDescriptorHasColors(STDOUT_FILENO); 261218885Sdim} 262218885Sdim 263218885Sdimbool Process::StandardErrHasColors() { 264239462Sdim return FileDescriptorHasColors(STDERR_FILENO); 265218885Sdim} 266218885Sdim 267218885Sdimbool Process::ColorNeedsFlush() { 268218885Sdim // No, we use ANSI escape sequences. 269218885Sdim return false; 270218885Sdim} 271218885Sdim 272218885Sdim#define COLOR(FGBG, CODE, BOLD) "\033[0;" BOLD FGBG CODE "m" 273218885Sdim 274218885Sdim#define ALLCOLORS(FGBG,BOLD) {\ 275218885Sdim COLOR(FGBG, "0", BOLD),\ 276218885Sdim COLOR(FGBG, "1", BOLD),\ 277218885Sdim COLOR(FGBG, "2", BOLD),\ 278218885Sdim COLOR(FGBG, "3", BOLD),\ 279218885Sdim COLOR(FGBG, "4", BOLD),\ 280218885Sdim COLOR(FGBG, "5", BOLD),\ 281218885Sdim COLOR(FGBG, "6", BOLD),\ 282218885Sdim COLOR(FGBG, "7", BOLD)\ 283218885Sdim } 284218885Sdim 285218885Sdimstatic const char colorcodes[2][2][8][10] = { 286218885Sdim { ALLCOLORS("3",""), ALLCOLORS("3","1;") }, 287218885Sdim { ALLCOLORS("4",""), ALLCOLORS("4","1;") } 288218885Sdim}; 289218885Sdim 290218885Sdimconst char *Process::OutputColor(char code, bool bold, bool bg) { 291218885Sdim return colorcodes[bg?1:0][bold?1:0][code&7]; 292218885Sdim} 293218885Sdim 294218885Sdimconst char *Process::OutputBold(bool bg) { 295218885Sdim return "\033[1m"; 296218885Sdim} 297218885Sdim 298234982Sdimconst char *Process::OutputReverse() { 299234982Sdim return "\033[7m"; 300234982Sdim} 301234982Sdim 302218885Sdimconst char *Process::ResetColor() { 303218885Sdim return "\033[0m"; 304218885Sdim} 305239462Sdim 306239462Sdim#if !defined(HAVE_ARC4RANDOM) 307239462Sdimstatic unsigned GetRandomNumberSeed() { 308239462Sdim // Attempt to get the initial seed from /dev/urandom, if possible. 309239462Sdim if (FILE *RandomSource = ::fopen("/dev/urandom", "r")) { 310239462Sdim unsigned seed; 311239462Sdim int count = ::fread((void *)&seed, sizeof(seed), 1, RandomSource); 312239462Sdim ::fclose(RandomSource); 313239462Sdim 314239462Sdim // Return the seed if the read was successful. 315239462Sdim if (count == 1) 316239462Sdim return seed; 317239462Sdim } 318239462Sdim 319239462Sdim // Otherwise, swizzle the current time and the process ID to form a reasonable 320239462Sdim // seed. 321239462Sdim TimeValue Now = llvm::TimeValue::now(); 322239462Sdim return hash_combine(Now.seconds(), Now.nanoseconds(), ::getpid()); 323239462Sdim} 324239462Sdim#endif 325239462Sdim 326239462Sdimunsigned llvm::sys::Process::GetRandomNumber() { 327239462Sdim#if defined(HAVE_ARC4RANDOM) 328239462Sdim return arc4random(); 329239462Sdim#else 330239462Sdim static int x = (::srand(GetRandomNumberSeed()), 0); 331239462Sdim (void)x; 332239462Sdim return ::rand(); 333239462Sdim#endif 334239462Sdim} 335