termios.h contains the winsize structure we need to determine the
[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(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
55 size_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
79 size_t
80 Process::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
99 void
100 Process::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
124 int Process::GetCurrentUserId() {
125   return getuid();
126 }
127
128 int Process::GetCurrentGroupId() {
129   return getgid();
130 }
131
132 #ifdef HAVE_MACH_MACH_H
133 #include <mach/mach.h>
134 #endif
135
136 // 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.
139 void 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
147   // 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
168   signal(SIGABRT, _exit);
169   signal(SIGILL,  _exit);
170   signal(SIGFPE,  _exit);
171   signal(SIGSEGV, _exit);
172   signal(SIGBUS,  _exit);
173 #endif
174 }
175
176 bool 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
184 bool 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
192 bool 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 }
199
200 static 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
210 #if defined(HAVE_SYS_IOCTL_H) && defined(HAVE_TERMIOS_H)
211   // 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
220 unsigned Process::StandardOutColumns() {
221   if (!StandardOutIsDisplayed())
222     return 0;
223
224   return getColumns(1);
225 }
226
227 unsigned Process::StandardErrColumns() {
228   if (!StandardErrIsDisplayed())
229     return 0;
230
231   return getColumns(2);
232 }