blob: 74b9bb8b142a9d256e0994704537973cff08bbe2 [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}