diff options
Diffstat (limited to 'llvm/lib/Support/Unix')
-rw-r--r-- | llvm/lib/Support/Unix/Host.inc | 2 | ||||
-rw-r--r-- | llvm/lib/Support/Unix/Memory.inc | 1 | ||||
-rw-r--r-- | llvm/lib/Support/Unix/Path.inc | 111 | ||||
-rw-r--r-- | llvm/lib/Support/Unix/Process.inc | 26 | ||||
-rw-r--r-- | llvm/lib/Support/Unix/Program.inc | 87 | ||||
-rw-r--r-- | llvm/lib/Support/Unix/Threading.inc | 35 | ||||
-rw-r--r-- | llvm/lib/Support/Unix/Unix.h | 4 |
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 |