1//===- Unix/Process.cpp - Unix Process Implementation --------- -*- C++ -*-===// 2// 3// The LLVM Compiler Infrastructure 4// 5// This file is distributed under the University of Illinois Open Source 6// License. See LICENSE.TXT for details. 7// 8//===----------------------------------------------------------------------===// 9// 10// This file provides the generic Unix implementation of the Process class. 11// 12//===----------------------------------------------------------------------===// 13 14#include "Unix.h" 15#include "llvm/ADT/Hashing.h" 16#include "llvm/ADT/StringRef.h" 17#include "llvm/Support/ManagedStatic.h" 18#include "llvm/Support/Mutex.h" 19#include "llvm/Support/MutexGuard.h" 20#if HAVE_FCNTL_H 21#include <fcntl.h> 22#endif 23#ifdef HAVE_SYS_TIME_H 24#include <sys/time.h> 25#endif 26#ifdef HAVE_SYS_RESOURCE_H 27#include <sys/resource.h> 28#endif 29#ifdef HAVE_SYS_STAT_H 30#include <sys/stat.h> 31#endif 32#if HAVE_SIGNAL_H 33#include <signal.h> 34#endif 35// DragonFlyBSD, OpenBSD, and Bitrig have deprecated <malloc.h> for 36// <stdlib.h> instead. Unix.h includes this for us already. 37#if defined(HAVE_MALLOC_H) && !defined(__DragonFly__) && \ 38 !defined(__FreeBSD__) && !defined(__OpenBSD__) && !defined(__Bitrig__) 39#include <malloc.h> 40#endif 41#if defined(HAVE_MALLCTL) 42#include <malloc_np.h> 43#endif 44#ifdef HAVE_MALLOC_MALLOC_H 45#include <malloc/malloc.h> 46#endif 47#ifdef HAVE_SYS_IOCTL_H 48# include <sys/ioctl.h> 49#endif 50#ifdef HAVE_TERMIOS_H 51# include <termios.h> 52#endif 53 54//===----------------------------------------------------------------------===// 55//=== WARNING: Implementation here must contain only generic UNIX code that 56//=== is guaranteed to work on *all* UNIX variants. 57//===----------------------------------------------------------------------===// 58 59using namespace llvm; 60using namespace sys; 61 62static std::pair<std::chrono::microseconds, std::chrono::microseconds> getRUsageTimes() { 63#if defined(HAVE_GETRUSAGE) 64 struct rusage RU; 65 ::getrusage(RUSAGE_SELF, &RU); 66 return { toDuration(RU.ru_utime), toDuration(RU.ru_stime) }; 67#else 68#if !defined(__Fuchsia__) 69#warning Cannot get usage times on this platform 70#endif 71 return { std::chrono::microseconds::zero(), std::chrono::microseconds::zero() }; 72#endif 73} 74 75// On Cygwin, getpagesize() returns 64k(AllocationGranularity) and 76// offset in mmap(3) should be aligned to the AllocationGranularity. 77unsigned Process::getPageSize() { 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#warning Cannot get the page size on this machine 84#endif 85 return static_cast<unsigned>(page_size); 86} 87 88size_t Process::GetMallocUsage() { 89#if defined(HAVE_MALLINFO) 90 struct mallinfo mi; 91 mi = ::mallinfo(); 92 return mi.uordblks; 93#elif defined(HAVE_MALLOC_ZONE_STATISTICS) && defined(HAVE_MALLOC_MALLOC_H) 94 malloc_statistics_t Stats; 95 malloc_zone_statistics(malloc_default_zone(), &Stats); 96 return Stats.size_in_use; // darwin 97#elif defined(HAVE_MALLCTL) 98 size_t alloc, sz; 99 sz = sizeof(size_t); 100 if (mallctl("stats.allocated", &alloc, &sz, NULL, 0) == 0) 101 return alloc; 102 return 0; 103#elif defined(HAVE_SBRK) 104 // Note this is only an approximation and more closely resembles 105 // the value returned by mallinfo in the arena field. 106 static char *StartOfMemory = reinterpret_cast<char*>(::sbrk(0)); 107 char *EndOfMemory = (char*)sbrk(0); 108 if (EndOfMemory != ((char*)-1) && StartOfMemory != ((char*)-1)) 109 return EndOfMemory - StartOfMemory; 110 return 0; 111#else 112#if !defined(__Fuchsia__) 113#warning Cannot get malloc info on this platform 114#endif 115 return 0; 116#endif 117} 118 119void Process::GetTimeUsage(TimePoint<> &elapsed, std::chrono::nanoseconds &user_time, 120 std::chrono::nanoseconds &sys_time) { 121 elapsed = std::chrono::system_clock::now(); 122 std::tie(user_time, sys_time) = getRUsageTimes(); 123} 124 125#if defined(HAVE_MACH_MACH_H) && !defined(__GNU__) 126#include <mach/mach.h> 127#endif 128 129// Some LLVM programs such as bugpoint produce core files as a normal part of 130// their operation. To prevent the disk from filling up, this function 131// does what's necessary to prevent their generation. 132void Process::PreventCoreFiles() { 133#if HAVE_SETRLIMIT 134 struct rlimit rlim; 135 rlim.rlim_cur = rlim.rlim_max = 0; 136 setrlimit(RLIMIT_CORE, &rlim); 137#endif 138 139#if defined(HAVE_MACH_MACH_H) && !defined(__GNU__) 140 // Disable crash reporting on Mac OS X 10.0-10.4 141 142 // get information about the original set of exception ports for the task 143 mach_msg_type_number_t Count = 0; 144 exception_mask_t OriginalMasks[EXC_TYPES_COUNT]; 145 exception_port_t OriginalPorts[EXC_TYPES_COUNT]; 146 exception_behavior_t OriginalBehaviors[EXC_TYPES_COUNT]; 147 thread_state_flavor_t OriginalFlavors[EXC_TYPES_COUNT]; 148 kern_return_t err = 149 task_get_exception_ports(mach_task_self(), EXC_MASK_ALL, OriginalMasks, 150 &Count, OriginalPorts, OriginalBehaviors, 151 OriginalFlavors); 152 if (err == KERN_SUCCESS) { 153 // replace each with MACH_PORT_NULL. 154 for (unsigned i = 0; i != Count; ++i) 155 task_set_exception_ports(mach_task_self(), OriginalMasks[i], 156 MACH_PORT_NULL, OriginalBehaviors[i], 157 OriginalFlavors[i]); 158 } 159 160 // Disable crash reporting on Mac OS X 10.5 161 signal(SIGABRT, _exit); 162 signal(SIGILL, _exit); 163 signal(SIGFPE, _exit); 164 signal(SIGSEGV, _exit); 165 signal(SIGBUS, _exit); 166#endif 167 168 coreFilesPrevented = true; 169} 170 171Optional<std::string> Process::GetEnv(StringRef Name) { 172 std::string NameStr = Name.str(); 173 const char *Val = ::getenv(NameStr.c_str()); 174 if (!Val) 175 return None; 176 return std::string(Val); 177} 178 179std::error_code 180Process::GetArgumentVector(SmallVectorImpl<const char *> &ArgsOut, 181 ArrayRef<const char *> ArgsIn, 182 SpecificBumpPtrAllocator<char> &) { 183 ArgsOut.append(ArgsIn.begin(), ArgsIn.end()); 184 185 return std::error_code(); 186} 187 188namespace { 189class FDCloser { 190public: 191 FDCloser(int &FD) : FD(FD), KeepOpen(false) {} 192 void keepOpen() { KeepOpen = true; } 193 ~FDCloser() { 194 if (!KeepOpen && FD >= 0) 195 ::close(FD); 196 } 197 198private: 199 FDCloser(const FDCloser &) = delete; 200 void operator=(const FDCloser &) = delete; 201 202 int &FD; 203 bool KeepOpen; 204}; 205} 206 207std::error_code Process::FixupStandardFileDescriptors() { 208 int NullFD = -1; 209 FDCloser FDC(NullFD); 210 const int StandardFDs[] = {STDIN_FILENO, STDOUT_FILENO, STDERR_FILENO}; 211 for (int StandardFD : StandardFDs) { 212 struct stat st; 213 errno = 0; 214 while (fstat(StandardFD, &st) < 0) { 215 assert(errno && "expected errno to be set if fstat failed!"); 216 // fstat should return EBADF if the file descriptor is closed. 217 if (errno == EBADF) 218 break; 219 // retry fstat if we got EINTR, otherwise bubble up the failure. 220 if (errno != EINTR) 221 return std::error_code(errno, std::generic_category()); 222 } 223 // if fstat succeeds, move on to the next FD. 224 if (!errno) 225 continue; 226 assert(errno == EBADF && "expected errno to have EBADF at this point!"); 227 228 if (NullFD < 0) { 229 while ((NullFD = open("/dev/null", O_RDWR)) < 0) { 230 if (errno == EINTR) 231 continue; 232 return std::error_code(errno, std::generic_category()); 233 } 234 } 235 236 if (NullFD == StandardFD) 237 FDC.keepOpen(); 238 else if (dup2(NullFD, StandardFD) < 0) 239 return std::error_code(errno, std::generic_category()); 240 } 241 return std::error_code(); 242} 243 244std::error_code Process::SafelyCloseFileDescriptor(int FD) { 245 // Create a signal set filled with *all* signals. 246 sigset_t FullSet; 247 if (sigfillset(&FullSet) < 0) 248 return std::error_code(errno, std::generic_category()); 249 // Atomically swap our current signal mask with a full mask. 250 sigset_t SavedSet; 251#if LLVM_ENABLE_THREADS 252 if (int EC = pthread_sigmask(SIG_SETMASK, &FullSet, &SavedSet)) 253 return std::error_code(EC, std::generic_category()); 254#else 255 if (sigprocmask(SIG_SETMASK, &FullSet, &SavedSet) < 0) 256 return std::error_code(errno, std::generic_category()); 257#endif 258 // Attempt to close the file descriptor. 259 // We need to save the error, if one occurs, because our subsequent call to 260 // pthread_sigmask might tamper with errno. 261 int ErrnoFromClose = 0; 262 if (::close(FD) < 0) 263 ErrnoFromClose = errno; 264 // Restore the signal mask back to what we saved earlier. 265 int EC = 0; 266#if LLVM_ENABLE_THREADS 267 EC = pthread_sigmask(SIG_SETMASK, &SavedSet, nullptr); 268#else 269 if (sigprocmask(SIG_SETMASK, &SavedSet, nullptr) < 0) 270 EC = errno; 271#endif 272 // The error code from close takes precedence over the one from 273 // pthread_sigmask. 274 if (ErrnoFromClose) 275 return std::error_code(ErrnoFromClose, std::generic_category()); 276 return std::error_code(EC, std::generic_category()); 277} 278 279bool Process::StandardInIsUserInput() { 280 return FileDescriptorIsDisplayed(STDIN_FILENO); 281} 282 283bool Process::StandardOutIsDisplayed() { 284 return FileDescriptorIsDisplayed(STDOUT_FILENO); 285} 286 287bool Process::StandardErrIsDisplayed() { 288 return FileDescriptorIsDisplayed(STDERR_FILENO); 289} 290 291bool Process::FileDescriptorIsDisplayed(int fd) { 292#if HAVE_ISATTY 293 return isatty(fd); 294#else 295 // If we don't have isatty, just return false. 296 return false; 297#endif 298} 299 300static unsigned getColumns(int FileID) { 301 // If COLUMNS is defined in the environment, wrap to that many columns. 302 if (const char *ColumnsStr = std::getenv("COLUMNS")) { 303 int Columns = std::atoi(ColumnsStr); 304 if (Columns > 0) 305 return Columns; 306 } 307 308 unsigned Columns = 0; 309 310#if defined(HAVE_SYS_IOCTL_H) && defined(HAVE_TERMIOS_H) 311 // Try to determine the width of the terminal. 312 struct winsize ws; 313 if (ioctl(FileID, TIOCGWINSZ, &ws) == 0) 314 Columns = ws.ws_col; 315#endif 316 317 return Columns; 318} 319 320unsigned Process::StandardOutColumns() { 321 if (!StandardOutIsDisplayed()) 322 return 0; 323 324 return getColumns(1); 325} 326 327unsigned Process::StandardErrColumns() { 328 if (!StandardErrIsDisplayed()) 329 return 0; 330 331 return getColumns(2); 332} 333 334#ifdef HAVE_TERMINFO 335// We manually declare these extern functions because finding the correct 336// headers from various terminfo, curses, or other sources is harder than 337// writing their specs down. 338extern "C" int setupterm(char *term, int filedes, int *errret); 339extern "C" struct term *set_curterm(struct term *termp); 340extern "C" int del_curterm(struct term *termp); 341extern "C" int tigetnum(char *capname); 342#endif 343 344#ifdef HAVE_TERMINFO 345static ManagedStatic<sys::Mutex> TermColorMutex; 346#endif 347 348static bool terminalHasColors(int fd) { 349#ifdef HAVE_TERMINFO 350 // First, acquire a global lock because these C routines are thread hostile. 351 MutexGuard G(*TermColorMutex); 352 353 int errret = 0; 354 if (setupterm((char *)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 bool HasColors = tigetnum(const_cast<char *>("colors")) > 0; 373 374 // Now extract the structure allocated by setupterm and free its memory 375 // through a really silly dance. 376 struct term *termp = set_curterm((struct term *)nullptr); 377 (void)del_curterm(termp); // Drop any errors here. 378 379 // Return true if we found a color capabilities for the current terminal. 380 if (HasColors) 381 return true; 382#endif 383 384 // Otherwise, be conservative. 385 return false; 386} 387 388bool Process::FileDescriptorHasColors(int fd) { 389 // A file descriptor has colors if it is displayed and the terminal has 390 // colors. 391 return FileDescriptorIsDisplayed(fd) && terminalHasColors(fd); 392} 393 394bool Process::StandardOutHasColors() { 395 return FileDescriptorHasColors(STDOUT_FILENO); 396} 397 398bool Process::StandardErrHasColors() { 399 return FileDescriptorHasColors(STDERR_FILENO); 400} 401 402void Process::UseANSIEscapeCodes(bool /*enable*/) { 403 // No effect. 404} 405 406bool Process::ColorNeedsFlush() { 407 // No, we use ANSI escape sequences. 408 return false; 409} 410 411const char *Process::OutputColor(char code, bool bold, bool bg) { 412 return colorcodes[bg?1:0][bold?1:0][code&7]; 413} 414 415const char *Process::OutputBold(bool bg) { 416 return "\033[1m"; 417} 418 419const char *Process::OutputReverse() { 420 return "\033[7m"; 421} 422 423const char *Process::ResetColor() { 424 return "\033[0m"; 425} 426 427#if !HAVE_DECL_ARC4RANDOM 428static unsigned GetRandomNumberSeed() { 429 // Attempt to get the initial seed from /dev/urandom, if possible. 430 int urandomFD = open("/dev/urandom", O_RDONLY); 431 432 if (urandomFD != -1) { 433 unsigned seed; 434 // Don't use a buffered read to avoid reading more data 435 // from /dev/urandom than we need. 436 int count = read(urandomFD, (void *)&seed, sizeof(seed)); 437 438 close(urandomFD); 439 440 // Return the seed if the read was successful. 441 if (count == sizeof(seed)) 442 return seed; 443 } 444 445 // Otherwise, swizzle the current time and the process ID to form a reasonable 446 // seed. 447 const auto Now = std::chrono::high_resolution_clock::now(); 448 return hash_combine(Now.time_since_epoch().count(), ::getpid()); 449} 450#endif 451 452unsigned llvm::sys::Process::GetRandomNumber() { 453#if HAVE_DECL_ARC4RANDOM 454 return arc4random(); 455#else 456 static int x = (static_cast<void>(::srand(GetRandomNumberSeed())), 0); 457 (void)x; 458 return ::rand(); 459#endif 460} 461