blob: b1286b7bfcd5e98050120d8837e0878a53d34512 [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
Dan Gohmanf17a25c2007-07-18 16:29:46 +000030
31//===----------------------------------------------------------------------===//
32//=== WARNING: Implementation here must contain only generic UNIX code that
33//=== is guaranteed to work on *all* UNIX variants.
34//===----------------------------------------------------------------------===//
35
36using namespace llvm;
37using namespace sys;
38
39unsigned
40Process::GetPageSize()
41{
42#if defined(HAVE_GETPAGESIZE)
43 static const int page_size = ::getpagesize();
44#elif defined(HAVE_SYSCONF)
45 static long page_size = ::sysconf(_SC_PAGE_SIZE);
46#else
47#warning Cannot get the page size on this machine
48#endif
49 return static_cast<unsigned>(page_size);
50}
51
52size_t Process::GetMallocUsage() {
53#if defined(HAVE_MALLINFO)
54 struct mallinfo mi;
55 mi = ::mallinfo();
56 return mi.uordblks;
57#elif defined(HAVE_MALLOC_ZONE_STATISTICS) && defined(HAVE_MALLOC_MALLOC_H)
58 malloc_statistics_t Stats;
59 malloc_zone_statistics(malloc_default_zone(), &Stats);
60 return Stats.size_in_use; // darwin
61#elif defined(HAVE_SBRK)
62 // Note this is only an approximation and more closely resembles
63 // the value returned by mallinfo in the arena field.
64 static char *StartOfMemory = reinterpret_cast<char*>(::sbrk(0));
65 char *EndOfMemory = (char*)sbrk(0);
66 if (EndOfMemory != ((char*)-1) && StartOfMemory != ((char*)-1))
67 return EndOfMemory - StartOfMemory;
68 else
69 return 0;
70#else
71#warning Cannot get malloc info on this platform
72 return 0;
73#endif
74}
75
76size_t
77Process::GetTotalMemoryUsage()
78{
79#if defined(HAVE_MALLINFO)
80 struct mallinfo mi = ::mallinfo();
81 return mi.uordblks + mi.hblkhd;
82#elif defined(HAVE_MALLOC_ZONE_STATISTICS) && defined(HAVE_MALLOC_MALLOC_H)
83 malloc_statistics_t Stats;
84 malloc_zone_statistics(malloc_default_zone(), &Stats);
85 return Stats.size_allocated; // darwin
86#elif defined(HAVE_GETRUSAGE)
87 struct rusage usage;
88 ::getrusage(RUSAGE_SELF, &usage);
89 return usage.ru_maxrss;
90#else
91#warning Cannot get total memory size on this platform
92 return 0;
93#endif
94}
95
96void
97Process::GetTimeUsage(TimeValue& elapsed, TimeValue& user_time,
98 TimeValue& sys_time)
99{
100 elapsed = TimeValue::now();
101#if defined(HAVE_GETRUSAGE)
102 struct rusage usage;
103 ::getrusage(RUSAGE_SELF, &usage);
104 user_time = TimeValue(
105 static_cast<TimeValue::SecondsType>( usage.ru_utime.tv_sec ),
106 static_cast<TimeValue::NanoSecondsType>( usage.ru_utime.tv_usec *
107 TimeValue::NANOSECONDS_PER_MICROSECOND ) );
108 sys_time = TimeValue(
109 static_cast<TimeValue::SecondsType>( usage.ru_stime.tv_sec ),
110 static_cast<TimeValue::NanoSecondsType>( usage.ru_stime.tv_usec *
111 TimeValue::NANOSECONDS_PER_MICROSECOND ) );
112#else
113#warning Cannot get usage times on this platform
114 user_time.seconds(0);
115 user_time.microseconds(0);
116 sys_time.seconds(0);
117 sys_time.microseconds(0);
118#endif
119}
120
121int Process::GetCurrentUserId() {
122 return getuid();
123}
124
125int Process::GetCurrentGroupId() {
126 return getgid();
127}
128
Nate Begeman703a4f82008-04-12 00:47:46 +0000129#ifdef HAVE_MACH_MACH_H
130#include <mach/mach.h>
131#endif
132
Dan Gohmanf17a25c2007-07-18 16:29:46 +0000133// Some LLVM programs such as bugpoint produce core files as a normal part of
134// their operation. To prevent the disk from filling up, this function
135// does what's necessary to prevent their generation.
136void Process::PreventCoreFiles() {
137#if HAVE_SETRLIMIT
138 struct rlimit rlim;
139 rlim.rlim_cur = rlim.rlim_max = 0;
140 setrlimit(RLIMIT_CORE, &rlim);
141#endif
142
143#ifdef HAVE_MACH_MACH_H
Nate Begeman703a4f82008-04-12 00:47:46 +0000144 // Disable crash reporting on Mac OS X 10.0-10.4
145
146 // get information about the original set of exception ports for the task
147 mach_msg_type_number_t Count = 0;
148 exception_mask_t OriginalMasks[EXC_TYPES_COUNT];
149 exception_port_t OriginalPorts[EXC_TYPES_COUNT];
150 exception_behavior_t OriginalBehaviors[EXC_TYPES_COUNT];
151 thread_state_flavor_t OriginalFlavors[EXC_TYPES_COUNT];
152 kern_return_t err =
153 task_get_exception_ports(mach_task_self(), EXC_MASK_ALL, OriginalMasks,
154 &Count, OriginalPorts, OriginalBehaviors,
155 OriginalFlavors);
156 if (err == KERN_SUCCESS) {
157 // replace each with MACH_PORT_NULL.
158 for (unsigned i = 0; i != Count; ++i)
159 task_set_exception_ports(mach_task_self(), OriginalMasks[i],
160 MACH_PORT_NULL, OriginalBehaviors[i],
161 OriginalFlavors[i]);
162 }
163
164 // Disable crash reporting on Mac OS X 10.5
Nate Begeman71742222008-03-31 22:19:25 +0000165 signal(SIGABRT, _exit);
166 signal(SIGILL, _exit);
167 signal(SIGFPE, _exit);
168 signal(SIGSEGV, _exit);
169 signal(SIGBUS, _exit);
Dan Gohmanf17a25c2007-07-18 16:29:46 +0000170#endif
171}
172
173bool Process::StandardInIsUserInput() {
174#if HAVE_ISATTY
175 return isatty(0);
176#endif
177 // If we don't have isatty, just return false.
178 return false;
179}
180
181bool Process::StandardOutIsDisplayed() {
182#if HAVE_ISATTY
183 return isatty(1);
184#endif
185 // If we don't have isatty, just return false.
186 return false;
187}
188
189bool Process::StandardErrIsDisplayed() {
190#if HAVE_ISATTY
191 return isatty(2);
192#endif
193 // If we don't have isatty, just return false.
194 return false;
195}
Douglas Gregord1e1dbc2009-05-11 18:05:52 +0000196
197static unsigned getColumns(int FileID) {
198 // If COLUMNS is defined in the environment, wrap to that many columns.
199 if (const char *ColumnsStr = std::getenv("COLUMNS")) {
200 int Columns = std::atoi(ColumnsStr);
201 if (Columns > 0)
202 return Columns;
203 }
204
205 unsigned Columns = 0;
206
207#ifdef HAVE_SYS_IOCTL_H
208 // Try to determine the width of the terminal.
209 struct winsize ws;
210 if (ioctl(FileID, TIOCGWINSZ, &ws) == 0)
211 Columns = ws.ws_col;
212#endif
213
214 return Columns;
215}
216
217unsigned Process::StandardOutColumns() {
218 if (!StandardOutIsDisplayed())
219 return 0;
220
221 return getColumns(1);
222}
223
224unsigned Process::StandardErrColumns() {
225 if (!StandardErrIsDisplayed())
226 return 0;
227
228 return getColumns(2);
229}