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