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