aboutsummaryrefslogtreecommitdiff
path: root/llvm/lib/Support/Unix
diff options
context:
space:
mode:
Diffstat (limited to 'llvm/lib/Support/Unix')
-rw-r--r--llvm/lib/Support/Unix/Host.inc2
-rw-r--r--llvm/lib/Support/Unix/Memory.inc1
-rw-r--r--llvm/lib/Support/Unix/Path.inc111
-rw-r--r--llvm/lib/Support/Unix/Process.inc26
-rw-r--r--llvm/lib/Support/Unix/Program.inc87
-rw-r--r--llvm/lib/Support/Unix/Threading.inc35
-rw-r--r--llvm/lib/Support/Unix/Unix.h4
7 files changed, 208 insertions, 58 deletions
diff --git a/llvm/lib/Support/Unix/Host.inc b/llvm/lib/Support/Unix/Host.inc
index 17d78dc18be7..dfcfdd0dee68 100644
--- a/llvm/lib/Support/Unix/Host.inc
+++ b/llvm/lib/Support/Unix/Host.inc
@@ -56,7 +56,7 @@ static std::string updateTripleOSVersion(std::string TargetTripleString) {
if (TT.getOS() == Triple::AIX && !TT.getOSMajorVersion()) {
struct utsname name;
if (uname(&name) != -1) {
- std::string NewOSName = Triple::getOSTypeName(Triple::AIX);
+ std::string NewOSName = std::string(Triple::getOSTypeName(Triple::AIX));
NewOSName += name.version;
NewOSName += '.';
NewOSName += name.release;
diff --git a/llvm/lib/Support/Unix/Memory.inc b/llvm/lib/Support/Unix/Memory.inc
index 79b1759359e1..be88e7db1400 100644
--- a/llvm/lib/Support/Unix/Memory.inc
+++ b/llvm/lib/Support/Unix/Memory.inc
@@ -12,6 +12,7 @@
#include "Unix.h"
#include "llvm/Config/config.h"
+#include "llvm/Support/Alignment.h"
#include "llvm/Support/DataTypes.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/Process.h"
diff --git a/llvm/lib/Support/Unix/Path.inc b/llvm/lib/Support/Unix/Path.inc
index 2a03dc682bce..d91b269cc6d3 100644
--- a/llvm/lib/Support/Unix/Path.inc
+++ b/llvm/lib/Support/Unix/Path.inc
@@ -48,6 +48,8 @@ extern char **environ;
#endif
#elif defined(__DragonFly__)
#include <sys/mount.h>
+#elif defined(__MVS__)
+#include <sys/ps.h>
#endif
// Both stdio.h and cstdio are included via different paths and
@@ -56,10 +58,13 @@ extern char **environ;
#undef ferror
#undef feof
+#if !defined(PATH_MAX)
// For GNU Hurd
-#if defined(__GNU__) && !defined(PATH_MAX)
-# define PATH_MAX 4096
-# define MAXPATHLEN 4096
+#if defined(__GNU__)
+#define PATH_MAX 4096
+#elif defined(__MVS__)
+#define PATH_MAX _XOPEN_PATH_MAX
+#endif
#endif
#include <sys/types.h>
@@ -101,7 +106,8 @@ typedef uint_t uint;
#define STATVFS_F_FRSIZE(vfs) static_cast<uint64_t>(vfs.f_bsize)
#endif
-#if defined(__NetBSD__) || defined(__DragonFly__) || defined(__GNU__)
+#if defined(__NetBSD__) || defined(__DragonFly__) || defined(__GNU__) || \
+ defined(__MVS__)
#define STATVFS_F_FLAG(vfs) (vfs).f_flag
#else
#define STATVFS_F_FLAG(vfs) (vfs).f_flags
@@ -184,10 +190,10 @@ std::string getMainExecutable(const char *argv0, void *MainAddr) {
// On OS X the executable path is saved to the stack by dyld. Reading it
// from there is much faster than calling dladdr, especially for large
// binaries with symbols.
- char exe_path[MAXPATHLEN];
+ char exe_path[PATH_MAX];
uint32_t size = sizeof(exe_path);
if (_NSGetExecutablePath(exe_path, &size) == 0) {
- char link_path[MAXPATHLEN];
+ char link_path[PATH_MAX];
if (realpath(exe_path, link_path))
return link_path;
}
@@ -208,14 +214,9 @@ std::string getMainExecutable(const char *argv0, void *MainAddr) {
while (*p++ != 0)
;
// Iterate through auxiliary vectors for AT_EXECPATH.
- for (;;) {
- switch (*(uintptr_t *)p++) {
- case AT_EXECPATH:
+ for (; *(uintptr_t *)p != AT_NULL; p++) {
+ if (*(uintptr_t *)p++ == AT_EXECPATH)
return *p;
- case AT_NULL:
- break;
- }
- p++;
}
#endif
// Fall back to argv[0] if auxiliary vectors are not available.
@@ -239,7 +240,7 @@ std::string getMainExecutable(const char *argv0, void *MainAddr) {
if (getprogpath(exe_path, argv0) != NULL)
return exe_path;
#elif defined(__linux__) || defined(__CYGWIN__) || defined(__gnu_hurd__)
- char exe_path[MAXPATHLEN];
+ char exe_path[PATH_MAX];
const char *aPath = "/proc/self/exe";
if (sys::fs::exists(aPath)) {
// /proc is not always mounted under Linux (chroot for example).
@@ -263,7 +264,7 @@ std::string getMainExecutable(const char *argv0, void *MainAddr) {
return ret;
}
#else
- char real_path[MAXPATHLEN];
+ char real_path[PATH_MAX];
if (realpath(exe_path, real_path))
return std::string(real_path);
#endif
@@ -271,6 +272,26 @@ std::string getMainExecutable(const char *argv0, void *MainAddr) {
// Fall back to the classical detection.
if (getprogpath(exe_path, argv0))
return exe_path;
+#elif defined(__MVS__)
+ int token = 0;
+ W_PSPROC buf;
+ char exe_path[PS_PATHBLEN];
+ pid_t pid = getpid();
+
+ memset(&buf, 0, sizeof(buf));
+ buf.ps_pathptr = exe_path;
+ buf.ps_pathlen = sizeof(exe_path);
+
+ while (true) {
+ if ((token = w_getpsent(token, &buf, sizeof(buf))) <= 0)
+ break;
+ if (buf.ps_pid != pid)
+ continue;
+ char real_path[PATH_MAX];
+ if (realpath(exe_path, real_path))
+ return std::string(real_path);
+ break; // Found entry, but realpath failed.
+ }
#elif defined(HAVE_DLFCN_H) && defined(HAVE_DLADDR)
// Use dladdr to get executable path if available.
Dl_info DLInfo;
@@ -280,7 +301,7 @@ std::string getMainExecutable(const char *argv0, void *MainAddr) {
// If the filename is a symlink, we need to resolve and return the location of
// the actual executable.
- char link_path[MAXPATHLEN];
+ char link_path[PATH_MAX];
if (realpath(DLInfo.dli_fname, link_path))
return link_path;
#else
@@ -330,12 +351,7 @@ std::error_code current_path(SmallVectorImpl<char> &result) {
return std::error_code();
}
-#ifdef MAXPATHLEN
- result.reserve(MAXPATHLEN);
-#else
-// For GNU Hurd
- result.reserve(1024);
-#endif
+ result.reserve(PATH_MAX);
while (true) {
if (::getcwd(result.data(), result.capacity()) == nullptr) {
@@ -504,6 +520,10 @@ static bool is_local_impl(struct STATVFS &Vfs) {
// vmount entry not found; "remote" is the conservative answer.
return false;
+#elif defined(__MVS__)
+ // The file system can have an arbitrary structure on z/OS; must go with the
+ // conservative answer.
+ return false;
#else
return !!(STATVFS_F_FLAG(Vfs) & MNT_LOCAL);
#endif
@@ -998,7 +1018,7 @@ std::error_code openFileForRead(const Twine &Name, int &ResultFD,
#if defined(F_GETPATH)
// When F_GETPATH is availble, it is the quickest way to get
// the real path name.
- char Buffer[MAXPATHLEN];
+ char Buffer[PATH_MAX];
if (::fcntl(ResultFD, F_GETPATH, Buffer) != -1)
RealPath->append(Buffer, Buffer + strlen(Buffer));
#else
@@ -1169,6 +1189,51 @@ static bool getDarwinConfDir(bool TempDir, SmallVectorImpl<char> &Result) {
return false;
}
+bool user_config_directory(SmallVectorImpl<char> &result) {
+#ifdef __APPLE__
+ // Mac: ~/Library/Preferences/
+ if (home_directory(result)) {
+ append(result, "Library", "Preferences");
+ return true;
+ }
+#else
+ // XDG_CONFIG_HOME as defined in the XDG Base Directory Specification:
+ // http://standards.freedesktop.org/basedir-spec/basedir-spec-latest.html
+ if (const char *RequestedDir = getenv("XDG_CONFIG_HOME")) {
+ result.clear();
+ result.append(RequestedDir, RequestedDir + strlen(RequestedDir));
+ return true;
+ }
+#endif
+ // Fallback: ~/.config
+ if (!home_directory(result)) {
+ return false;
+ }
+ append(result, ".config");
+ return true;
+}
+
+bool cache_directory(SmallVectorImpl<char> &result) {
+#ifdef __APPLE__
+ if (getDarwinConfDir(false/*tempDir*/, result)) {
+ return true;
+ }
+#else
+ // XDG_CACHE_HOME as defined in the XDG Base Directory Specification:
+ // http://standards.freedesktop.org/basedir-spec/basedir-spec-latest.html
+ if (const char *RequestedDir = getenv("XDG_CACHE_HOME")) {
+ result.clear();
+ result.append(RequestedDir, RequestedDir + strlen(RequestedDir));
+ return true;
+ }
+#endif
+ if (!home_directory(result)) {
+ return false;
+ }
+ append(result, ".cache");
+ return true;
+}
+
static const char *getEnvTempDir() {
// Check whether the temporary directory is specified by an environment
// variable.
diff --git a/llvm/lib/Support/Unix/Process.inc b/llvm/lib/Support/Unix/Process.inc
index dfe81d7e2833..24f16b51af7b 100644
--- a/llvm/lib/Support/Unix/Process.inc
+++ b/llvm/lib/Support/Unix/Process.inc
@@ -66,6 +66,12 @@ static std::pair<std::chrono::microseconds, std::chrono::microseconds> getRUsage
#endif
}
+Process::Pid Process::getProcessId() {
+ static_assert(sizeof(Pid) >= sizeof(pid_t),
+ "Process::Pid should be big enough to store pid_t");
+ return Pid(::getpid());
+}
+
// On Cygwin, getpagesize() returns 64k(AllocationGranularity) and
// offset in mmap(3) should be aligned to the AllocationGranularity.
Expected<unsigned> Process::getPageSize() {
@@ -280,7 +286,7 @@ bool Process::FileDescriptorIsDisplayed(int fd) {
#endif
}
-static unsigned getColumns(int FileID) {
+static unsigned getColumns() {
// If COLUMNS is defined in the environment, wrap to that many columns.
if (const char *ColumnsStr = std::getenv("COLUMNS")) {
int Columns = std::atoi(ColumnsStr);
@@ -288,31 +294,23 @@ static unsigned getColumns(int FileID) {
return Columns;
}
- unsigned Columns = 0;
-
-#if defined(HAVE_SYS_IOCTL_H) && defined(HAVE_TERMIOS_H) \
- && !(defined(_XOPEN_SOURCE) || defined(_POSIX_C_SOURCE))
- // Try to determine the width of the terminal.
- struct winsize ws;
- if (ioctl(FileID, TIOCGWINSZ, &ws) == 0)
- Columns = ws.ws_col;
-#endif
-
- return Columns;
+ // We used to call ioctl TIOCGWINSZ to determine the width. It is considered
+ // unuseful.
+ return 0;
}
unsigned Process::StandardOutColumns() {
if (!StandardOutIsDisplayed())
return 0;
- return getColumns(1);
+ return getColumns();
}
unsigned Process::StandardErrColumns() {
if (!StandardErrIsDisplayed())
return 0;
- return getColumns(2);
+ return getColumns();
}
#ifdef HAVE_TERMINFO
diff --git a/llvm/lib/Support/Unix/Program.inc b/llvm/lib/Support/Unix/Program.inc
index 520685a0e987..8f41fc015163 100644
--- a/llvm/lib/Support/Unix/Program.inc
+++ b/llvm/lib/Support/Unix/Program.inc
@@ -15,6 +15,8 @@
//=== is guaranteed to work on *all* UNIX variants.
//===----------------------------------------------------------------------===//
+#include "llvm/Support/Program.h"
+
#include "Unix.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/Config/config.h"
@@ -59,8 +61,7 @@
#endif
#endif
-namespace llvm {
-
+using namespace llvm;
using namespace sys;
ProcessInfo::ProcessInfo() : Pid(0), ReturnCode(0) {}
@@ -70,8 +71,7 @@ ErrorOr<std::string> sys::findProgramByName(StringRef Name,
assert(!Name.empty() && "Must have a name!");
// Use the given path verbatim if it contains any slashes; this matches
// the behavior of sh(1) and friends.
- if (Name.find('/') != StringRef::npos)
- return std::string(Name);
+ if (Name.find('/') != StringRef::npos) return std::string(Name);
SmallVector<StringRef, 16> EnvironmentPaths;
if (Paths.empty())
@@ -88,7 +88,7 @@ ErrorOr<std::string> sys::findProgramByName(StringRef Name,
SmallString<128> FilePath(Path);
sys::path::append(FilePath, Name);
if (sys::fs::can_execute(FilePath.c_str()))
- return std::string(FilePath.str()); // Found the executable!
+ return std::string(FilePath.str()); // Found the executable!
}
return errc::no_such_file_or_directory;
}
@@ -101,7 +101,7 @@ static bool RedirectIO(Optional<StringRef> Path, int FD, std::string* ErrMsg) {
// Redirect empty paths to /dev/null
File = "/dev/null";
else
- File = *Path;
+ File = std::string(*Path);
// Open the file
int InFD = open(File.c_str(), FD == 0 ? O_RDONLY : O_WRONLY|O_CREAT, 0666);
@@ -162,8 +162,6 @@ static void SetMemoryLimits(unsigned size) {
#endif
}
-}
-
static std::vector<const char *>
toNullTerminatedCStringArray(ArrayRef<StringRef> Strings, StringSaver &Saver) {
std::vector<const char *> Result;
@@ -213,7 +211,7 @@ static bool Execute(ProcessInfo &PI, StringRef Program,
std::string *RedirectsStr[3] = {nullptr, nullptr, nullptr};
for (int I = 0; I < 3; ++I) {
if (Redirects[I]) {
- RedirectsStorage[I] = *Redirects[I];
+ RedirectsStorage[I] = std::string(*Redirects[I]);
RedirectsStr[I] = &RedirectsStorage[I];
}
}
@@ -304,7 +302,7 @@ static bool Execute(ProcessInfo &PI, StringRef Program,
}
// Execute!
- std::string PathStr = Program;
+ std::string PathStr = std::string(Program);
if (Envp != nullptr)
execve(PathStr.c_str(), const_cast<char **>(Argv),
const_cast<char **>(Envp));
@@ -331,9 +329,54 @@ static bool Execute(ProcessInfo &PI, StringRef Program,
}
namespace llvm {
+namespace sys {
+
+#ifndef _AIX
+using ::wait4;
+#else
+static pid_t (wait4)(pid_t pid, int *status, int options, struct rusage *usage);
+#endif
-ProcessInfo sys::Wait(const ProcessInfo &PI, unsigned SecondsToWait,
- bool WaitUntilTerminates, std::string *ErrMsg) {
+} // namespace sys
+} // namespace llvm
+
+#ifdef _AIX
+#ifndef _ALL_SOURCE
+extern "C" pid_t (wait4)(pid_t pid, int *status, int options,
+ struct rusage *usage);
+#endif
+pid_t (llvm::sys::wait4)(pid_t pid, int *status, int options,
+ struct rusage *usage) {
+ assert(pid > 0 && "Only expecting to handle actual PID values!");
+ assert((options & ~WNOHANG) == 0 && "Expecting WNOHANG at most!");
+ assert(usage && "Expecting usage collection!");
+
+ // AIX wait4 does not work well with WNOHANG.
+ if (!(options & WNOHANG))
+ return ::wait4(pid, status, options, usage);
+
+ // For WNOHANG, we use waitid (which supports WNOWAIT) until the child process
+ // has terminated.
+ siginfo_t WaitIdInfo;
+ WaitIdInfo.si_pid = 0;
+ int WaitIdRetVal =
+ waitid(P_PID, pid, &WaitIdInfo, WNOWAIT | WEXITED | options);
+
+ if (WaitIdRetVal == -1 || WaitIdInfo.si_pid == 0)
+ return WaitIdRetVal;
+
+ assert(WaitIdInfo.si_pid == pid);
+
+ // The child has already terminated, so a blocking wait on it is okay in the
+ // absence of indiscriminate `wait` calls from the current process (which
+ // would cause the call here to fail with ECHILD).
+ return ::wait4(pid, status, options & ~WNOHANG, usage);
+}
+#endif
+
+ProcessInfo llvm::sys::Wait(const ProcessInfo &PI, unsigned SecondsToWait,
+ bool WaitUntilTerminates, std::string *ErrMsg,
+ Optional<ProcessStatistics> *ProcStat) {
struct sigaction Act, Old;
assert(PI.Pid && "invalid pid to wait on, process not started?");
@@ -349,6 +392,7 @@ ProcessInfo sys::Wait(const ProcessInfo &PI, unsigned SecondsToWait,
Act.sa_handler = TimeOutHandler;
sigemptyset(&Act.sa_mask);
sigaction(SIGALRM, &Act, &Old);
+ // FIXME The alarm signal may be delivered to another thread.
alarm(SecondsToWait);
} else if (SecondsToWait == 0)
WaitPidOptions = WNOHANG;
@@ -356,9 +400,12 @@ ProcessInfo sys::Wait(const ProcessInfo &PI, unsigned SecondsToWait,
// Parent process: Wait for the child process to terminate.
int status;
ProcessInfo WaitResult;
+ rusage Info;
+ if (ProcStat)
+ ProcStat->reset();
do {
- WaitResult.Pid = waitpid(ChildPid, &status, WaitPidOptions);
+ WaitResult.Pid = sys::wait4(ChildPid, &status, WaitPidOptions, &Info);
} while (WaitUntilTerminates && WaitResult.Pid == -1 && errno == EINTR);
if (WaitResult.Pid != PI.Pid) {
@@ -375,6 +422,8 @@ ProcessInfo sys::Wait(const ProcessInfo &PI, unsigned SecondsToWait,
sigaction(SIGALRM, &Old, nullptr);
// Wait for child to die
+ // FIXME This could grab some other child process out from another
+ // waiting thread and then leave a zombie anyway.
if (wait(&status) != ChildPid)
MakeErrMsg(ErrMsg, "Child timed out but wouldn't die");
else
@@ -396,6 +445,13 @@ ProcessInfo sys::Wait(const ProcessInfo &PI, unsigned SecondsToWait,
sigaction(SIGALRM, &Old, nullptr);
}
+ if (ProcStat) {
+ std::chrono::microseconds UserT = toDuration(Info.ru_utime);
+ std::chrono::microseconds KernelT = toDuration(Info.ru_stime);
+ uint64_t PeakMemory = static_cast<uint64_t>(Info.ru_maxrss);
+ *ProcStat = ProcessStatistics{UserT + KernelT, UserT, PeakMemory};
+ }
+
// Return the proper exit status. Detect error conditions
// so we can return -1 for them and set ErrMsg informatively.
int result = 0;
@@ -430,12 +486,12 @@ ProcessInfo sys::Wait(const ProcessInfo &PI, unsigned SecondsToWait,
return WaitResult;
}
-std::error_code sys::ChangeStdinToBinary() {
+std::error_code llvm::sys::ChangeStdinToBinary() {
// Do nothing, as Unix doesn't differentiate between text and binary.
return std::error_code();
}
-std::error_code sys::ChangeStdoutToBinary() {
+std::error_code llvm::sys::ChangeStdoutToBinary() {
// Do nothing, as Unix doesn't differentiate between text and binary.
return std::error_code();
}
@@ -497,4 +553,3 @@ bool llvm::sys::commandLineFitsWithinSystemLimits(StringRef Program,
return true;
}
-}
diff --git a/llvm/lib/Support/Unix/Threading.inc b/llvm/lib/Support/Unix/Threading.inc
index afb887fc1096..2d0aacabf092 100644
--- a/llvm/lib/Support/Unix/Threading.inc
+++ b/llvm/lib/Support/Unix/Threading.inc
@@ -37,7 +37,12 @@
#include <lwp.h> // For _lwp_self()
#endif
+#if defined(__OpenBSD__)
+#include <unistd.h> // For getthrid()
+#endif
+
#if defined(__linux__)
+#include <sched.h> // For sched_getaffinity
#include <sys/syscall.h> // For syscall codes
#include <unistd.h> // For syscall()
#endif
@@ -89,6 +94,10 @@ llvm_execute_on_thread_impl(void *(*ThreadFunc)(void *), void *Arg,
if ((errnum = ::pthread_join(Thread, nullptr)) != 0) {
ReportErrnumFatal("pthread_join failed", errnum);
}
+ } else if (JP == JoiningPolicy::Detach) {
+ if ((errnum = ::pthread_detach(Thread)) != 0) {
+ ReportErrnumFatal("pthread_detach failed", errnum);
+ }
}
}
@@ -104,6 +113,8 @@ uint64_t llvm::get_threadid() {
return uint64_t(pthread_getthreadid_np());
#elif defined(__NetBSD__)
return uint64_t(_lwp_self());
+#elif defined(__OpenBSD__)
+ return uint64_t(getthrid());
#elif defined(__ANDROID__)
return uint64_t(gettid());
#elif defined(__linux__)
@@ -267,3 +278,27 @@ SetThreadPriorityResult llvm::set_thread_priority(ThreadPriority Priority) {
#endif
return SetThreadPriorityResult::FAILURE;
}
+
+#include <thread>
+
+int computeHostNumHardwareThreads() {
+#ifdef __linux__
+ cpu_set_t Set;
+ if (sched_getaffinity(0, sizeof(Set), &Set) == 0)
+ return CPU_COUNT(&Set);
+#endif
+ // Guard against std::thread::hardware_concurrency() returning 0.
+ if (unsigned Val = std::thread::hardware_concurrency())
+ return Val;
+ return 1;
+}
+
+void llvm::ThreadPoolStrategy::apply_thread_strategy(
+ unsigned ThreadPoolNum) const {}
+
+llvm::BitVector llvm::get_thread_affinity_mask() {
+ // FIXME: Implement
+ llvm_unreachable("Not implemented!");
+}
+
+unsigned llvm::get_cpus() { return 1; }
diff --git a/llvm/lib/Support/Unix/Unix.h b/llvm/lib/Support/Unix/Unix.h
index 1fc9a414f749..60929139598b 100644
--- a/llvm/lib/Support/Unix/Unix.h
+++ b/llvm/lib/Support/Unix/Unix.h
@@ -36,10 +36,6 @@
#include <unistd.h>
#endif
-#ifdef HAVE_SYS_PARAM_H
-#include <sys/param.h>
-#endif
-
#ifdef HAVE_SYS_TIME_H
# include <sys/time.h>
#endif