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