1335b78e86b255b84f706460160a4a0055d6ff0d
[oota-llvm.git] / lib / Support / Unix / Process.inc
1 //===- Unix/Process.cpp - Unix Process Implementation --------- -*- C++ -*-===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 //
10 // This file provides the generic Unix implementation of the Process class.
11 //
12 //===----------------------------------------------------------------------===//
13
14 #include "Unix.h"
15 #include "llvm/ADT/Hashing.h"
16 #include "llvm/Support/TimeValue.h"
17 #ifdef HAVE_SYS_TIME_H
18 #include <sys/time.h>
19 #endif
20 #ifdef HAVE_SYS_RESOURCE_H
21 #include <sys/resource.h>
22 #endif
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__)
27 #include <malloc.h>
28 #endif
29 #ifdef HAVE_MALLOC_MALLOC_H
30 #include <malloc/malloc.h>
31 #endif
32 #ifdef HAVE_SYS_IOCTL_H
33 #  include <sys/ioctl.h>
34 #endif
35 #ifdef HAVE_TERMIOS_H
36 #  include <termios.h>
37 #endif
38
39 //===----------------------------------------------------------------------===//
40 //=== WARNING: Implementation here must contain only generic UNIX code that
41 //===          is guaranteed to work on *all* UNIX variants.
42 //===----------------------------------------------------------------------===//
43
44 using namespace llvm;
45 using namespace sys;
46
47
48 process::id_type self_process::get_id() {
49   return getpid();
50 }
51
52 static std::pair<TimeValue, TimeValue> getRUsageTimes() {
53 #if defined(HAVE_GETRUSAGE)
54   struct rusage RU;
55   ::getrusage(RUSAGE_SELF, &RU);
56   return std::make_pair(
57       TimeValue(
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)),
61       TimeValue(
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)));
65 #else
66 #warning Cannot get usage times on this platform
67   return std::make_pair(TimeValue(), TimeValue());
68 #endif
69 }
70
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.
74   struct timespec TS;
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));
78 #endif
79
80   // Otherwise fall back to rusage based timing.
81   return getRUsageTimes().first;
82 }
83
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;
87 }
88
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);
99 #else
100 #warning Cannot get the page size on this machine
101 #endif
102   return static_cast<unsigned>(page_size);
103 }
104
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()) {
108 }
109
110
111 size_t Process::GetMallocUsage() {
112 #if defined(HAVE_MALLINFO)
113   struct mallinfo mi;
114   mi = ::mallinfo();
115   return mi.uordblks;
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;
127   else
128     return 0;
129 #else
130 #warning Cannot get malloc info on this platform
131   return 0;
132 #endif
133 }
134
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();
139 }
140
141 int Process::GetCurrentUserId() {
142   return getuid();
143 }
144
145 int Process::GetCurrentGroupId() {
146   return getgid();
147 }
148
149 #if defined(HAVE_MACH_MACH_H) && !defined(__GNU__)
150 #include <mach/mach.h>
151 #endif
152
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() {
157 #if HAVE_SETRLIMIT
158   struct rlimit rlim;
159   rlim.rlim_cur = rlim.rlim_max = 0;
160   setrlimit(RLIMIT_CORE, &rlim);
161 #endif
162
163 #if defined(HAVE_MACH_MACH_H) && !defined(__GNU__)
164   // Disable crash reporting on Mac OS X 10.0-10.4
165
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];
172   kern_return_t err =
173     task_get_exception_ports(mach_task_self(), EXC_MASK_ALL, OriginalMasks,
174                              &Count, OriginalPorts, OriginalBehaviors,
175                              OriginalFlavors);
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],
181                                OriginalFlavors[i]);
182   }
183
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);
190 #endif
191 }
192
193 bool Process::StandardInIsUserInput() {
194   return FileDescriptorIsDisplayed(STDIN_FILENO);
195 }
196
197 bool Process::StandardOutIsDisplayed() {
198   return FileDescriptorIsDisplayed(STDOUT_FILENO);
199 }
200
201 bool Process::StandardErrIsDisplayed() {
202   return FileDescriptorIsDisplayed(STDERR_FILENO);
203 }
204
205 bool Process::FileDescriptorIsDisplayed(int fd) {
206 #if HAVE_ISATTY
207   return isatty(fd);
208 #else
209   // If we don't have isatty, just return false.
210   return false;
211 #endif
212 }
213
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);
218     if (Columns > 0)
219       return Columns;
220   }
221
222   unsigned Columns = 0;
223
224 #if defined(HAVE_SYS_IOCTL_H) && defined(HAVE_TERMIOS_H)
225   // Try to determine the width of the terminal.
226   struct winsize ws;
227   if (ioctl(FileID, TIOCGWINSZ, &ws) == 0)
228     Columns = ws.ws_col;
229 #endif
230
231   return Columns;
232 }
233
234 unsigned Process::StandardOutColumns() {
235   if (!StandardOutIsDisplayed())
236     return 0;
237
238   return getColumns(1);
239 }
240
241 unsigned Process::StandardErrColumns() {
242   if (!StandardErrIsDisplayed())
243     return 0;
244
245   return getColumns(2);
246 }
247
248 static bool terminalHasColors() {
249   if (const char *term = std::getenv("TERM")) {
250     // Most modern terminals support ANSI escape sequences for colors.
251     // We could check terminfo, or have a list of known terms that support
252     // colors, but that would be overkill.
253     // The user can always ask for no colors by setting TERM to dumb, or
254     // using a commandline flag.
255     return strcmp(term, "dumb") != 0;
256   }
257   return false;
258 }
259
260 bool Process::FileDescriptorHasColors(int fd) {
261   // A file descriptor has colors if it is displayed and the terminal has
262   // colors.
263   return FileDescriptorIsDisplayed(fd) && terminalHasColors();
264 }
265
266 bool Process::StandardOutHasColors() {
267   return FileDescriptorHasColors(STDOUT_FILENO);
268 }
269
270 bool Process::StandardErrHasColors() {
271   return FileDescriptorHasColors(STDERR_FILENO);
272 }
273
274 bool Process::ColorNeedsFlush() {
275   // No, we use ANSI escape sequences.
276   return false;
277 }
278
279 #define COLOR(FGBG, CODE, BOLD) "\033[0;" BOLD FGBG CODE "m"
280
281 #define ALLCOLORS(FGBG,BOLD) {\
282     COLOR(FGBG, "0", BOLD),\
283     COLOR(FGBG, "1", BOLD),\
284     COLOR(FGBG, "2", BOLD),\
285     COLOR(FGBG, "3", BOLD),\
286     COLOR(FGBG, "4", BOLD),\
287     COLOR(FGBG, "5", BOLD),\
288     COLOR(FGBG, "6", BOLD),\
289     COLOR(FGBG, "7", BOLD)\
290   }
291
292 static const char colorcodes[2][2][8][10] = {
293  { ALLCOLORS("3",""), ALLCOLORS("3","1;") },
294  { ALLCOLORS("4",""), ALLCOLORS("4","1;") }
295 };
296
297 const char *Process::OutputColor(char code, bool bold, bool bg) {
298   return colorcodes[bg?1:0][bold?1:0][code&7];
299 }
300
301 const char *Process::OutputBold(bool bg) {
302   return "\033[1m";
303 }
304
305 const char *Process::OutputReverse() {
306   return "\033[7m";
307 }
308
309 const char *Process::ResetColor() {
310   return "\033[0m";
311 }
312
313 #if !defined(HAVE_ARC4RANDOM)
314 static unsigned GetRandomNumberSeed() {
315   // Attempt to get the initial seed from /dev/urandom, if possible.
316   if (FILE *RandomSource = ::fopen("/dev/urandom", "r")) {
317     unsigned seed;
318     int count = ::fread((void *)&seed, sizeof(seed), 1, RandomSource);
319     ::fclose(RandomSource);
320
321     // Return the seed if the read was successful.
322     if (count == 1)
323       return seed;
324   }
325
326   // Otherwise, swizzle the current time and the process ID to form a reasonable
327   // seed.
328   TimeValue Now = TimeValue::now();
329   return hash_combine(Now.seconds(), Now.nanoseconds(), ::getpid());
330 }
331 #endif
332
333 unsigned llvm::sys::Process::GetRandomNumber() {
334 #if defined(HAVE_ARC4RANDOM)
335   return arc4random();
336 #else
337   static int x = (::srand(GetRandomNumberSeed()), 0);
338   (void)x;
339   return ::rand();
340 #endif
341 }