OSDN Git Service

Process: Add sys::Process::FileDescriptorHasColors().
[android-x86/external-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 // 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__)
26 #include <malloc.h>
27 #endif
28 #ifdef HAVE_MALLOC_MALLOC_H
29 #include <malloc/malloc.h>
30 #endif
31 #ifdef HAVE_SYS_IOCTL_H
32 #  include <sys/ioctl.h>
33 #endif
34 #ifdef HAVE_TERMIOS_H
35 #  include <termios.h>
36 #endif
37
38 //===----------------------------------------------------------------------===//
39 //=== WARNING: Implementation here must contain only generic UNIX code that
40 //===          is guaranteed to work on *all* UNIX variants.
41 //===----------------------------------------------------------------------===//
42
43 using namespace llvm;
44 using namespace sys;
45
46 unsigned
47 Process::GetPageSize()
48 {
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);
58 #else
59 #warning Cannot get the page size on this machine
60 #endif
61   return static_cast<unsigned>(page_size);
62 }
63
64 size_t Process::GetMallocUsage() {
65 #if defined(HAVE_MALLINFO)
66   struct mallinfo mi;
67   mi = ::mallinfo();
68   return mi.uordblks;
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;
80   else
81     return 0;
82 #else
83 #warning Cannot get malloc info on this platform
84   return 0;
85 #endif
86 }
87
88 size_t
89 Process::GetTotalMemoryUsage()
90 {
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__)
99   struct rusage usage;
100   ::getrusage(RUSAGE_SELF, &usage);
101   return usage.ru_maxrss;
102 #else
103 #warning Cannot get total memory size on this platform
104   return 0;
105 #endif
106 }
107
108 void
109 Process::GetTimeUsage(TimeValue& elapsed, TimeValue& user_time,
110                       TimeValue& sys_time)
111 {
112   elapsed = TimeValue::now();
113 #if defined(HAVE_GETRUSAGE)
114   struct rusage usage;
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 ) );
124 #else
125 #warning Cannot get usage times on this platform
126   user_time.seconds(0);
127   user_time.microseconds(0);
128   sys_time.seconds(0);
129   sys_time.microseconds(0);
130 #endif
131 }
132
133 int Process::GetCurrentUserId() {
134   return getuid();
135 }
136
137 int Process::GetCurrentGroupId() {
138   return getgid();
139 }
140
141 #if defined(HAVE_MACH_MACH_H) && !defined(__GNU__)
142 #include <mach/mach.h>
143 #endif
144
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() {
149 #if HAVE_SETRLIMIT
150   struct rlimit rlim;
151   rlim.rlim_cur = rlim.rlim_max = 0;
152   setrlimit(RLIMIT_CORE, &rlim);
153 #endif
154
155 #if defined(HAVE_MACH_MACH_H) && !defined(__GNU__)
156   // Disable crash reporting on Mac OS X 10.0-10.4
157
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];
164   kern_return_t err =
165     task_get_exception_ports(mach_task_self(), EXC_MASK_ALL, OriginalMasks,
166                              &Count, OriginalPorts, OriginalBehaviors,
167                              OriginalFlavors);
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],
173                                OriginalFlavors[i]);
174   }
175
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);
182 #endif
183 }
184
185 bool Process::StandardInIsUserInput() {
186   return FileDescriptorIsDisplayed(STDIN_FILENO);
187 }
188
189 bool Process::StandardOutIsDisplayed() {
190   return FileDescriptorIsDisplayed(STDOUT_FILENO);
191 }
192
193 bool Process::StandardErrIsDisplayed() {
194   return FileDescriptorIsDisplayed(STDERR_FILENO);
195 }
196
197 bool Process::FileDescriptorIsDisplayed(int fd) {
198 #if HAVE_ISATTY
199   return isatty(fd);
200 #else
201   // If we don't have isatty, just return false.
202   return false;
203 #endif
204 }
205
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);
210     if (Columns > 0)
211       return Columns;
212   }
213
214   unsigned Columns = 0;
215
216 #if defined(HAVE_SYS_IOCTL_H) && defined(HAVE_TERMIOS_H)
217   // Try to determine the width of the terminal.
218   struct winsize ws;
219   if (ioctl(FileID, TIOCGWINSZ, &ws) == 0)
220     Columns = ws.ws_col;
221 #endif
222
223   return Columns;
224 }
225
226 unsigned Process::StandardOutColumns() {
227   if (!StandardOutIsDisplayed())
228     return 0;
229
230   return getColumns(1);
231 }
232
233 unsigned Process::StandardErrColumns() {
234   if (!StandardErrIsDisplayed())
235     return 0;
236
237   return getColumns(2);
238 }
239
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;
248   }
249   return false;
250 }
251
252 bool Process::FileDescriptorHasColors(int fd) {
253   // A file descriptor has colors if it is displayed and the terminal has
254   // colors.
255   return FileDescriptorIsDisplayed(fd) && terminalHasColors();
256 }
257
258 bool Process::StandardOutHasColors() {
259   return FileDescriptorHasColors(STDOUT_FILENO);
260 }
261
262 bool Process::StandardErrHasColors() {
263   return FileDescriptorHasColors(STDERR_FILENO);
264 }
265
266 bool Process::ColorNeedsFlush() {
267   // No, we use ANSI escape sequences.
268   return false;
269 }
270
271 #define COLOR(FGBG, CODE, BOLD) "\033[0;" BOLD FGBG CODE "m"
272
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)\
282   }
283
284 static const char colorcodes[2][2][8][10] = {
285  { ALLCOLORS("3",""), ALLCOLORS("3","1;") },
286  { ALLCOLORS("4",""), ALLCOLORS("4","1;") }
287 };
288
289 const char *Process::OutputColor(char code, bool bold, bool bg) {
290   return colorcodes[bg?1:0][bold?1:0][code&7];
291 }
292
293 const char *Process::OutputBold(bool bg) {
294   return "\033[1m";
295 }
296
297 const char *Process::OutputReverse() {
298   return "\033[7m";
299 }
300
301 const char *Process::ResetColor() {
302   return "\033[0m";
303 }
304
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")) {
309     unsigned seed;
310     int count = ::fread((void *)&seed, sizeof(seed), 1, RandomSource);
311     ::fclose(RandomSource);
312
313     // Return the seed if the read was successful.
314     if (count == 1)
315       return seed;
316   }
317
318   // Otherwise, swizzle the current time and the process ID to form a reasonable
319   // seed.
320   TimeValue Now = llvm::TimeValue::now();
321   return hash_combine(Now.seconds(), Now.nanoseconds(), ::getpid());
322 }
323 #endif
324
325 unsigned llvm::sys::Process::GetRandomNumber() {
326 #if defined(HAVE_ARC4RANDOM)
327   return arc4random();
328 #else
329   static int x = (::srand(GetRandomNumberSeed()), 0);
330   (void)x;
331   return ::rand();
332 #endif
333 }