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 unsigned getPageSize() {
53 #if defined(__CYGWIN__)
54 // On Cygwin, getpagesize() returns 64k but the page size for the purposes of
55 // memory protection and mmap() is 4k.
56 // See http://www.cygwin.com/ml/cygwin/2009-01/threads.html#00492
57 const int page_size = 0x1000;
58 #elif defined(HAVE_GETPAGESIZE)
59 const int page_size = ::getpagesize();
60 #elif defined(HAVE_SYSCONF)
61 long page_size = ::sysconf(_SC_PAGE_SIZE);
63 #warning Cannot get the page size on this machine
65 return static_cast<unsigned>(page_size);
68 // This constructor guaranteed to be run exactly once on a single thread, and
69 // sets up various process invariants that can be queried cheaply from then on.
70 self_process::self_process() : PageSize(getPageSize()) {
74 size_t Process::GetMallocUsage() {
75 #if defined(HAVE_MALLINFO)
79 #elif defined(HAVE_MALLOC_ZONE_STATISTICS) && defined(HAVE_MALLOC_MALLOC_H)
80 malloc_statistics_t Stats;
81 malloc_zone_statistics(malloc_default_zone(), &Stats);
82 return Stats.size_in_use; // darwin
83 #elif defined(HAVE_SBRK)
84 // Note this is only an approximation and more closely resembles
85 // the value returned by mallinfo in the arena field.
86 static char *StartOfMemory = reinterpret_cast<char*>(::sbrk(0));
87 char *EndOfMemory = (char*)sbrk(0);
88 if (EndOfMemory != ((char*)-1) && StartOfMemory != ((char*)-1))
89 return EndOfMemory - StartOfMemory;
93 #warning Cannot get malloc info on this platform
99 Process::GetTimeUsage(TimeValue& elapsed, TimeValue& user_time,
102 elapsed = TimeValue::now();
103 #if defined(HAVE_GETRUSAGE)
105 ::getrusage(RUSAGE_SELF, &usage);
106 user_time = TimeValue(
107 static_cast<TimeValue::SecondsType>( usage.ru_utime.tv_sec ),
108 static_cast<TimeValue::NanoSecondsType>( usage.ru_utime.tv_usec *
109 TimeValue::NANOSECONDS_PER_MICROSECOND ) );
110 sys_time = TimeValue(
111 static_cast<TimeValue::SecondsType>( usage.ru_stime.tv_sec ),
112 static_cast<TimeValue::NanoSecondsType>( usage.ru_stime.tv_usec *
113 TimeValue::NANOSECONDS_PER_MICROSECOND ) );
115 #warning Cannot get usage times on this platform
116 user_time.seconds(0);
117 user_time.microseconds(0);
119 sys_time.microseconds(0);
123 int Process::GetCurrentUserId() {
127 int Process::GetCurrentGroupId() {
131 #if defined(HAVE_MACH_MACH_H) && !defined(__GNU__)
132 #include <mach/mach.h>
135 // Some LLVM programs such as bugpoint produce core files as a normal part of
136 // their operation. To prevent the disk from filling up, this function
137 // does what's necessary to prevent their generation.
138 void Process::PreventCoreFiles() {
141 rlim.rlim_cur = rlim.rlim_max = 0;
142 setrlimit(RLIMIT_CORE, &rlim);
145 #if defined(HAVE_MACH_MACH_H) && !defined(__GNU__)
146 // Disable crash reporting on Mac OS X 10.0-10.4
148 // get information about the original set of exception ports for the task
149 mach_msg_type_number_t Count = 0;
150 exception_mask_t OriginalMasks[EXC_TYPES_COUNT];
151 exception_port_t OriginalPorts[EXC_TYPES_COUNT];
152 exception_behavior_t OriginalBehaviors[EXC_TYPES_COUNT];
153 thread_state_flavor_t OriginalFlavors[EXC_TYPES_COUNT];
155 task_get_exception_ports(mach_task_self(), EXC_MASK_ALL, OriginalMasks,
156 &Count, OriginalPorts, OriginalBehaviors,
158 if (err == KERN_SUCCESS) {
159 // replace each with MACH_PORT_NULL.
160 for (unsigned i = 0; i != Count; ++i)
161 task_set_exception_ports(mach_task_self(), OriginalMasks[i],
162 MACH_PORT_NULL, OriginalBehaviors[i],
166 // Disable crash reporting on Mac OS X 10.5
167 signal(SIGABRT, _exit);
168 signal(SIGILL, _exit);
169 signal(SIGFPE, _exit);
170 signal(SIGSEGV, _exit);
171 signal(SIGBUS, _exit);
175 bool Process::StandardInIsUserInput() {
176 return FileDescriptorIsDisplayed(STDIN_FILENO);
179 bool Process::StandardOutIsDisplayed() {
180 return FileDescriptorIsDisplayed(STDOUT_FILENO);
183 bool Process::StandardErrIsDisplayed() {
184 return FileDescriptorIsDisplayed(STDERR_FILENO);
187 bool Process::FileDescriptorIsDisplayed(int fd) {
191 // If we don't have isatty, just return false.
196 static unsigned getColumns(int FileID) {
197 // If COLUMNS is defined in the environment, wrap to that many columns.
198 if (const char *ColumnsStr = std::getenv("COLUMNS")) {
199 int Columns = std::atoi(ColumnsStr);
204 unsigned Columns = 0;
206 #if defined(HAVE_SYS_IOCTL_H) && defined(HAVE_TERMIOS_H)
207 // Try to determine the width of the terminal.
209 if (ioctl(FileID, TIOCGWINSZ, &ws) == 0)
216 unsigned Process::StandardOutColumns() {
217 if (!StandardOutIsDisplayed())
220 return getColumns(1);
223 unsigned Process::StandardErrColumns() {
224 if (!StandardErrIsDisplayed())
227 return getColumns(2);
230 static bool terminalHasColors() {
231 if (const char *term = std::getenv("TERM")) {
232 // Most modern terminals support ANSI escape sequences for colors.
233 // We could check terminfo, or have a list of known terms that support
234 // colors, but that would be overkill.
235 // The user can always ask for no colors by setting TERM to dumb, or
236 // using a commandline flag.
237 return strcmp(term, "dumb") != 0;
242 bool Process::FileDescriptorHasColors(int fd) {
243 // A file descriptor has colors if it is displayed and the terminal has
245 return FileDescriptorIsDisplayed(fd) && terminalHasColors();
248 bool Process::StandardOutHasColors() {
249 return FileDescriptorHasColors(STDOUT_FILENO);
252 bool Process::StandardErrHasColors() {
253 return FileDescriptorHasColors(STDERR_FILENO);
256 bool Process::ColorNeedsFlush() {
257 // No, we use ANSI escape sequences.
261 #define COLOR(FGBG, CODE, BOLD) "\033[0;" BOLD FGBG CODE "m"
263 #define ALLCOLORS(FGBG,BOLD) {\
264 COLOR(FGBG, "0", BOLD),\
265 COLOR(FGBG, "1", BOLD),\
266 COLOR(FGBG, "2", BOLD),\
267 COLOR(FGBG, "3", BOLD),\
268 COLOR(FGBG, "4", BOLD),\
269 COLOR(FGBG, "5", BOLD),\
270 COLOR(FGBG, "6", BOLD),\
271 COLOR(FGBG, "7", BOLD)\
274 static const char colorcodes[2][2][8][10] = {
275 { ALLCOLORS("3",""), ALLCOLORS("3","1;") },
276 { ALLCOLORS("4",""), ALLCOLORS("4","1;") }
279 const char *Process::OutputColor(char code, bool bold, bool bg) {
280 return colorcodes[bg?1:0][bold?1:0][code&7];
283 const char *Process::OutputBold(bool bg) {
287 const char *Process::OutputReverse() {
291 const char *Process::ResetColor() {
295 #if !defined(HAVE_ARC4RANDOM)
296 static unsigned GetRandomNumberSeed() {
297 // Attempt to get the initial seed from /dev/urandom, if possible.
298 if (FILE *RandomSource = ::fopen("/dev/urandom", "r")) {
300 int count = ::fread((void *)&seed, sizeof(seed), 1, RandomSource);
301 ::fclose(RandomSource);
303 // Return the seed if the read was successful.
308 // Otherwise, swizzle the current time and the process ID to form a reasonable
310 TimeValue Now = TimeValue::now();
311 return hash_combine(Now.seconds(), Now.nanoseconds(), ::getpid());
315 unsigned llvm::sys::Process::GetRandomNumber() {
316 #if defined(HAVE_ARC4RANDOM)
319 static int x = (::srand(GetRandomNumberSeed()), 0);