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