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() {
54 Process::GetPageSize()
56 #if defined(__CYGWIN__)
57 // On Cygwin, getpagesize() returns 64k but the page size for the purposes of
58 // memory protection and mmap() is 4k.
59 // See http://www.cygwin.com/ml/cygwin/2009-01/threads.html#00492
60 const int page_size = 0x1000;
61 #elif defined(HAVE_GETPAGESIZE)
62 const int page_size = ::getpagesize();
63 #elif defined(HAVE_SYSCONF)
64 long page_size = ::sysconf(_SC_PAGE_SIZE);
66 #warning Cannot get the page size on this machine
68 return static_cast<unsigned>(page_size);
71 size_t Process::GetMallocUsage() {
72 #if defined(HAVE_MALLINFO)
76 #elif defined(HAVE_MALLOC_ZONE_STATISTICS) && defined(HAVE_MALLOC_MALLOC_H)
77 malloc_statistics_t Stats;
78 malloc_zone_statistics(malloc_default_zone(), &Stats);
79 return Stats.size_in_use; // darwin
80 #elif defined(HAVE_SBRK)
81 // Note this is only an approximation and more closely resembles
82 // the value returned by mallinfo in the arena field.
83 static char *StartOfMemory = reinterpret_cast<char*>(::sbrk(0));
84 char *EndOfMemory = (char*)sbrk(0);
85 if (EndOfMemory != ((char*)-1) && StartOfMemory != ((char*)-1))
86 return EndOfMemory - StartOfMemory;
90 #warning Cannot get malloc info on this platform
96 Process::GetTotalMemoryUsage()
98 #if defined(HAVE_MALLINFO)
99 struct mallinfo mi = ::mallinfo();
100 return mi.uordblks + mi.hblkhd;
101 #elif defined(HAVE_MALLOC_ZONE_STATISTICS) && defined(HAVE_MALLOC_MALLOC_H)
102 malloc_statistics_t Stats;
103 malloc_zone_statistics(malloc_default_zone(), &Stats);
104 return Stats.size_allocated; // darwin
105 #elif defined(HAVE_GETRUSAGE) && !defined(__HAIKU__)
107 ::getrusage(RUSAGE_SELF, &usage);
108 return usage.ru_maxrss;
110 #warning Cannot get total memory size on this platform
116 Process::GetTimeUsage(TimeValue& elapsed, TimeValue& user_time,
119 elapsed = TimeValue::now();
120 #if defined(HAVE_GETRUSAGE)
122 ::getrusage(RUSAGE_SELF, &usage);
123 user_time = TimeValue(
124 static_cast<TimeValue::SecondsType>( usage.ru_utime.tv_sec ),
125 static_cast<TimeValue::NanoSecondsType>( usage.ru_utime.tv_usec *
126 TimeValue::NANOSECONDS_PER_MICROSECOND ) );
127 sys_time = TimeValue(
128 static_cast<TimeValue::SecondsType>( usage.ru_stime.tv_sec ),
129 static_cast<TimeValue::NanoSecondsType>( usage.ru_stime.tv_usec *
130 TimeValue::NANOSECONDS_PER_MICROSECOND ) );
132 #warning Cannot get usage times on this platform
133 user_time.seconds(0);
134 user_time.microseconds(0);
136 sys_time.microseconds(0);
140 int Process::GetCurrentUserId() {
144 int Process::GetCurrentGroupId() {
148 #if defined(HAVE_MACH_MACH_H) && !defined(__GNU__)
149 #include <mach/mach.h>
152 // Some LLVM programs such as bugpoint produce core files as a normal part of
153 // their operation. To prevent the disk from filling up, this function
154 // does what's necessary to prevent their generation.
155 void Process::PreventCoreFiles() {
158 rlim.rlim_cur = rlim.rlim_max = 0;
159 setrlimit(RLIMIT_CORE, &rlim);
162 #if defined(HAVE_MACH_MACH_H) && !defined(__GNU__)
163 // Disable crash reporting on Mac OS X 10.0-10.4
165 // get information about the original set of exception ports for the task
166 mach_msg_type_number_t Count = 0;
167 exception_mask_t OriginalMasks[EXC_TYPES_COUNT];
168 exception_port_t OriginalPorts[EXC_TYPES_COUNT];
169 exception_behavior_t OriginalBehaviors[EXC_TYPES_COUNT];
170 thread_state_flavor_t OriginalFlavors[EXC_TYPES_COUNT];
172 task_get_exception_ports(mach_task_self(), EXC_MASK_ALL, OriginalMasks,
173 &Count, OriginalPorts, OriginalBehaviors,
175 if (err == KERN_SUCCESS) {
176 // replace each with MACH_PORT_NULL.
177 for (unsigned i = 0; i != Count; ++i)
178 task_set_exception_ports(mach_task_self(), OriginalMasks[i],
179 MACH_PORT_NULL, OriginalBehaviors[i],
183 // Disable crash reporting on Mac OS X 10.5
184 signal(SIGABRT, _exit);
185 signal(SIGILL, _exit);
186 signal(SIGFPE, _exit);
187 signal(SIGSEGV, _exit);
188 signal(SIGBUS, _exit);
192 bool Process::StandardInIsUserInput() {
193 return FileDescriptorIsDisplayed(STDIN_FILENO);
196 bool Process::StandardOutIsDisplayed() {
197 return FileDescriptorIsDisplayed(STDOUT_FILENO);
200 bool Process::StandardErrIsDisplayed() {
201 return FileDescriptorIsDisplayed(STDERR_FILENO);
204 bool Process::FileDescriptorIsDisplayed(int fd) {
208 // If we don't have isatty, just return false.
213 static unsigned getColumns(int FileID) {
214 // If COLUMNS is defined in the environment, wrap to that many columns.
215 if (const char *ColumnsStr = std::getenv("COLUMNS")) {
216 int Columns = std::atoi(ColumnsStr);
221 unsigned Columns = 0;
223 #if defined(HAVE_SYS_IOCTL_H) && defined(HAVE_TERMIOS_H)
224 // Try to determine the width of the terminal.
226 if (ioctl(FileID, TIOCGWINSZ, &ws) == 0)
233 unsigned Process::StandardOutColumns() {
234 if (!StandardOutIsDisplayed())
237 return getColumns(1);
240 unsigned Process::StandardErrColumns() {
241 if (!StandardErrIsDisplayed())
244 return getColumns(2);
247 static bool terminalHasColors() {
248 if (const char *term = std::getenv("TERM")) {
249 // Most modern terminals support ANSI escape sequences for colors.
250 // We could check terminfo, or have a list of known terms that support
251 // colors, but that would be overkill.
252 // The user can always ask for no colors by setting TERM to dumb, or
253 // using a commandline flag.
254 return strcmp(term, "dumb") != 0;
259 bool Process::FileDescriptorHasColors(int fd) {
260 // A file descriptor has colors if it is displayed and the terminal has
262 return FileDescriptorIsDisplayed(fd) && terminalHasColors();
265 bool Process::StandardOutHasColors() {
266 return FileDescriptorHasColors(STDOUT_FILENO);
269 bool Process::StandardErrHasColors() {
270 return FileDescriptorHasColors(STDERR_FILENO);
273 bool Process::ColorNeedsFlush() {
274 // No, we use ANSI escape sequences.
278 #define COLOR(FGBG, CODE, BOLD) "\033[0;" BOLD FGBG CODE "m"
280 #define ALLCOLORS(FGBG,BOLD) {\
281 COLOR(FGBG, "0", BOLD),\
282 COLOR(FGBG, "1", BOLD),\
283 COLOR(FGBG, "2", BOLD),\
284 COLOR(FGBG, "3", BOLD),\
285 COLOR(FGBG, "4", BOLD),\
286 COLOR(FGBG, "5", BOLD),\
287 COLOR(FGBG, "6", BOLD),\
288 COLOR(FGBG, "7", BOLD)\
291 static const char colorcodes[2][2][8][10] = {
292 { ALLCOLORS("3",""), ALLCOLORS("3","1;") },
293 { ALLCOLORS("4",""), ALLCOLORS("4","1;") }
296 const char *Process::OutputColor(char code, bool bold, bool bg) {
297 return colorcodes[bg?1:0][bold?1:0][code&7];
300 const char *Process::OutputBold(bool bg) {
304 const char *Process::OutputReverse() {
308 const char *Process::ResetColor() {
312 #if !defined(HAVE_ARC4RANDOM)
313 static unsigned GetRandomNumberSeed() {
314 // Attempt to get the initial seed from /dev/urandom, if possible.
315 if (FILE *RandomSource = ::fopen("/dev/urandom", "r")) {
317 int count = ::fread((void *)&seed, sizeof(seed), 1, RandomSource);
318 ::fclose(RandomSource);
320 // Return the seed if the read was successful.
325 // Otherwise, swizzle the current time and the process ID to form a reasonable
327 TimeValue Now = TimeValue::now();
328 return hash_combine(Now.seconds(), Now.nanoseconds(), ::getpid());
332 unsigned llvm::sys::Process::GetRandomNumber() {
333 #if defined(HAVE_ARC4RANDOM)
336 static int x = (::srand(GetRandomNumberSeed()), 0);