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