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