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