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::GetPageSize()
50 #if defined(__CYGWIN__)
51 // On Cygwin, getpagesize() returns 64k but the page size for the purposes of
52 // memory protection and mmap() is 4k.
53 // See http://www.cygwin.com/ml/cygwin/2009-01/threads.html#00492
54 const int page_size = 0x1000;
55 #elif defined(HAVE_GETPAGESIZE)
56 const int page_size = ::getpagesize();
57 #elif defined(HAVE_SYSCONF)
58 long page_size = ::sysconf(_SC_PAGE_SIZE);
60 #warning Cannot get the page size on this machine
62 return static_cast<unsigned>(page_size);
65 size_t Process::GetMallocUsage() {
66 #if defined(HAVE_MALLINFO)
70 #elif defined(HAVE_MALLOC_ZONE_STATISTICS) && defined(HAVE_MALLOC_MALLOC_H)
71 malloc_statistics_t Stats;
72 malloc_zone_statistics(malloc_default_zone(), &Stats);
73 return Stats.size_in_use; // darwin
74 #elif defined(HAVE_SBRK)
75 // Note this is only an approximation and more closely resembles
76 // the value returned by mallinfo in the arena field.
77 static char *StartOfMemory = reinterpret_cast<char*>(::sbrk(0));
78 char *EndOfMemory = (char*)sbrk(0);
79 if (EndOfMemory != ((char*)-1) && StartOfMemory != ((char*)-1))
80 return EndOfMemory - StartOfMemory;
84 #warning Cannot get malloc info on this platform
90 Process::GetTotalMemoryUsage()
92 #if defined(HAVE_MALLINFO)
93 struct mallinfo mi = ::mallinfo();
94 return mi.uordblks + mi.hblkhd;
95 #elif defined(HAVE_MALLOC_ZONE_STATISTICS) && defined(HAVE_MALLOC_MALLOC_H)
96 malloc_statistics_t Stats;
97 malloc_zone_statistics(malloc_default_zone(), &Stats);
98 return Stats.size_allocated; // darwin
99 #elif defined(HAVE_GETRUSAGE) && !defined(__HAIKU__)
101 ::getrusage(RUSAGE_SELF, &usage);
102 return usage.ru_maxrss;
104 #warning Cannot get total memory size on this platform
110 Process::GetTimeUsage(TimeValue& elapsed, TimeValue& user_time,
113 elapsed = TimeValue::now();
114 #if defined(HAVE_GETRUSAGE)
116 ::getrusage(RUSAGE_SELF, &usage);
117 user_time = TimeValue(
118 static_cast<TimeValue::SecondsType>( usage.ru_utime.tv_sec ),
119 static_cast<TimeValue::NanoSecondsType>( usage.ru_utime.tv_usec *
120 TimeValue::NANOSECONDS_PER_MICROSECOND ) );
121 sys_time = TimeValue(
122 static_cast<TimeValue::SecondsType>( usage.ru_stime.tv_sec ),
123 static_cast<TimeValue::NanoSecondsType>( usage.ru_stime.tv_usec *
124 TimeValue::NANOSECONDS_PER_MICROSECOND ) );
126 #warning Cannot get usage times on this platform
127 user_time.seconds(0);
128 user_time.microseconds(0);
130 sys_time.microseconds(0);
134 int Process::GetCurrentUserId() {
138 int Process::GetCurrentGroupId() {
142 #if defined(HAVE_MACH_MACH_H) && !defined(__GNU__)
143 #include <mach/mach.h>
146 // Some LLVM programs such as bugpoint produce core files as a normal part of
147 // their operation. To prevent the disk from filling up, this function
148 // does what's necessary to prevent their generation.
149 void Process::PreventCoreFiles() {
152 rlim.rlim_cur = rlim.rlim_max = 0;
153 setrlimit(RLIMIT_CORE, &rlim);
156 #if defined(HAVE_MACH_MACH_H) && !defined(__GNU__)
157 // Disable crash reporting on Mac OS X 10.0-10.4
159 // get information about the original set of exception ports for the task
160 mach_msg_type_number_t Count = 0;
161 exception_mask_t OriginalMasks[EXC_TYPES_COUNT];
162 exception_port_t OriginalPorts[EXC_TYPES_COUNT];
163 exception_behavior_t OriginalBehaviors[EXC_TYPES_COUNT];
164 thread_state_flavor_t OriginalFlavors[EXC_TYPES_COUNT];
166 task_get_exception_ports(mach_task_self(), EXC_MASK_ALL, OriginalMasks,
167 &Count, OriginalPorts, OriginalBehaviors,
169 if (err == KERN_SUCCESS) {
170 // replace each with MACH_PORT_NULL.
171 for (unsigned i = 0; i != Count; ++i)
172 task_set_exception_ports(mach_task_self(), OriginalMasks[i],
173 MACH_PORT_NULL, OriginalBehaviors[i],
177 // Disable crash reporting on Mac OS X 10.5
178 signal(SIGABRT, _exit);
179 signal(SIGILL, _exit);
180 signal(SIGFPE, _exit);
181 signal(SIGSEGV, _exit);
182 signal(SIGBUS, _exit);
186 bool Process::StandardInIsUserInput() {
187 return FileDescriptorIsDisplayed(STDIN_FILENO);
190 bool Process::StandardOutIsDisplayed() {
191 return FileDescriptorIsDisplayed(STDOUT_FILENO);
194 bool Process::StandardErrIsDisplayed() {
195 return FileDescriptorIsDisplayed(STDERR_FILENO);
198 bool Process::FileDescriptorIsDisplayed(int fd) {
202 // If we don't have isatty, just return false.
207 static unsigned getColumns(int FileID) {
208 // If COLUMNS is defined in the environment, wrap to that many columns.
209 if (const char *ColumnsStr = std::getenv("COLUMNS")) {
210 int Columns = std::atoi(ColumnsStr);
215 unsigned Columns = 0;
217 #if defined(HAVE_SYS_IOCTL_H) && defined(HAVE_TERMIOS_H)
218 // Try to determine the width of the terminal.
220 if (ioctl(FileID, TIOCGWINSZ, &ws) == 0)
227 unsigned Process::StandardOutColumns() {
228 if (!StandardOutIsDisplayed())
231 return getColumns(1);
234 unsigned Process::StandardErrColumns() {
235 if (!StandardErrIsDisplayed())
238 return getColumns(2);
241 static bool terminalHasColors() {
242 if (const char *term = std::getenv("TERM")) {
243 // Most modern terminals support ANSI escape sequences for colors.
244 // We could check terminfo, or have a list of known terms that support
245 // colors, but that would be overkill.
246 // The user can always ask for no colors by setting TERM to dumb, or
247 // using a commandline flag.
248 return strcmp(term, "dumb") != 0;
253 bool Process::FileDescriptorHasColors(int fd) {
254 // A file descriptor has colors if it is displayed and the terminal has
256 return FileDescriptorIsDisplayed(fd) && terminalHasColors();
259 bool Process::StandardOutHasColors() {
260 return FileDescriptorHasColors(STDOUT_FILENO);
263 bool Process::StandardErrHasColors() {
264 return FileDescriptorHasColors(STDERR_FILENO);
267 bool Process::ColorNeedsFlush() {
268 // No, we use ANSI escape sequences.
272 #define COLOR(FGBG, CODE, BOLD) "\033[0;" BOLD FGBG CODE "m"
274 #define ALLCOLORS(FGBG,BOLD) {\
275 COLOR(FGBG, "0", BOLD),\
276 COLOR(FGBG, "1", BOLD),\
277 COLOR(FGBG, "2", BOLD),\
278 COLOR(FGBG, "3", BOLD),\
279 COLOR(FGBG, "4", BOLD),\
280 COLOR(FGBG, "5", BOLD),\
281 COLOR(FGBG, "6", BOLD),\
282 COLOR(FGBG, "7", BOLD)\
285 static const char colorcodes[2][2][8][10] = {
286 { ALLCOLORS("3",""), ALLCOLORS("3","1;") },
287 { ALLCOLORS("4",""), ALLCOLORS("4","1;") }
290 const char *Process::OutputColor(char code, bool bold, bool bg) {
291 return colorcodes[bg?1:0][bold?1:0][code&7];
294 const char *Process::OutputBold(bool bg) {
298 const char *Process::OutputReverse() {
302 const char *Process::ResetColor() {
306 #if !defined(HAVE_ARC4RANDOM)
307 static unsigned GetRandomNumberSeed() {
308 // Attempt to get the initial seed from /dev/urandom, if possible.
309 if (FILE *RandomSource = ::fopen("/dev/urandom", "r")) {
311 int count = ::fread((void *)&seed, sizeof(seed), 1, RandomSource);
312 ::fclose(RandomSource);
314 // Return the seed if the read was successful.
319 // Otherwise, swizzle the current time and the process ID to form a reasonable
321 TimeValue Now = llvm::TimeValue::now();
322 return hash_combine(Now.seconds(), Now.nanoseconds(), ::getpid());
326 unsigned llvm::sys::Process::GetRandomNumber() {
327 #if defined(HAVE_ARC4RANDOM)
330 static int x = (::srand(GetRandomNumberSeed()), 0);