blob: cf6a47a31c80d33b72fc2f525c23f6e3a0b9d15a [file] [log] [blame]
Reid Spencer27dafe12004-09-11 04:56:56 +00001//===- Unix/Process.cpp - Unix Process Implementation --------- -*- C++ -*-===//
2//
3// The LLVM Compiler Infrastructure
4//
Chris Lattner4ee451d2007-12-29 20:36:04 +00005// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
Reid Spencer27dafe12004-09-11 04:56:56 +00007//
8//===----------------------------------------------------------------------===//
9//
10// This file provides the generic Unix implementation of the Process class.
11//
12//===----------------------------------------------------------------------===//
13
Reid Spencer721d9aa2004-12-20 00:59:28 +000014#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
Edward O'Callaghanbd5dc452009-11-02 03:20:57 +000021// 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__)
Reid Spencer721d9aa2004-12-20 00:59:28 +000024#include <malloc.h>
25#endif
Chris Lattner513a9542005-11-14 07:00:29 +000026#ifdef HAVE_MALLOC_MALLOC_H
27#include <malloc/malloc.h>
28#endif
Douglas Gregor01746742009-05-11 18:05:52 +000029#ifdef HAVE_SYS_IOCTL_H
30# include <sys/ioctl.h>
31#endif
Douglas Gregor071d73d2009-05-18 17:21:34 +000032#ifdef HAVE_TERMIOS_H
33# include <termios.h>
34#endif
Reid Spencer27dafe12004-09-11 04:56:56 +000035
36//===----------------------------------------------------------------------===//
37//=== WARNING: Implementation here must contain only generic UNIX code that
38//=== is guaranteed to work on *all* UNIX variants.
39//===----------------------------------------------------------------------===//
40
Chris Lattner26b6c0b2006-09-14 06:01:41 +000041using namespace llvm;
Reid Spencer27dafe12004-09-11 04:56:56 +000042using namespace sys;
43
44unsigned
Reid Spencer721d9aa2004-12-20 00:59:28 +000045Process::GetPageSize()
46{
Jay Foada14be3b2009-05-23 17:57:59 +000047#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
Owen Anderson0d1ea252009-08-19 21:48:34 +000051 const int page_size = 0x1000;
Jay Foada14be3b2009-05-23 17:57:59 +000052#elif defined(HAVE_GETPAGESIZE)
Owen Anderson0d1ea252009-08-19 21:48:34 +000053 const int page_size = ::getpagesize();
Reid Spencer721d9aa2004-12-20 00:59:28 +000054#elif defined(HAVE_SYSCONF)
Owen Anderson0d1ea252009-08-19 21:48:34 +000055 long page_size = ::sysconf(_SC_PAGE_SIZE);
Reid Spencer721d9aa2004-12-20 00:59:28 +000056#else
57#warning Cannot get the page size on this machine
58#endif
Reid Spencer27dafe12004-09-11 04:56:56 +000059 return static_cast<unsigned>(page_size);
60}
61
Chris Lattner513a9542005-11-14 07:00:29 +000062size_t Process::GetMallocUsage() {
Reid Spencerbc1ee842004-12-20 16:06:44 +000063#if defined(HAVE_MALLINFO)
Reid Spencer721d9aa2004-12-20 00:59:28 +000064 struct mallinfo mi;
65 mi = ::mallinfo();
66 return mi.uordblks;
Chris Lattnerc590e9a2005-11-14 07:27:56 +000067#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
Reid Spencerbc1ee842004-12-20 16:06:44 +000071#elif defined(HAVE_SBRK)
Reid Spencer721d9aa2004-12-20 00:59:28 +000072 // Note this is only an approximation and more closely resembles
73 // the value returned by mallinfo in the arena field.
Chris Lattner513a9542005-11-14 07:00:29 +000074 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;
Reid Spencer721d9aa2004-12-20 00:59:28 +000078 else
79 return 0;
80#else
81#warning Cannot get malloc info on this platform
82 return 0;
83#endif
84}
85
Jeff Cohene269a1a2005-01-08 20:15:57 +000086size_t
Reid Spencer721d9aa2004-12-20 00:59:28 +000087Process::GetTotalMemoryUsage()
88{
Reid Spencerbc1ee842004-12-20 16:06:44 +000089#if defined(HAVE_MALLINFO)
Reid Spencer721d9aa2004-12-20 00:59:28 +000090 struct mallinfo mi = ::mallinfo();
91 return mi.uordblks + mi.hblkhd;
Chris Lattnerc590e9a2005-11-14 07:27:56 +000092#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
Edward O'Callaghandf406642009-10-12 04:57:20 +000096#elif defined(HAVE_GETRUSAGE) && !defined(__HAIKU__)
Reid Spencered5e7bf2004-12-20 16:33:37 +000097 struct rusage usage;
98 ::getrusage(RUSAGE_SELF, &usage);
99 return usage.ru_maxrss;
Reid Spencer721d9aa2004-12-20 00:59:28 +0000100#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();
Chris Lattner095cc372006-05-12 18:20:39 +0000111#if defined(HAVE_GETRUSAGE)
Reid Spencer721d9aa2004-12-20 00:59:28 +0000112 struct rusage usage;
113 ::getrusage(RUSAGE_SELF, &usage);
Reid Spencer8b662892004-12-20 21:43:33 +0000114 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 ) );
Reid Spencer721d9aa2004-12-20 00:59:28 +0000122#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
Chris Lattner26b6c0b2006-09-14 06:01:41 +0000131int Process::GetCurrentUserId() {
Reid Spencer93b34732005-04-21 16:12:57 +0000132 return getuid();
133}
134
Chris Lattner26b6c0b2006-09-14 06:01:41 +0000135int Process::GetCurrentGroupId() {
Reid Spencer93b34732005-04-21 16:12:57 +0000136 return getgid();
137}
138
Nate Begemane9563982008-04-12 00:47:46 +0000139#ifdef HAVE_MACH_MACH_H
140#include <mach/mach.h>
141#endif
142
Reid Spencer68fdcc12004-12-27 06:17:27 +0000143// 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;
Chris Lattner505f9c82006-05-14 18:53:09 +0000150 setrlimit(RLIMIT_CORE, &rlim);
Reid Spencer68fdcc12004-12-27 06:17:27 +0000151#endif
Chris Lattner26b6c0b2006-09-14 06:01:41 +0000152
Chris Lattner5f1d0132006-09-14 06:21:59 +0000153#ifdef HAVE_MACH_MACH_H
Nate Begemane9563982008-04-12 00:47:46 +0000154 // 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
Nate Begeman82b53cd2008-03-31 22:19:25 +0000175 signal(SIGABRT, _exit);
176 signal(SIGILL, _exit);
177 signal(SIGFPE, _exit);
178 signal(SIGSEGV, _exit);
179 signal(SIGBUS, _exit);
Chris Lattner26b6c0b2006-09-14 06:01:41 +0000180#endif
Reid Spencer68fdcc12004-12-27 06:17:27 +0000181}
Reid Spencer721d9aa2004-12-20 00:59:28 +0000182
Reid Spencera01aade2005-01-01 22:29:26 +0000183bool Process::StandardInIsUserInput() {
Dan Gohmanec080462009-09-11 20:46:33 +0000184 return FileDescriptorIsDisplayed(STDIN_FILENO);
Reid Spencera01aade2005-01-01 22:29:26 +0000185}
186
187bool Process::StandardOutIsDisplayed() {
Dan Gohmanec080462009-09-11 20:46:33 +0000188 return FileDescriptorIsDisplayed(STDOUT_FILENO);
Reid Spencera01aade2005-01-01 22:29:26 +0000189}
190
191bool Process::StandardErrIsDisplayed() {
Dan Gohmanec080462009-09-11 20:46:33 +0000192 return FileDescriptorIsDisplayed(STDERR_FILENO);
193}
194
195bool Process::FileDescriptorIsDisplayed(int fd) {
Reid Spencera01aade2005-01-01 22:29:26 +0000196#if HAVE_ISATTY
Dan Gohmanec080462009-09-11 20:46:33 +0000197 return isatty(fd);
Duncan Sands740eb532009-09-06 10:53:22 +0000198#else
Reid Spencera01aade2005-01-01 22:29:26 +0000199 // If we don't have isatty, just return false.
200 return false;
Duncan Sands740eb532009-09-06 10:53:22 +0000201#endif
Reid Spencera01aade2005-01-01 22:29:26 +0000202}
Douglas Gregor01746742009-05-11 18:05:52 +0000203
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
Douglas Gregor071d73d2009-05-18 17:21:34 +0000214#if defined(HAVE_SYS_IOCTL_H) && defined(HAVE_TERMIOS_H)
Douglas Gregor01746742009-05-11 18:05:52 +0000215 // 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}
Torok Edwine8ebb0f2009-06-04 07:09:50 +0000237
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
Nuno Lopesec9d8b02009-12-23 17:48:10 +0000280static const char colorcodes[2][2][8][10] = {
Torok Edwine8ebb0f2009-06-04 07:09:50 +0000281 { 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}