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