1 //===- Unix/Process.cpp - Unix Process Implementation --------- -*- C++ -*-===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
10 // This file provides the generic Unix implementation of the Process class.
12 //===----------------------------------------------------------------------===//
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
22 #ifdef HAVE_SYS_RESOURCE_H
23 #include <sys/resource.h>
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__)
31 #ifdef HAVE_MALLOC_MALLOC_H
32 #include <malloc/malloc.h>
34 #ifdef HAVE_SYS_IOCTL_H
35 # include <sys/ioctl.h>
41 // See if we can use curses to detect information about a terminal when
44 # if defined(HAVE_CURSES_H)
46 # elif defined(HAVE_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>
55 # error Have a curses library but unable to find a curses header!
60 //===----------------------------------------------------------------------===//
61 //=== WARNING: Implementation here must contain only generic UNIX code that
62 //=== is guaranteed to work on *all* UNIX variants.
63 //===----------------------------------------------------------------------===//
69 process::id_type self_process::get_id() {
73 static std::pair<TimeValue, TimeValue> getRUsageTimes() {
74 #if defined(HAVE_GETRUSAGE)
76 ::getrusage(RUSAGE_SELF, &RU);
77 return std::make_pair(
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)),
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)));
87 #warning Cannot get usage times on this platform
88 return std::make_pair(TimeValue(), TimeValue());
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.
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));
101 // Otherwise fall back to rusage based timing.
102 return getRUsageTimes().first;
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;
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);
121 #warning Cannot get the page size on this machine
123 return static_cast<unsigned>(page_size);
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()) {
132 size_t Process::GetMallocUsage() {
133 #if defined(HAVE_MALLINFO)
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;
151 #warning Cannot get malloc info on this platform
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();
162 int Process::GetCurrentUserId() {
166 int Process::GetCurrentGroupId() {
170 #if defined(HAVE_MACH_MACH_H) && !defined(__GNU__)
171 #include <mach/mach.h>
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() {
180 rlim.rlim_cur = rlim.rlim_max = 0;
181 setrlimit(RLIMIT_CORE, &rlim);
184 #if defined(HAVE_MACH_MACH_H) && !defined(__GNU__)
185 // Disable crash reporting on Mac OS X 10.0-10.4
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];
194 task_get_exception_ports(mach_task_self(), EXC_MASK_ALL, OriginalMasks,
195 &Count, OriginalPorts, OriginalBehaviors,
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],
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);
214 bool Process::StandardInIsUserInput() {
215 return FileDescriptorIsDisplayed(STDIN_FILENO);
218 bool Process::StandardOutIsDisplayed() {
219 return FileDescriptorIsDisplayed(STDOUT_FILENO);
222 bool Process::StandardErrIsDisplayed() {
223 return FileDescriptorIsDisplayed(STDERR_FILENO);
226 bool Process::FileDescriptorIsDisplayed(int fd) {
230 // If we don't have isatty, just return false.
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);
243 unsigned Columns = 0;
245 #if defined(HAVE_SYS_IOCTL_H) && defined(HAVE_TERMIOS_H)
246 // Try to determine the width of the terminal.
248 if (ioctl(FileID, TIOCGWINSZ, &ws) == 0)
255 unsigned Process::StandardOutColumns() {
256 if (!StandardOutIsDisplayed())
259 return getColumns(1);
262 unsigned Process::StandardErrColumns() {
263 if (!StandardErrIsDisplayed())
266 return getColumns(2);
269 static bool terminalHasColors(int fd) {
271 // First, acquire a global lock because the curses C routines are thread
277 if (setupterm((char *)0, fd, &errret) != OK)
278 // Regardless of why, if we can't get terminfo, we shouldn't try to print
282 // Test whether the terminal as set up supports color output.
283 if (has_colors() == TRUE)
287 // Otherwise, be conservative.
291 bool Process::FileDescriptorHasColors(int fd) {
292 // A file descriptor has colors if it is displayed and the terminal has
294 return FileDescriptorIsDisplayed(fd) && terminalHasColors(fd);
297 bool Process::StandardOutHasColors() {
298 return FileDescriptorHasColors(STDOUT_FILENO);
301 bool Process::StandardErrHasColors() {
302 return FileDescriptorHasColors(STDERR_FILENO);
305 bool Process::ColorNeedsFlush() {
306 // No, we use ANSI escape sequences.
310 #define COLOR(FGBG, CODE, BOLD) "\033[0;" BOLD FGBG CODE "m"
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)\
323 static const char colorcodes[2][2][8][10] = {
324 { ALLCOLORS("3",""), ALLCOLORS("3","1;") },
325 { ALLCOLORS("4",""), ALLCOLORS("4","1;") }
328 const char *Process::OutputColor(char code, bool bold, bool bg) {
329 return colorcodes[bg?1:0][bold?1:0][code&7];
332 const char *Process::OutputBold(bool bg) {
336 const char *Process::OutputReverse() {
340 const char *Process::ResetColor() {
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")) {
349 int count = ::fread((void *)&seed, sizeof(seed), 1, RandomSource);
350 ::fclose(RandomSource);
352 // Return the seed if the read was successful.
357 // Otherwise, swizzle the current time and the process ID to form a reasonable
359 TimeValue Now = TimeValue::now();
360 return hash_combine(Now.seconds(), Now.nanoseconds(), ::getpid());
364 unsigned llvm::sys::Process::GetRandomNumber() {
365 #if defined(HAVE_ARC4RANDOM)
368 static int x = (::srand(GetRandomNumberSeed()), 0);