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 // DragonFly BSD has deprecated <malloc.h> for <stdlib.h> instead,
24 // Unix.h includes this for us already.
25 #if defined(HAVE_MALLOC_H) && !defined(__DragonFly__)
28 #ifdef HAVE_MALLOC_MALLOC_H
29 #include <malloc/malloc.h>
31 #ifdef HAVE_SYS_IOCTL_H
32 # include <sys/ioctl.h>
38 //===----------------------------------------------------------------------===//
39 //=== WARNING: Implementation here must contain only generic UNIX code that
40 //=== is guaranteed to work on *all* UNIX variants.
41 //===----------------------------------------------------------------------===//
47 Process::GetPageSize()
49 #if defined(__CYGWIN__)
50 // On Cygwin, getpagesize() returns 64k but the page size for the purposes of
51 // memory protection and mmap() is 4k.
52 // See http://www.cygwin.com/ml/cygwin/2009-01/threads.html#00492
53 const int page_size = 0x1000;
54 #elif defined(HAVE_GETPAGESIZE)
55 const int page_size = ::getpagesize();
56 #elif defined(HAVE_SYSCONF)
57 long page_size = ::sysconf(_SC_PAGE_SIZE);
59 #warning Cannot get the page size on this machine
61 return static_cast<unsigned>(page_size);
64 size_t Process::GetMallocUsage() {
65 #if defined(HAVE_MALLINFO)
69 #elif defined(HAVE_MALLOC_ZONE_STATISTICS) && defined(HAVE_MALLOC_MALLOC_H)
70 malloc_statistics_t Stats;
71 malloc_zone_statistics(malloc_default_zone(), &Stats);
72 return Stats.size_in_use; // darwin
73 #elif defined(HAVE_SBRK)
74 // Note this is only an approximation and more closely resembles
75 // the value returned by mallinfo in the arena field.
76 static char *StartOfMemory = reinterpret_cast<char*>(::sbrk(0));
77 char *EndOfMemory = (char*)sbrk(0);
78 if (EndOfMemory != ((char*)-1) && StartOfMemory != ((char*)-1))
79 return EndOfMemory - StartOfMemory;
83 #warning Cannot get malloc info on this platform
89 Process::GetTotalMemoryUsage()
91 #if defined(HAVE_MALLINFO)
92 struct mallinfo mi = ::mallinfo();
93 return mi.uordblks + mi.hblkhd;
94 #elif defined(HAVE_MALLOC_ZONE_STATISTICS) && defined(HAVE_MALLOC_MALLOC_H)
95 malloc_statistics_t Stats;
96 malloc_zone_statistics(malloc_default_zone(), &Stats);
97 return Stats.size_allocated; // darwin
98 #elif defined(HAVE_GETRUSAGE) && !defined(__HAIKU__)
100 ::getrusage(RUSAGE_SELF, &usage);
101 return usage.ru_maxrss;
103 #warning Cannot get total memory size on this platform
109 Process::GetTimeUsage(TimeValue& elapsed, TimeValue& user_time,
112 elapsed = TimeValue::now();
113 #if defined(HAVE_GETRUSAGE)
115 ::getrusage(RUSAGE_SELF, &usage);
116 user_time = TimeValue(
117 static_cast<TimeValue::SecondsType>( usage.ru_utime.tv_sec ),
118 static_cast<TimeValue::NanoSecondsType>( usage.ru_utime.tv_usec *
119 TimeValue::NANOSECONDS_PER_MICROSECOND ) );
120 sys_time = TimeValue(
121 static_cast<TimeValue::SecondsType>( usage.ru_stime.tv_sec ),
122 static_cast<TimeValue::NanoSecondsType>( usage.ru_stime.tv_usec *
123 TimeValue::NANOSECONDS_PER_MICROSECOND ) );
125 #warning Cannot get usage times on this platform
126 user_time.seconds(0);
127 user_time.microseconds(0);
129 sys_time.microseconds(0);
133 int Process::GetCurrentUserId() {
137 int Process::GetCurrentGroupId() {
141 #if defined(HAVE_MACH_MACH_H) && !defined(__GNU__)
142 #include <mach/mach.h>
145 // Some LLVM programs such as bugpoint produce core files as a normal part of
146 // their operation. To prevent the disk from filling up, this function
147 // does what's necessary to prevent their generation.
148 void Process::PreventCoreFiles() {
151 rlim.rlim_cur = rlim.rlim_max = 0;
152 setrlimit(RLIMIT_CORE, &rlim);
155 #if defined(HAVE_MACH_MACH_H) && !defined(__GNU__)
156 // Disable crash reporting on Mac OS X 10.0-10.4
158 // get information about the original set of exception ports for the task
159 mach_msg_type_number_t Count = 0;
160 exception_mask_t OriginalMasks[EXC_TYPES_COUNT];
161 exception_port_t OriginalPorts[EXC_TYPES_COUNT];
162 exception_behavior_t OriginalBehaviors[EXC_TYPES_COUNT];
163 thread_state_flavor_t OriginalFlavors[EXC_TYPES_COUNT];
165 task_get_exception_ports(mach_task_self(), EXC_MASK_ALL, OriginalMasks,
166 &Count, OriginalPorts, OriginalBehaviors,
168 if (err == KERN_SUCCESS) {
169 // replace each with MACH_PORT_NULL.
170 for (unsigned i = 0; i != Count; ++i)
171 task_set_exception_ports(mach_task_self(), OriginalMasks[i],
172 MACH_PORT_NULL, OriginalBehaviors[i],
176 // Disable crash reporting on Mac OS X 10.5
177 signal(SIGABRT, _exit);
178 signal(SIGILL, _exit);
179 signal(SIGFPE, _exit);
180 signal(SIGSEGV, _exit);
181 signal(SIGBUS, _exit);
185 bool Process::StandardInIsUserInput() {
186 return FileDescriptorIsDisplayed(STDIN_FILENO);
189 bool Process::StandardOutIsDisplayed() {
190 return FileDescriptorIsDisplayed(STDOUT_FILENO);
193 bool Process::StandardErrIsDisplayed() {
194 return FileDescriptorIsDisplayed(STDERR_FILENO);
197 bool Process::FileDescriptorIsDisplayed(int fd) {
201 // If we don't have isatty, just return false.
206 static unsigned getColumns(int FileID) {
207 // If COLUMNS is defined in the environment, wrap to that many columns.
208 if (const char *ColumnsStr = std::getenv("COLUMNS")) {
209 int Columns = std::atoi(ColumnsStr);
214 unsigned Columns = 0;
216 #if defined(HAVE_SYS_IOCTL_H) && defined(HAVE_TERMIOS_H)
217 // Try to determine the width of the terminal.
219 if (ioctl(FileID, TIOCGWINSZ, &ws) == 0)
226 unsigned Process::StandardOutColumns() {
227 if (!StandardOutIsDisplayed())
230 return getColumns(1);
233 unsigned Process::StandardErrColumns() {
234 if (!StandardErrIsDisplayed())
237 return getColumns(2);
240 static bool terminalHasColors() {
241 if (const char *term = std::getenv("TERM")) {
242 // Most modern terminals support ANSI escape sequences for colors.
243 // We could check terminfo, or have a list of known terms that support
244 // colors, but that would be overkill.
245 // The user can always ask for no colors by setting TERM to dumb, or
246 // using a commandline flag.
247 return strcmp(term, "dumb") != 0;
252 bool Process::FileDescriptorHasColors(int fd) {
253 // A file descriptor has colors if it is displayed and the terminal has
255 return FileDescriptorIsDisplayed(fd) && terminalHasColors();
258 bool Process::StandardOutHasColors() {
259 return FileDescriptorHasColors(STDOUT_FILENO);
262 bool Process::StandardErrHasColors() {
263 return FileDescriptorHasColors(STDERR_FILENO);
266 bool Process::ColorNeedsFlush() {
267 // No, we use ANSI escape sequences.
271 #define COLOR(FGBG, CODE, BOLD) "\033[0;" BOLD FGBG CODE "m"
273 #define ALLCOLORS(FGBG,BOLD) {\
274 COLOR(FGBG, "0", BOLD),\
275 COLOR(FGBG, "1", BOLD),\
276 COLOR(FGBG, "2", BOLD),\
277 COLOR(FGBG, "3", BOLD),\
278 COLOR(FGBG, "4", BOLD),\
279 COLOR(FGBG, "5", BOLD),\
280 COLOR(FGBG, "6", BOLD),\
281 COLOR(FGBG, "7", BOLD)\
284 static const char colorcodes[2][2][8][10] = {
285 { ALLCOLORS("3",""), ALLCOLORS("3","1;") },
286 { ALLCOLORS("4",""), ALLCOLORS("4","1;") }
289 const char *Process::OutputColor(char code, bool bold, bool bg) {
290 return colorcodes[bg?1:0][bold?1:0][code&7];
293 const char *Process::OutputBold(bool bg) {
297 const char *Process::OutputReverse() {
301 const char *Process::ResetColor() {
305 #if !defined(HAVE_ARC4RANDOM)
306 static unsigned GetRandomNumberSeed() {
307 // Attempt to get the initial seed from /dev/urandom, if possible.
308 if (FILE *RandomSource = ::fopen("/dev/urandom", "r")) {
310 int count = ::fread((void *)&seed, sizeof(seed), 1, RandomSource);
311 ::fclose(RandomSource);
313 // Return the seed if the read was successful.
318 // Otherwise, swizzle the current time and the process ID to form a reasonable
320 TimeValue Now = llvm::TimeValue::now();
321 return hash_combine(Now.seconds(), Now.nanoseconds(), ::getpid());
325 unsigned llvm::sys::Process::GetRandomNumber() {
326 #if defined(HAVE_ARC4RANDOM)
329 static int x = (::srand(GetRandomNumberSeed()), 0);