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