b1286b7bfcd5e98050120d8837e0878a53d34512
[oota-llvm.git] / lib / System / Unix / Process.inc
1 //===- Unix/Process.cpp - Unix Process Implementation --------- -*- C++ -*-===//
2 // 
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 // 
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
27 #ifdef HAVE_SYS_IOCTL_H
28 #  include <sys/ioctl.h>
29 #endif
30
31 //===----------------------------------------------------------------------===//
32 //=== WARNING: Implementation here must contain only generic UNIX code that
33 //===          is guaranteed to work on *all* UNIX variants.
34 //===----------------------------------------------------------------------===//
35
36 using namespace llvm;
37 using namespace sys;
38
39 unsigned 
40 Process::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
52 size_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
76 size_t
77 Process::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
96 void
97 Process::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
121 int Process::GetCurrentUserId() {
122   return getuid();
123 }
124
125 int Process::GetCurrentGroupId() {
126   return getgid();
127 }
128
129 #ifdef HAVE_MACH_MACH_H
130 #include <mach/mach.h>
131 #endif
132
133 // 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.
136 void 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
144   // 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
165   signal(SIGABRT, _exit);
166   signal(SIGILL,  _exit);
167   signal(SIGFPE,  _exit);
168   signal(SIGSEGV, _exit);
169   signal(SIGBUS,  _exit);
170 #endif
171 }
172
173 bool 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
181 bool 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
189 bool 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 }
196
197 static 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
217 unsigned Process::StandardOutColumns() {
218   if (!StandardOutIsDisplayed())
219     return 0;
220
221   return getColumns(1);
222 }
223
224 unsigned Process::StandardErrColumns() {
225   if (!StandardErrIsDisplayed())
226     return 0;
227
228   return getColumns(2);
229 }