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