Target a minimal terminfo library rather than necessarily a full curses
[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/Mutex.h"
17 #include "llvm/Support/MutexGuard.h"
18 #include "llvm/Support/TimeValue.h"
19 #ifdef HAVE_SYS_TIME_H
20 #include <sys/time.h>
21 #endif
22 #ifdef HAVE_SYS_RESOURCE_H
23 #include <sys/resource.h>
24 #endif
25 // DragonFlyBSD, OpenBSD, and Bitrig have deprecated <malloc.h> for
26 // <stdlib.h> instead. Unix.h includes this for us already.
27 #if defined(HAVE_MALLOC_H) && !defined(__DragonFly__) && \
28     !defined(__OpenBSD__) && !defined(__Bitrig__)
29 #include <malloc.h>
30 #endif
31 #ifdef HAVE_MALLOC_MALLOC_H
32 #include <malloc/malloc.h>
33 #endif
34 #ifdef HAVE_SYS_IOCTL_H
35 #  include <sys/ioctl.h>
36 #endif
37 #ifdef HAVE_TERMIOS_H
38 #  include <termios.h>
39 #endif
40
41 // Pull in the headers we found to go with the terminfo reading library (tinfo,
42 // curses, whatever it may be). We have to pull in the 'curses.h' header as the
43 // SysV spec only provides certain values and defines from that header even
44 // though we work hard to not link against all of the curses implementation
45 // when avoidable.
46 #ifdef HAVE_TERMINFO
47 # if defined(HAVE_CURSES_H)
48 #  include <curses.h>
49 # elif defined(HAVE_NCURSES_H)
50 #  include <ncurses.h>
51 # elif defined(HAVE_NCURSESW_H)
52 #  include <ncursesw.h>
53 # elif defined(HAVE_NCURSES_CURSES_H)
54 #  include <ncurses/curses.h>
55 # elif defined(HAVE_NCURSESW_CURSES_H)
56 #  include <ncursesw/curses.h>
57 # endif
58 # if defined(HAVE_TERM_H)
59 #  include <term.h>
60 # endif
61 #endif
62
63 //===----------------------------------------------------------------------===//
64 //=== WARNING: Implementation here must contain only generic UNIX code that
65 //===          is guaranteed to work on *all* UNIX variants.
66 //===----------------------------------------------------------------------===//
67
68 using namespace llvm;
69 using namespace sys;
70
71
72 process::id_type self_process::get_id() {
73   return getpid();
74 }
75
76 static std::pair<TimeValue, TimeValue> getRUsageTimes() {
77 #if defined(HAVE_GETRUSAGE)
78   struct rusage RU;
79   ::getrusage(RUSAGE_SELF, &RU);
80   return std::make_pair(
81       TimeValue(
82           static_cast<TimeValue::SecondsType>(RU.ru_utime.tv_sec),
83           static_cast<TimeValue::NanoSecondsType>(
84               RU.ru_utime.tv_usec * TimeValue::NANOSECONDS_PER_MICROSECOND)),
85       TimeValue(
86           static_cast<TimeValue::SecondsType>(RU.ru_stime.tv_sec),
87           static_cast<TimeValue::NanoSecondsType>(
88               RU.ru_stime.tv_usec * TimeValue::NANOSECONDS_PER_MICROSECOND)));
89 #else
90 #warning Cannot get usage times on this platform
91   return std::make_pair(TimeValue(), TimeValue());
92 #endif
93 }
94
95 TimeValue self_process::get_user_time() const {
96 #if _POSIX_TIMERS > 0 && _POSIX_CPUTIME > 0
97   // Try to get a high resolution CPU timer.
98   struct timespec TS;
99   if (::clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &TS) == 0)
100     return TimeValue(static_cast<TimeValue::SecondsType>(TS.tv_sec),
101                      static_cast<TimeValue::NanoSecondsType>(TS.tv_nsec));
102 #endif
103
104   // Otherwise fall back to rusage based timing.
105   return getRUsageTimes().first;
106 }
107
108 TimeValue self_process::get_system_time() const {
109   // We can only collect system time by inspecting the results of getrusage.
110   return getRUsageTimes().second;
111 }
112
113 static unsigned getPageSize() {
114 #if defined(__CYGWIN__)
115   // On Cygwin, getpagesize() returns 64k but the page size for the purposes of
116   // memory protection and mmap() is 4k.
117   // See http://www.cygwin.com/ml/cygwin/2009-01/threads.html#00492
118   const int page_size = 0x1000;
119 #elif defined(HAVE_GETPAGESIZE)
120   const int page_size = ::getpagesize();
121 #elif defined(HAVE_SYSCONF)
122   long page_size = ::sysconf(_SC_PAGE_SIZE);
123 #else
124 #warning Cannot get the page size on this machine
125 #endif
126   return static_cast<unsigned>(page_size);
127 }
128
129 // This constructor guaranteed to be run exactly once on a single thread, and
130 // sets up various process invariants that can be queried cheaply from then on.
131 self_process::self_process() : PageSize(getPageSize()) {
132 }
133
134
135 size_t Process::GetMallocUsage() {
136 #if defined(HAVE_MALLINFO)
137   struct mallinfo mi;
138   mi = ::mallinfo();
139   return mi.uordblks;
140 #elif defined(HAVE_MALLOC_ZONE_STATISTICS) && defined(HAVE_MALLOC_MALLOC_H)
141   malloc_statistics_t Stats;
142   malloc_zone_statistics(malloc_default_zone(), &Stats);
143   return Stats.size_in_use;   // darwin
144 #elif defined(HAVE_SBRK)
145   // Note this is only an approximation and more closely resembles
146   // the value returned by mallinfo in the arena field.
147   static char *StartOfMemory = reinterpret_cast<char*>(::sbrk(0));
148   char *EndOfMemory = (char*)sbrk(0);
149   if (EndOfMemory != ((char*)-1) && StartOfMemory != ((char*)-1))
150     return EndOfMemory - StartOfMemory;
151   else
152     return 0;
153 #else
154 #warning Cannot get malloc info on this platform
155   return 0;
156 #endif
157 }
158
159 void Process::GetTimeUsage(TimeValue &elapsed, TimeValue &user_time,
160                            TimeValue &sys_time) {
161   elapsed = TimeValue::now();
162   llvm::tie(user_time, sys_time) = getRUsageTimes();
163 }
164
165 int Process::GetCurrentUserId() {
166   return getuid();
167 }
168
169 int Process::GetCurrentGroupId() {
170   return getgid();
171 }
172
173 #if defined(HAVE_MACH_MACH_H) && !defined(__GNU__)
174 #include <mach/mach.h>
175 #endif
176
177 // Some LLVM programs such as bugpoint produce core files as a normal part of
178 // their operation. To prevent the disk from filling up, this function
179 // does what's necessary to prevent their generation.
180 void Process::PreventCoreFiles() {
181 #if HAVE_SETRLIMIT
182   struct rlimit rlim;
183   rlim.rlim_cur = rlim.rlim_max = 0;
184   setrlimit(RLIMIT_CORE, &rlim);
185 #endif
186
187 #if defined(HAVE_MACH_MACH_H) && !defined(__GNU__)
188   // Disable crash reporting on Mac OS X 10.0-10.4
189
190   // get information about the original set of exception ports for the task
191   mach_msg_type_number_t Count = 0;
192   exception_mask_t OriginalMasks[EXC_TYPES_COUNT];
193   exception_port_t OriginalPorts[EXC_TYPES_COUNT];
194   exception_behavior_t OriginalBehaviors[EXC_TYPES_COUNT];
195   thread_state_flavor_t OriginalFlavors[EXC_TYPES_COUNT];
196   kern_return_t err =
197     task_get_exception_ports(mach_task_self(), EXC_MASK_ALL, OriginalMasks,
198                              &Count, OriginalPorts, OriginalBehaviors,
199                              OriginalFlavors);
200   if (err == KERN_SUCCESS) {
201     // replace each with MACH_PORT_NULL.
202     for (unsigned i = 0; i != Count; ++i)
203       task_set_exception_ports(mach_task_self(), OriginalMasks[i],
204                                MACH_PORT_NULL, OriginalBehaviors[i],
205                                OriginalFlavors[i]);
206   }
207
208   // Disable crash reporting on Mac OS X 10.5
209   signal(SIGABRT, _exit);
210   signal(SIGILL,  _exit);
211   signal(SIGFPE,  _exit);
212   signal(SIGSEGV, _exit);
213   signal(SIGBUS,  _exit);
214 #endif
215 }
216
217 bool Process::StandardInIsUserInput() {
218   return FileDescriptorIsDisplayed(STDIN_FILENO);
219 }
220
221 bool Process::StandardOutIsDisplayed() {
222   return FileDescriptorIsDisplayed(STDOUT_FILENO);
223 }
224
225 bool Process::StandardErrIsDisplayed() {
226   return FileDescriptorIsDisplayed(STDERR_FILENO);
227 }
228
229 bool Process::FileDescriptorIsDisplayed(int fd) {
230 #if HAVE_ISATTY
231   return isatty(fd);
232 #else
233   // If we don't have isatty, just return false.
234   return false;
235 #endif
236 }
237
238 static unsigned getColumns(int FileID) {
239   // If COLUMNS is defined in the environment, wrap to that many columns.
240   if (const char *ColumnsStr = std::getenv("COLUMNS")) {
241     int Columns = std::atoi(ColumnsStr);
242     if (Columns > 0)
243       return Columns;
244   }
245
246   unsigned Columns = 0;
247
248 #if defined(HAVE_SYS_IOCTL_H) && defined(HAVE_TERMIOS_H)
249   // Try to determine the width of the terminal.
250   struct winsize ws;
251   if (ioctl(FileID, TIOCGWINSZ, &ws) == 0)
252     Columns = ws.ws_col;
253 #endif
254
255   return Columns;
256 }
257
258 unsigned Process::StandardOutColumns() {
259   if (!StandardOutIsDisplayed())
260     return 0;
261
262   return getColumns(1);
263 }
264
265 unsigned Process::StandardErrColumns() {
266   if (!StandardErrIsDisplayed())
267     return 0;
268
269   return getColumns(2);
270 }
271
272 static bool terminalHasColors(int fd) {
273 #ifdef HAVE_TERMINFO
274   // First, acquire a global lock because these C routines are thread hostile.
275   static sys::Mutex M;
276   MutexGuard G(M);
277
278   int errret = 0;
279   if (setupterm((char *)0, fd, &errret) != OK)
280     // Regardless of why, if we can't get terminfo, we shouldn't try to print
281     // colors.
282     return false;
283
284   // Test whether the terminal as set up supports color output. How to do this
285   // isn't entirely obvious. We can use the curses routine 'has_colors' but it
286   // would be nice to avoid a dependency on curses proper when we can make do
287   // with a minimal terminfo parsing library. Also, we don't really care whether
288   // the terminal supports the curses-specific color changing routines, merely
289   // if it will interpret ANSI color escape codes in a reasonable way. Thus, the
290   // strategy here is just to query the baseline colors capability and if it
291   // supports colors at all to assume it will translate the escape codes into
292   // whatever range of colors it does support. We can add more detailed tests
293   // here if users report them as necessary.
294   //
295   // The 'tigetnum' routine returns -2 or -1 on errors, and might return 0 if
296   // the terminfo says that no colors are supported.
297   if (tigetnum("colors") > 0)
298     return true;
299 #endif
300
301   // Otherwise, be conservative.
302   return false;
303 }
304
305 bool Process::FileDescriptorHasColors(int fd) {
306   // A file descriptor has colors if it is displayed and the terminal has
307   // colors.
308   return FileDescriptorIsDisplayed(fd) && terminalHasColors(fd);
309 }
310
311 bool Process::StandardOutHasColors() {
312   return FileDescriptorHasColors(STDOUT_FILENO);
313 }
314
315 bool Process::StandardErrHasColors() {
316   return FileDescriptorHasColors(STDERR_FILENO);
317 }
318
319 bool Process::ColorNeedsFlush() {
320   // No, we use ANSI escape sequences.
321   return false;
322 }
323
324 #define COLOR(FGBG, CODE, BOLD) "\033[0;" BOLD FGBG CODE "m"
325
326 #define ALLCOLORS(FGBG,BOLD) {\
327     COLOR(FGBG, "0", BOLD),\
328     COLOR(FGBG, "1", BOLD),\
329     COLOR(FGBG, "2", BOLD),\
330     COLOR(FGBG, "3", BOLD),\
331     COLOR(FGBG, "4", BOLD),\
332     COLOR(FGBG, "5", BOLD),\
333     COLOR(FGBG, "6", BOLD),\
334     COLOR(FGBG, "7", BOLD)\
335   }
336
337 static const char colorcodes[2][2][8][10] = {
338  { ALLCOLORS("3",""), ALLCOLORS("3","1;") },
339  { ALLCOLORS("4",""), ALLCOLORS("4","1;") }
340 };
341
342 const char *Process::OutputColor(char code, bool bold, bool bg) {
343   return colorcodes[bg?1:0][bold?1:0][code&7];
344 }
345
346 const char *Process::OutputBold(bool bg) {
347   return "\033[1m";
348 }
349
350 const char *Process::OutputReverse() {
351   return "\033[7m";
352 }
353
354 const char *Process::ResetColor() {
355   return "\033[0m";
356 }
357
358 #if !defined(HAVE_ARC4RANDOM)
359 static unsigned GetRandomNumberSeed() {
360   // Attempt to get the initial seed from /dev/urandom, if possible.
361   if (FILE *RandomSource = ::fopen("/dev/urandom", "r")) {
362     unsigned seed;
363     int count = ::fread((void *)&seed, sizeof(seed), 1, RandomSource);
364     ::fclose(RandomSource);
365
366     // Return the seed if the read was successful.
367     if (count == 1)
368       return seed;
369   }
370
371   // Otherwise, swizzle the current time and the process ID to form a reasonable
372   // seed.
373   TimeValue Now = TimeValue::now();
374   return hash_combine(Now.seconds(), Now.nanoseconds(), ::getpid());
375 }
376 #endif
377
378 unsigned llvm::sys::Process::GetRandomNumber() {
379 #if defined(HAVE_ARC4RANDOM)
380   return arc4random();
381 #else
382   static int x = (::srand(GetRandomNumberSeed()), 0);
383   (void)x;
384   return ::rand();
385 #endif
386 }