#include "Unix.h"
#include "llvm/ADT/Hashing.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/Support/Mutex.h"
#include "llvm/Support/MutexGuard.h"
#include "llvm/Support/TimeValue.h"
#ifdef HAVE_SYS_TIME_H
#include <sys/time.h>
#endif
#ifdef HAVE_SYS_RESOURCE_H
#include <sys/resource.h>
#endif
#if defined(HAVE_MALLOC_H) && !defined(__DragonFly__) && \
!defined(__OpenBSD__) && !defined(__Bitrig__)
#include <malloc.h>
#endif
#ifdef HAVE_MALLOC_MALLOC_H
#include <malloc/malloc.h>
#endif
#ifdef HAVE_SYS_IOCTL_H
# include <sys/ioctl.h>
#endif
#ifdef HAVE_TERMIOS_H
# include <termios.h>
#endif
using namespace llvm;
using namespace sys;
process::id_type self_process::get_id() {
return getpid();
}
static std::pair<TimeValue, TimeValue> getRUsageTimes() {
#if defined(HAVE_GETRUSAGE)
struct rusage RU;
::getrusage(RUSAGE_SELF, &RU);
return std::make_pair(
TimeValue(
static_cast<TimeValue::SecondsType>(RU.ru_utime.tv_sec),
static_cast<TimeValue::NanoSecondsType>(
RU.ru_utime.tv_usec * TimeValue::NANOSECONDS_PER_MICROSECOND)),
TimeValue(
static_cast<TimeValue::SecondsType>(RU.ru_stime.tv_sec),
static_cast<TimeValue::NanoSecondsType>(
RU.ru_stime.tv_usec * TimeValue::NANOSECONDS_PER_MICROSECOND)));
#else
#warning Cannot get usage times on this platform
return std::make_pair(TimeValue(), TimeValue());
#endif
}
TimeValue self_process::get_user_time() const {
#if _POSIX_TIMERS > 0 && _POSIX_CPUTIME > 0
struct timespec TS;
if (::clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &TS) == 0)
return TimeValue(static_cast<TimeValue::SecondsType>(TS.tv_sec),
static_cast<TimeValue::NanoSecondsType>(TS.tv_nsec));
#endif
return getRUsageTimes().first;
}
TimeValue self_process::get_system_time() const {
return getRUsageTimes().second;
}
static unsigned getPageSize() {
#if defined(HAVE_GETPAGESIZE)
const int page_size = ::getpagesize();
#elif defined(HAVE_SYSCONF)
long page_size = ::sysconf(_SC_PAGE_SIZE);
#else
#warning Cannot get the page size on this machine
#endif
return static_cast<unsigned>(page_size);
}
self_process::self_process() : PageSize(getPageSize()) {
}
size_t Process::GetMallocUsage() {
#if defined(HAVE_MALLINFO)
struct mallinfo mi;
mi = ::mallinfo();
return mi.uordblks;
#elif defined(HAVE_MALLOC_ZONE_STATISTICS) && defined(HAVE_MALLOC_MALLOC_H)
malloc_statistics_t Stats;
malloc_zone_statistics(malloc_default_zone(), &Stats);
return Stats.size_in_use; #elif defined(HAVE_SBRK)
static char *StartOfMemory = reinterpret_cast<char*>(::sbrk(0));
char *EndOfMemory = (char*)sbrk(0);
if (EndOfMemory != ((char*)-1) && StartOfMemory != ((char*)-1))
return EndOfMemory - StartOfMemory;
else
return 0;
#else
#warning Cannot get malloc info on this platform
return 0;
#endif
}
void Process::GetTimeUsage(TimeValue &elapsed, TimeValue &user_time,
TimeValue &sys_time) {
elapsed = TimeValue::now();
llvm::tie(user_time, sys_time) = getRUsageTimes();
}
#if defined(HAVE_MACH_MACH_H) && !defined(__GNU__)
#include <mach/mach.h>
#endif
void Process::PreventCoreFiles() {
#if HAVE_SETRLIMIT
struct rlimit rlim;
rlim.rlim_cur = rlim.rlim_max = 0;
setrlimit(RLIMIT_CORE, &rlim);
#endif
#if defined(HAVE_MACH_MACH_H) && !defined(__GNU__)
mach_msg_type_number_t Count = 0;
exception_mask_t OriginalMasks[EXC_TYPES_COUNT];
exception_port_t OriginalPorts[EXC_TYPES_COUNT];
exception_behavior_t OriginalBehaviors[EXC_TYPES_COUNT];
thread_state_flavor_t OriginalFlavors[EXC_TYPES_COUNT];
kern_return_t err =
task_get_exception_ports(mach_task_self(), EXC_MASK_ALL, OriginalMasks,
&Count, OriginalPorts, OriginalBehaviors,
OriginalFlavors);
if (err == KERN_SUCCESS) {
for (unsigned i = 0; i != Count; ++i)
task_set_exception_ports(mach_task_self(), OriginalMasks[i],
MACH_PORT_NULL, OriginalBehaviors[i],
OriginalFlavors[i]);
}
signal(SIGABRT, _exit);
signal(SIGILL, _exit);
signal(SIGFPE, _exit);
signal(SIGSEGV, _exit);
signal(SIGBUS, _exit);
#endif
}
Optional<std::string> Process::GetEnv(StringRef Name) {
std::string NameStr = Name.str();
const char *Val = ::getenv(NameStr.c_str());
if (!Val)
return None;
return std::string(Val);
}
error_code Process::GetArgumentVector(SmallVectorImpl<const char *> &ArgsOut,
ArrayRef<const char *> ArgsIn,
SpecificBumpPtrAllocator<char> &) {
ArgsOut.append(ArgsIn.begin(), ArgsIn.end());
return error_code::success();
}
bool Process::StandardInIsUserInput() {
return FileDescriptorIsDisplayed(STDIN_FILENO);
}
bool Process::StandardOutIsDisplayed() {
return FileDescriptorIsDisplayed(STDOUT_FILENO);
}
bool Process::StandardErrIsDisplayed() {
return FileDescriptorIsDisplayed(STDERR_FILENO);
}
bool Process::FileDescriptorIsDisplayed(int fd) {
#if HAVE_ISATTY
return isatty(fd);
#else
return false;
#endif
}
static unsigned getColumns(int FileID) {
if (const char *ColumnsStr = std::getenv("COLUMNS")) {
int Columns = std::atoi(ColumnsStr);
if (Columns > 0)
return Columns;
}
unsigned Columns = 0;
#if defined(HAVE_SYS_IOCTL_H) && defined(HAVE_TERMIOS_H)
struct winsize ws;
if (ioctl(FileID, TIOCGWINSZ, &ws) == 0)
Columns = ws.ws_col;
#endif
return Columns;
}
unsigned Process::StandardOutColumns() {
if (!StandardOutIsDisplayed())
return 0;
return getColumns(1);
}
unsigned Process::StandardErrColumns() {
if (!StandardErrIsDisplayed())
return 0;
return getColumns(2);
}
#ifdef HAVE_TERMINFO
extern "C" int setupterm(char *term, int filedes, int *errret);
extern "C" struct term *set_curterm(struct term *termp);
extern "C" int del_curterm(struct term *termp);
extern "C" int tigetnum(char *capname);
#endif
static bool terminalHasColors(int fd) {
#ifdef HAVE_TERMINFO
static sys::Mutex M;
MutexGuard G(M);
int errret = 0;
if (setupterm((char *)0, fd, &errret) != 0)
return false;
bool HasColors = tigetnum(const_cast<char *>("colors")) > 0;
struct term *termp = set_curterm((struct term *)0);
(void)del_curterm(termp);
if (HasColors)
return true;
#endif
return false;
}
bool Process::FileDescriptorHasColors(int fd) {
return FileDescriptorIsDisplayed(fd) && terminalHasColors(fd);
}
bool Process::StandardOutHasColors() {
return FileDescriptorHasColors(STDOUT_FILENO);
}
bool Process::StandardErrHasColors() {
return FileDescriptorHasColors(STDERR_FILENO);
}
void Process::UseANSIEscapeCodes(bool ) {
}
bool Process::ColorNeedsFlush() {
return false;
}
const char *Process::OutputColor(char code, bool bold, bool bg) {
return colorcodes[bg?1:0][bold?1:0][code&7];
}
const char *Process::OutputBold(bool bg) {
return "\033[1m";
}
const char *Process::OutputReverse() {
return "\033[7m";
}
const char *Process::ResetColor() {
return "\033[0m";
}
#if !defined(HAVE_ARC4RANDOM)
static unsigned GetRandomNumberSeed() {
if (FILE *RandomSource = ::fopen("/dev/urandom", "r")) {
unsigned seed;
int count = ::fread((void *)&seed, sizeof(seed), 1, RandomSource);
::fclose(RandomSource);
if (count == 1)
return seed;
}
TimeValue Now = TimeValue::now();
return hash_combine(Now.seconds(), Now.nanoseconds(), ::getpid());
}
#endif
unsigned llvm::sys::Process::GetRandomNumber() {
#if defined(HAVE_ARC4RANDOM)
return arc4random();
#else
static int x = (::srand(GetRandomNumberSeed()), 0);
(void)x;
return ::rand();
#endif
}