Process.inc revision 234982
1218885Sdim//===- Unix/Process.cpp - Unix Process Implementation --------- -*- C++ -*-===//
2218885Sdim//
3218885Sdim//                     The LLVM Compiler Infrastructure
4218885Sdim//
5218885Sdim// This file is distributed under the University of Illinois Open Source
6218885Sdim// License. See LICENSE.TXT for details.
7218885Sdim//
8218885Sdim//===----------------------------------------------------------------------===//
9218885Sdim//
10218885Sdim// This file provides the generic Unix implementation of the Process class.
11218885Sdim//
12218885Sdim//===----------------------------------------------------------------------===//
13218885Sdim
14218885Sdim#include "Unix.h"
15218885Sdim#ifdef HAVE_SYS_TIME_H
16218885Sdim#include <sys/time.h>
17218885Sdim#endif
18218885Sdim#ifdef HAVE_SYS_RESOURCE_H
19218885Sdim#include <sys/resource.h>
20218885Sdim#endif
21218885Sdim// DragonFly BSD has deprecated <malloc.h> for <stdlib.h> instead,
22218885Sdim//  Unix.h includes this for us already.
23218885Sdim#if defined(HAVE_MALLOC_H) && !defined(__DragonFly__)
24218885Sdim#include <malloc.h>
25218885Sdim#endif
26218885Sdim#ifdef HAVE_MALLOC_MALLOC_H
27218885Sdim#include <malloc/malloc.h>
28218885Sdim#endif
29218885Sdim#ifdef HAVE_SYS_IOCTL_H
30218885Sdim#  include <sys/ioctl.h>
31218885Sdim#endif
32218885Sdim#ifdef HAVE_TERMIOS_H
33218885Sdim#  include <termios.h>
34218885Sdim#endif
35218885Sdim
36218885Sdim//===----------------------------------------------------------------------===//
37218885Sdim//=== WARNING: Implementation here must contain only generic UNIX code that
38218885Sdim//===          is guaranteed to work on *all* UNIX variants.
39218885Sdim//===----------------------------------------------------------------------===//
40218885Sdim
41218885Sdimusing namespace llvm;
42218885Sdimusing namespace sys;
43218885Sdim
44218885Sdimunsigned
45218885SdimProcess::GetPageSize()
46218885Sdim{
47218885Sdim#if defined(__CYGWIN__)
48218885Sdim  // On Cygwin, getpagesize() returns 64k but the page size for the purposes of
49218885Sdim  // memory protection and mmap() is 4k.
50218885Sdim  // See http://www.cygwin.com/ml/cygwin/2009-01/threads.html#00492
51218885Sdim  const int page_size = 0x1000;
52218885Sdim#elif defined(HAVE_GETPAGESIZE)
53218885Sdim  const int page_size = ::getpagesize();
54218885Sdim#elif defined(HAVE_SYSCONF)
55218885Sdim  long page_size = ::sysconf(_SC_PAGE_SIZE);
56218885Sdim#else
57218885Sdim#warning Cannot get the page size on this machine
58218885Sdim#endif
59218885Sdim  return static_cast<unsigned>(page_size);
60218885Sdim}
61218885Sdim
62218885Sdimsize_t Process::GetMallocUsage() {
63218885Sdim#if defined(HAVE_MALLINFO)
64218885Sdim  struct mallinfo mi;
65218885Sdim  mi = ::mallinfo();
66218885Sdim  return mi.uordblks;
67218885Sdim#elif defined(HAVE_MALLOC_ZONE_STATISTICS) && defined(HAVE_MALLOC_MALLOC_H)
68218885Sdim  malloc_statistics_t Stats;
69218885Sdim  malloc_zone_statistics(malloc_default_zone(), &Stats);
70218885Sdim  return Stats.size_in_use;   // darwin
71218885Sdim#elif defined(HAVE_SBRK)
72218885Sdim  // Note this is only an approximation and more closely resembles
73218885Sdim  // the value returned by mallinfo in the arena field.
74218885Sdim  static char *StartOfMemory = reinterpret_cast<char*>(::sbrk(0));
75218885Sdim  char *EndOfMemory = (char*)sbrk(0);
76218885Sdim  if (EndOfMemory != ((char*)-1) && StartOfMemory != ((char*)-1))
77218885Sdim    return EndOfMemory - StartOfMemory;
78218885Sdim  else
79218885Sdim    return 0;
80218885Sdim#else
81218885Sdim#warning Cannot get malloc info on this platform
82218885Sdim  return 0;
83218885Sdim#endif
84218885Sdim}
85218885Sdim
86218885Sdimsize_t
87218885SdimProcess::GetTotalMemoryUsage()
88218885Sdim{
89218885Sdim#if defined(HAVE_MALLINFO)
90218885Sdim  struct mallinfo mi = ::mallinfo();
91218885Sdim  return mi.uordblks + mi.hblkhd;
92218885Sdim#elif defined(HAVE_MALLOC_ZONE_STATISTICS) && defined(HAVE_MALLOC_MALLOC_H)
93218885Sdim  malloc_statistics_t Stats;
94218885Sdim  malloc_zone_statistics(malloc_default_zone(), &Stats);
95218885Sdim  return Stats.size_allocated;   // darwin
96218885Sdim#elif defined(HAVE_GETRUSAGE) && !defined(__HAIKU__)
97218885Sdim  struct rusage usage;
98218885Sdim  ::getrusage(RUSAGE_SELF, &usage);
99218885Sdim  return usage.ru_maxrss;
100218885Sdim#else
101218885Sdim#warning Cannot get total memory size on this platform
102218885Sdim  return 0;
103218885Sdim#endif
104218885Sdim}
105218885Sdim
106218885Sdimvoid
107218885SdimProcess::GetTimeUsage(TimeValue& elapsed, TimeValue& user_time,
108218885Sdim                      TimeValue& sys_time)
109218885Sdim{
110218885Sdim  elapsed = TimeValue::now();
111218885Sdim#if defined(HAVE_GETRUSAGE)
112218885Sdim  struct rusage usage;
113218885Sdim  ::getrusage(RUSAGE_SELF, &usage);
114218885Sdim  user_time = TimeValue(
115218885Sdim    static_cast<TimeValue::SecondsType>( usage.ru_utime.tv_sec ),
116218885Sdim    static_cast<TimeValue::NanoSecondsType>( usage.ru_utime.tv_usec *
117218885Sdim      TimeValue::NANOSECONDS_PER_MICROSECOND ) );
118218885Sdim  sys_time = TimeValue(
119218885Sdim    static_cast<TimeValue::SecondsType>( usage.ru_stime.tv_sec ),
120218885Sdim    static_cast<TimeValue::NanoSecondsType>( usage.ru_stime.tv_usec *
121218885Sdim      TimeValue::NANOSECONDS_PER_MICROSECOND ) );
122218885Sdim#else
123218885Sdim#warning Cannot get usage times on this platform
124218885Sdim  user_time.seconds(0);
125218885Sdim  user_time.microseconds(0);
126218885Sdim  sys_time.seconds(0);
127218885Sdim  sys_time.microseconds(0);
128218885Sdim#endif
129218885Sdim}
130218885Sdim
131218885Sdimint Process::GetCurrentUserId() {
132218885Sdim  return getuid();
133218885Sdim}
134218885Sdim
135218885Sdimint Process::GetCurrentGroupId() {
136218885Sdim  return getgid();
137218885Sdim}
138218885Sdim
139234353Sdim#if defined(HAVE_MACH_MACH_H) && !defined(__GNU__)
140218885Sdim#include <mach/mach.h>
141218885Sdim#endif
142218885Sdim
143218885Sdim// Some LLVM programs such as bugpoint produce core files as a normal part of
144218885Sdim// their operation. To prevent the disk from filling up, this function
145218885Sdim// does what's necessary to prevent their generation.
146218885Sdimvoid Process::PreventCoreFiles() {
147218885Sdim#if HAVE_SETRLIMIT
148218885Sdim  struct rlimit rlim;
149218885Sdim  rlim.rlim_cur = rlim.rlim_max = 0;
150218885Sdim  setrlimit(RLIMIT_CORE, &rlim);
151218885Sdim#endif
152218885Sdim
153234353Sdim#if defined(HAVE_MACH_MACH_H) && !defined(__GNU__)
154218885Sdim  // Disable crash reporting on Mac OS X 10.0-10.4
155218885Sdim
156218885Sdim  // get information about the original set of exception ports for the task
157218885Sdim  mach_msg_type_number_t Count = 0;
158218885Sdim  exception_mask_t OriginalMasks[EXC_TYPES_COUNT];
159218885Sdim  exception_port_t OriginalPorts[EXC_TYPES_COUNT];
160218885Sdim  exception_behavior_t OriginalBehaviors[EXC_TYPES_COUNT];
161218885Sdim  thread_state_flavor_t OriginalFlavors[EXC_TYPES_COUNT];
162218885Sdim  kern_return_t err =
163218885Sdim    task_get_exception_ports(mach_task_self(), EXC_MASK_ALL, OriginalMasks,
164218885Sdim                             &Count, OriginalPorts, OriginalBehaviors,
165218885Sdim                             OriginalFlavors);
166218885Sdim  if (err == KERN_SUCCESS) {
167218885Sdim    // replace each with MACH_PORT_NULL.
168218885Sdim    for (unsigned i = 0; i != Count; ++i)
169218885Sdim      task_set_exception_ports(mach_task_self(), OriginalMasks[i],
170218885Sdim                               MACH_PORT_NULL, OriginalBehaviors[i],
171218885Sdim                               OriginalFlavors[i]);
172218885Sdim  }
173218885Sdim
174218885Sdim  // Disable crash reporting on Mac OS X 10.5
175218885Sdim  signal(SIGABRT, _exit);
176218885Sdim  signal(SIGILL,  _exit);
177218885Sdim  signal(SIGFPE,  _exit);
178218885Sdim  signal(SIGSEGV, _exit);
179218885Sdim  signal(SIGBUS,  _exit);
180218885Sdim#endif
181218885Sdim}
182218885Sdim
183218885Sdimbool Process::StandardInIsUserInput() {
184218885Sdim  return FileDescriptorIsDisplayed(STDIN_FILENO);
185218885Sdim}
186218885Sdim
187218885Sdimbool Process::StandardOutIsDisplayed() {
188218885Sdim  return FileDescriptorIsDisplayed(STDOUT_FILENO);
189218885Sdim}
190218885Sdim
191218885Sdimbool Process::StandardErrIsDisplayed() {
192218885Sdim  return FileDescriptorIsDisplayed(STDERR_FILENO);
193218885Sdim}
194218885Sdim
195218885Sdimbool Process::FileDescriptorIsDisplayed(int fd) {
196218885Sdim#if HAVE_ISATTY
197218885Sdim  return isatty(fd);
198218885Sdim#else
199218885Sdim  // If we don't have isatty, just return false.
200218885Sdim  return false;
201218885Sdim#endif
202218885Sdim}
203218885Sdim
204218885Sdimstatic unsigned getColumns(int FileID) {
205218885Sdim  // If COLUMNS is defined in the environment, wrap to that many columns.
206218885Sdim  if (const char *ColumnsStr = std::getenv("COLUMNS")) {
207218885Sdim    int Columns = std::atoi(ColumnsStr);
208218885Sdim    if (Columns > 0)
209218885Sdim      return Columns;
210218885Sdim  }
211218885Sdim
212218885Sdim  unsigned Columns = 0;
213218885Sdim
214218885Sdim#if defined(HAVE_SYS_IOCTL_H) && defined(HAVE_TERMIOS_H)
215218885Sdim  // Try to determine the width of the terminal.
216218885Sdim  struct winsize ws;
217218885Sdim  if (ioctl(FileID, TIOCGWINSZ, &ws) == 0)
218218885Sdim    Columns = ws.ws_col;
219218885Sdim#endif
220218885Sdim
221218885Sdim  return Columns;
222218885Sdim}
223218885Sdim
224218885Sdimunsigned Process::StandardOutColumns() {
225218885Sdim  if (!StandardOutIsDisplayed())
226218885Sdim    return 0;
227218885Sdim
228218885Sdim  return getColumns(1);
229218885Sdim}
230218885Sdim
231218885Sdimunsigned Process::StandardErrColumns() {
232218885Sdim  if (!StandardErrIsDisplayed())
233218885Sdim    return 0;
234218885Sdim
235218885Sdim  return getColumns(2);
236218885Sdim}
237218885Sdim
238218885Sdimstatic bool terminalHasColors() {
239218885Sdim  if (const char *term = std::getenv("TERM")) {
240218885Sdim    // Most modern terminals support ANSI escape sequences for colors.
241218885Sdim    // We could check terminfo, or have a list of known terms that support
242218885Sdim    // colors, but that would be overkill.
243218885Sdim    // The user can always ask for no colors by setting TERM to dumb, or
244218885Sdim    // using a commandline flag.
245218885Sdim    return strcmp(term, "dumb") != 0;
246218885Sdim  }
247218885Sdim  return false;
248218885Sdim}
249218885Sdim
250218885Sdimbool Process::StandardOutHasColors() {
251218885Sdim  if (!StandardOutIsDisplayed())
252218885Sdim    return false;
253218885Sdim  return terminalHasColors();
254218885Sdim}
255218885Sdim
256218885Sdimbool Process::StandardErrHasColors() {
257218885Sdim  if (!StandardErrIsDisplayed())
258218885Sdim    return false;
259218885Sdim  return terminalHasColors();
260218885Sdim}
261218885Sdim
262218885Sdimbool Process::ColorNeedsFlush() {
263218885Sdim  // No, we use ANSI escape sequences.
264218885Sdim  return false;
265218885Sdim}
266218885Sdim
267218885Sdim#define COLOR(FGBG, CODE, BOLD) "\033[0;" BOLD FGBG CODE "m"
268218885Sdim
269218885Sdim#define ALLCOLORS(FGBG,BOLD) {\
270218885Sdim    COLOR(FGBG, "0", BOLD),\
271218885Sdim    COLOR(FGBG, "1", BOLD),\
272218885Sdim    COLOR(FGBG, "2", BOLD),\
273218885Sdim    COLOR(FGBG, "3", BOLD),\
274218885Sdim    COLOR(FGBG, "4", BOLD),\
275218885Sdim    COLOR(FGBG, "5", BOLD),\
276218885Sdim    COLOR(FGBG, "6", BOLD),\
277218885Sdim    COLOR(FGBG, "7", BOLD)\
278218885Sdim  }
279218885Sdim
280218885Sdimstatic const char colorcodes[2][2][8][10] = {
281218885Sdim { ALLCOLORS("3",""), ALLCOLORS("3","1;") },
282218885Sdim { ALLCOLORS("4",""), ALLCOLORS("4","1;") }
283218885Sdim};
284218885Sdim
285218885Sdimconst char *Process::OutputColor(char code, bool bold, bool bg) {
286218885Sdim  return colorcodes[bg?1:0][bold?1:0][code&7];
287218885Sdim}
288218885Sdim
289218885Sdimconst char *Process::OutputBold(bool bg) {
290218885Sdim  return "\033[1m";
291218885Sdim}
292218885Sdim
293234982Sdimconst char *Process::OutputReverse() {
294234982Sdim  return "\033[7m";
295234982Sdim}
296234982Sdim
297218885Sdimconst char *Process::ResetColor() {
298218885Sdim  return "\033[0m";
299218885Sdim}
300