Process.inc revision 234982
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" 15218885Sdim#ifdef HAVE_SYS_TIME_H 16218885Sdim#include <sys/time.h> 17218885Sdim#endif 18218885Sdim#ifdef HAVE_SYS_RESOURCE_H 19218885Sdim#include <sys/resource.h> 20218885Sdim#endif 21218885Sdim// DragonFly BSD has deprecated <malloc.h> for <stdlib.h> instead, 22218885Sdim// Unix.h includes this for us already. 23218885Sdim#if defined(HAVE_MALLOC_H) && !defined(__DragonFly__) 24218885Sdim#include <malloc.h> 25218885Sdim#endif 26218885Sdim#ifdef HAVE_MALLOC_MALLOC_H 27218885Sdim#include <malloc/malloc.h> 28218885Sdim#endif 29218885Sdim#ifdef HAVE_SYS_IOCTL_H 30218885Sdim# include <sys/ioctl.h> 31218885Sdim#endif 32218885Sdim#ifdef HAVE_TERMIOS_H 33218885Sdim# include <termios.h> 34218885Sdim#endif 35218885Sdim 36218885Sdim//===----------------------------------------------------------------------===// 37218885Sdim//=== WARNING: Implementation here must contain only generic UNIX code that 38218885Sdim//=== is guaranteed to work on *all* UNIX variants. 39218885Sdim//===----------------------------------------------------------------------===// 40218885Sdim 41218885Sdimusing namespace llvm; 42218885Sdimusing namespace sys; 43218885Sdim 44218885Sdimunsigned 45218885SdimProcess::GetPageSize() 46218885Sdim{ 47218885Sdim#if defined(__CYGWIN__) 48218885Sdim // On Cygwin, getpagesize() returns 64k but the page size for the purposes of 49218885Sdim // memory protection and mmap() is 4k. 50218885Sdim // See http://www.cygwin.com/ml/cygwin/2009-01/threads.html#00492 51218885Sdim const int page_size = 0x1000; 52218885Sdim#elif defined(HAVE_GETPAGESIZE) 53218885Sdim const int page_size = ::getpagesize(); 54218885Sdim#elif defined(HAVE_SYSCONF) 55218885Sdim long page_size = ::sysconf(_SC_PAGE_SIZE); 56218885Sdim#else 57218885Sdim#warning Cannot get the page size on this machine 58218885Sdim#endif 59218885Sdim return static_cast<unsigned>(page_size); 60218885Sdim} 61218885Sdim 62218885Sdimsize_t Process::GetMallocUsage() { 63218885Sdim#if defined(HAVE_MALLINFO) 64218885Sdim struct mallinfo mi; 65218885Sdim mi = ::mallinfo(); 66218885Sdim return mi.uordblks; 67218885Sdim#elif defined(HAVE_MALLOC_ZONE_STATISTICS) && defined(HAVE_MALLOC_MALLOC_H) 68218885Sdim malloc_statistics_t Stats; 69218885Sdim malloc_zone_statistics(malloc_default_zone(), &Stats); 70218885Sdim return Stats.size_in_use; // darwin 71218885Sdim#elif defined(HAVE_SBRK) 72218885Sdim // Note this is only an approximation and more closely resembles 73218885Sdim // the value returned by mallinfo in the arena field. 74218885Sdim static char *StartOfMemory = reinterpret_cast<char*>(::sbrk(0)); 75218885Sdim char *EndOfMemory = (char*)sbrk(0); 76218885Sdim if (EndOfMemory != ((char*)-1) && StartOfMemory != ((char*)-1)) 77218885Sdim return EndOfMemory - StartOfMemory; 78218885Sdim else 79218885Sdim return 0; 80218885Sdim#else 81218885Sdim#warning Cannot get malloc info on this platform 82218885Sdim return 0; 83218885Sdim#endif 84218885Sdim} 85218885Sdim 86218885Sdimsize_t 87218885SdimProcess::GetTotalMemoryUsage() 88218885Sdim{ 89218885Sdim#if defined(HAVE_MALLINFO) 90218885Sdim struct mallinfo mi = ::mallinfo(); 91218885Sdim return mi.uordblks + mi.hblkhd; 92218885Sdim#elif defined(HAVE_MALLOC_ZONE_STATISTICS) && defined(HAVE_MALLOC_MALLOC_H) 93218885Sdim malloc_statistics_t Stats; 94218885Sdim malloc_zone_statistics(malloc_default_zone(), &Stats); 95218885Sdim return Stats.size_allocated; // darwin 96218885Sdim#elif defined(HAVE_GETRUSAGE) && !defined(__HAIKU__) 97218885Sdim struct rusage usage; 98218885Sdim ::getrusage(RUSAGE_SELF, &usage); 99218885Sdim return usage.ru_maxrss; 100218885Sdim#else 101218885Sdim#warning Cannot get total memory size on this platform 102218885Sdim return 0; 103218885Sdim#endif 104218885Sdim} 105218885Sdim 106218885Sdimvoid 107218885SdimProcess::GetTimeUsage(TimeValue& elapsed, TimeValue& user_time, 108218885Sdim TimeValue& sys_time) 109218885Sdim{ 110218885Sdim elapsed = TimeValue::now(); 111218885Sdim#if defined(HAVE_GETRUSAGE) 112218885Sdim struct rusage usage; 113218885Sdim ::getrusage(RUSAGE_SELF, &usage); 114218885Sdim user_time = TimeValue( 115218885Sdim static_cast<TimeValue::SecondsType>( usage.ru_utime.tv_sec ), 116218885Sdim static_cast<TimeValue::NanoSecondsType>( usage.ru_utime.tv_usec * 117218885Sdim TimeValue::NANOSECONDS_PER_MICROSECOND ) ); 118218885Sdim sys_time = TimeValue( 119218885Sdim static_cast<TimeValue::SecondsType>( usage.ru_stime.tv_sec ), 120218885Sdim static_cast<TimeValue::NanoSecondsType>( usage.ru_stime.tv_usec * 121218885Sdim TimeValue::NANOSECONDS_PER_MICROSECOND ) ); 122218885Sdim#else 123218885Sdim#warning Cannot get usage times on this platform 124218885Sdim user_time.seconds(0); 125218885Sdim user_time.microseconds(0); 126218885Sdim sys_time.seconds(0); 127218885Sdim sys_time.microseconds(0); 128218885Sdim#endif 129218885Sdim} 130218885Sdim 131218885Sdimint Process::GetCurrentUserId() { 132218885Sdim return getuid(); 133218885Sdim} 134218885Sdim 135218885Sdimint Process::GetCurrentGroupId() { 136218885Sdim return getgid(); 137218885Sdim} 138218885Sdim 139234353Sdim#if defined(HAVE_MACH_MACH_H) && !defined(__GNU__) 140218885Sdim#include <mach/mach.h> 141218885Sdim#endif 142218885Sdim 143218885Sdim// Some LLVM programs such as bugpoint produce core files as a normal part of 144218885Sdim// their operation. To prevent the disk from filling up, this function 145218885Sdim// does what's necessary to prevent their generation. 146218885Sdimvoid Process::PreventCoreFiles() { 147218885Sdim#if HAVE_SETRLIMIT 148218885Sdim struct rlimit rlim; 149218885Sdim rlim.rlim_cur = rlim.rlim_max = 0; 150218885Sdim setrlimit(RLIMIT_CORE, &rlim); 151218885Sdim#endif 152218885Sdim 153234353Sdim#if defined(HAVE_MACH_MACH_H) && !defined(__GNU__) 154218885Sdim // Disable crash reporting on Mac OS X 10.0-10.4 155218885Sdim 156218885Sdim // get information about the original set of exception ports for the task 157218885Sdim mach_msg_type_number_t Count = 0; 158218885Sdim exception_mask_t OriginalMasks[EXC_TYPES_COUNT]; 159218885Sdim exception_port_t OriginalPorts[EXC_TYPES_COUNT]; 160218885Sdim exception_behavior_t OriginalBehaviors[EXC_TYPES_COUNT]; 161218885Sdim thread_state_flavor_t OriginalFlavors[EXC_TYPES_COUNT]; 162218885Sdim kern_return_t err = 163218885Sdim task_get_exception_ports(mach_task_self(), EXC_MASK_ALL, OriginalMasks, 164218885Sdim &Count, OriginalPorts, OriginalBehaviors, 165218885Sdim OriginalFlavors); 166218885Sdim if (err == KERN_SUCCESS) { 167218885Sdim // replace each with MACH_PORT_NULL. 168218885Sdim for (unsigned i = 0; i != Count; ++i) 169218885Sdim task_set_exception_ports(mach_task_self(), OriginalMasks[i], 170218885Sdim MACH_PORT_NULL, OriginalBehaviors[i], 171218885Sdim OriginalFlavors[i]); 172218885Sdim } 173218885Sdim 174218885Sdim // Disable crash reporting on Mac OS X 10.5 175218885Sdim signal(SIGABRT, _exit); 176218885Sdim signal(SIGILL, _exit); 177218885Sdim signal(SIGFPE, _exit); 178218885Sdim signal(SIGSEGV, _exit); 179218885Sdim signal(SIGBUS, _exit); 180218885Sdim#endif 181218885Sdim} 182218885Sdim 183218885Sdimbool Process::StandardInIsUserInput() { 184218885Sdim return FileDescriptorIsDisplayed(STDIN_FILENO); 185218885Sdim} 186218885Sdim 187218885Sdimbool Process::StandardOutIsDisplayed() { 188218885Sdim return FileDescriptorIsDisplayed(STDOUT_FILENO); 189218885Sdim} 190218885Sdim 191218885Sdimbool Process::StandardErrIsDisplayed() { 192218885Sdim return FileDescriptorIsDisplayed(STDERR_FILENO); 193218885Sdim} 194218885Sdim 195218885Sdimbool Process::FileDescriptorIsDisplayed(int fd) { 196218885Sdim#if HAVE_ISATTY 197218885Sdim return isatty(fd); 198218885Sdim#else 199218885Sdim // If we don't have isatty, just return false. 200218885Sdim return false; 201218885Sdim#endif 202218885Sdim} 203218885Sdim 204218885Sdimstatic unsigned getColumns(int FileID) { 205218885Sdim // If COLUMNS is defined in the environment, wrap to that many columns. 206218885Sdim if (const char *ColumnsStr = std::getenv("COLUMNS")) { 207218885Sdim int Columns = std::atoi(ColumnsStr); 208218885Sdim if (Columns > 0) 209218885Sdim return Columns; 210218885Sdim } 211218885Sdim 212218885Sdim unsigned Columns = 0; 213218885Sdim 214218885Sdim#if defined(HAVE_SYS_IOCTL_H) && defined(HAVE_TERMIOS_H) 215218885Sdim // Try to determine the width of the terminal. 216218885Sdim struct winsize ws; 217218885Sdim if (ioctl(FileID, TIOCGWINSZ, &ws) == 0) 218218885Sdim Columns = ws.ws_col; 219218885Sdim#endif 220218885Sdim 221218885Sdim return Columns; 222218885Sdim} 223218885Sdim 224218885Sdimunsigned Process::StandardOutColumns() { 225218885Sdim if (!StandardOutIsDisplayed()) 226218885Sdim return 0; 227218885Sdim 228218885Sdim return getColumns(1); 229218885Sdim} 230218885Sdim 231218885Sdimunsigned Process::StandardErrColumns() { 232218885Sdim if (!StandardErrIsDisplayed()) 233218885Sdim return 0; 234218885Sdim 235218885Sdim return getColumns(2); 236218885Sdim} 237218885Sdim 238218885Sdimstatic bool terminalHasColors() { 239218885Sdim if (const char *term = std::getenv("TERM")) { 240218885Sdim // Most modern terminals support ANSI escape sequences for colors. 241218885Sdim // We could check terminfo, or have a list of known terms that support 242218885Sdim // colors, but that would be overkill. 243218885Sdim // The user can always ask for no colors by setting TERM to dumb, or 244218885Sdim // using a commandline flag. 245218885Sdim return strcmp(term, "dumb") != 0; 246218885Sdim } 247218885Sdim return false; 248218885Sdim} 249218885Sdim 250218885Sdimbool Process::StandardOutHasColors() { 251218885Sdim if (!StandardOutIsDisplayed()) 252218885Sdim return false; 253218885Sdim return terminalHasColors(); 254218885Sdim} 255218885Sdim 256218885Sdimbool Process::StandardErrHasColors() { 257218885Sdim if (!StandardErrIsDisplayed()) 258218885Sdim return false; 259218885Sdim return terminalHasColors(); 260218885Sdim} 261218885Sdim 262218885Sdimbool Process::ColorNeedsFlush() { 263218885Sdim // No, we use ANSI escape sequences. 264218885Sdim return false; 265218885Sdim} 266218885Sdim 267218885Sdim#define COLOR(FGBG, CODE, BOLD) "\033[0;" BOLD FGBG CODE "m" 268218885Sdim 269218885Sdim#define ALLCOLORS(FGBG,BOLD) {\ 270218885Sdim COLOR(FGBG, "0", BOLD),\ 271218885Sdim COLOR(FGBG, "1", BOLD),\ 272218885Sdim COLOR(FGBG, "2", BOLD),\ 273218885Sdim COLOR(FGBG, "3", BOLD),\ 274218885Sdim COLOR(FGBG, "4", BOLD),\ 275218885Sdim COLOR(FGBG, "5", BOLD),\ 276218885Sdim COLOR(FGBG, "6", BOLD),\ 277218885Sdim COLOR(FGBG, "7", BOLD)\ 278218885Sdim } 279218885Sdim 280218885Sdimstatic const char colorcodes[2][2][8][10] = { 281218885Sdim { ALLCOLORS("3",""), ALLCOLORS("3","1;") }, 282218885Sdim { ALLCOLORS("4",""), ALLCOLORS("4","1;") } 283218885Sdim}; 284218885Sdim 285218885Sdimconst char *Process::OutputColor(char code, bool bold, bool bg) { 286218885Sdim return colorcodes[bg?1:0][bold?1:0][code&7]; 287218885Sdim} 288218885Sdim 289218885Sdimconst char *Process::OutputBold(bool bg) { 290218885Sdim return "\033[1m"; 291218885Sdim} 292218885Sdim 293234982Sdimconst char *Process::OutputReverse() { 294234982Sdim return "\033[7m"; 295234982Sdim} 296234982Sdim 297218885Sdimconst char *Process::ResetColor() { 298218885Sdim return "\033[0m"; 299218885Sdim} 300