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