Get rid of the Pid_ member in the Program class.
[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   const int page_size = 0x1000;
50 #elif defined(HAVE_GETPAGESIZE)
51   const int page_size = ::getpagesize();
52 #elif defined(HAVE_SYSCONF)
53   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 #else
185   // If we don't have isatty, just return false.
186   return false;
187 #endif
188 }
189
190 bool Process::StandardOutIsDisplayed() {
191 #if HAVE_ISATTY
192   return isatty(1);
193 #else
194   // If we don't have isatty, just return false.
195   return false;
196 #endif
197 }
198
199 bool Process::StandardErrIsDisplayed() {
200 #if HAVE_ISATTY
201   return isatty(2);
202 #else
203   // If we don't have isatty, just return false.
204   return false;
205 #endif
206 }
207
208 static unsigned getColumns(int FileID) {
209   // If COLUMNS is defined in the environment, wrap to that many columns.
210   if (const char *ColumnsStr = std::getenv("COLUMNS")) {
211     int Columns = std::atoi(ColumnsStr);
212     if (Columns > 0)
213       return Columns;
214   }
215
216   unsigned Columns = 0;
217
218 #if defined(HAVE_SYS_IOCTL_H) && defined(HAVE_TERMIOS_H)
219   // Try to determine the width of the terminal.
220   struct winsize ws;
221   if (ioctl(FileID, TIOCGWINSZ, &ws) == 0)
222     Columns = ws.ws_col;
223 #endif
224
225   return Columns;
226 }
227
228 unsigned Process::StandardOutColumns() {
229   if (!StandardOutIsDisplayed())
230     return 0;
231
232   return getColumns(1);
233 }
234
235 unsigned Process::StandardErrColumns() {
236   if (!StandardErrIsDisplayed())
237     return 0;
238
239   return getColumns(2);
240 }
241
242 static bool terminalHasColors() {
243   if (const char *term = std::getenv("TERM")) {
244     // Most modern terminals support ANSI escape sequences for colors.
245     // We could check terminfo, or have a list of known terms that support
246     // colors, but that would be overkill.
247     // The user can always ask for no colors by setting TERM to dumb, or
248     // using a commandline flag.
249     return strcmp(term, "dumb") != 0;
250   }
251   return false;
252 }
253
254 bool Process::StandardOutHasColors() {
255   if (!StandardOutIsDisplayed())
256     return false;
257   return terminalHasColors();
258 }
259
260 bool Process::StandardErrHasColors() {
261   if (!StandardErrIsDisplayed())
262     return false;
263   return terminalHasColors();
264 }
265
266 bool Process::ColorNeedsFlush() {
267   // No, we use ANSI escape sequences.
268   return false;
269 }
270
271 #define COLOR(FGBG, CODE, BOLD) "\033[0;" BOLD FGBG CODE "m"
272
273 #define ALLCOLORS(FGBG,BOLD) {\
274     COLOR(FGBG, "0", BOLD),\
275     COLOR(FGBG, "1", BOLD),\
276     COLOR(FGBG, "2", BOLD),\
277     COLOR(FGBG, "3", BOLD),\
278     COLOR(FGBG, "4", BOLD),\
279     COLOR(FGBG, "5", BOLD),\
280     COLOR(FGBG, "6", BOLD),\
281     COLOR(FGBG, "7", BOLD)\
282   }
283
284 static const char* colorcodes[2][2][8] = {
285  { ALLCOLORS("3",""), ALLCOLORS("3","1;") },
286  { ALLCOLORS("4",""), ALLCOLORS("4","1;") }
287 };
288
289 const char *Process::OutputColor(char code, bool bold, bool bg) {
290   return colorcodes[bg?1:0][bold?1:0][code&7];
291 }
292
293 const char *Process::OutputBold(bool bg) {
294   return "\033[1m";
295 }
296
297 const char *Process::ResetColor() {
298   return "\033[0m";
299 }