blob: 2da31c9f215b5e198e426547031e6907f3d1667c [file] [log] [blame]
Dan Gohmanf17a25c2007-07-18 16:29:46 +00001//===- Unix/Process.cpp - Unix Process Implementation --------- -*- C++ -*-===//
2//
3// The LLVM Compiler Infrastructure
4//
Chris Lattner081ce942007-12-29 20:36:04 +00005// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
Dan Gohmanf17a25c2007-07-18 16:29:46 +00007//
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
Douglas Gregord1e1dbc2009-05-11 18:05:52 +000027#ifdef HAVE_SYS_IOCTL_H
28# include <sys/ioctl.h>
29#endif
Douglas Gregor6230bee2009-05-18 17:21:34 +000030#ifdef HAVE_TERMIOS_H
31# include <termios.h>
32#endif
Dan Gohmanf17a25c2007-07-18 16:29:46 +000033
34//===----------------------------------------------------------------------===//
35//=== WARNING: Implementation here must contain only generic UNIX code that
36//=== is guaranteed to work on *all* UNIX variants.
37//===----------------------------------------------------------------------===//
38
39using namespace llvm;
40using namespace sys;
41
42unsigned
43Process::GetPageSize()
44{
Jay Foaddc3e36d2009-05-23 17:57:59 +000045#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)
Dan Gohmanf17a25c2007-07-18 16:29:46 +000051 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
60size_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
84size_t
85Process::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
104void
105Process::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
129int Process::GetCurrentUserId() {
130 return getuid();
131}
132
133int Process::GetCurrentGroupId() {
134 return getgid();
135}
136
Nate Begeman703a4f82008-04-12 00:47:46 +0000137#ifdef HAVE_MACH_MACH_H
138#include <mach/mach.h>
139#endif
140
Dan Gohmanf17a25c2007-07-18 16:29:46 +0000141// 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.
144void 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
Nate Begeman703a4f82008-04-12 00:47:46 +0000152 // 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
Nate Begeman71742222008-03-31 22:19:25 +0000173 signal(SIGABRT, _exit);
174 signal(SIGILL, _exit);
175 signal(SIGFPE, _exit);
176 signal(SIGSEGV, _exit);
177 signal(SIGBUS, _exit);
Dan Gohmanf17a25c2007-07-18 16:29:46 +0000178#endif
179}
180
181bool 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
189bool 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
197bool 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}
Douglas Gregord1e1dbc2009-05-11 18:05:52 +0000204
205static 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
Douglas Gregor6230bee2009-05-18 17:21:34 +0000215#if defined(HAVE_SYS_IOCTL_H) && defined(HAVE_TERMIOS_H)
Douglas Gregord1e1dbc2009-05-11 18:05:52 +0000216 // 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
225unsigned Process::StandardOutColumns() {
226 if (!StandardOutIsDisplayed())
227 return 0;
228
229 return getColumns(1);
230}
231
232unsigned Process::StandardErrColumns() {
233 if (!StandardErrIsDisplayed())
234 return 0;
235
236 return getColumns(2);
237}
Edwin Török8a06a5b2009-06-04 07:09:50 +0000238
239static 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
251bool Process::StandardOutHasColors() {
252 if (!StandardOutIsDisplayed())
253 return false;
254 return terminalHasColors();
255}
256
257bool Process::StandardErrHasColors() {
258 if (!StandardErrIsDisplayed())
259 return false;
260 return terminalHasColors();
261}
262
263bool 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
281static const char* colorcodes[2][2][8] = {
282 { ALLCOLORS("3",""), ALLCOLORS("3","1;") },
283 { ALLCOLORS("4",""), ALLCOLORS("4","1;") }
284};
285
286const char *Process::OutputColor(char code, bool bold, bool bg) {
287 return colorcodes[bg?1:0][bold?1:0][code&7];
288}
289
290const char *Process::OutputBold(bool bg) {
291 return "\033[1m";
292}
293
294const char *Process::ResetColor() {
295 return "\033[0m";
296}