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