//===- Unix/Process.cpp - Unix Process Implementation --------- -*- C++ -*-===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // This file provides the generic Unix implementation of the Process class. // //===----------------------------------------------------------------------===// #include "Unix.h" #ifdef HAVE_SYS_TIME_H #include #endif #ifdef HAVE_SYS_RESOURCE_H #include #endif #ifdef HAVE_MALLOC_H #include #endif #ifdef HAVE_MALLOC_MALLOC_H #include #endif #ifdef HAVE_SYS_IOCTL_H # include #endif #ifdef HAVE_TERMIOS_H # include #endif //===----------------------------------------------------------------------===// //=== WARNING: Implementation here must contain only generic UNIX code that //=== is guaranteed to work on *all* UNIX variants. //===----------------------------------------------------------------------===// using namespace llvm; using namespace sys; unsigned Process::GetPageSize() { #if defined(__CYGWIN__) // On Cygwin, getpagesize() returns 64k but the page size for the purposes of // memory protection and mmap() is 4k. // See http://www.cygwin.com/ml/cygwin/2009-01/threads.html#00492 const int page_size = 0x1000; #elif defined(HAVE_GETPAGESIZE) const int page_size = ::getpagesize(); #elif defined(HAVE_SYSCONF) long page_size = ::sysconf(_SC_PAGE_SIZE); #else #warning Cannot get the page size on this machine #endif return static_cast(page_size); } size_t Process::GetMallocUsage() { #if defined(HAVE_MALLINFO) struct mallinfo mi; mi = ::mallinfo(); return mi.uordblks; #elif defined(HAVE_MALLOC_ZONE_STATISTICS) && defined(HAVE_MALLOC_MALLOC_H) malloc_statistics_t Stats; malloc_zone_statistics(malloc_default_zone(), &Stats); return Stats.size_in_use; // darwin #elif defined(HAVE_SBRK) // Note this is only an approximation and more closely resembles // the value returned by mallinfo in the arena field. static char *StartOfMemory = reinterpret_cast(::sbrk(0)); char *EndOfMemory = (char*)sbrk(0); if (EndOfMemory != ((char*)-1) && StartOfMemory != ((char*)-1)) return EndOfMemory - StartOfMemory; else return 0; #else #warning Cannot get malloc info on this platform return 0; #endif } size_t Process::GetTotalMemoryUsage() { #if defined(HAVE_MALLINFO) struct mallinfo mi = ::mallinfo(); return mi.uordblks + mi.hblkhd; #elif defined(HAVE_MALLOC_ZONE_STATISTICS) && defined(HAVE_MALLOC_MALLOC_H) malloc_statistics_t Stats; malloc_zone_statistics(malloc_default_zone(), &Stats); return Stats.size_allocated; // darwin #elif defined(HAVE_GETRUSAGE) struct rusage usage; ::getrusage(RUSAGE_SELF, &usage); return usage.ru_maxrss; #else #warning Cannot get total memory size on this platform return 0; #endif } void Process::GetTimeUsage(TimeValue& elapsed, TimeValue& user_time, TimeValue& sys_time) { elapsed = TimeValue::now(); #if defined(HAVE_GETRUSAGE) struct rusage usage; ::getrusage(RUSAGE_SELF, &usage); user_time = TimeValue( static_cast( usage.ru_utime.tv_sec ), static_cast( usage.ru_utime.tv_usec * TimeValue::NANOSECONDS_PER_MICROSECOND ) ); sys_time = TimeValue( static_cast( usage.ru_stime.tv_sec ), static_cast( usage.ru_stime.tv_usec * TimeValue::NANOSECONDS_PER_MICROSECOND ) ); #else #warning Cannot get usage times on this platform user_time.seconds(0); user_time.microseconds(0); sys_time.seconds(0); sys_time.microseconds(0); #endif } int Process::GetCurrentUserId() { return getuid(); } int Process::GetCurrentGroupId() { return getgid(); } #ifdef HAVE_MACH_MACH_H #include #endif // Some LLVM programs such as bugpoint produce core files as a normal part of // their operation. To prevent the disk from filling up, this function // does what's necessary to prevent their generation. void Process::PreventCoreFiles() { #if HAVE_SETRLIMIT struct rlimit rlim; rlim.rlim_cur = rlim.rlim_max = 0; setrlimit(RLIMIT_CORE, &rlim); #endif #ifdef HAVE_MACH_MACH_H // Disable crash reporting on Mac OS X 10.0-10.4 // get information about the original set of exception ports for the task mach_msg_type_number_t Count = 0; exception_mask_t OriginalMasks[EXC_TYPES_COUNT]; exception_port_t OriginalPorts[EXC_TYPES_COUNT]; exception_behavior_t OriginalBehaviors[EXC_TYPES_COUNT]; thread_state_flavor_t OriginalFlavors[EXC_TYPES_COUNT]; kern_return_t err = task_get_exception_ports(mach_task_self(), EXC_MASK_ALL, OriginalMasks, &Count, OriginalPorts, OriginalBehaviors, OriginalFlavors); if (err == KERN_SUCCESS) { // replace each with MACH_PORT_NULL. for (unsigned i = 0; i != Count; ++i) task_set_exception_ports(mach_task_self(), OriginalMasks[i], MACH_PORT_NULL, OriginalBehaviors[i], OriginalFlavors[i]); } // Disable crash reporting on Mac OS X 10.5 signal(SIGABRT, _exit); signal(SIGILL, _exit); signal(SIGFPE, _exit); signal(SIGSEGV, _exit); signal(SIGBUS, _exit); #endif } bool Process::StandardInIsUserInput() { #if HAVE_ISATTY return isatty(0); #else // If we don't have isatty, just return false. return false; #endif } bool Process::StandardOutIsDisplayed() { #if HAVE_ISATTY return isatty(1); #else // If we don't have isatty, just return false. return false; #endif } bool Process::StandardErrIsDisplayed() { #if HAVE_ISATTY return isatty(2); #else // If we don't have isatty, just return false. return false; #endif } static unsigned getColumns(int FileID) { // If COLUMNS is defined in the environment, wrap to that many columns. if (const char *ColumnsStr = std::getenv("COLUMNS")) { int Columns = std::atoi(ColumnsStr); if (Columns > 0) return Columns; } unsigned Columns = 0; #if defined(HAVE_SYS_IOCTL_H) && defined(HAVE_TERMIOS_H) // Try to determine the width of the terminal. struct winsize ws; if (ioctl(FileID, TIOCGWINSZ, &ws) == 0) Columns = ws.ws_col; #endif return Columns; } unsigned Process::StandardOutColumns() { if (!StandardOutIsDisplayed()) return 0; return getColumns(1); } unsigned Process::StandardErrColumns() { if (!StandardErrIsDisplayed()) return 0; return getColumns(2); } static bool terminalHasColors() { if (const char *term = std::getenv("TERM")) { // Most modern terminals support ANSI escape sequences for colors. // We could check terminfo, or have a list of known terms that support // colors, but that would be overkill. // The user can always ask for no colors by setting TERM to dumb, or // using a commandline flag. return strcmp(term, "dumb") != 0; } return false; } bool Process::StandardOutHasColors() { if (!StandardOutIsDisplayed()) return false; return terminalHasColors(); } bool Process::StandardErrHasColors() { if (!StandardErrIsDisplayed()) return false; return terminalHasColors(); } bool Process::ColorNeedsFlush() { // No, we use ANSI escape sequences. return false; } #define COLOR(FGBG, CODE, BOLD) "\033[0;" BOLD FGBG CODE "m" #define ALLCOLORS(FGBG,BOLD) {\ COLOR(FGBG, "0", BOLD),\ COLOR(FGBG, "1", BOLD),\ COLOR(FGBG, "2", BOLD),\ COLOR(FGBG, "3", BOLD),\ COLOR(FGBG, "4", BOLD),\ COLOR(FGBG, "5", BOLD),\ COLOR(FGBG, "6", BOLD),\ COLOR(FGBG, "7", BOLD)\ } static const char* colorcodes[2][2][8] = { { ALLCOLORS("3",""), ALLCOLORS("3","1;") }, { ALLCOLORS("4",""), ALLCOLORS("4","1;") } }; const char *Process::OutputColor(char code, bool bold, bool bg) { return colorcodes[bg?1:0][bold?1:0][code&7]; } const char *Process::OutputBold(bool bg) { return "\033[1m"; } const char *Process::ResetColor() { return "\033[0m"; }