Work around a page size issue on Cygwin.
[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 #ifdef HAVE_TERMIOS_H
31 #  include <termios.h>
32 #endif
33
34 //===----------------------------------------------------------------------===//
35 //=== WARNING: Implementation here must contain only generic UNIX code that
36 //===          is guaranteed to work on *all* UNIX variants.
37 //===----------------------------------------------------------------------===//
38
39 using namespace llvm;
40 using namespace sys;
41
42 unsigned 
43 Process::GetPageSize() 
44 {
45 #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)
51   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
60 size_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
84 size_t
85 Process::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
104 void
105 Process::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
129 int Process::GetCurrentUserId() {
130   return getuid();
131 }
132
133 int Process::GetCurrentGroupId() {
134   return getgid();
135 }
136
137 #ifdef HAVE_MACH_MACH_H
138 #include <mach/mach.h>
139 #endif
140
141 // 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.
144 void 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
152   // 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
173   signal(SIGABRT, _exit);
174   signal(SIGILL,  _exit);
175   signal(SIGFPE,  _exit);
176   signal(SIGSEGV, _exit);
177   signal(SIGBUS,  _exit);
178 #endif
179 }
180
181 bool 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
189 bool 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
197 bool 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 }
204
205 static 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
215 #if defined(HAVE_SYS_IOCTL_H) && defined(HAVE_TERMIOS_H)
216   // 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
225 unsigned Process::StandardOutColumns() {
226   if (!StandardOutIsDisplayed())
227     return 0;
228
229   return getColumns(1);
230 }
231
232 unsigned Process::StandardErrColumns() {
233   if (!StandardErrIsDisplayed())
234     return 0;
235
236   return getColumns(2);
237 }