Process.inc revision 259065
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
44using namespace llvm;
45using namespace sys;
46
47
48process::id_type self_process::get_id() {
49  return getpid();
50}
51
52static 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
71TimeValue 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
84TimeValue 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
89static 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.
107self_process::self_process() : PageSize(getPageSize()) {
108}
109
110
111size_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
135void 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
141int Process::GetCurrentUserId() {
142  return getuid();
143}
144
145int 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.
156void 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
193bool Process::StandardInIsUserInput() {
194  return FileDescriptorIsDisplayed(STDIN_FILENO);
195}
196
197bool Process::StandardOutIsDisplayed() {
198  return FileDescriptorIsDisplayed(STDOUT_FILENO);
199}
200
201bool Process::StandardErrIsDisplayed() {
202  return FileDescriptorIsDisplayed(STDERR_FILENO);
203}
204
205bool 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
214static 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
236unsigned Process::StandardOutColumns() {
237  if (!StandardOutIsDisplayed())
238    return 0;
239
240  return getColumns(1);
241}
242
243unsigned Process::StandardErrColumns() {
244  if (!StandardErrIsDisplayed())
245    return 0;
246
247  return getColumns(2);
248}
249
250static 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
262bool 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
268bool Process::StandardOutHasColors() {
269  return FileDescriptorHasColors(STDOUT_FILENO);
270}
271
272bool Process::StandardErrHasColors() {
273  return FileDescriptorHasColors(STDERR_FILENO);
274}
275
276bool 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
294static const char colorcodes[2][2][8][10] = {
295 { ALLCOLORS("3",""), ALLCOLORS("3","1;") },
296 { ALLCOLORS("4",""), ALLCOLORS("4","1;") }
297};
298
299const char *Process::OutputColor(char code, bool bold, bool bg) {
300  return colorcodes[bg?1:0][bold?1:0][code&7];
301}
302
303const char *Process::OutputBold(bool bg) {
304  return "\033[1m";
305}
306
307const char *Process::OutputReverse() {
308  return "\033[7m";
309}
310
311const char *Process::ResetColor() {
312  return "\033[0m";
313}
314
315#if !defined(HAVE_ARC4RANDOM)
316static 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
335unsigned 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}
344