LLVM 23.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 "llvm/Config/llvm-config.h" // for LLVM_ENABLE_THREADS
18#include <mutex>
19#include <optional>
20#include <fcntl.h>
21#include <sys/time.h>
22#include <sys/resource.h>
23#include <sys/stat.h>
24#include <signal.h>
25#if defined(HAVE_MALLINFO) || defined(HAVE_MALLINFO2)
26#include <malloc.h>
27#endif
28#if defined(HAVE_MALLCTL)
29#include <malloc_np.h>
30#endif
31#ifdef HAVE_MALLOC_MALLOC_H
32#include <malloc/malloc.h>
33#endif
34#ifdef HAVE_GETAUXVAL
35#include <sys/auxv.h>
36#endif
37#ifdef HAVE_SYS_IOCTL_H
38#include <sys/ioctl.h>
39#endif
40
41//===----------------------------------------------------------------------===//
42//=== WARNING: Implementation here must contain only generic UNIX code that
43//=== is guaranteed to work on *all* UNIX variants.
44//===----------------------------------------------------------------------===//
45
46using namespace llvm;
47using namespace sys;
48
49static std::pair<std::chrono::microseconds, std::chrono::microseconds>
50getRUsageTimes() {
51#if defined(HAVE_GETRUSAGE)
52 struct rusage RU;
53 ::getrusage(RUSAGE_SELF, &RU);
54 return {toDuration(RU.ru_utime), toDuration(RU.ru_stime)};
55#else
56#ifndef __MVS__ // Exclude for MVS in case -pedantic is used
57#warning Cannot get usage times on this platform
58#endif
59 return {std::chrono::microseconds::zero(), std::chrono::microseconds::zero()};
60#endif
61}
62
64 static_assert(sizeof(Pid) >= sizeof(pid_t),
65 "Process::Pid should be big enough to store pid_t");
66 return Pid(::getpid());
67}
68
69// On Cygwin, getpagesize() returns 64k(AllocationGranularity) and
70// offset in mmap(3) should be aligned to the AllocationGranularity.
71Expected<unsigned> Process::getPageSize() {
72#if defined(HAVE_GETAUXVAL)
73 static const int page_size = ::getauxval(AT_PAGESZ);
74#elif defined(HAVE_GETPAGESIZE)
75 static const int page_size = ::getpagesize();
76#elif defined(HAVE_SYSCONF)
77 static long page_size = ::sysconf(_SC_PAGE_SIZE);
78#else
79#error Cannot get the page size on this machine
80#endif
81 if (page_size == -1)
83
84 assert(page_size > 0 && "Page size cannot be 0");
85 assert((page_size % 1024) == 0 && "Page size must be aligned by 1024");
86 return static_cast<unsigned>(page_size);
87}
88
90#if defined(HAVE_MALLINFO2)
91 struct mallinfo2 mi;
92 mi = ::mallinfo2();
93 return mi.uordblks;
94#elif defined(HAVE_MALLINFO)
95 struct mallinfo mi;
96 mi = ::mallinfo();
97 return mi.uordblks;
98#elif defined(HAVE_MALLOC_ZONE_STATISTICS) && defined(HAVE_MALLOC_MALLOC_H)
99 malloc_statistics_t Stats;
100 malloc_zone_statistics(malloc_default_zone(), &Stats);
101 return Stats.size_in_use; // darwin
102#elif defined(HAVE_MALLCTL)
103 size_t alloc, sz;
104 sz = sizeof(size_t);
105 if (mallctl("stats.allocated", &alloc, &sz, NULL, 0) == 0)
106 return alloc;
107 return 0;
108#elif defined(HAVE_SBRK)
109 // Note this is only an approximation and more closely resembles
110 // the value returned by mallinfo in the arena field.
111 static char *StartOfMemory = reinterpret_cast<char *>(::sbrk(0));
112 char *EndOfMemory = (char *)sbrk(0);
113 if (EndOfMemory != ((char *)-1) && StartOfMemory != ((char *)-1))
114 return EndOfMemory - StartOfMemory;
115 return 0;
116#else
117#ifndef __MVS__ // Exclude for MVS in case -pedantic is used
118#warning Cannot get malloc info on this platform
119#endif
120 return 0;
121#endif
122}
123
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 llvm-reduce produce core files as a normal part of
136// their operation. To prevent the disk from filling up, this function does
137// what's necessary to prevent their generation.
139 struct rlimit rlim;
140 getrlimit(RLIMIT_CORE, &rlim);
141#ifdef __linux__
142 // On Linux, if the kernel.core_pattern sysctl starts with a '|' (i.e. it
143 // is being piped to a coredump handler such as systemd-coredumpd), the
144 // kernel ignores RLIMIT_CORE (since we aren't creating a file in the file
145 // system) except for the magic value of 1, which disables coredumps when
146 // piping. 1 byte is too small for any kind of valid core dump, so it
147 // also disables coredumps if kernel.core_pattern creates files directly.
148 // While most piped coredump handlers do respect the crashing processes'
149 // RLIMIT_CORE, this is notable not the case for Debian's systemd-coredump
150 // due to a local patch that changes sysctl.d/50-coredump.conf to ignore
151 // the specified limit and instead use RLIM_INFINITY.
152 //
153 // The alternative to using RLIMIT_CORE=1 would be to use prctl() with the
154 // PR_SET_DUMPABLE flag, however that also prevents ptrace(), so makes it
155 // impossible to attach a debugger.
156 rlim.rlim_cur = std::min<rlim_t>(1, rlim.rlim_max);
157#else
158 rlim.rlim_cur = 0;
159#endif
160 setrlimit(RLIMIT_CORE, &rlim);
161
162#if defined(HAVE_MACH_MACH_H) && !defined(__GNU__)
163 // Disable crash reporting on Mac OS X 10.0-10.4
164
165 // get information about the original set of exception ports for the task
166 mach_msg_type_number_t Count = 0;
167 exception_mask_t OriginalMasks[EXC_TYPES_COUNT];
168 exception_port_t OriginalPorts[EXC_TYPES_COUNT];
169 exception_behavior_t OriginalBehaviors[EXC_TYPES_COUNT];
170 thread_state_flavor_t OriginalFlavors[EXC_TYPES_COUNT];
171 kern_return_t err = task_get_exception_ports(
172 mach_task_self(), EXC_MASK_ALL, OriginalMasks, &Count, OriginalPorts,
173 OriginalBehaviors, OriginalFlavors);
174 if (err == KERN_SUCCESS) {
175 // replace each with MACH_PORT_NULL.
176 for (unsigned i = 0; i != Count; ++i)
177 task_set_exception_ports(mach_task_self(), OriginalMasks[i],
178 MACH_PORT_NULL, OriginalBehaviors[i],
179 OriginalFlavors[i]);
180 }
181
182 // Disable crash reporting on Mac OS X 10.5
183 signal(SIGABRT, _exit);
184 signal(SIGILL, _exit);
185 signal(SIGFPE, _exit);
186 signal(SIGSEGV, _exit);
187 signal(SIGBUS, _exit);
188#endif
189
190 coreFilesPrevented = true;
191}
192
193std::optional<std::string> Process::GetEnv(StringRef Name) {
194 std::string NameStr = Name.str();
195 const char *Val = ::getenv(NameStr.c_str());
196 if (!Val)
197 return std::nullopt;
198 return std::string(Val);
199}
200
201namespace {
202class FDCloser {
203public:
204 FDCloser(int &FD) : FD(FD), KeepOpen(false) {}
205 void keepOpen() { KeepOpen = true; }
206 ~FDCloser() {
207 if (!KeepOpen && FD >= 0)
208 ::close(FD);
209 }
210
211private:
212 FDCloser(const FDCloser &) = delete;
213 void operator=(const FDCloser &) = delete;
214
215 int &FD;
216 bool KeepOpen;
217};
218} // namespace
219
221 int NullFD = -1;
222 FDCloser FDC(NullFD);
223 const int StandardFDs[] = {STDIN_FILENO, STDOUT_FILENO, STDERR_FILENO};
224 for (int StandardFD : StandardFDs) {
225 struct stat st;
226 errno = 0;
227 if (RetryAfterSignal(-1, ::fstat, StandardFD, &st) < 0) {
228 assert(errno && "expected errno to be set if fstat failed!");
229 // fstat should return EBADF if the file descriptor is closed.
230 if (errno != EBADF)
231 return errnoAsErrorCode();
232 }
233 // if fstat succeeds, move on to the next FD.
234 if (!errno)
235 continue;
236 assert(errno == EBADF && "expected errno to have EBADF at this point!");
237
238 if (NullFD < 0) {
239 // Call ::open in a lambda to avoid overload resolution in
240 // RetryAfterSignal when open is overloaded, such as in Bionic.
241 auto Open = [&]() { return ::open("/dev/null", O_RDWR); };
242 if ((NullFD = RetryAfterSignal(-1, Open)) < 0)
243 return errnoAsErrorCode();
244 }
245
246 if (NullFD == StandardFD)
247 FDC.keepOpen();
248 else if (dup2(NullFD, StandardFD) < 0)
249 return errnoAsErrorCode();
250 }
251 return std::error_code();
252}
253
254std::error_code Process::SafelyCloseFileDescriptor(int FD) {
255 // Create a signal set filled with *all* signals.
256 sigset_t FullSet, SavedSet;
257 if (sigfillset(&FullSet) < 0 || sigfillset(&SavedSet) < 0)
258 return errnoAsErrorCode();
259
260 // Atomically swap our current signal mask with a full mask.
261#if LLVM_ENABLE_THREADS
262 if (int EC = pthread_sigmask(SIG_SETMASK, &FullSet, &SavedSet))
263 return std::error_code(EC, std::generic_category());
264#else
265 if (sigprocmask(SIG_SETMASK, &FullSet, &SavedSet) < 0)
266 return errnoAsErrorCode();
267#endif
268 // Attempt to close the file descriptor.
269 // We need to save the error, if one occurs, because our subsequent call to
270 // pthread_sigmask might tamper with errno.
271 int ErrnoFromClose = 0;
272 if (::close(FD) < 0)
273 ErrnoFromClose = errno;
274 // Restore the signal mask back to what we saved earlier.
275 int EC = 0;
276#if LLVM_ENABLE_THREADS
277 EC = pthread_sigmask(SIG_SETMASK, &SavedSet, nullptr);
278#else
279 if (sigprocmask(SIG_SETMASK, &SavedSet, nullptr) < 0)
280 EC = errno;
281#endif
282 // The error code from close takes precedence over the one from
283 // pthread_sigmask.
284 if (ErrnoFromClose)
285 return std::error_code(ErrnoFromClose, std::generic_category());
286 return std::error_code(EC, std::generic_category());
287}
288
290 return FileDescriptorIsDisplayed(STDIN_FILENO);
291}
292
294 return FileDescriptorIsDisplayed(STDOUT_FILENO);
295}
296
298 return FileDescriptorIsDisplayed(STDERR_FILENO);
299}
300
302#if HAVE_ISATTY
303 return isatty(fd);
304#else
305 // If we don't have isatty, just return false.
306 return false;
307#endif
308}
309
310static unsigned getColumns(int FileID) {
311 // If COLUMNS is defined in the environment, wrap to that many columns.
312 // This matches GCC.
313 if (const char *ColumnsStr = std::getenv("COLUMNS")) {
314 int Columns = std::atoi(ColumnsStr);
315 if (Columns > 0)
316 return Columns;
317 }
318
319 // Some shells do not export COLUMNS; query the column count via ioctl()
320 // instead if it isn't available.
321 unsigned Columns = 0;
322
323#if defined(HAVE_SYS_IOCTL_H) && !defined(__sun__)
324 struct winsize ws;
325 if (ioctl(FileID, TIOCGWINSZ, &ws) == 0)
326 Columns = ws.ws_col;
327#endif
328
329 return Columns;
330}
331
333 if (!StandardOutIsDisplayed())
334 return 0;
335
336 return getColumns(0);
337}
338
340 if (!StandardErrIsDisplayed())
341 return 0;
342
343 return getColumns(1);
344}
345
346static bool terminalHasColors() {
347 // Check if the current terminal is one of terminals that are known to support
348 // ANSI color escape codes.
349 if (const char *TermStr = std::getenv("TERM")) {
350 return StringSwitch<bool>(TermStr)
351 .Case("alacritty", true)
352 .Case("ansi", true)
353 .Case("cygwin", true)
354 .Case("ghostty", true)
355 .Case("kitty", true)
356 .Case("linux", true)
357 .StartsWith("screen", true)
358 .StartsWith("xterm", true)
359 .StartsWith("vt100", true)
360 .StartsWith("rxvt", true)
361 .EndsWith("color", true)
362 .Default(false);
363 }
364
365 return false;
366}
367
369 // A file descriptor has colors if it is displayed and the terminal has
370 // colors.
371 return FileDescriptorIsDisplayed(fd) && terminalHasColors();
372}
373
375 return FileDescriptorHasColors(STDOUT_FILENO);
376}
377
379 return FileDescriptorHasColors(STDERR_FILENO);
380}
381
382void Process::UseANSIEscapeCodes(bool /*enable*/) {
383 // No effect.
384}
385
387 // No, we use ANSI escape sequences.
388 return false;
389}
390
391const char *Process::OutputColor(char code, bool bold, bool bg) {
392 return colorcodes[bg ? 1 : 0][bold ? 1 : 0][code & 15];
393}
394
395const char *Process::OutputBold(bool bg) { return "\033[1m"; }
396
397const char *Process::OutputReverse() { return "\033[7m"; }
398
399const char *Process::ResetColor() { return "\033[0m"; }
400
401#if !HAVE_DECL_ARC4RANDOM
402static unsigned GetRandomNumberSeed() {
403 // Attempt to get the initial seed from /dev/urandom, if possible.
404 int urandomFD = open("/dev/urandom", O_RDONLY);
405
406 if (urandomFD != -1) {
407 unsigned seed;
408 // Don't use a buffered read to avoid reading more data
409 // from /dev/urandom than we need.
410 int count = read(urandomFD, (void *)&seed, sizeof(seed));
411
412 close(urandomFD);
413
414 // Return the seed if the read was successful.
415 if (count == sizeof(seed))
416 return seed;
417 }
418
419 // Otherwise, swizzle the current time and the process ID to form a reasonable
420 // seed.
421 const auto Now = std::chrono::high_resolution_clock::now();
422 return hash_combine(Now.time_since_epoch().count(), ::getpid());
423}
424#endif
425
427#if HAVE_DECL_ARC4RANDOM
428 return arc4random();
429#else
430 static int x = (static_cast<void>(::srand(GetRandomNumberSeed())), 0);
431 (void)x;
432 return ::rand();
433#endif
434}
435
436[[noreturn]] void Process::ExitNoCleanup(int RetCode) { _Exit(RetCode); }
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
Function Alias Analysis false
#define STDOUT_FILENO
Definition InitLLVM.cpp:28
#define STDERR_FILENO
Definition InitLLVM.cpp:31
#define STDIN_FILENO
Definition InitLLVM.cpp:25
block placement Basic Block Placement Stats
static bool coreFilesPrevented
Definition Process.cpp:106
static const char colorcodes[2][2][16][11]
Definition Process.cpp:98
StringRef - Represent a constant reference to a string, i.e.
Definition StringRef.h:55
A switch()-like statement whose cases are string literals.
StringSwitch & Case(StringLiteral S, T Value)
StringSwitch & StartsWith(StringLiteral S, T Value)
StringSwitch & EndsWith(StringLiteral S, T Value)
static LLVM_ABI void UseANSIEscapeCodes(bool enable)
Enables or disables whether ANSI escape sequences are used to output colors.
static LLVM_ABI std::error_code SafelyCloseFileDescriptor(int FD)
static LLVM_ABI 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 LLVM_ABI std::error_code FixupStandardFileDescriptors()
static LLVM_ABI Pid getProcessId()
Get the process's identifier.
static LLVM_ABI size_t GetMallocUsage()
Return process memory usage.
static LLVM_ABI bool ColorNeedsFlush()
Whether changing colors requires the output to be flushed.
static LLVM_ABI const char * ResetColor()
Resets the terminals colors, or returns an escape sequence to do so.
static LLVM_ABI unsigned GetRandomNumber()
Get the result of a process wide random number generator.
static LLVM_ABI bool FileDescriptorIsDisplayed(int fd)
This function determines if the given file descriptor is connected to a "tty" or "console" window.
static LLVM_ABI Expected< unsigned > getPageSize()
Get the process's page size.
static LLVM_ABI const char * OutputColor(char c, bool bold, bool bg)
This function returns the colorcode escape sequences.
static LLVM_ABI const char * OutputBold(bool bg)
Same as OutputColor, but only enables the bold attribute.
static LLVM_ABI unsigned StandardErrColumns()
This function determines the number of columns in the window if standard error is connected to a "tty...
static LLVM_ABI std::optional< std::string > GetEnv(StringRef name)
static LLVM_ABI bool FileDescriptorHasColors(int fd)
This function determines if the given file descriptor is displayd and supports colors.
static LLVM_ABI bool StandardInIsUserInput()
This function determines if the standard input is connected directly to a user's input (keyboard prob...
static LLVM_ABI void PreventCoreFiles()
This function makes the necessary calls to the operating system to prevent core files or any other ki...
static LLVM_ABI bool StandardErrHasColors()
This function determines whether the terminal connected to standard error supports colors.
static LLVM_ABI const char * OutputReverse()
This function returns the escape sequence to reverse forground and background colors.
static LLVM_ABI bool StandardErrIsDisplayed()
This function determines if the standard error is connected to a "tty" or "console" window.
static LLVM_ABI bool StandardOutHasColors()
This function determines whether the terminal connected to standard output supports colors.
static LLVM_ABI unsigned StandardOutColumns()
This function determines the number of columns in the window if standard output is connected to a "tt...
static LLVM_ABI bool StandardOutIsDisplayed()
This function determines if the standard output is connected to a "tty" or "console" window.
value_type read(const void *memory, endianness endian)
Read a value of a particular endianness from memory.
Definition Endian.h:60
decltype(auto) RetryAfterSignal(const FailT &Fail, const Fun &F, const Args &... As)
Definition Errno.h:33
std::chrono::nanoseconds toDuration(FILETIME Time)
std::chrono::time_point< std::chrono::system_clock, D > TimePoint
A time point on the system clock.
Definition Chrono.h:34
This is an optimization pass for GlobalISel generic memory operations.
FunctionAddr VTableAddr Count
Definition InstrProf.h:139
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:2012
LLVM_ABI Error errorCodeToError(std::error_code EC)
Helper for converting an std::error_code to a Error.
Definition Error.cpp:107
hash_code hash_combine(const Ts &...args)
Combine values into a single hash_code.
Definition Hashing.h:592
std::error_code errnoAsErrorCode()
Helper to get errno as an std::error_code.
Definition Error.h:1240