Switch this code to a more idiomatic double using namespace directive.
[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
53 unsigned
54 Process::GetPageSize()
55 {
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);
65 #else
66 #warning Cannot get the page size on this machine
67 #endif
68   return static_cast<unsigned>(page_size);
69 }
70
71 size_t Process::GetMallocUsage() {
72 #if defined(HAVE_MALLINFO)
73   struct mallinfo mi;
74   mi = ::mallinfo();
75   return mi.uordblks;
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;
87   else
88     return 0;
89 #else
90 #warning Cannot get malloc info on this platform
91   return 0;
92 #endif
93 }
94
95 size_t
96 Process::GetTotalMemoryUsage()
97 {
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__)
106   struct rusage usage;
107   ::getrusage(RUSAGE_SELF, &usage);
108   return usage.ru_maxrss;
109 #else
110 #warning Cannot get total memory size on this platform
111   return 0;
112 #endif
113 }
114
115 void
116 Process::GetTimeUsage(TimeValue& elapsed, TimeValue& user_time,
117                       TimeValue& sys_time)
118 {
119   elapsed = TimeValue::now();
120 #if defined(HAVE_GETRUSAGE)
121   struct rusage usage;
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 ) );
131 #else
132 #warning Cannot get usage times on this platform
133   user_time.seconds(0);
134   user_time.microseconds(0);
135   sys_time.seconds(0);
136   sys_time.microseconds(0);
137 #endif
138 }
139
140 int Process::GetCurrentUserId() {
141   return getuid();
142 }
143
144 int Process::GetCurrentGroupId() {
145   return getgid();
146 }
147
148 #if defined(HAVE_MACH_MACH_H) && !defined(__GNU__)
149 #include <mach/mach.h>
150 #endif
151
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() {
156 #if HAVE_SETRLIMIT
157   struct rlimit rlim;
158   rlim.rlim_cur = rlim.rlim_max = 0;
159   setrlimit(RLIMIT_CORE, &rlim);
160 #endif
161
162 #if defined(HAVE_MACH_MACH_H) && !defined(__GNU__)
163   // Disable crash reporting on Mac OS X 10.0-10.4
164
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];
171   kern_return_t err =
172     task_get_exception_ports(mach_task_self(), EXC_MASK_ALL, OriginalMasks,
173                              &Count, OriginalPorts, OriginalBehaviors,
174                              OriginalFlavors);
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],
180                                OriginalFlavors[i]);
181   }
182
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);
189 #endif
190 }
191
192 bool Process::StandardInIsUserInput() {
193   return FileDescriptorIsDisplayed(STDIN_FILENO);
194 }
195
196 bool Process::StandardOutIsDisplayed() {
197   return FileDescriptorIsDisplayed(STDOUT_FILENO);
198 }
199
200 bool Process::StandardErrIsDisplayed() {
201   return FileDescriptorIsDisplayed(STDERR_FILENO);
202 }
203
204 bool Process::FileDescriptorIsDisplayed(int fd) {
205 #if HAVE_ISATTY
206   return isatty(fd);
207 #else
208   // If we don't have isatty, just return false.
209   return false;
210 #endif
211 }
212
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);
217     if (Columns > 0)
218       return Columns;
219   }
220
221   unsigned Columns = 0;
222
223 #if defined(HAVE_SYS_IOCTL_H) && defined(HAVE_TERMIOS_H)
224   // Try to determine the width of the terminal.
225   struct winsize ws;
226   if (ioctl(FileID, TIOCGWINSZ, &ws) == 0)
227     Columns = ws.ws_col;
228 #endif
229
230   return Columns;
231 }
232
233 unsigned Process::StandardOutColumns() {
234   if (!StandardOutIsDisplayed())
235     return 0;
236
237   return getColumns(1);
238 }
239
240 unsigned Process::StandardErrColumns() {
241   if (!StandardErrIsDisplayed())
242     return 0;
243
244   return getColumns(2);
245 }
246
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;
255   }
256   return false;
257 }
258
259 bool Process::FileDescriptorHasColors(int fd) {
260   // A file descriptor has colors if it is displayed and the terminal has
261   // colors.
262   return FileDescriptorIsDisplayed(fd) && terminalHasColors();
263 }
264
265 bool Process::StandardOutHasColors() {
266   return FileDescriptorHasColors(STDOUT_FILENO);
267 }
268
269 bool Process::StandardErrHasColors() {
270   return FileDescriptorHasColors(STDERR_FILENO);
271 }
272
273 bool Process::ColorNeedsFlush() {
274   // No, we use ANSI escape sequences.
275   return false;
276 }
277
278 #define COLOR(FGBG, CODE, BOLD) "\033[0;" BOLD FGBG CODE "m"
279
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)\
289   }
290
291 static const char colorcodes[2][2][8][10] = {
292  { ALLCOLORS("3",""), ALLCOLORS("3","1;") },
293  { ALLCOLORS("4",""), ALLCOLORS("4","1;") }
294 };
295
296 const char *Process::OutputColor(char code, bool bold, bool bg) {
297   return colorcodes[bg?1:0][bold?1:0][code&7];
298 }
299
300 const char *Process::OutputBold(bool bg) {
301   return "\033[1m";
302 }
303
304 const char *Process::OutputReverse() {
305   return "\033[7m";
306 }
307
308 const char *Process::ResetColor() {
309   return "\033[0m";
310 }
311
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")) {
316     unsigned seed;
317     int count = ::fread((void *)&seed, sizeof(seed), 1, RandomSource);
318     ::fclose(RandomSource);
319
320     // Return the seed if the read was successful.
321     if (count == 1)
322       return seed;
323   }
324
325   // Otherwise, swizzle the current time and the process ID to form a reasonable
326   // seed.
327   TimeValue Now = TimeValue::now();
328   return hash_combine(Now.seconds(), Now.nanoseconds(), ::getpid());
329 }
330 #endif
331
332 unsigned llvm::sys::Process::GetRandomNumber() {
333 #if defined(HAVE_ARC4RANDOM)
334   return arc4random();
335 #else
336   static int x = (::srand(GetRandomNumberSeed()), 0);
337   (void)x;
338   return ::rand();
339 #endif
340 }