blob: 9ad6272bab48b3f3239b9feb08e54c58dbe25942 [file] [log] [blame]
Reid Spencer33b9d772004-09-11 04:56:56 +00001//===- Unix/Process.cpp - Unix Process Implementation --------- -*- C++ -*-===//
Michael J. Spencer447762d2010-11-29 18:16:10 +00002//
Reid Spencer33b9d772004-09-11 04:56:56 +00003// The LLVM Compiler Infrastructure
4//
Chris Lattnerf3ebc3f2007-12-29 20:36:04 +00005// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
Michael J. Spencer447762d2010-11-29 18:16:10 +00007//
Reid Spencer33b9d772004-09-11 04:56:56 +00008//===----------------------------------------------------------------------===//
9//
10// This file provides the generic Unix implementation of the Process class.
11//
12//===----------------------------------------------------------------------===//
13
Reid Spencerac38f3a2004-12-20 00:59:28 +000014#include "Unix.h"
Daniel Dunbar5f1c9562012-05-08 20:38:00 +000015#include "llvm/ADT/Hashing.h"
16#include "llvm/Support/TimeValue.h"
Reid Spencerac38f3a2004-12-20 00:59:28 +000017#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
Eric Christopher22738d02012-08-06 20:52:18 +000023// 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__)
Reid Spencerac38f3a2004-12-20 00:59:28 +000027#include <malloc.h>
28#endif
Chris Lattner698fa762005-11-14 07:00:29 +000029#ifdef HAVE_MALLOC_MALLOC_H
30#include <malloc/malloc.h>
31#endif
Douglas Gregor15436612009-05-11 18:05:52 +000032#ifdef HAVE_SYS_IOCTL_H
33# include <sys/ioctl.h>
34#endif
Douglas Gregorb81294d2009-05-18 17:21:34 +000035#ifdef HAVE_TERMIOS_H
36# include <termios.h>
37#endif
Reid Spencer33b9d772004-09-11 04:56:56 +000038
39//===----------------------------------------------------------------------===//
40//=== WARNING: Implementation here must contain only generic UNIX code that
41//=== is guaranteed to work on *all* UNIX variants.
42//===----------------------------------------------------------------------===//
43
Chris Lattner2f107cf2006-09-14 06:01:41 +000044using namespace llvm;
Reid Spencer33b9d772004-09-11 04:56:56 +000045using namespace sys;
46
Chandler Carruth97683aa2012-12-31 11:17:50 +000047
48process::id_type self_process::get_id() {
49 return getpid();
50}
51
Chandler Carruth15dcad92012-12-31 23:23:35 +000052static unsigned getPageSize() {
Jay Foadc1fca9fb2009-05-23 17:57:59 +000053#if defined(__CYGWIN__)
54 // On Cygwin, getpagesize() returns 64k but the page size for the purposes of
55 // memory protection and mmap() is 4k.
56 // See http://www.cygwin.com/ml/cygwin/2009-01/threads.html#00492
Owen Andersona83e8682009-08-19 21:48:34 +000057 const int page_size = 0x1000;
Jay Foadc1fca9fb2009-05-23 17:57:59 +000058#elif defined(HAVE_GETPAGESIZE)
Owen Andersona83e8682009-08-19 21:48:34 +000059 const int page_size = ::getpagesize();
Reid Spencerac38f3a2004-12-20 00:59:28 +000060#elif defined(HAVE_SYSCONF)
Owen Andersona83e8682009-08-19 21:48:34 +000061 long page_size = ::sysconf(_SC_PAGE_SIZE);
Reid Spencerac38f3a2004-12-20 00:59:28 +000062#else
63#warning Cannot get the page size on this machine
64#endif
Reid Spencer33b9d772004-09-11 04:56:56 +000065 return static_cast<unsigned>(page_size);
66}
67
Chandler Carruth15dcad92012-12-31 23:23:35 +000068// This constructor guaranteed to be run exactly once on a single thread, and
69// sets up various process invariants that can be queried cheaply from then on.
70self_process::self_process() : PageSize(getPageSize()) {
71}
72
73
Chris Lattner698fa762005-11-14 07:00:29 +000074size_t Process::GetMallocUsage() {
Reid Spencer1cf74ce2004-12-20 16:06:44 +000075#if defined(HAVE_MALLINFO)
Reid Spencerac38f3a2004-12-20 00:59:28 +000076 struct mallinfo mi;
77 mi = ::mallinfo();
78 return mi.uordblks;
Chris Lattner16cbc6a2005-11-14 07:27:56 +000079#elif defined(HAVE_MALLOC_ZONE_STATISTICS) && defined(HAVE_MALLOC_MALLOC_H)
80 malloc_statistics_t Stats;
81 malloc_zone_statistics(malloc_default_zone(), &Stats);
82 return Stats.size_in_use; // darwin
Reid Spencer1cf74ce2004-12-20 16:06:44 +000083#elif defined(HAVE_SBRK)
Reid Spencerac38f3a2004-12-20 00:59:28 +000084 // Note this is only an approximation and more closely resembles
85 // the value returned by mallinfo in the arena field.
Chris Lattner698fa762005-11-14 07:00:29 +000086 static char *StartOfMemory = reinterpret_cast<char*>(::sbrk(0));
87 char *EndOfMemory = (char*)sbrk(0);
88 if (EndOfMemory != ((char*)-1) && StartOfMemory != ((char*)-1))
89 return EndOfMemory - StartOfMemory;
Reid Spencerac38f3a2004-12-20 00:59:28 +000090 else
91 return 0;
92#else
93#warning Cannot get malloc info on this platform
94 return 0;
95#endif
96}
97
Reid Spencerac38f3a2004-12-20 00:59:28 +000098void
Michael J. Spencer447762d2010-11-29 18:16:10 +000099Process::GetTimeUsage(TimeValue& elapsed, TimeValue& user_time,
Reid Spencerac38f3a2004-12-20 00:59:28 +0000100 TimeValue& sys_time)
101{
102 elapsed = TimeValue::now();
Chris Lattner227d4422006-05-12 18:20:39 +0000103#if defined(HAVE_GETRUSAGE)
Reid Spencerac38f3a2004-12-20 00:59:28 +0000104 struct rusage usage;
105 ::getrusage(RUSAGE_SELF, &usage);
Michael J. Spencer447762d2010-11-29 18:16:10 +0000106 user_time = TimeValue(
107 static_cast<TimeValue::SecondsType>( usage.ru_utime.tv_sec ),
108 static_cast<TimeValue::NanoSecondsType>( usage.ru_utime.tv_usec *
Reid Spencerd4c69882004-12-20 21:43:33 +0000109 TimeValue::NANOSECONDS_PER_MICROSECOND ) );
Michael J. Spencer447762d2010-11-29 18:16:10 +0000110 sys_time = TimeValue(
111 static_cast<TimeValue::SecondsType>( usage.ru_stime.tv_sec ),
112 static_cast<TimeValue::NanoSecondsType>( usage.ru_stime.tv_usec *
Reid Spencerd4c69882004-12-20 21:43:33 +0000113 TimeValue::NANOSECONDS_PER_MICROSECOND ) );
Reid Spencerac38f3a2004-12-20 00:59:28 +0000114#else
115#warning Cannot get usage times on this platform
116 user_time.seconds(0);
117 user_time.microseconds(0);
118 sys_time.seconds(0);
119 sys_time.microseconds(0);
120#endif
121}
122
Chris Lattner2f107cf2006-09-14 06:01:41 +0000123int Process::GetCurrentUserId() {
Reid Spencer2d45e252005-04-21 16:12:57 +0000124 return getuid();
125}
126
Chris Lattner2f107cf2006-09-14 06:01:41 +0000127int Process::GetCurrentGroupId() {
Reid Spencer2d45e252005-04-21 16:12:57 +0000128 return getgid();
129}
130
Sylvestre Ledru14ada942012-04-11 15:35:36 +0000131#if defined(HAVE_MACH_MACH_H) && !defined(__GNU__)
Nate Begeman48405152008-04-12 00:47:46 +0000132#include <mach/mach.h>
133#endif
134
Reid Spencercf15b872004-12-27 06:17:27 +0000135// Some LLVM programs such as bugpoint produce core files as a normal part of
136// their operation. To prevent the disk from filling up, this function
137// does what's necessary to prevent their generation.
138void Process::PreventCoreFiles() {
139#if HAVE_SETRLIMIT
140 struct rlimit rlim;
141 rlim.rlim_cur = rlim.rlim_max = 0;
Chris Lattnerf64397b2006-05-14 18:53:09 +0000142 setrlimit(RLIMIT_CORE, &rlim);
Reid Spencercf15b872004-12-27 06:17:27 +0000143#endif
Chris Lattner2f107cf2006-09-14 06:01:41 +0000144
Sylvestre Ledru14ada942012-04-11 15:35:36 +0000145#if defined(HAVE_MACH_MACH_H) && !defined(__GNU__)
Nate Begeman48405152008-04-12 00:47:46 +0000146 // Disable crash reporting on Mac OS X 10.0-10.4
147
148 // get information about the original set of exception ports for the task
149 mach_msg_type_number_t Count = 0;
150 exception_mask_t OriginalMasks[EXC_TYPES_COUNT];
151 exception_port_t OriginalPorts[EXC_TYPES_COUNT];
152 exception_behavior_t OriginalBehaviors[EXC_TYPES_COUNT];
153 thread_state_flavor_t OriginalFlavors[EXC_TYPES_COUNT];
Michael J. Spencer447762d2010-11-29 18:16:10 +0000154 kern_return_t err =
Nate Begeman48405152008-04-12 00:47:46 +0000155 task_get_exception_ports(mach_task_self(), EXC_MASK_ALL, OriginalMasks,
156 &Count, OriginalPorts, OriginalBehaviors,
157 OriginalFlavors);
158 if (err == KERN_SUCCESS) {
159 // replace each with MACH_PORT_NULL.
160 for (unsigned i = 0; i != Count; ++i)
Michael J. Spencer447762d2010-11-29 18:16:10 +0000161 task_set_exception_ports(mach_task_self(), OriginalMasks[i],
Nate Begeman48405152008-04-12 00:47:46 +0000162 MACH_PORT_NULL, OriginalBehaviors[i],
163 OriginalFlavors[i]);
164 }
165
166 // Disable crash reporting on Mac OS X 10.5
Nate Begemanf8be3832008-03-31 22:19:25 +0000167 signal(SIGABRT, _exit);
168 signal(SIGILL, _exit);
169 signal(SIGFPE, _exit);
170 signal(SIGSEGV, _exit);
171 signal(SIGBUS, _exit);
Chris Lattner2f107cf2006-09-14 06:01:41 +0000172#endif
Reid Spencercf15b872004-12-27 06:17:27 +0000173}
Reid Spencerac38f3a2004-12-20 00:59:28 +0000174
Reid Spencer6f802ba2005-01-01 22:29:26 +0000175bool Process::StandardInIsUserInput() {
Dan Gohmane5929232009-09-11 20:46:33 +0000176 return FileDescriptorIsDisplayed(STDIN_FILENO);
Reid Spencer6f802ba2005-01-01 22:29:26 +0000177}
178
179bool Process::StandardOutIsDisplayed() {
Dan Gohmane5929232009-09-11 20:46:33 +0000180 return FileDescriptorIsDisplayed(STDOUT_FILENO);
Reid Spencer6f802ba2005-01-01 22:29:26 +0000181}
182
183bool Process::StandardErrIsDisplayed() {
Dan Gohmane5929232009-09-11 20:46:33 +0000184 return FileDescriptorIsDisplayed(STDERR_FILENO);
185}
186
187bool Process::FileDescriptorIsDisplayed(int fd) {
Reid Spencer6f802ba2005-01-01 22:29:26 +0000188#if HAVE_ISATTY
Dan Gohmane5929232009-09-11 20:46:33 +0000189 return isatty(fd);
Duncan Sands44d423a2009-09-06 10:53:22 +0000190#else
Reid Spencer6f802ba2005-01-01 22:29:26 +0000191 // If we don't have isatty, just return false.
192 return false;
Duncan Sands44d423a2009-09-06 10:53:22 +0000193#endif
Reid Spencer6f802ba2005-01-01 22:29:26 +0000194}
Douglas Gregor15436612009-05-11 18:05:52 +0000195
196static unsigned getColumns(int FileID) {
197 // If COLUMNS is defined in the environment, wrap to that many columns.
198 if (const char *ColumnsStr = std::getenv("COLUMNS")) {
199 int Columns = std::atoi(ColumnsStr);
200 if (Columns > 0)
201 return Columns;
202 }
203
204 unsigned Columns = 0;
205
Douglas Gregorb81294d2009-05-18 17:21:34 +0000206#if defined(HAVE_SYS_IOCTL_H) && defined(HAVE_TERMIOS_H)
Douglas Gregor15436612009-05-11 18:05:52 +0000207 // Try to determine the width of the terminal.
208 struct winsize ws;
209 if (ioctl(FileID, TIOCGWINSZ, &ws) == 0)
210 Columns = ws.ws_col;
211#endif
212
213 return Columns;
214}
215
216unsigned Process::StandardOutColumns() {
217 if (!StandardOutIsDisplayed())
218 return 0;
219
220 return getColumns(1);
221}
222
223unsigned Process::StandardErrColumns() {
224 if (!StandardErrIsDisplayed())
225 return 0;
226
227 return getColumns(2);
228}
Torok Edwin9b5a47f2009-06-04 07:09:50 +0000229
230static bool terminalHasColors() {
231 if (const char *term = std::getenv("TERM")) {
232 // Most modern terminals support ANSI escape sequences for colors.
233 // We could check terminfo, or have a list of known terms that support
234 // colors, but that would be overkill.
235 // The user can always ask for no colors by setting TERM to dumb, or
236 // using a commandline flag.
237 return strcmp(term, "dumb") != 0;
238 }
239 return false;
240}
241
Daniel Dunbar712de822012-07-20 18:29:38 +0000242bool Process::FileDescriptorHasColors(int fd) {
243 // A file descriptor has colors if it is displayed and the terminal has
244 // colors.
245 return FileDescriptorIsDisplayed(fd) && terminalHasColors();
246}
247
Torok Edwin9b5a47f2009-06-04 07:09:50 +0000248bool Process::StandardOutHasColors() {
Daniel Dunbar712de822012-07-20 18:29:38 +0000249 return FileDescriptorHasColors(STDOUT_FILENO);
Torok Edwin9b5a47f2009-06-04 07:09:50 +0000250}
251
252bool Process::StandardErrHasColors() {
Daniel Dunbar712de822012-07-20 18:29:38 +0000253 return FileDescriptorHasColors(STDERR_FILENO);
Torok Edwin9b5a47f2009-06-04 07:09:50 +0000254}
255
256bool Process::ColorNeedsFlush() {
257 // No, we use ANSI escape sequences.
258 return false;
259}
260
261#define COLOR(FGBG, CODE, BOLD) "\033[0;" BOLD FGBG CODE "m"
262
263#define ALLCOLORS(FGBG,BOLD) {\
264 COLOR(FGBG, "0", BOLD),\
265 COLOR(FGBG, "1", BOLD),\
266 COLOR(FGBG, "2", BOLD),\
267 COLOR(FGBG, "3", BOLD),\
268 COLOR(FGBG, "4", BOLD),\
269 COLOR(FGBG, "5", BOLD),\
270 COLOR(FGBG, "6", BOLD),\
271 COLOR(FGBG, "7", BOLD)\
272 }
273
Nuno Lopes129819d2009-12-23 17:48:10 +0000274static const char colorcodes[2][2][8][10] = {
Torok Edwin9b5a47f2009-06-04 07:09:50 +0000275 { ALLCOLORS("3",""), ALLCOLORS("3","1;") },
276 { ALLCOLORS("4",""), ALLCOLORS("4","1;") }
277};
278
279const char *Process::OutputColor(char code, bool bold, bool bg) {
280 return colorcodes[bg?1:0][bold?1:0][code&7];
281}
282
283const char *Process::OutputBold(bool bg) {
284 return "\033[1m";
285}
286
Benjamin Kramer13d16f32012-04-16 08:56:50 +0000287const char *Process::OutputReverse() {
288 return "\033[7m";
289}
290
Torok Edwin9b5a47f2009-06-04 07:09:50 +0000291const char *Process::ResetColor() {
292 return "\033[0m";
293}
NAKAMURA Takumi54acb282012-05-06 08:24:18 +0000294
NAKAMURA Takumi7bec7412012-05-06 08:24:24 +0000295#if !defined(HAVE_ARC4RANDOM)
296static unsigned GetRandomNumberSeed() {
Daniel Dunbar5f1c9562012-05-08 20:38:00 +0000297 // Attempt to get the initial seed from /dev/urandom, if possible.
298 if (FILE *RandomSource = ::fopen("/dev/urandom", "r")) {
299 unsigned seed;
300 int count = ::fread((void *)&seed, sizeof(seed), 1, RandomSource);
NAKAMURA Takumi7bec7412012-05-06 08:24:24 +0000301 ::fclose(RandomSource);
Daniel Dunbar5f1c9562012-05-08 20:38:00 +0000302
303 // Return the seed if the read was successful.
304 if (count == 1)
305 return seed;
NAKAMURA Takumi7bec7412012-05-06 08:24:24 +0000306 }
Daniel Dunbar5f1c9562012-05-08 20:38:00 +0000307
308 // Otherwise, swizzle the current time and the process ID to form a reasonable
309 // seed.
Chandler Carruth5473dfb2012-12-31 11:45:20 +0000310 TimeValue Now = TimeValue::now();
Daniel Dunbar5f1c9562012-05-08 20:38:00 +0000311 return hash_combine(Now.seconds(), Now.nanoseconds(), ::getpid());
NAKAMURA Takumi7bec7412012-05-06 08:24:24 +0000312}
313#endif
314
NAKAMURA Takumi54acb282012-05-06 08:24:18 +0000315unsigned llvm::sys::Process::GetRandomNumber() {
316#if defined(HAVE_ARC4RANDOM)
317 return arc4random();
318#else
NAKAMURA Takumi7bec7412012-05-06 08:24:24 +0000319 static int x = (::srand(GetRandomNumberSeed()), 0);
320 (void)x;
NAKAMURA Takumi54acb282012-05-06 08:24:18 +0000321 return ::rand();
322#endif
323}