Flesh out a page size accessor in the new API.
[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 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);
62 #else
63 #warning Cannot get the page size on this machine
64 #endif
65   return static_cast<unsigned>(page_size);
66 }
67
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()) {
71 }
72
73
74 size_t Process::GetMallocUsage() {
75 #if defined(HAVE_MALLINFO)
76   struct mallinfo mi;
77   mi = ::mallinfo();
78   return mi.uordblks;
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;
90   else
91     return 0;
92 #else
93 #warning Cannot get malloc info on this platform
94   return 0;
95 #endif
96 }
97
98 void
99 Process::GetTimeUsage(TimeValue& elapsed, TimeValue& user_time,
100                       TimeValue& sys_time)
101 {
102   elapsed = TimeValue::now();
103 #if defined(HAVE_GETRUSAGE)
104   struct rusage usage;
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 ) );
114 #else
115 #warning Cannot get usage times on this platform
116   user_time.seconds(0);
117   user_time.microseconds(0);
118   sys_time.seconds(0);
119   sys_time.microseconds(0);
120 #endif
121 }
122
123 int Process::GetCurrentUserId() {
124   return getuid();
125 }
126
127 int Process::GetCurrentGroupId() {
128   return getgid();
129 }
130
131 #if defined(HAVE_MACH_MACH_H) && !defined(__GNU__)
132 #include <mach/mach.h>
133 #endif
134
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() {
139 #if HAVE_SETRLIMIT
140   struct rlimit rlim;
141   rlim.rlim_cur = rlim.rlim_max = 0;
142   setrlimit(RLIMIT_CORE, &rlim);
143 #endif
144
145 #if defined(HAVE_MACH_MACH_H) && !defined(__GNU__)
146   // Disable crash reporting on Mac OS X 10.0-10.4
147
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];
154   kern_return_t err =
155     task_get_exception_ports(mach_task_self(), EXC_MASK_ALL, OriginalMasks,
156                              &Count, OriginalPorts, OriginalBehaviors,
157                              OriginalFlavors);
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],
163                                OriginalFlavors[i]);
164   }
165
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);
172 #endif
173 }
174
175 bool Process::StandardInIsUserInput() {
176   return FileDescriptorIsDisplayed(STDIN_FILENO);
177 }
178
179 bool Process::StandardOutIsDisplayed() {
180   return FileDescriptorIsDisplayed(STDOUT_FILENO);
181 }
182
183 bool Process::StandardErrIsDisplayed() {
184   return FileDescriptorIsDisplayed(STDERR_FILENO);
185 }
186
187 bool Process::FileDescriptorIsDisplayed(int fd) {
188 #if HAVE_ISATTY
189   return isatty(fd);
190 #else
191   // If we don't have isatty, just return false.
192   return false;
193 #endif
194 }
195
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);
200     if (Columns > 0)
201       return Columns;
202   }
203
204   unsigned Columns = 0;
205
206 #if defined(HAVE_SYS_IOCTL_H) && defined(HAVE_TERMIOS_H)
207   // Try to determine the width of the terminal.
208   struct winsize ws;
209   if (ioctl(FileID, TIOCGWINSZ, &ws) == 0)
210     Columns = ws.ws_col;
211 #endif
212
213   return Columns;
214 }
215
216 unsigned Process::StandardOutColumns() {
217   if (!StandardOutIsDisplayed())
218     return 0;
219
220   return getColumns(1);
221 }
222
223 unsigned Process::StandardErrColumns() {
224   if (!StandardErrIsDisplayed())
225     return 0;
226
227   return getColumns(2);
228 }
229
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;
238   }
239   return false;
240 }
241
242 bool Process::FileDescriptorHasColors(int fd) {
243   // A file descriptor has colors if it is displayed and the terminal has
244   // colors.
245   return FileDescriptorIsDisplayed(fd) && terminalHasColors();
246 }
247
248 bool Process::StandardOutHasColors() {
249   return FileDescriptorHasColors(STDOUT_FILENO);
250 }
251
252 bool Process::StandardErrHasColors() {
253   return FileDescriptorHasColors(STDERR_FILENO);
254 }
255
256 bool Process::ColorNeedsFlush() {
257   // No, we use ANSI escape sequences.
258   return false;
259 }
260
261 #define COLOR(FGBG, CODE, BOLD) "\033[0;" BOLD FGBG CODE "m"
262
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)\
272   }
273
274 static const char colorcodes[2][2][8][10] = {
275  { ALLCOLORS("3",""), ALLCOLORS("3","1;") },
276  { ALLCOLORS("4",""), ALLCOLORS("4","1;") }
277 };
278
279 const char *Process::OutputColor(char code, bool bold, bool bg) {
280   return colorcodes[bg?1:0][bold?1:0][code&7];
281 }
282
283 const char *Process::OutputBold(bool bg) {
284   return "\033[1m";
285 }
286
287 const char *Process::OutputReverse() {
288   return "\033[7m";
289 }
290
291 const char *Process::ResetColor() {
292   return "\033[0m";
293 }
294
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")) {
299     unsigned seed;
300     int count = ::fread((void *)&seed, sizeof(seed), 1, RandomSource);
301     ::fclose(RandomSource);
302
303     // Return the seed if the read was successful.
304     if (count == 1)
305       return seed;
306   }
307
308   // Otherwise, swizzle the current time and the process ID to form a reasonable
309   // seed.
310   TimeValue Now = TimeValue::now();
311   return hash_combine(Now.seconds(), Now.nanoseconds(), ::getpid());
312 }
313 #endif
314
315 unsigned llvm::sys::Process::GetRandomNumber() {
316 #if defined(HAVE_ARC4RANDOM)
317   return arc4random();
318 #else
319   static int x = (::srand(GetRandomNumberSeed()), 0);
320   (void)x;
321   return ::rand();
322 #endif
323 }