LLVM  15.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> 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
65 #endif
66 }
67 
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.
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 
90 size_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 
123 void 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.
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 
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 
183 namespace {
184 class FDCloser {
185 public:
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 
193 private:
194  FDCloser(const FDCloser &) = delete;
195  void operator=(const FDCloser &) = delete;
196 
197  int &FD;
198  bool KeepOpen;
199 };
200 }
201 
202 std::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 
236 std::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 
272  return FileDescriptorIsDisplayed(STDIN_FILENO);
273 }
274 
276  return FileDescriptorIsDisplayed(STDOUT_FILENO);
277 }
278 
280  return FileDescriptorIsDisplayed(STDERR_FILENO);
281 }
282 
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 
292 static 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 
305 unsigned Process::StandardOutColumns() {
306  if (!StandardOutIsDisplayed())
307  return 0;
308 
309  return getColumns();
310 }
311 
312 unsigned 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.
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 bool 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 
346 static 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 
390  // A file descriptor has colors if it is displayed and the terminal has
391  // colors.
392  return FileDescriptorIsDisplayed(fd) && terminalHasColors(fd);
393 }
394 
396  return FileDescriptorHasColors(STDOUT_FILENO);
397 }
398 
400  return FileDescriptorHasColors(STDERR_FILENO);
401 }
402 
403 void Process::UseANSIEscapeCodes(bool /*enable*/) {
404  // No effect.
405 }
406 
408  // No, we use ANSI escape sequences.
409  return false;
410 }
411 
412 const char *Process::OutputColor(char code, bool bold, bool bg) {
413  return colorcodes[bg?1:0][bold?1:0][code&7];
414 }
415 
416 const char *Process::OutputBold(bool bg) {
417  return "\033[1m";
418 }
419 
420 const char *Process::OutputReverse() {
421  return "\033[7m";
422 }
423 
424 const char *Process::ResetColor() {
425  return "\033[0m";
426 }
427 
428 #if !HAVE_DECL_ARC4RANDOM
429 static 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 
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); }
llvm::StringSwitch::Case
StringSwitch & Case(StringLiteral S, T Value)
Definition: StringSwitch.h:69
i
i
Definition: README.txt:29
llvm::StringSwitch::StartsWith
StringSwitch & StartsWith(StringLiteral S, T Value)
Definition: StringSwitch.h:83
llvm
This is an optimization pass for GlobalISel generic memory operations.
Definition: AddressRanges.h:17
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::Default
LLVM_NODISCARD R Default(T Value)
Definition: StringSwitch.h:183
llvm::StringSwitch::EndsWith
StringSwitch & EndsWith(StringLiteral S, T Value)
Definition: StringSwitch.h:76
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:1709
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:58
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:3656
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
A switch()-like statement whose cases are string literals.
Definition: StringSwitch.h:44
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...