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