LLVM  16.0.0git
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"
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 
54 using namespace llvm;
55 using namespace sys;
56 
57 static std::pair<std::chrono::microseconds, std::chrono::microseconds>
58 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 
70  static_assert(sizeof(Pid) >= sizeof(pid_t),
71  "Process::Pid should be big enough to store pid_t");
72  return Pid(::getpid());
73 }
74 
75 // On Cygwin, getpagesize() returns 64k(AllocationGranularity) and
76 // offset in mmap(3) should be aligned to the AllocationGranularity.
78 #if defined(HAVE_GETPAGESIZE)
79  static const int page_size = ::getpagesize();
80 #elif defined(HAVE_SYSCONF)
81  static long page_size = ::sysconf(_SC_PAGE_SIZE);
82 #else
83 #error Cannot get the page size on this machine
84 #endif
85  if (page_size == -1)
86  return errorCodeToError(std::error_code(errno, std::generic_category()));
87 
88  return static_cast<unsigned>(page_size);
89 }
90 
91 size_t Process::GetMallocUsage() {
92 #if defined(HAVE_MALLINFO2)
93  struct mallinfo2 mi;
94  mi = ::mallinfo2();
95  return mi.uordblks;
96 #elif defined(HAVE_MALLINFO)
97  struct mallinfo mi;
98  mi = ::mallinfo();
99  return mi.uordblks;
100 #elif defined(HAVE_MALLOC_ZONE_STATISTICS) && defined(HAVE_MALLOC_MALLOC_H)
101  malloc_statistics_t Stats;
102  malloc_zone_statistics(malloc_default_zone(), &Stats);
103  return Stats.size_in_use; // darwin
104 #elif defined(HAVE_MALLCTL)
105  size_t alloc, sz;
106  sz = sizeof(size_t);
107  if (mallctl("stats.allocated", &alloc, &sz, NULL, 0) == 0)
108  return alloc;
109  return 0;
110 #elif defined(HAVE_SBRK)
111  // Note this is only an approximation and more closely resembles
112  // the value returned by mallinfo in the arena field.
113  static char *StartOfMemory = reinterpret_cast<char *>(::sbrk(0));
114  char *EndOfMemory = (char *)sbrk(0);
115  if (EndOfMemory != ((char *)-1) && StartOfMemory != ((char *)-1))
116  return EndOfMemory - StartOfMemory;
117  return 0;
118 #else
119 #warning Cannot get malloc info on this platform
120  return 0;
121 #endif
122 }
123 
124 void Process::GetTimeUsage(TimePoint<> &elapsed,
125  std::chrono::nanoseconds &user_time,
126  std::chrono::nanoseconds &sys_time) {
127  elapsed = std::chrono::system_clock::now();
128  std::tie(user_time, sys_time) = getRUsageTimes();
129 }
130 
131 #if defined(HAVE_MACH_MACH_H) && !defined(__GNU__)
132 #include <mach/mach.h>
133 #endif
134 
135 // Some LLVM programs such as bugpoint produce core files as a normal part of
136 // their operation. To prevent the disk from filling up, this function
137 // does what's necessary to prevent their generation.
139 #if HAVE_SETRLIMIT
140  struct rlimit rlim;
141  rlim.rlim_cur = rlim.rlim_max = 0;
142  setrlimit(RLIMIT_CORE, &rlim);
143 #endif
144 
145 #if defined(HAVE_MACH_MACH_H) && !defined(__GNU__)
146  // Disable crash reporting on Mac OS X 10.0-10.4
147 
148  // get information about the original set of exception ports for the task
149  mach_msg_type_number_t Count = 0;
150  exception_mask_t OriginalMasks[EXC_TYPES_COUNT];
151  exception_port_t OriginalPorts[EXC_TYPES_COUNT];
152  exception_behavior_t OriginalBehaviors[EXC_TYPES_COUNT];
153  thread_state_flavor_t OriginalFlavors[EXC_TYPES_COUNT];
154  kern_return_t err = task_get_exception_ports(
155  mach_task_self(), EXC_MASK_ALL, OriginalMasks, &Count, OriginalPorts,
156  OriginalBehaviors, OriginalFlavors);
157  if (err == KERN_SUCCESS) {
158  // replace each with MACH_PORT_NULL.
159  for (unsigned i = 0; i != Count; ++i)
160  task_set_exception_ports(mach_task_self(), OriginalMasks[i],
161  MACH_PORT_NULL, OriginalBehaviors[i],
162  OriginalFlavors[i]);
163  }
164 
165  // Disable crash reporting on Mac OS X 10.5
166  signal(SIGABRT, _exit);
167  signal(SIGILL, _exit);
168  signal(SIGFPE, _exit);
169  signal(SIGSEGV, _exit);
170  signal(SIGBUS, _exit);
171 #endif
172 
173  coreFilesPrevented = true;
174 }
175 
177  std::string NameStr = Name.str();
178  const char *Val = ::getenv(NameStr.c_str());
179  if (!Val)
180  return None;
181  return std::string(Val);
182 }
183 
184 namespace {
185 class FDCloser {
186 public:
187  FDCloser(int &FD) : FD(FD), KeepOpen(false) {}
188  void keepOpen() { KeepOpen = true; }
189  ~FDCloser() {
190  if (!KeepOpen && FD >= 0)
191  ::close(FD);
192  }
193 
194 private:
195  FDCloser(const FDCloser &) = delete;
196  void operator=(const FDCloser &) = delete;
197 
198  int &FD;
199  bool KeepOpen;
200 };
201 } // namespace
202 
203 std::error_code Process::FixupStandardFileDescriptors() {
204  int NullFD = -1;
205  FDCloser FDC(NullFD);
206  const int StandardFDs[] = {STDIN_FILENO, STDOUT_FILENO, STDERR_FILENO};
207  for (int StandardFD : StandardFDs) {
208  struct stat st;
209  errno = 0;
210  if (RetryAfterSignal(-1, ::fstat, StandardFD, &st) < 0) {
211  assert(errno && "expected errno to be set if fstat failed!");
212  // fstat should return EBADF if the file descriptor is closed.
213  if (errno != EBADF)
214  return std::error_code(errno, std::generic_category());
215  }
216  // if fstat succeeds, move on to the next FD.
217  if (!errno)
218  continue;
219  assert(errno == EBADF && "expected errno to have EBADF at this point!");
220 
221  if (NullFD < 0) {
222  // Call ::open in a lambda to avoid overload resolution in
223  // RetryAfterSignal when open is overloaded, such as in Bionic.
224  auto Open = [&]() { return ::open("/dev/null", O_RDWR); };
225  if ((NullFD = RetryAfterSignal(-1, Open)) < 0)
226  return std::error_code(errno, std::generic_category());
227  }
228 
229  if (NullFD == StandardFD)
230  FDC.keepOpen();
231  else if (dup2(NullFD, StandardFD) < 0)
232  return std::error_code(errno, std::generic_category());
233  }
234  return std::error_code();
235 }
236 
237 std::error_code Process::SafelyCloseFileDescriptor(int FD) {
238  // Create a signal set filled with *all* signals.
239  sigset_t FullSet, SavedSet;
240  if (sigfillset(&FullSet) < 0 || sigfillset(&SavedSet) < 0)
241  return std::error_code(errno, std::generic_category());
242 
243  // Atomically swap our current signal mask with a full mask.
244 #if LLVM_ENABLE_THREADS
245  if (int EC = pthread_sigmask(SIG_SETMASK, &FullSet, &SavedSet))
246  return std::error_code(EC, std::generic_category());
247 #else
248  if (sigprocmask(SIG_SETMASK, &FullSet, &SavedSet) < 0)
249  return std::error_code(errno, std::generic_category());
250 #endif
251  // Attempt to close the file descriptor.
252  // We need to save the error, if one occurs, because our subsequent call to
253  // pthread_sigmask might tamper with errno.
254  int ErrnoFromClose = 0;
255  if (::close(FD) < 0)
256  ErrnoFromClose = errno;
257  // Restore the signal mask back to what we saved earlier.
258  int EC = 0;
259 #if LLVM_ENABLE_THREADS
260  EC = pthread_sigmask(SIG_SETMASK, &SavedSet, nullptr);
261 #else
262  if (sigprocmask(SIG_SETMASK, &SavedSet, nullptr) < 0)
263  EC = errno;
264 #endif
265  // The error code from close takes precedence over the one from
266  // pthread_sigmask.
267  if (ErrnoFromClose)
268  return std::error_code(ErrnoFromClose, std::generic_category());
269  return std::error_code(EC, std::generic_category());
270 }
271 
273  return FileDescriptorIsDisplayed(STDIN_FILENO);
274 }
275 
277  return FileDescriptorIsDisplayed(STDOUT_FILENO);
278 }
279 
281  return FileDescriptorIsDisplayed(STDERR_FILENO);
282 }
283 
285 #if HAVE_ISATTY
286  return isatty(fd);
287 #else
288  // If we don't have isatty, just return false.
289  return false;
290 #endif
291 }
292 
293 static unsigned getColumns() {
294  // If COLUMNS is defined in the environment, wrap to that many columns.
295  if (const char *ColumnsStr = std::getenv("COLUMNS")) {
296  int Columns = std::atoi(ColumnsStr);
297  if (Columns > 0)
298  return Columns;
299  }
300 
301  // We used to call ioctl TIOCGWINSZ to determine the width. It is considered
302  // unuseful.
303  return 0;
304 }
305 
306 unsigned Process::StandardOutColumns() {
307  if (!StandardOutIsDisplayed())
308  return 0;
309 
310  return getColumns();
311 }
312 
313 unsigned Process::StandardErrColumns() {
314  if (!StandardErrIsDisplayed())
315  return 0;
316 
317  return getColumns();
318 }
319 
320 #ifdef LLVM_ENABLE_TERMINFO
321 // We manually declare these extern functions because finding the correct
322 // headers from various terminfo, curses, or other sources is harder than
323 // writing their specs down.
324 extern "C" int setupterm(char *term, int filedes, int *errret);
325 extern "C" struct term *set_curterm(struct term *termp);
326 extern "C" int del_curterm(struct term *termp);
327 extern "C" int tigetnum(char *capname);
328 #endif
329 
330 bool checkTerminalEnvironmentForColors() {
331  if (const char *TermStr = std::getenv("TERM")) {
332  return StringSwitch<bool>(TermStr)
333  .Case("ansi", true)
334  .Case("cygwin", true)
335  .Case("linux", true)
336  .StartsWith("screen", true)
337  .StartsWith("xterm", true)
338  .StartsWith("vt100", true)
339  .StartsWith("rxvt", true)
340  .EndsWith("color", true)
341  .Default(false);
342  }
343 
344  return false;
345 }
346 
347 static bool terminalHasColors(int fd) {
348 #ifdef LLVM_ENABLE_TERMINFO
349  // First, acquire a global lock because these C routines are thread hostile.
350  static std::mutex TermColorMutex;
351  std::lock_guard<std::mutex> G(TermColorMutex);
352 
353  struct term *previous_term = set_curterm(nullptr);
354  int errret = 0;
355  if (setupterm(nullptr, fd, &errret) != 0)
356  // Regardless of why, if we can't get terminfo, we shouldn't try to print
357  // colors.
358  return false;
359 
360  // Test whether the terminal as set up supports color output. How to do this
361  // isn't entirely obvious. We can use the curses routine 'has_colors' but it
362  // would be nice to avoid a dependency on curses proper when we can make do
363  // with a minimal terminfo parsing library. Also, we don't really care whether
364  // the terminal supports the curses-specific color changing routines, merely
365  // if it will interpret ANSI color escape codes in a reasonable way. Thus, the
366  // strategy here is just to query the baseline colors capability and if it
367  // supports colors at all to assume it will translate the escape codes into
368  // whatever range of colors it does support. We can add more detailed tests
369  // here if users report them as necessary.
370  //
371  // The 'tigetnum' routine returns -2 or -1 on errors, and might return 0 if
372  // the terminfo says that no colors are supported.
373  int colors_ti = tigetnum(const_cast<char *>("colors"));
374  bool HasColors =
375  colors_ti >= 0 ? colors_ti : checkTerminalEnvironmentForColors();
376 
377  // Now extract the structure allocated by setupterm and free its memory
378  // through a really silly dance.
379  struct term *termp = set_curterm(previous_term);
380  (void)del_curterm(termp); // Drop any errors here.
381 
382  // Return true if we found a color capabilities for the current terminal.
383  return HasColors;
384 #else
385  // When the terminfo database is not available, check if the current terminal
386  // is one of terminals that are known to support ANSI color escape codes.
387  return checkTerminalEnvironmentForColors();
388 #endif
389 }
390 
392  // A file descriptor has colors if it is displayed and the terminal has
393  // colors.
394  return FileDescriptorIsDisplayed(fd) && terminalHasColors(fd);
395 }
396 
398  return FileDescriptorHasColors(STDOUT_FILENO);
399 }
400 
402  return FileDescriptorHasColors(STDERR_FILENO);
403 }
404 
405 void Process::UseANSIEscapeCodes(bool /*enable*/) {
406  // No effect.
407 }
408 
410  // No, we use ANSI escape sequences.
411  return false;
412 }
413 
414 const char *Process::OutputColor(char code, bool bold, bool bg) {
415  return colorcodes[bg ? 1 : 0][bold ? 1 : 0][code & 7];
416 }
417 
418 const char *Process::OutputBold(bool bg) { return "\033[1m"; }
419 
420 const char *Process::OutputReverse() { return "\033[7m"; }
421 
422 const char *Process::ResetColor() { return "\033[0m"; }
423 
424 #if !HAVE_DECL_ARC4RANDOM
425 static unsigned GetRandomNumberSeed() {
426  // Attempt to get the initial seed from /dev/urandom, if possible.
427  int urandomFD = open("/dev/urandom", O_RDONLY);
428 
429  if (urandomFD != -1) {
430  unsigned seed;
431  // Don't use a buffered read to avoid reading more data
432  // from /dev/urandom than we need.
433  int count = read(urandomFD, (void *)&seed, sizeof(seed));
434 
435  close(urandomFD);
436 
437  // Return the seed if the read was successful.
438  if (count == sizeof(seed))
439  return seed;
440  }
441 
442  // Otherwise, swizzle the current time and the process ID to form a reasonable
443  // seed.
444  const auto Now = std::chrono::high_resolution_clock::now();
445  return hash_combine(Now.time_since_epoch().count(), ::getpid());
446 }
447 #endif
448 
450 #if HAVE_DECL_ARC4RANDOM
451  return arc4random();
452 #else
453  static int x = (static_cast<void>(::srand(GetRandomNumberSeed())), 0);
454  (void)x;
455  return ::rand();
456 #endif
457 }
458 
459 [[noreturn]] void Process::ExitNoCleanup(int RetCode) { _Exit(RetCode); }
llvm::StringSwitch::Case
StringSwitch & Case(StringLiteral S, T Value)
Definition: StringSwitch.h:70
i
i
Definition: README.txt:29
llvm::StringSwitch::StartsWith
StringSwitch & StartsWith(StringLiteral S, T Value)
Definition: StringSwitch.h:84
llvm
This is an optimization pass for GlobalISel generic memory operations.
Definition: AddressRanges.h:18
zero
We currently generate a but we really shouldn eax ecx xorl edx divl ecx eax divl ecx movl eax ret A similar code sequence works for division We currently compile i32 v2 eax eax jo LBB1_2 atomic and others It is also currently not done for read modify write instructions It is also current not done if the OF or CF flags are needed The shift operators have the complication that when the shift count is zero
Definition: README.txt:1277
llvm::sys::Process::UseANSIEscapeCodes
static void UseANSIEscapeCodes(bool enable)
Enables or disables whether ANSI escape sequences are used to output colors.
StringRef.h
llvm::StringSwitch::EndsWith
StringSwitch & EndsWith(StringLiteral S, T Value)
Definition: StringSwitch.h:77
llvm::sys::Process::StandardErrColumns
static unsigned StandardErrColumns()
This function determines the number of columns in the window if standard error is connected to a "tty...
llvm::sys::RetryAfterSignal
decltype(auto) RetryAfterSignal(const FailT &Fail, const Fun &F, const Args &... As)
Definition: Errno.h:32
llvm::sys::Process::PreventCoreFiles
static void PreventCoreFiles()
This function makes the necessary calls to the operating system to prevent core files or any other ki...
llvm::Optional< std::string >
llvm::sys::Process::Pid
int32_t Pid
Definition: Process.h:45
Hashing.h
llvm::Expected
Tagged union holding either a T or a Error.
Definition: APFloat.h:41
Unix.h
llvm::sys::Process::StandardOutHasColors
static bool StandardOutHasColors()
This function determines whether the terminal connected to standard output supports colors.
llvm::sys::Process::GetRandomNumber
static unsigned GetRandomNumber()
Get the result of a process wide random number generator.
llvm::errorCodeToError
Error errorCodeToError(std::error_code EC)
Helper for converting an std::error_code to a Error.
Definition: Error.cpp:92
false
Definition: StackSlotColoring.cpp:141
llvm::sys::Process::GetTimeUsage
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...
DebugLocVerifyLevel::None
@ None
colorcodes
static const char colorcodes[2][2][8][10]
Definition: Process.cpp:84
now
static sys::TimePoint< std::chrono::seconds > now(bool Deterministic)
Definition: ArchiveWriter.cpp:327
llvm::sys::Process::OutputBold
static const char * OutputBold(bool bg)
Same as OutputColor, but only enables the bold attribute.
G
const DataFlowGraph & G
Definition: RDFGraph.cpp:200
llvm::sys::Process::SafelyCloseFileDescriptor
static std::error_code SafelyCloseFileDescriptor(int FD)
llvm::sys::Process::FileDescriptorHasColors
static bool FileDescriptorHasColors(int fd)
This function determines if the given file descriptor is displayd and supports colors.
llvm::count
auto count(R &&Range, const E &Element)
Wrapper function around std::count to count the number of times an element Element occurs in the give...
Definition: STLExtras.h:1870
llvm::sys::Process::ResetColor
static const char * ResetColor()
Resets the terminals colors, or returns an escape sequence to do so.
llvm::sys::Process::OutputColor
static const char * OutputColor(char c, bool bold, bool bg)
This function returns the colorcode escape sequences.
llvm::sys::Process::getPageSize
static Expected< unsigned > getPageSize()
Get the process's page size.
assert
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
llvm::sys::Process::GetEnv
static Optional< std::string > GetEnv(StringRef name)
llvm::codeview::CompileSym2Flags::EC
@ EC
llvm::sys::Process::StandardErrHasColors
static bool StandardErrHasColors()
This function determines whether the terminal connected to standard error supports colors.
llvm::StringRef
StringRef - Represent a constant reference to a string, i.e.
Definition: StringRef.h:50
llvm::sys::Process::OutputReverse
static const char * OutputReverse()
This function returns the escape sequence to reverse forground and background colors.
llvm::GraphProgram::Name
Name
Definition: GraphWriter.h:50
Stats
block placement Basic Block Placement Stats
Definition: MachineBlockPlacement.cpp:3670
llvm::sys::Process::StandardOutIsDisplayed
static bool StandardOutIsDisplayed()
This function determines if the standard output is connected to a "tty" or "console" window.
code
*Add support for compiling functions in both ARM and Thumb then taking the smallest *Add support for compiling individual basic blocks in thumb when in a larger ARM function This can be used for presumed cold code
Definition: README-Thumb.txt:9
llvm::support::endian::read
value_type read(const void *memory, endianness endian)
Read a value of a particular endianness from memory.
Definition: Endian.h:63
llvm::sys::Process::StandardOutColumns
static unsigned StandardOutColumns()
This function determines the number of columns in the window if standard output is connected to a "tt...
llvm::sys::toDuration
std::chrono::nanoseconds toDuration(FILETIME Time)
Definition: WindowsSupport.h:201
x
TODO unsigned x
Definition: README.txt:10
llvm::sys::Process::FileDescriptorIsDisplayed
static bool FileDescriptorIsDisplayed(int fd)
This function determines if the given file descriptor is connected to a "tty" or "console" window.
llvm::sys::Process::ColorNeedsFlush
static bool ColorNeedsFlush()
Whether changing colors requires the output to be flushed.
llvm::sys::Process::getProcessId
static Pid getProcessId()
Get the process's identifier.
llvm::hash_combine
hash_code hash_combine(const Ts &...args)
Combine values into a single hash_code.
Definition: Hashing.h:605
llvm::sys::Process::FixupStandardFileDescriptors
static std::error_code FixupStandardFileDescriptors()
llvm::StringSwitch::Default
R Default(T Value)
Definition: StringSwitch.h:183
llvm::StringSwitch
A switch()-like statement whose cases are string literals.
Definition: StringSwitch.h:45
coreFilesPrevented
static bool coreFilesPrevented
Definition: Process.cpp:91
llvm::sys::Process::GetMallocUsage
static size_t GetMallocUsage()
Return process memory usage.
llvm::sys::Process::StandardErrIsDisplayed
static bool StandardErrIsDisplayed()
This function determines if the standard error is connected to a "tty" or "console" window.
llvm::sys::Process::StandardInIsUserInput
static bool StandardInIsUserInput()
This function determines if the standard input is connected directly to a user's input (keyboard prob...