LLVM  9.0.0svn
Process.inc
Go to the documentation of this file.
1 //===- Unix/Process.cpp - Unix Process Implementation --------- -*- C++ -*-===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // This file provides the generic Unix implementation of the Process class.
10 //
11 //===----------------------------------------------------------------------===//
12 
13 #include "Unix.h"
14 #include "llvm/ADT/Hashing.h"
15 #include "llvm/ADT/StringRef.h"
16 #include "llvm/Config/config.h"
18 #include "llvm/Support/Mutex.h"
20 #if HAVE_FCNTL_H
21 #include <fcntl.h>
22 #endif
23 #ifdef HAVE_SYS_TIME_H
24 #include <sys/time.h>
25 #endif
26 #ifdef HAVE_SYS_RESOURCE_H
27 #include <sys/resource.h>
28 #endif
29 #ifdef HAVE_SYS_STAT_H
30 #include <sys/stat.h>
31 #endif
32 #if HAVE_SIGNAL_H
33 #include <signal.h>
34 #endif
35 #if defined(HAVE_MALLINFO)
36 #include <malloc.h>
37 #endif
38 #if defined(HAVE_MALLCTL)
39 #include <malloc_np.h>
40 #endif
41 #ifdef HAVE_MALLOC_MALLOC_H
42 #include <malloc/malloc.h>
43 #endif
44 #ifdef HAVE_SYS_IOCTL_H
45 # include <sys/ioctl.h>
46 #endif
47 #ifdef HAVE_TERMIOS_H
48 # include <termios.h>
49 #endif
50 
51 //===----------------------------------------------------------------------===//
52 //=== WARNING: Implementation here must contain only generic UNIX code that
53 //=== is guaranteed to work on *all* UNIX variants.
54 //===----------------------------------------------------------------------===//
55 
56 using namespace llvm;
57 using namespace sys;
58 
59 static std::pair<std::chrono::microseconds, std::chrono::microseconds> getRUsageTimes() {
60 #if defined(HAVE_GETRUSAGE)
61  struct rusage RU;
62  ::getrusage(RUSAGE_SELF, &RU);
63  return { toDuration(RU.ru_utime), toDuration(RU.ru_stime) };
64 #else
65 #warning Cannot get usage times on this platform
66  return { std::chrono::microseconds::zero(), std::chrono::microseconds::zero() };
67 #endif
68 }
69 
70 // On Cygwin, getpagesize() returns 64k(AllocationGranularity) and
71 // offset in mmap(3) should be aligned to the AllocationGranularity.
73 #if defined(HAVE_GETPAGESIZE)
74  static const int page_size = ::getpagesize();
75 #elif defined(HAVE_SYSCONF)
76  static long page_size = ::sysconf(_SC_PAGE_SIZE);
77 #else
78 #error Cannot get the page size on this machine
79 #endif
80  if (page_size == -1)
81  return errorCodeToError(std::error_code(errno, std::generic_category()));
82 
83  return static_cast<unsigned>(page_size);
84 }
85 
86 size_t Process::GetMallocUsage() {
87 #if defined(HAVE_MALLINFO)
88  struct mallinfo mi;
89  mi = ::mallinfo();
90  return mi.uordblks;
91 #elif defined(HAVE_MALLOC_ZONE_STATISTICS) && defined(HAVE_MALLOC_MALLOC_H)
92  malloc_statistics_t Stats;
93  malloc_zone_statistics(malloc_default_zone(), &Stats);
94  return Stats.size_in_use; // darwin
95 #elif defined(HAVE_MALLCTL)
96  size_t alloc, sz;
97  sz = sizeof(size_t);
98  if (mallctl("stats.allocated", &alloc, &sz, NULL, 0) == 0)
99  return alloc;
100  return 0;
101 #elif defined(HAVE_SBRK)
102  // Note this is only an approximation and more closely resembles
103  // the value returned by mallinfo in the arena field.
104  static char *StartOfMemory = reinterpret_cast<char*>(::sbrk(0));
105  char *EndOfMemory = (char*)sbrk(0);
106  if (EndOfMemory != ((char*)-1) && StartOfMemory != ((char*)-1))
107  return EndOfMemory - StartOfMemory;
108  return 0;
109 #else
110 #warning Cannot get malloc info on this platform
111  return 0;
112 #endif
113 }
114 
115 void Process::GetTimeUsage(TimePoint<> &elapsed, std::chrono::nanoseconds &user_time,
116  std::chrono::nanoseconds &sys_time) {
117  elapsed = std::chrono::system_clock::now();
118  std::tie(user_time, sys_time) = getRUsageTimes();
119 }
120 
121 #if defined(HAVE_MACH_MACH_H) && !defined(__GNU__)
122 #include <mach/mach.h>
123 #endif
124 
125 // Some LLVM programs such as bugpoint produce core files as a normal part of
126 // their operation. To prevent the disk from filling up, this function
127 // does what's necessary to prevent their generation.
129 #if HAVE_SETRLIMIT
130  struct rlimit rlim;
131  rlim.rlim_cur = rlim.rlim_max = 0;
132  setrlimit(RLIMIT_CORE, &rlim);
133 #endif
134 
135 #if defined(HAVE_MACH_MACH_H) && !defined(__GNU__)
136  // Disable crash reporting on Mac OS X 10.0-10.4
137 
138  // get information about the original set of exception ports for the task
139  mach_msg_type_number_t Count = 0;
140  exception_mask_t OriginalMasks[EXC_TYPES_COUNT];
141  exception_port_t OriginalPorts[EXC_TYPES_COUNT];
142  exception_behavior_t OriginalBehaviors[EXC_TYPES_COUNT];
143  thread_state_flavor_t OriginalFlavors[EXC_TYPES_COUNT];
144  kern_return_t err =
145  task_get_exception_ports(mach_task_self(), EXC_MASK_ALL, OriginalMasks,
146  &Count, OriginalPorts, OriginalBehaviors,
147  OriginalFlavors);
148  if (err == KERN_SUCCESS) {
149  // replace each with MACH_PORT_NULL.
150  for (unsigned i = 0; i != Count; ++i)
151  task_set_exception_ports(mach_task_self(), OriginalMasks[i],
152  MACH_PORT_NULL, OriginalBehaviors[i],
153  OriginalFlavors[i]);
154  }
155 
156  // Disable crash reporting on Mac OS X 10.5
157  signal(SIGABRT, _exit);
158  signal(SIGILL, _exit);
159  signal(SIGFPE, _exit);
160  signal(SIGSEGV, _exit);
161  signal(SIGBUS, _exit);
162 #endif
163 
164  coreFilesPrevented = true;
165 }
166 
168  std::string NameStr = Name.str();
169  const char *Val = ::getenv(NameStr.c_str());
170  if (!Val)
171  return None;
172  return std::string(Val);
173 }
174 
175 namespace {
176 class FDCloser {
177 public:
178  FDCloser(int &FD) : FD(FD), KeepOpen(false) {}
179  void keepOpen() { KeepOpen = true; }
180  ~FDCloser() {
181  if (!KeepOpen && FD >= 0)
182  ::close(FD);
183  }
184 
185 private:
186  FDCloser(const FDCloser &) = delete;
187  void operator=(const FDCloser &) = delete;
188 
189  int &FD;
190  bool KeepOpen;
191 };
192 }
193 
194 std::error_code Process::FixupStandardFileDescriptors() {
195  int NullFD = -1;
196  FDCloser FDC(NullFD);
197  const int StandardFDs[] = {STDIN_FILENO, STDOUT_FILENO, STDERR_FILENO};
198  for (int StandardFD : StandardFDs) {
199  struct stat st;
200  errno = 0;
201  if (RetryAfterSignal(-1, ::fstat, StandardFD, &st) < 0) {
202  assert(errno && "expected errno to be set if fstat failed!");
203  // fstat should return EBADF if the file descriptor is closed.
204  if (errno != EBADF)
205  return std::error_code(errno, std::generic_category());
206  }
207  // if fstat succeeds, move on to the next FD.
208  if (!errno)
209  continue;
210  assert(errno == EBADF && "expected errno to have EBADF at this point!");
211 
212  if (NullFD < 0) {
213  // Call ::open in a lambda to avoid overload resolution in
214  // RetryAfterSignal when open is overloaded, such as in Bionic.
215  auto Open = [&]() { return ::open("/dev/null", O_RDWR); };
216  if ((NullFD = RetryAfterSignal(-1, Open)) < 0)
217  return std::error_code(errno, std::generic_category());
218  }
219 
220  if (NullFD == StandardFD)
221  FDC.keepOpen();
222  else if (dup2(NullFD, StandardFD) < 0)
223  return std::error_code(errno, std::generic_category());
224  }
225  return std::error_code();
226 }
227 
228 std::error_code Process::SafelyCloseFileDescriptor(int FD) {
229  // Create a signal set filled with *all* signals.
230  sigset_t FullSet;
231  if (sigfillset(&FullSet) < 0)
232  return std::error_code(errno, std::generic_category());
233  // Atomically swap our current signal mask with a full mask.
234  sigset_t SavedSet;
235 #if LLVM_ENABLE_THREADS
236  if (int EC = pthread_sigmask(SIG_SETMASK, &FullSet, &SavedSet))
237  return std::error_code(EC, std::generic_category());
238 #else
239  if (sigprocmask(SIG_SETMASK, &FullSet, &SavedSet) < 0)
240  return std::error_code(errno, std::generic_category());
241 #endif
242  // Attempt to close the file descriptor.
243  // We need to save the error, if one occurs, because our subsequent call to
244  // pthread_sigmask might tamper with errno.
245  int ErrnoFromClose = 0;
246  if (::close(FD) < 0)
247  ErrnoFromClose = errno;
248  // Restore the signal mask back to what we saved earlier.
249  int EC = 0;
250 #if LLVM_ENABLE_THREADS
251  EC = pthread_sigmask(SIG_SETMASK, &SavedSet, nullptr);
252 #else
253  if (sigprocmask(SIG_SETMASK, &SavedSet, nullptr) < 0)
254  EC = errno;
255 #endif
256  // The error code from close takes precedence over the one from
257  // pthread_sigmask.
258  if (ErrnoFromClose)
259  return std::error_code(ErrnoFromClose, std::generic_category());
260  return std::error_code(EC, std::generic_category());
261 }
262 
264  return FileDescriptorIsDisplayed(STDIN_FILENO);
265 }
266 
268  return FileDescriptorIsDisplayed(STDOUT_FILENO);
269 }
270 
272  return FileDescriptorIsDisplayed(STDERR_FILENO);
273 }
274 
276 #if HAVE_ISATTY
277  return isatty(fd);
278 #else
279  // If we don't have isatty, just return false.
280  return false;
281 #endif
282 }
283 
284 static unsigned getColumns(int FileID) {
285  // If COLUMNS is defined in the environment, wrap to that many columns.
286  if (const char *ColumnsStr = std::getenv("COLUMNS")) {
287  int Columns = std::atoi(ColumnsStr);
288  if (Columns > 0)
289  return Columns;
290  }
291 
292  unsigned Columns = 0;
293 
294 #if defined(HAVE_SYS_IOCTL_H) && defined(HAVE_TERMIOS_H) \
295  && !(defined(_XOPEN_SOURCE) || defined(_POSIX_C_SOURCE))
296  // Try to determine the width of the terminal.
297  struct winsize ws;
298  if (ioctl(FileID, TIOCGWINSZ, &ws) == 0)
299  Columns = ws.ws_col;
300 #endif
301 
302  return Columns;
303 }
304 
305 unsigned Process::StandardOutColumns() {
306  if (!StandardOutIsDisplayed())
307  return 0;
308 
309  return getColumns(1);
310 }
311 
312 unsigned Process::StandardErrColumns() {
313  if (!StandardErrIsDisplayed())
314  return 0;
315 
316  return getColumns(2);
317 }
318 
319 #ifdef HAVE_TERMINFO
320 // We manually declare these extern functions because finding the correct
321 // headers from various terminfo, curses, or other sources is harder than
322 // writing their specs down.
323 extern "C" int setupterm(char *term, int filedes, int *errret);
324 extern "C" struct term *set_curterm(struct term *termp);
325 extern "C" int del_curterm(struct term *termp);
326 extern "C" int tigetnum(char *capname);
327 #endif
328 
329 #ifdef HAVE_TERMINFO
330 static ManagedStatic<sys::Mutex> TermColorMutex;
331 #endif
332 
333 static bool terminalHasColors(int fd) {
334 #ifdef HAVE_TERMINFO
335  // First, acquire a global lock because these C routines are thread hostile.
336  MutexGuard G(*TermColorMutex);
337 
338  int errret = 0;
339  if (setupterm(nullptr, fd, &errret) != 0)
340  // Regardless of why, if we can't get terminfo, we shouldn't try to print
341  // colors.
342  return false;
343 
344  // Test whether the terminal as set up supports color output. How to do this
345  // isn't entirely obvious. We can use the curses routine 'has_colors' but it
346  // would be nice to avoid a dependency on curses proper when we can make do
347  // with a minimal terminfo parsing library. Also, we don't really care whether
348  // the terminal supports the curses-specific color changing routines, merely
349  // if it will interpret ANSI color escape codes in a reasonable way. Thus, the
350  // strategy here is just to query the baseline colors capability and if it
351  // supports colors at all to assume it will translate the escape codes into
352  // whatever range of colors it does support. We can add more detailed tests
353  // here if users report them as necessary.
354  //
355  // The 'tigetnum' routine returns -2 or -1 on errors, and might return 0 if
356  // the terminfo says that no colors are supported.
357  bool HasColors = tigetnum(const_cast<char *>("colors")) > 0;
358 
359  // Now extract the structure allocated by setupterm and free its memory
360  // through a really silly dance.
361  struct term *termp = set_curterm(nullptr);
362  (void)del_curterm(termp); // Drop any errors here.
363 
364  // Return true if we found a color capabilities for the current terminal.
365  if (HasColors)
366  return true;
367 #else
368  // When the terminfo database is not available, check if the current terminal
369  // is one of terminals that are known to support ANSI color escape codes.
370  if (const char *TermStr = std::getenv("TERM")) {
371  return StringSwitch<bool>(TermStr)
372  .Case("ansi", true)
373  .Case("cygwin", true)
374  .Case("linux", true)
375  .StartsWith("screen", true)
376  .StartsWith("xterm", true)
377  .StartsWith("vt100", true)
378  .StartsWith("rxvt", true)
379  .EndsWith("color", true)
380  .Default(false);
381  }
382 #endif
383 
384  // Otherwise, be conservative.
385  return false;
386 }
387 
389  // A file descriptor has colors if it is displayed and the terminal has
390  // colors.
391  return FileDescriptorIsDisplayed(fd) && terminalHasColors(fd);
392 }
393 
395  return FileDescriptorHasColors(STDOUT_FILENO);
396 }
397 
399  return FileDescriptorHasColors(STDERR_FILENO);
400 }
401 
402 void Process::UseANSIEscapeCodes(bool /*enable*/) {
403  // No effect.
404 }
405 
407  // No, we use ANSI escape sequences.
408  return false;
409 }
410 
411 const char *Process::OutputColor(char code, bool bold, bool bg) {
412  return colorcodes[bg?1:0][bold?1:0][code&7];
413 }
414 
415 const char *Process::OutputBold(bool bg) {
416  return "\033[1m";
417 }
418 
419 const char *Process::OutputReverse() {
420  return "\033[7m";
421 }
422 
423 const char *Process::ResetColor() {
424  return "\033[0m";
425 }
426 
427 #if !HAVE_DECL_ARC4RANDOM
428 static unsigned GetRandomNumberSeed() {
429  // Attempt to get the initial seed from /dev/urandom, if possible.
430  int urandomFD = open("/dev/urandom", O_RDONLY);
431 
432  if (urandomFD != -1) {
433  unsigned seed;
434  // Don't use a buffered read to avoid reading more data
435  // from /dev/urandom than we need.
436  int count = read(urandomFD, (void *)&seed, sizeof(seed));
437 
438  close(urandomFD);
439 
440  // Return the seed if the read was successful.
441  if (count == sizeof(seed))
442  return seed;
443  }
444 
445  // Otherwise, swizzle the current time and the process ID to form a reasonable
446  // seed.
447  const auto Now = std::chrono::high_resolution_clock::now();
448  return hash_combine(Now.time_since_epoch().count(), ::getpid());
449 }
450 #endif
451 
453 #if HAVE_DECL_ARC4RANDOM
454  return arc4random();
455 #else
456  static int x = (static_cast<void>(::srand(GetRandomNumberSeed())), 0);
457  (void)x;
458  return ::rand();
459 #endif
460 }
LLVM_NODISCARD std::string str() const
str - Get the contents as an std::string.
Definition: StringRef.h:218
This class represents lattice values for constants.
Definition: AllocatorList.h:23
static const char * ResetColor()
Resets the terminals colors, or returns an escape sequence to do so.
static const char * OutputColor(char c, bool bold, bool bg)
This function returns the colorcode escape sequences.
amdgpu Simplify well known AMD library false FunctionCallee Value const Twine & Name
static bool StandardErrHasColors()
This function determines whether the terminal connected to standard error supports colors...
static bool FileDescriptorHasColors(int fd)
This function determines if the given file descriptor is displayd and supports colors.
StringSwitch & StartsWith(StringLiteral S, T Value)
Definition: StringSwitch.h:81
static bool FileDescriptorIsDisplayed(int fd)
This function determines if the given file descriptor is connected to a "tty" or "console" window...
StringSwitch & Case(StringLiteral S, T Value)
Definition: StringSwitch.h:67
static std::error_code FixupStandardFileDescriptors()
static bool ColorNeedsFlush()
Whether changing colors requires the output to be flushed.
static const char * OutputReverse()
This function returns the escape sequence to reverse forground and background colors.
LLVM_NODISCARD R Default(T Value)
Definition: StringSwitch.h:181
static const char colorcodes[2][2][8][10]
Definition: Process.cpp:80
Tagged union holding either a T or a Error.
Definition: CachePruning.h:22
block placement Basic Block Placement Stats
static bool StandardInIsUserInput()
This function determines if the standard input is connected directly to a user&#39;s input (keyboard prob...
auto count(R &&Range, const E &Element) -> typename std::iterator_traits< decltype(adl_begin(Range))>::difference_type
Wrapper function around std::count to count the number of times an element Element occurs in the give...
Definition: STLExtras.h:1258
static bool StandardOutIsDisplayed()
This function determines if the standard output is connected to a "tty" or "console" window...
static void UseANSIEscapeCodes(bool enable)
Enables or disables whether ANSI escape sequences are used to output colors.
Instances of this class acquire a given Mutex Lock when constructed and hold that lock until destruct...
Definition: MutexGuard.h:26
A switch()-like statement whose cases are string literals.
Definition: StringSwitch.h:42
static unsigned StandardOutColumns()
This function determines the number of columns in the window if standard output is connected to a "tt...
Error errorCodeToError(std::error_code EC)
Helper for converting an std::error_code to a Error.
Definition: Error.cpp:87
StringSwitch & EndsWith(StringLiteral S, T Value)
Definition: StringSwitch.h:74
static sys::TimePoint< std::chrono::seconds > now(bool Deterministic)
static bool coreFilesPrevented
Definition: Process.cpp:87
auto RetryAfterSignal(const FailT &Fail, const Fun &F, const Args &... As) -> decltype(F(As...))
Definition: Errno.h:33
static size_t GetMallocUsage()
Return process memory usage.
static bool StandardErrIsDisplayed()
This function determines if the standard error is connected to a "tty" or "console" window...
static void PreventCoreFiles()
This function makes the necessary calls to the operating system to prevent core files or any other ki...
const DataFlowGraph & G
Definition: RDFGraph.cpp:202
static unsigned StandardErrColumns()
This function determines the number of columns in the window if standard error is connected to a "tty...
static bool StandardOutHasColors()
This function determines whether the terminal connected to standard output supports colors...
hash_code hash_combine(const Ts &...args)
Combine values into a single hash_code.
Definition: Hashing.h:600
static unsigned GetRandomNumber()
Get the result of a process wide random number generator.
value_type read(const void *memory, endianness endian)
Read a value of a particular endianness from memory.
Definition: Endian.h:65
std::chrono::microseconds toDuration(const struct timeval &TV)
Convert a struct timeval to a duration.
Definition: Unix.h:77
static void GetTimeUsage(TimePoint<> &elapsed, std::chrono::nanoseconds &user_time, std::chrono::nanoseconds &sys_time)
This static function will set user_time to the amount of CPU time spent in user (non-kernel) mode and...
static const char * OutputBold(bool bg)
Same as OutputColor, but only enables the bold attribute.
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
static Expected< unsigned > getPageSize()
Get the process&#39;s page size.
static std::error_code SafelyCloseFileDescriptor(int FD)
StringRef - Represent a constant reference to a string, i.e.
Definition: StringRef.h:48
ManagedStatic - This transparently changes the behavior of global statics to be lazily constructed on...
Definition: ManagedStatic.h:83
static Optional< std::string > GetEnv(StringRef name)