]> CyberLeo.Net >> Repos - FreeBSD/stable/9.git/blob - contrib/llvm/lib/Support/Unix/Process.inc
MFC r244628:
[FreeBSD/stable/9.git] / contrib / llvm / 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 unsigned
48 Process::GetPageSize()
49 {
50 #if defined(__CYGWIN__)
51   // On Cygwin, getpagesize() returns 64k but the page size for the purposes of
52   // memory protection and mmap() is 4k.
53   // See http://www.cygwin.com/ml/cygwin/2009-01/threads.html#00492
54   const int page_size = 0x1000;
55 #elif defined(HAVE_GETPAGESIZE)
56   const int page_size = ::getpagesize();
57 #elif defined(HAVE_SYSCONF)
58   long page_size = ::sysconf(_SC_PAGE_SIZE);
59 #else
60 #warning Cannot get the page size on this machine
61 #endif
62   return static_cast<unsigned>(page_size);
63 }
64
65 size_t Process::GetMallocUsage() {
66 #if defined(HAVE_MALLINFO)
67   struct mallinfo mi;
68   mi = ::mallinfo();
69   return mi.uordblks;
70 #elif defined(HAVE_MALLOC_ZONE_STATISTICS) && defined(HAVE_MALLOC_MALLOC_H)
71   malloc_statistics_t Stats;
72   malloc_zone_statistics(malloc_default_zone(), &Stats);
73   return Stats.size_in_use;   // darwin
74 #elif defined(HAVE_SBRK)
75   // Note this is only an approximation and more closely resembles
76   // the value returned by mallinfo in the arena field.
77   static char *StartOfMemory = reinterpret_cast<char*>(::sbrk(0));
78   char *EndOfMemory = (char*)sbrk(0);
79   if (EndOfMemory != ((char*)-1) && StartOfMemory != ((char*)-1))
80     return EndOfMemory - StartOfMemory;
81   else
82     return 0;
83 #else
84 #warning Cannot get malloc info on this platform
85   return 0;
86 #endif
87 }
88
89 size_t
90 Process::GetTotalMemoryUsage()
91 {
92 #if defined(HAVE_MALLINFO)
93   struct mallinfo mi = ::mallinfo();
94   return mi.uordblks + mi.hblkhd;
95 #elif defined(HAVE_MALLOC_ZONE_STATISTICS) && defined(HAVE_MALLOC_MALLOC_H)
96   malloc_statistics_t Stats;
97   malloc_zone_statistics(malloc_default_zone(), &Stats);
98   return Stats.size_allocated;   // darwin
99 #elif defined(HAVE_GETRUSAGE) && !defined(__HAIKU__)
100   struct rusage usage;
101   ::getrusage(RUSAGE_SELF, &usage);
102   return usage.ru_maxrss;
103 #else
104 #warning Cannot get total memory size on this platform
105   return 0;
106 #endif
107 }
108
109 void
110 Process::GetTimeUsage(TimeValue& elapsed, TimeValue& user_time,
111                       TimeValue& sys_time)
112 {
113   elapsed = TimeValue::now();
114 #if defined(HAVE_GETRUSAGE)
115   struct rusage usage;
116   ::getrusage(RUSAGE_SELF, &usage);
117   user_time = TimeValue(
118     static_cast<TimeValue::SecondsType>( usage.ru_utime.tv_sec ),
119     static_cast<TimeValue::NanoSecondsType>( usage.ru_utime.tv_usec *
120       TimeValue::NANOSECONDS_PER_MICROSECOND ) );
121   sys_time = TimeValue(
122     static_cast<TimeValue::SecondsType>( usage.ru_stime.tv_sec ),
123     static_cast<TimeValue::NanoSecondsType>( usage.ru_stime.tv_usec *
124       TimeValue::NANOSECONDS_PER_MICROSECOND ) );
125 #else
126 #warning Cannot get usage times on this platform
127   user_time.seconds(0);
128   user_time.microseconds(0);
129   sys_time.seconds(0);
130   sys_time.microseconds(0);
131 #endif
132 }
133
134 int Process::GetCurrentUserId() {
135   return getuid();
136 }
137
138 int Process::GetCurrentGroupId() {
139   return getgid();
140 }
141
142 #if defined(HAVE_MACH_MACH_H) && !defined(__GNU__)
143 #include <mach/mach.h>
144 #endif
145
146 // Some LLVM programs such as bugpoint produce core files as a normal part of
147 // their operation. To prevent the disk from filling up, this function
148 // does what's necessary to prevent their generation.
149 void Process::PreventCoreFiles() {
150 #if HAVE_SETRLIMIT
151   struct rlimit rlim;
152   rlim.rlim_cur = rlim.rlim_max = 0;
153   setrlimit(RLIMIT_CORE, &rlim);
154 #endif
155
156 #if defined(HAVE_MACH_MACH_H) && !defined(__GNU__)
157   // Disable crash reporting on Mac OS X 10.0-10.4
158
159   // get information about the original set of exception ports for the task
160   mach_msg_type_number_t Count = 0;
161   exception_mask_t OriginalMasks[EXC_TYPES_COUNT];
162   exception_port_t OriginalPorts[EXC_TYPES_COUNT];
163   exception_behavior_t OriginalBehaviors[EXC_TYPES_COUNT];
164   thread_state_flavor_t OriginalFlavors[EXC_TYPES_COUNT];
165   kern_return_t err =
166     task_get_exception_ports(mach_task_self(), EXC_MASK_ALL, OriginalMasks,
167                              &Count, OriginalPorts, OriginalBehaviors,
168                              OriginalFlavors);
169   if (err == KERN_SUCCESS) {
170     // replace each with MACH_PORT_NULL.
171     for (unsigned i = 0; i != Count; ++i)
172       task_set_exception_ports(mach_task_self(), OriginalMasks[i],
173                                MACH_PORT_NULL, OriginalBehaviors[i],
174                                OriginalFlavors[i]);
175   }
176
177   // Disable crash reporting on Mac OS X 10.5
178   signal(SIGABRT, _exit);
179   signal(SIGILL,  _exit);
180   signal(SIGFPE,  _exit);
181   signal(SIGSEGV, _exit);
182   signal(SIGBUS,  _exit);
183 #endif
184 }
185
186 bool Process::StandardInIsUserInput() {
187   return FileDescriptorIsDisplayed(STDIN_FILENO);
188 }
189
190 bool Process::StandardOutIsDisplayed() {
191   return FileDescriptorIsDisplayed(STDOUT_FILENO);
192 }
193
194 bool Process::StandardErrIsDisplayed() {
195   return FileDescriptorIsDisplayed(STDERR_FILENO);
196 }
197
198 bool Process::FileDescriptorIsDisplayed(int fd) {
199 #if HAVE_ISATTY
200   return isatty(fd);
201 #else
202   // If we don't have isatty, just return false.
203   return false;
204 #endif
205 }
206
207 static unsigned getColumns(int FileID) {
208   // If COLUMNS is defined in the environment, wrap to that many columns.
209   if (const char *ColumnsStr = std::getenv("COLUMNS")) {
210     int Columns = std::atoi(ColumnsStr);
211     if (Columns > 0)
212       return Columns;
213   }
214
215   unsigned Columns = 0;
216
217 #if defined(HAVE_SYS_IOCTL_H) && defined(HAVE_TERMIOS_H)
218   // Try to determine the width of the terminal.
219   struct winsize ws;
220   if (ioctl(FileID, TIOCGWINSZ, &ws) == 0)
221     Columns = ws.ws_col;
222 #endif
223
224   return Columns;
225 }
226
227 unsigned Process::StandardOutColumns() {
228   if (!StandardOutIsDisplayed())
229     return 0;
230
231   return getColumns(1);
232 }
233
234 unsigned Process::StandardErrColumns() {
235   if (!StandardErrIsDisplayed())
236     return 0;
237
238   return getColumns(2);
239 }
240
241 static bool terminalHasColors() {
242   if (const char *term = std::getenv("TERM")) {
243     // Most modern terminals support ANSI escape sequences for colors.
244     // We could check terminfo, or have a list of known terms that support
245     // colors, but that would be overkill.
246     // The user can always ask for no colors by setting TERM to dumb, or
247     // using a commandline flag.
248     return strcmp(term, "dumb") != 0;
249   }
250   return false;
251 }
252
253 bool Process::FileDescriptorHasColors(int fd) {
254   // A file descriptor has colors if it is displayed and the terminal has
255   // colors.
256   return FileDescriptorIsDisplayed(fd) && terminalHasColors();
257 }
258
259 bool Process::StandardOutHasColors() {
260   return FileDescriptorHasColors(STDOUT_FILENO);
261 }
262
263 bool Process::StandardErrHasColors() {
264   return FileDescriptorHasColors(STDERR_FILENO);
265 }
266
267 bool Process::ColorNeedsFlush() {
268   // No, we use ANSI escape sequences.
269   return false;
270 }
271
272 #define COLOR(FGBG, CODE, BOLD) "\033[0;" BOLD FGBG CODE "m"
273
274 #define ALLCOLORS(FGBG,BOLD) {\
275     COLOR(FGBG, "0", BOLD),\
276     COLOR(FGBG, "1", BOLD),\
277     COLOR(FGBG, "2", BOLD),\
278     COLOR(FGBG, "3", BOLD),\
279     COLOR(FGBG, "4", BOLD),\
280     COLOR(FGBG, "5", BOLD),\
281     COLOR(FGBG, "6", BOLD),\
282     COLOR(FGBG, "7", BOLD)\
283   }
284
285 static const char colorcodes[2][2][8][10] = {
286  { ALLCOLORS("3",""), ALLCOLORS("3","1;") },
287  { ALLCOLORS("4",""), ALLCOLORS("4","1;") }
288 };
289
290 const char *Process::OutputColor(char code, bool bold, bool bg) {
291   return colorcodes[bg?1:0][bold?1:0][code&7];
292 }
293
294 const char *Process::OutputBold(bool bg) {
295   return "\033[1m";
296 }
297
298 const char *Process::OutputReverse() {
299   return "\033[7m";
300 }
301
302 const char *Process::ResetColor() {
303   return "\033[0m";
304 }
305
306 #if !defined(HAVE_ARC4RANDOM)
307 static unsigned GetRandomNumberSeed() {
308   // Attempt to get the initial seed from /dev/urandom, if possible.
309   if (FILE *RandomSource = ::fopen("/dev/urandom", "r")) {
310     unsigned seed;
311     int count = ::fread((void *)&seed, sizeof(seed), 1, RandomSource);
312     ::fclose(RandomSource);
313
314     // Return the seed if the read was successful.
315     if (count == 1)
316       return seed;
317   }
318
319   // Otherwise, swizzle the current time and the process ID to form a reasonable
320   // seed.
321   TimeValue Now = llvm::TimeValue::now();
322   return hash_combine(Now.seconds(), Now.nanoseconds(), ::getpid());
323 }
324 #endif
325
326 unsigned llvm::sys::Process::GetRandomNumber() {
327 #if defined(HAVE_ARC4RANDOM)
328   return arc4random();
329 #else
330   static int x = (::srand(GetRandomNumberSeed()), 0);
331   (void)x;
332   return ::rand();
333 #endif
334 }