Process.inc revision 239462
1218885Sdim//===- Unix/Process.cpp - Unix Process Implementation --------- -*- C++ -*-===//
2218885Sdim//
3218885Sdim//                     The LLVM Compiler Infrastructure
4218885Sdim//
5218885Sdim// This file is distributed under the University of Illinois Open Source
6218885Sdim// License. See LICENSE.TXT for details.
7218885Sdim//
8218885Sdim//===----------------------------------------------------------------------===//
9218885Sdim//
10218885Sdim// This file provides the generic Unix implementation of the Process class.
11218885Sdim//
12218885Sdim//===----------------------------------------------------------------------===//
13218885Sdim
14218885Sdim#include "Unix.h"
15239462Sdim#include "llvm/ADT/Hashing.h"
16239462Sdim#include "llvm/Support/TimeValue.h"
17218885Sdim#ifdef HAVE_SYS_TIME_H
18218885Sdim#include <sys/time.h>
19218885Sdim#endif
20218885Sdim#ifdef HAVE_SYS_RESOURCE_H
21218885Sdim#include <sys/resource.h>
22218885Sdim#endif
23239462Sdim// DragonFlyBSD, OpenBSD, and Bitrig have deprecated <malloc.h> for
24239462Sdim// <stdlib.h> instead. Unix.h includes this for us already.
25239462Sdim#if defined(HAVE_MALLOC_H) && !defined(__DragonFly__) && \
26239462Sdim    !defined(__OpenBSD__) && !defined(__Bitrig__)
27218885Sdim#include <malloc.h>
28218885Sdim#endif
29218885Sdim#ifdef HAVE_MALLOC_MALLOC_H
30218885Sdim#include <malloc/malloc.h>
31218885Sdim#endif
32218885Sdim#ifdef HAVE_SYS_IOCTL_H
33218885Sdim#  include <sys/ioctl.h>
34218885Sdim#endif
35218885Sdim#ifdef HAVE_TERMIOS_H
36218885Sdim#  include <termios.h>
37218885Sdim#endif
38218885Sdim
39218885Sdim//===----------------------------------------------------------------------===//
40218885Sdim//=== WARNING: Implementation here must contain only generic UNIX code that
41218885Sdim//===          is guaranteed to work on *all* UNIX variants.
42218885Sdim//===----------------------------------------------------------------------===//
43218885Sdim
44218885Sdimusing namespace llvm;
45218885Sdimusing namespace sys;
46218885Sdim
47218885Sdimunsigned
48218885SdimProcess::GetPageSize()
49218885Sdim{
50218885Sdim#if defined(__CYGWIN__)
51218885Sdim  // On Cygwin, getpagesize() returns 64k but the page size for the purposes of
52218885Sdim  // memory protection and mmap() is 4k.
53218885Sdim  // See http://www.cygwin.com/ml/cygwin/2009-01/threads.html#00492
54218885Sdim  const int page_size = 0x1000;
55218885Sdim#elif defined(HAVE_GETPAGESIZE)
56218885Sdim  const int page_size = ::getpagesize();
57218885Sdim#elif defined(HAVE_SYSCONF)
58218885Sdim  long page_size = ::sysconf(_SC_PAGE_SIZE);
59218885Sdim#else
60218885Sdim#warning Cannot get the page size on this machine
61218885Sdim#endif
62218885Sdim  return static_cast<unsigned>(page_size);
63218885Sdim}
64218885Sdim
65218885Sdimsize_t Process::GetMallocUsage() {
66218885Sdim#if defined(HAVE_MALLINFO)
67218885Sdim  struct mallinfo mi;
68218885Sdim  mi = ::mallinfo();
69218885Sdim  return mi.uordblks;
70218885Sdim#elif defined(HAVE_MALLOC_ZONE_STATISTICS) && defined(HAVE_MALLOC_MALLOC_H)
71218885Sdim  malloc_statistics_t Stats;
72218885Sdim  malloc_zone_statistics(malloc_default_zone(), &Stats);
73218885Sdim  return Stats.size_in_use;   // darwin
74218885Sdim#elif defined(HAVE_SBRK)
75218885Sdim  // Note this is only an approximation and more closely resembles
76218885Sdim  // the value returned by mallinfo in the arena field.
77218885Sdim  static char *StartOfMemory = reinterpret_cast<char*>(::sbrk(0));
78218885Sdim  char *EndOfMemory = (char*)sbrk(0);
79218885Sdim  if (EndOfMemory != ((char*)-1) && StartOfMemory != ((char*)-1))
80218885Sdim    return EndOfMemory - StartOfMemory;
81218885Sdim  else
82218885Sdim    return 0;
83218885Sdim#else
84218885Sdim#warning Cannot get malloc info on this platform
85218885Sdim  return 0;
86218885Sdim#endif
87218885Sdim}
88218885Sdim
89218885Sdimsize_t
90218885SdimProcess::GetTotalMemoryUsage()
91218885Sdim{
92218885Sdim#if defined(HAVE_MALLINFO)
93218885Sdim  struct mallinfo mi = ::mallinfo();
94218885Sdim  return mi.uordblks + mi.hblkhd;
95218885Sdim#elif defined(HAVE_MALLOC_ZONE_STATISTICS) && defined(HAVE_MALLOC_MALLOC_H)
96218885Sdim  malloc_statistics_t Stats;
97218885Sdim  malloc_zone_statistics(malloc_default_zone(), &Stats);
98218885Sdim  return Stats.size_allocated;   // darwin
99218885Sdim#elif defined(HAVE_GETRUSAGE) && !defined(__HAIKU__)
100218885Sdim  struct rusage usage;
101218885Sdim  ::getrusage(RUSAGE_SELF, &usage);
102218885Sdim  return usage.ru_maxrss;
103218885Sdim#else
104218885Sdim#warning Cannot get total memory size on this platform
105218885Sdim  return 0;
106218885Sdim#endif
107218885Sdim}
108218885Sdim
109218885Sdimvoid
110218885SdimProcess::GetTimeUsage(TimeValue& elapsed, TimeValue& user_time,
111218885Sdim                      TimeValue& sys_time)
112218885Sdim{
113218885Sdim  elapsed = TimeValue::now();
114218885Sdim#if defined(HAVE_GETRUSAGE)
115218885Sdim  struct rusage usage;
116218885Sdim  ::getrusage(RUSAGE_SELF, &usage);
117218885Sdim  user_time = TimeValue(
118218885Sdim    static_cast<TimeValue::SecondsType>( usage.ru_utime.tv_sec ),
119218885Sdim    static_cast<TimeValue::NanoSecondsType>( usage.ru_utime.tv_usec *
120218885Sdim      TimeValue::NANOSECONDS_PER_MICROSECOND ) );
121218885Sdim  sys_time = TimeValue(
122218885Sdim    static_cast<TimeValue::SecondsType>( usage.ru_stime.tv_sec ),
123218885Sdim    static_cast<TimeValue::NanoSecondsType>( usage.ru_stime.tv_usec *
124218885Sdim      TimeValue::NANOSECONDS_PER_MICROSECOND ) );
125218885Sdim#else
126218885Sdim#warning Cannot get usage times on this platform
127218885Sdim  user_time.seconds(0);
128218885Sdim  user_time.microseconds(0);
129218885Sdim  sys_time.seconds(0);
130218885Sdim  sys_time.microseconds(0);
131218885Sdim#endif
132218885Sdim}
133218885Sdim
134218885Sdimint Process::GetCurrentUserId() {
135218885Sdim  return getuid();
136218885Sdim}
137218885Sdim
138218885Sdimint Process::GetCurrentGroupId() {
139218885Sdim  return getgid();
140218885Sdim}
141218885Sdim
142234353Sdim#if defined(HAVE_MACH_MACH_H) && !defined(__GNU__)
143218885Sdim#include <mach/mach.h>
144218885Sdim#endif
145218885Sdim
146218885Sdim// Some LLVM programs such as bugpoint produce core files as a normal part of
147218885Sdim// their operation. To prevent the disk from filling up, this function
148218885Sdim// does what's necessary to prevent their generation.
149218885Sdimvoid Process::PreventCoreFiles() {
150218885Sdim#if HAVE_SETRLIMIT
151218885Sdim  struct rlimit rlim;
152218885Sdim  rlim.rlim_cur = rlim.rlim_max = 0;
153218885Sdim  setrlimit(RLIMIT_CORE, &rlim);
154218885Sdim#endif
155218885Sdim
156234353Sdim#if defined(HAVE_MACH_MACH_H) && !defined(__GNU__)
157218885Sdim  // Disable crash reporting on Mac OS X 10.0-10.4
158218885Sdim
159218885Sdim  // get information about the original set of exception ports for the task
160218885Sdim  mach_msg_type_number_t Count = 0;
161218885Sdim  exception_mask_t OriginalMasks[EXC_TYPES_COUNT];
162218885Sdim  exception_port_t OriginalPorts[EXC_TYPES_COUNT];
163218885Sdim  exception_behavior_t OriginalBehaviors[EXC_TYPES_COUNT];
164218885Sdim  thread_state_flavor_t OriginalFlavors[EXC_TYPES_COUNT];
165218885Sdim  kern_return_t err =
166218885Sdim    task_get_exception_ports(mach_task_self(), EXC_MASK_ALL, OriginalMasks,
167218885Sdim                             &Count, OriginalPorts, OriginalBehaviors,
168218885Sdim                             OriginalFlavors);
169218885Sdim  if (err == KERN_SUCCESS) {
170218885Sdim    // replace each with MACH_PORT_NULL.
171218885Sdim    for (unsigned i = 0; i != Count; ++i)
172218885Sdim      task_set_exception_ports(mach_task_self(), OriginalMasks[i],
173218885Sdim                               MACH_PORT_NULL, OriginalBehaviors[i],
174218885Sdim                               OriginalFlavors[i]);
175218885Sdim  }
176218885Sdim
177218885Sdim  // Disable crash reporting on Mac OS X 10.5
178218885Sdim  signal(SIGABRT, _exit);
179218885Sdim  signal(SIGILL,  _exit);
180218885Sdim  signal(SIGFPE,  _exit);
181218885Sdim  signal(SIGSEGV, _exit);
182218885Sdim  signal(SIGBUS,  _exit);
183218885Sdim#endif
184218885Sdim}
185218885Sdim
186218885Sdimbool Process::StandardInIsUserInput() {
187218885Sdim  return FileDescriptorIsDisplayed(STDIN_FILENO);
188218885Sdim}
189218885Sdim
190218885Sdimbool Process::StandardOutIsDisplayed() {
191218885Sdim  return FileDescriptorIsDisplayed(STDOUT_FILENO);
192218885Sdim}
193218885Sdim
194218885Sdimbool Process::StandardErrIsDisplayed() {
195218885Sdim  return FileDescriptorIsDisplayed(STDERR_FILENO);
196218885Sdim}
197218885Sdim
198218885Sdimbool Process::FileDescriptorIsDisplayed(int fd) {
199218885Sdim#if HAVE_ISATTY
200218885Sdim  return isatty(fd);
201218885Sdim#else
202218885Sdim  // If we don't have isatty, just return false.
203218885Sdim  return false;
204218885Sdim#endif
205218885Sdim}
206218885Sdim
207218885Sdimstatic unsigned getColumns(int FileID) {
208218885Sdim  // If COLUMNS is defined in the environment, wrap to that many columns.
209218885Sdim  if (const char *ColumnsStr = std::getenv("COLUMNS")) {
210218885Sdim    int Columns = std::atoi(ColumnsStr);
211218885Sdim    if (Columns > 0)
212218885Sdim      return Columns;
213218885Sdim  }
214218885Sdim
215218885Sdim  unsigned Columns = 0;
216218885Sdim
217218885Sdim#if defined(HAVE_SYS_IOCTL_H) && defined(HAVE_TERMIOS_H)
218218885Sdim  // Try to determine the width of the terminal.
219218885Sdim  struct winsize ws;
220218885Sdim  if (ioctl(FileID, TIOCGWINSZ, &ws) == 0)
221218885Sdim    Columns = ws.ws_col;
222218885Sdim#endif
223218885Sdim
224218885Sdim  return Columns;
225218885Sdim}
226218885Sdim
227218885Sdimunsigned Process::StandardOutColumns() {
228218885Sdim  if (!StandardOutIsDisplayed())
229218885Sdim    return 0;
230218885Sdim
231218885Sdim  return getColumns(1);
232218885Sdim}
233218885Sdim
234218885Sdimunsigned Process::StandardErrColumns() {
235218885Sdim  if (!StandardErrIsDisplayed())
236218885Sdim    return 0;
237218885Sdim
238218885Sdim  return getColumns(2);
239218885Sdim}
240218885Sdim
241218885Sdimstatic bool terminalHasColors() {
242218885Sdim  if (const char *term = std::getenv("TERM")) {
243218885Sdim    // Most modern terminals support ANSI escape sequences for colors.
244218885Sdim    // We could check terminfo, or have a list of known terms that support
245218885Sdim    // colors, but that would be overkill.
246218885Sdim    // The user can always ask for no colors by setting TERM to dumb, or
247218885Sdim    // using a commandline flag.
248218885Sdim    return strcmp(term, "dumb") != 0;
249218885Sdim  }
250218885Sdim  return false;
251218885Sdim}
252218885Sdim
253239462Sdimbool Process::FileDescriptorHasColors(int fd) {
254239462Sdim  // A file descriptor has colors if it is displayed and the terminal has
255239462Sdim  // colors.
256239462Sdim  return FileDescriptorIsDisplayed(fd) && terminalHasColors();
257239462Sdim}
258239462Sdim
259218885Sdimbool Process::StandardOutHasColors() {
260239462Sdim  return FileDescriptorHasColors(STDOUT_FILENO);
261218885Sdim}
262218885Sdim
263218885Sdimbool Process::StandardErrHasColors() {
264239462Sdim  return FileDescriptorHasColors(STDERR_FILENO);
265218885Sdim}
266218885Sdim
267218885Sdimbool Process::ColorNeedsFlush() {
268218885Sdim  // No, we use ANSI escape sequences.
269218885Sdim  return false;
270218885Sdim}
271218885Sdim
272218885Sdim#define COLOR(FGBG, CODE, BOLD) "\033[0;" BOLD FGBG CODE "m"
273218885Sdim
274218885Sdim#define ALLCOLORS(FGBG,BOLD) {\
275218885Sdim    COLOR(FGBG, "0", BOLD),\
276218885Sdim    COLOR(FGBG, "1", BOLD),\
277218885Sdim    COLOR(FGBG, "2", BOLD),\
278218885Sdim    COLOR(FGBG, "3", BOLD),\
279218885Sdim    COLOR(FGBG, "4", BOLD),\
280218885Sdim    COLOR(FGBG, "5", BOLD),\
281218885Sdim    COLOR(FGBG, "6", BOLD),\
282218885Sdim    COLOR(FGBG, "7", BOLD)\
283218885Sdim  }
284218885Sdim
285218885Sdimstatic const char colorcodes[2][2][8][10] = {
286218885Sdim { ALLCOLORS("3",""), ALLCOLORS("3","1;") },
287218885Sdim { ALLCOLORS("4",""), ALLCOLORS("4","1;") }
288218885Sdim};
289218885Sdim
290218885Sdimconst char *Process::OutputColor(char code, bool bold, bool bg) {
291218885Sdim  return colorcodes[bg?1:0][bold?1:0][code&7];
292218885Sdim}
293218885Sdim
294218885Sdimconst char *Process::OutputBold(bool bg) {
295218885Sdim  return "\033[1m";
296218885Sdim}
297218885Sdim
298234982Sdimconst char *Process::OutputReverse() {
299234982Sdim  return "\033[7m";
300234982Sdim}
301234982Sdim
302218885Sdimconst char *Process::ResetColor() {
303218885Sdim  return "\033[0m";
304218885Sdim}
305239462Sdim
306239462Sdim#if !defined(HAVE_ARC4RANDOM)
307239462Sdimstatic unsigned GetRandomNumberSeed() {
308239462Sdim  // Attempt to get the initial seed from /dev/urandom, if possible.
309239462Sdim  if (FILE *RandomSource = ::fopen("/dev/urandom", "r")) {
310239462Sdim    unsigned seed;
311239462Sdim    int count = ::fread((void *)&seed, sizeof(seed), 1, RandomSource);
312239462Sdim    ::fclose(RandomSource);
313239462Sdim
314239462Sdim    // Return the seed if the read was successful.
315239462Sdim    if (count == 1)
316239462Sdim      return seed;
317239462Sdim  }
318239462Sdim
319239462Sdim  // Otherwise, swizzle the current time and the process ID to form a reasonable
320239462Sdim  // seed.
321239462Sdim  TimeValue Now = llvm::TimeValue::now();
322239462Sdim  return hash_combine(Now.seconds(), Now.nanoseconds(), ::getpid());
323239462Sdim}
324239462Sdim#endif
325239462Sdim
326239462Sdimunsigned llvm::sys::Process::GetRandomNumber() {
327239462Sdim#if defined(HAVE_ARC4RANDOM)
328239462Sdim  return arc4random();
329239462Sdim#else
330239462Sdim  static int x = (::srand(GetRandomNumberSeed()), 0);
331239462Sdim  (void)x;
332239462Sdim  return ::rand();
333239462Sdim#endif
334239462Sdim}
335