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/TimeValue.h"
17 #ifdef HAVE_SYS_TIME_H
20 #ifdef HAVE_SYS_RESOURCE_H
21 #include <sys/resource.h>
23 // DragonFlyBSD, OpenBSD, and Bitrig have deprecated <malloc.h> for
24 // <stdlib.h> instead. Unix.h includes this for us already.
25 #if defined(HAVE_MALLOC_H) && !defined(__DragonFly__) && \
26 !defined(__OpenBSD__) && !defined(__Bitrig__)
29 #ifdef HAVE_MALLOC_MALLOC_H
30 #include <malloc/malloc.h>
32 #ifdef HAVE_SYS_IOCTL_H
33 # include <sys/ioctl.h>
39 //===----------------------------------------------------------------------===//
40 //=== WARNING: Implementation here must contain only generic UNIX code that
41 //=== is guaranteed to work on *all* UNIX variants.
42 //===----------------------------------------------------------------------===//
48 process::id_type self_process::get_id() {
52 static std::pair<TimeValue, TimeValue> getRUsageTimes() {
53 #if defined(HAVE_GETRUSAGE)
55 ::getrusage(RUSAGE_SELF, &RU);
56 return std::make_pair(
58 static_cast<TimeValue::SecondsType>(RU.ru_utime.tv_sec),
59 static_cast<TimeValue::NanoSecondsType>(
60 RU.ru_utime.tv_usec * TimeValue::NANOSECONDS_PER_MICROSECOND)),
62 static_cast<TimeValue::SecondsType>(RU.ru_stime.tv_sec),
63 static_cast<TimeValue::NanoSecondsType>(
64 RU.ru_stime.tv_usec * TimeValue::NANOSECONDS_PER_MICROSECOND)));
66 #warning Cannot get usage times on this platform
67 return std::make_pair(TimeValue(), TimeValue());
71 TimeValue self_process::get_user_time() const {
72 #if _POSIX_TIMERS > 0 && _POSIX_CPUTIME > 0
73 // Try to get a high resolution CPU timer.
75 if (::clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &TS) == 0)
76 return TimeValue(static_cast<TimeValue::SecondsType>(TS.tv_sec),
77 static_cast<TimeValue::NanoSecondsType>(TS.tv_nsec));
80 // Otherwise fall back to rusage based timing.
81 return getRUsageTimes().first;
84 TimeValue self_process::get_system_time() const {
85 // We can only collect system time by inspecting the results of getrusage.
86 return getRUsageTimes().second;
89 static unsigned getPageSize() {
90 #if defined(__CYGWIN__)
91 // On Cygwin, getpagesize() returns 64k but the page size for the purposes of
92 // memory protection and mmap() is 4k.
93 // See http://www.cygwin.com/ml/cygwin/2009-01/threads.html#00492
94 const int page_size = 0x1000;
95 #elif defined(HAVE_GETPAGESIZE)
96 const int page_size = ::getpagesize();
97 #elif defined(HAVE_SYSCONF)
98 long page_size = ::sysconf(_SC_PAGE_SIZE);
100 #warning Cannot get the page size on this machine
102 return static_cast<unsigned>(page_size);
105 // This constructor guaranteed to be run exactly once on a single thread, and
106 // sets up various process invariants that can be queried cheaply from then on.
107 self_process::self_process() : PageSize(getPageSize()) {
111 size_t Process::GetMallocUsage() {
112 #if defined(HAVE_MALLINFO)
116 #elif defined(HAVE_MALLOC_ZONE_STATISTICS) && defined(HAVE_MALLOC_MALLOC_H)
117 malloc_statistics_t Stats;
118 malloc_zone_statistics(malloc_default_zone(), &Stats);
119 return Stats.size_in_use; // darwin
120 #elif defined(HAVE_SBRK)
121 // Note this is only an approximation and more closely resembles
122 // the value returned by mallinfo in the arena field.
123 static char *StartOfMemory = reinterpret_cast<char*>(::sbrk(0));
124 char *EndOfMemory = (char*)sbrk(0);
125 if (EndOfMemory != ((char*)-1) && StartOfMemory != ((char*)-1))
126 return EndOfMemory - StartOfMemory;
130 #warning Cannot get malloc info on this platform
135 void Process::GetTimeUsage(TimeValue &elapsed, TimeValue &user_time,
136 TimeValue &sys_time) {
137 elapsed = TimeValue::now();
138 llvm::tie(user_time, sys_time) = getRUsageTimes();
141 int Process::GetCurrentUserId() {
145 int Process::GetCurrentGroupId() {
149 #if defined(HAVE_MACH_MACH_H) && !defined(__GNU__)
150 #include <mach/mach.h>
153 // Some LLVM programs such as bugpoint produce core files as a normal part of
154 // their operation. To prevent the disk from filling up, this function
155 // does what's necessary to prevent their generation.
156 void Process::PreventCoreFiles() {
159 rlim.rlim_cur = rlim.rlim_max = 0;
160 setrlimit(RLIMIT_CORE, &rlim);
163 #if defined(HAVE_MACH_MACH_H) && !defined(__GNU__)
164 // Disable crash reporting on Mac OS X 10.0-10.4
166 // get information about the original set of exception ports for the task
167 mach_msg_type_number_t Count = 0;
168 exception_mask_t OriginalMasks[EXC_TYPES_COUNT];
169 exception_port_t OriginalPorts[EXC_TYPES_COUNT];
170 exception_behavior_t OriginalBehaviors[EXC_TYPES_COUNT];
171 thread_state_flavor_t OriginalFlavors[EXC_TYPES_COUNT];
173 task_get_exception_ports(mach_task_self(), EXC_MASK_ALL, OriginalMasks,
174 &Count, OriginalPorts, OriginalBehaviors,
176 if (err == KERN_SUCCESS) {
177 // replace each with MACH_PORT_NULL.
178 for (unsigned i = 0; i != Count; ++i)
179 task_set_exception_ports(mach_task_self(), OriginalMasks[i],
180 MACH_PORT_NULL, OriginalBehaviors[i],
184 // Disable crash reporting on Mac OS X 10.5
185 signal(SIGABRT, _exit);
186 signal(SIGILL, _exit);
187 signal(SIGFPE, _exit);
188 signal(SIGSEGV, _exit);
189 signal(SIGBUS, _exit);
193 bool Process::StandardInIsUserInput() {
194 return FileDescriptorIsDisplayed(STDIN_FILENO);
197 bool Process::StandardOutIsDisplayed() {
198 return FileDescriptorIsDisplayed(STDOUT_FILENO);
201 bool Process::StandardErrIsDisplayed() {
202 return FileDescriptorIsDisplayed(STDERR_FILENO);
205 bool Process::FileDescriptorIsDisplayed(int fd) {
209 // If we don't have isatty, just return false.
214 static unsigned getColumns(int FileID) {
215 // If COLUMNS is defined in the environment, wrap to that many columns.
216 if (const char *ColumnsStr = std::getenv("COLUMNS")) {
217 int Columns = std::atoi(ColumnsStr);
222 unsigned Columns = 0;
224 #if defined(HAVE_SYS_IOCTL_H) && defined(HAVE_TERMIOS_H)
225 // Try to determine the width of the terminal.
227 // Zero-fill ws to avoid a false positive from MemorySanitizer.
228 memset(&ws, 0, sizeof(ws));
229 if (ioctl(FileID, TIOCGWINSZ, &ws) == 0)
236 unsigned Process::StandardOutColumns() {
237 if (!StandardOutIsDisplayed())
240 return getColumns(1);
243 unsigned Process::StandardErrColumns() {
244 if (!StandardErrIsDisplayed())
247 return getColumns(2);
250 static bool terminalHasColors() {
251 if (const char *term = std::getenv("TERM")) {
252 // Most modern terminals support ANSI escape sequences for colors.
253 // We could check terminfo, or have a list of known terms that support
254 // colors, but that would be overkill.
255 // The user can always ask for no colors by setting TERM to dumb, or
256 // using a commandline flag.
257 return strcmp(term, "dumb") != 0;
262 bool Process::FileDescriptorHasColors(int fd) {
263 // A file descriptor has colors if it is displayed and the terminal has
265 return FileDescriptorIsDisplayed(fd) && terminalHasColors();
268 bool Process::StandardOutHasColors() {
269 return FileDescriptorHasColors(STDOUT_FILENO);
272 bool Process::StandardErrHasColors() {
273 return FileDescriptorHasColors(STDERR_FILENO);
276 bool Process::ColorNeedsFlush() {
277 // No, we use ANSI escape sequences.
281 #define COLOR(FGBG, CODE, BOLD) "\033[0;" BOLD FGBG CODE "m"
283 #define ALLCOLORS(FGBG,BOLD) {\
284 COLOR(FGBG, "0", BOLD),\
285 COLOR(FGBG, "1", BOLD),\
286 COLOR(FGBG, "2", BOLD),\
287 COLOR(FGBG, "3", BOLD),\
288 COLOR(FGBG, "4", BOLD),\
289 COLOR(FGBG, "5", BOLD),\
290 COLOR(FGBG, "6", BOLD),\
291 COLOR(FGBG, "7", BOLD)\
294 static const char colorcodes[2][2][8][10] = {
295 { ALLCOLORS("3",""), ALLCOLORS("3","1;") },
296 { ALLCOLORS("4",""), ALLCOLORS("4","1;") }
299 const char *Process::OutputColor(char code, bool bold, bool bg) {
300 return colorcodes[bg?1:0][bold?1:0][code&7];
303 const char *Process::OutputBold(bool bg) {
307 const char *Process::OutputReverse() {
311 const char *Process::ResetColor() {
315 #if !defined(HAVE_ARC4RANDOM)
316 static unsigned GetRandomNumberSeed() {
317 // Attempt to get the initial seed from /dev/urandom, if possible.
318 if (FILE *RandomSource = ::fopen("/dev/urandom", "r")) {
320 int count = ::fread((void *)&seed, sizeof(seed), 1, RandomSource);
321 ::fclose(RandomSource);
323 // Return the seed if the read was successful.
328 // Otherwise, swizzle the current time and the process ID to form a reasonable
330 TimeValue Now = TimeValue::now();
331 return hash_combine(Now.seconds(), Now.nanoseconds(), ::getpid());
335 unsigned llvm::sys::Process::GetRandomNumber() {
336 #if defined(HAVE_ARC4RANDOM)
339 static int x = (::srand(GetRandomNumberSeed()), 0);