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#ifdef HAVE_SYS_TIME_H 16#include <sys/time.h> 17#endif 18#ifdef HAVE_SYS_RESOURCE_H 19#include <sys/resource.h> 20#endif 21// DragonFly BSD has deprecated <malloc.h> for <stdlib.h> instead, 22// Unix.h includes this for us already. 23#if defined(HAVE_MALLOC_H) && !defined(__DragonFly__) 24#include <malloc.h> 25#endif 26#ifdef HAVE_MALLOC_MALLOC_H 27#include <malloc/malloc.h> 28#endif 29#ifdef HAVE_SYS_IOCTL_H 30# include <sys/ioctl.h> 31#endif 32#ifdef HAVE_TERMIOS_H 33# include <termios.h> 34#endif 35 36//===----------------------------------------------------------------------===// 37//=== WARNING: Implementation here must contain only generic UNIX code that 38//=== is guaranteed to work on *all* UNIX variants. 39//===----------------------------------------------------------------------===// 40 41using namespace llvm; 42using namespace sys; 43 44unsigned 45Process::GetPageSize() 46{ 47#if defined(__CYGWIN__) 48 // On Cygwin, getpagesize() returns 64k but the page size for the purposes of 49 // memory protection and mmap() is 4k. 50 // See http://www.cygwin.com/ml/cygwin/2009-01/threads.html#00492 51 const int page_size = 0x1000; 52#elif defined(HAVE_GETPAGESIZE) 53 const int page_size = ::getpagesize(); 54#elif defined(HAVE_SYSCONF) 55 long page_size = ::sysconf(_SC_PAGE_SIZE); 56#else 57#warning Cannot get the page size on this machine 58#endif 59 return static_cast<unsigned>(page_size); 60} 61 62size_t Process::GetMallocUsage() { 63#if defined(HAVE_MALLINFO) 64 struct mallinfo mi; 65 mi = ::mallinfo(); 66 return mi.uordblks; 67#elif defined(HAVE_MALLOC_ZONE_STATISTICS) && defined(HAVE_MALLOC_MALLOC_H) 68 malloc_statistics_t Stats; 69 malloc_zone_statistics(malloc_default_zone(), &Stats); 70 return Stats.size_in_use; // darwin 71#elif defined(HAVE_SBRK) 72 // Note this is only an approximation and more closely resembles 73 // the value returned by mallinfo in the arena field. 74 static char *StartOfMemory = reinterpret_cast<char*>(::sbrk(0)); 75 char *EndOfMemory = (char*)sbrk(0); 76 if (EndOfMemory != ((char*)-1) && StartOfMemory != ((char*)-1)) 77 return EndOfMemory - StartOfMemory; 78 else 79 return 0; 80#else 81#warning Cannot get malloc info on this platform 82 return 0; 83#endif 84} 85 86size_t 87Process::GetTotalMemoryUsage() 88{ 89#if defined(HAVE_MALLINFO) 90 struct mallinfo mi = ::mallinfo(); 91 return mi.uordblks + mi.hblkhd; 92#elif defined(HAVE_MALLOC_ZONE_STATISTICS) && defined(HAVE_MALLOC_MALLOC_H) 93 malloc_statistics_t Stats; 94 malloc_zone_statistics(malloc_default_zone(), &Stats); 95 return Stats.size_allocated; // darwin 96#elif defined(HAVE_GETRUSAGE) && !defined(__HAIKU__) 97 struct rusage usage; 98 ::getrusage(RUSAGE_SELF, &usage); 99 return usage.ru_maxrss; 100#else 101#warning Cannot get total memory size on this platform 102 return 0; 103#endif 104} 105 106void 107Process::GetTimeUsage(TimeValue& elapsed, TimeValue& user_time, 108 TimeValue& sys_time) 109{ 110 elapsed = TimeValue::now(); 111#if defined(HAVE_GETRUSAGE) 112 struct rusage usage; 113 ::getrusage(RUSAGE_SELF, &usage); 114 user_time = TimeValue( 115 static_cast<TimeValue::SecondsType>( usage.ru_utime.tv_sec ), 116 static_cast<TimeValue::NanoSecondsType>( usage.ru_utime.tv_usec * 117 TimeValue::NANOSECONDS_PER_MICROSECOND ) ); 118 sys_time = TimeValue( 119 static_cast<TimeValue::SecondsType>( usage.ru_stime.tv_sec ), 120 static_cast<TimeValue::NanoSecondsType>( usage.ru_stime.tv_usec * 121 TimeValue::NANOSECONDS_PER_MICROSECOND ) ); 122#else 123#warning Cannot get usage times on this platform 124 user_time.seconds(0); 125 user_time.microseconds(0); 126 sys_time.seconds(0); 127 sys_time.microseconds(0); 128#endif 129} 130 131int Process::GetCurrentUserId() { 132 return getuid(); 133} 134 135int Process::GetCurrentGroupId() { 136 return getgid(); 137} 138 139#if defined(HAVE_MACH_MACH_H) && !defined(__GNU__) 140#include <mach/mach.h> 141#endif 142 143// Some LLVM programs such as bugpoint produce core files as a normal part of 144// their operation. To prevent the disk from filling up, this function 145// does what's necessary to prevent their generation. 146void Process::PreventCoreFiles() { 147#if HAVE_SETRLIMIT 148 struct rlimit rlim; 149 rlim.rlim_cur = rlim.rlim_max = 0; 150 setrlimit(RLIMIT_CORE, &rlim); 151#endif 152 153#if defined(HAVE_MACH_MACH_H) && !defined(__GNU__) 154 // Disable crash reporting on Mac OS X 10.0-10.4 155 156 // get information about the original set of exception ports for the task 157 mach_msg_type_number_t Count = 0; 158 exception_mask_t OriginalMasks[EXC_TYPES_COUNT]; 159 exception_port_t OriginalPorts[EXC_TYPES_COUNT]; 160 exception_behavior_t OriginalBehaviors[EXC_TYPES_COUNT]; 161 thread_state_flavor_t OriginalFlavors[EXC_TYPES_COUNT]; 162 kern_return_t err = 163 task_get_exception_ports(mach_task_self(), EXC_MASK_ALL, OriginalMasks, 164 &Count, OriginalPorts, OriginalBehaviors, 165 OriginalFlavors); 166 if (err == KERN_SUCCESS) { 167 // replace each with MACH_PORT_NULL. 168 for (unsigned i = 0; i != Count; ++i) 169 task_set_exception_ports(mach_task_self(), OriginalMasks[i], 170 MACH_PORT_NULL, OriginalBehaviors[i], 171 OriginalFlavors[i]); 172 } 173 174 // Disable crash reporting on Mac OS X 10.5 175 signal(SIGABRT, _exit); 176 signal(SIGILL, _exit); 177 signal(SIGFPE, _exit); 178 signal(SIGSEGV, _exit); 179 signal(SIGBUS, _exit); 180#endif 181} 182 183bool Process::StandardInIsUserInput() { 184 return FileDescriptorIsDisplayed(STDIN_FILENO); 185} 186 187bool Process::StandardOutIsDisplayed() { 188 return FileDescriptorIsDisplayed(STDOUT_FILENO); 189} 190 191bool Process::StandardErrIsDisplayed() { 192 return FileDescriptorIsDisplayed(STDERR_FILENO); 193} 194 195bool Process::FileDescriptorIsDisplayed(int fd) { 196#if HAVE_ISATTY 197 return isatty(fd); 198#else 199 // If we don't have isatty, just return false. 200 return false; 201#endif 202} 203 204static unsigned getColumns(int FileID) { 205 // If COLUMNS is defined in the environment, wrap to that many columns. 206 if (const char *ColumnsStr = std::getenv("COLUMNS")) { 207 int Columns = std::atoi(ColumnsStr); 208 if (Columns > 0) 209 return Columns; 210 } 211 212 unsigned Columns = 0; 213 214#if defined(HAVE_SYS_IOCTL_H) && defined(HAVE_TERMIOS_H) 215 // Try to determine the width of the terminal. 216 struct winsize ws; 217 if (ioctl(FileID, TIOCGWINSZ, &ws) == 0) 218 Columns = ws.ws_col; 219#endif 220 221 return Columns; 222} 223 224unsigned Process::StandardOutColumns() { 225 if (!StandardOutIsDisplayed()) 226 return 0; 227 228 return getColumns(1); 229} 230 231unsigned Process::StandardErrColumns() { 232 if (!StandardErrIsDisplayed()) 233 return 0; 234 235 return getColumns(2); 236} 237 238static bool terminalHasColors() { 239 if (const char *term = std::getenv("TERM")) { 240 // Most modern terminals support ANSI escape sequences for colors. 241 // We could check terminfo, or have a list of known terms that support 242 // colors, but that would be overkill. 243 // The user can always ask for no colors by setting TERM to dumb, or 244 // using a commandline flag. 245 return strcmp(term, "dumb") != 0; 246 } 247 return false; 248} 249 250bool Process::StandardOutHasColors() { 251 if (!StandardOutIsDisplayed()) 252 return false; 253 return terminalHasColors(); 254} 255 256bool Process::StandardErrHasColors() { 257 if (!StandardErrIsDisplayed()) 258 return false; 259 return terminalHasColors(); 260} 261 262bool Process::ColorNeedsFlush() { 263 // No, we use ANSI escape sequences. 264 return false; 265} 266 267#define COLOR(FGBG, CODE, BOLD) "\033[0;" BOLD FGBG CODE "m" 268 269#define ALLCOLORS(FGBG,BOLD) {\ 270 COLOR(FGBG, "0", BOLD),\ 271 COLOR(FGBG, "1", BOLD),\ 272 COLOR(FGBG, "2", BOLD),\ 273 COLOR(FGBG, "3", BOLD),\ 274 COLOR(FGBG, "4", BOLD),\ 275 COLOR(FGBG, "5", BOLD),\ 276 COLOR(FGBG, "6", BOLD),\ 277 COLOR(FGBG, "7", BOLD)\ 278 } 279 280static const char colorcodes[2][2][8][10] = { 281 { ALLCOLORS("3",""), ALLCOLORS("3","1;") }, 282 { ALLCOLORS("4",""), ALLCOLORS("4","1;") } 283}; 284 285const char *Process::OutputColor(char code, bool bold, bool bg) { 286 return colorcodes[bg?1:0][bold?1:0][code&7]; 287} 288 289const char *Process::OutputBold(bool bg) { 290 return "\033[1m"; 291} 292 293const char *Process::OutputReverse() { 294 return "\033[7m"; 295} 296 297const char *Process::ResetColor() { 298 return "\033[0m"; 299} 300