diff options
author | John Criswell <criswell@uiuc.edu> | 2005-11-02 18:05:50 +0000 |
---|---|---|
committer | John Criswell <criswell@uiuc.edu> | 2005-11-02 18:05:50 +0000 |
commit | cfa435f79bf39fead32263a8b71c9ae440b55214 (patch) | |
tree | 2f1ef0a4c3fb5549b8bbb014891f92866d46e042 /lib/System/Unix |
Mark these as failing on sparc instead of sparcv9.
The configure script no longer tells us that we're configuring for SparcV9
specifically.
2004-06-17-UnorderedCompares may work on SparcV8, but it's experiental
anyway.
2005-02-20-AggregateSAVEEXPR should fail on any Solaris machine, as Solaris
doesn't provide complex number support.
git-svn-id: https://llvm.org/svn/llvm-project/llvm/branches/release_16@24155 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/System/Unix')
-rw-r--r-- | lib/System/Unix/MappedFile.inc | 154 | ||||
-rw-r--r-- | lib/System/Unix/Memory.inc | 75 | ||||
-rw-r--r-- | lib/System/Unix/Mutex.inc | 46 | ||||
-rw-r--r-- | lib/System/Unix/Path.inc | 747 | ||||
-rw-r--r-- | lib/System/Unix/Process.inc | 159 | ||||
-rw-r--r-- | lib/System/Unix/Program.inc | 225 | ||||
-rw-r--r-- | lib/System/Unix/README.txt | 16 | ||||
-rw-r--r-- | lib/System/Unix/SUS/Process.cpp | 30 | ||||
-rw-r--r-- | lib/System/Unix/Signals.inc | 185 | ||||
-rw-r--r-- | lib/System/Unix/TimeValue.inc | 51 | ||||
-rw-r--r-- | lib/System/Unix/Unix.h | 93 |
11 files changed, 1781 insertions, 0 deletions
diff --git a/lib/System/Unix/MappedFile.inc b/lib/System/Unix/MappedFile.inc new file mode 100644 index 0000000000..508d4235c4 --- /dev/null +++ b/lib/System/Unix/MappedFile.inc @@ -0,0 +1,154 @@ +//===- Unix/MappedFile.cpp - Unix MappedFile Implementation -----*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file was developed by Reid Spencer and is distributed under the +// University of Illinois Open Source License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file provides the generic Unix implementation of the MappedFile concept. +// +//===----------------------------------------------------------------------===// + +//===----------------------------------------------------------------------===// +//=== WARNING: Implementation here must contain only generic UNIX code that +//=== is guaranteed to work on *all* UNIX variants. +//===----------------------------------------------------------------------===// + +#include "Unix.h" +#include "llvm/System/Process.h" + +#ifdef HAVE_FCNTL_H +#include <fcntl.h> +#endif + +#ifdef HAVE_SYS_MMAN_H +#include <sys/mman.h> +#endif + +#ifdef HAVE_SYS_STAT_H +#include <sys/stat.h> +#endif + +namespace llvm { +using namespace sys; + +struct sys::MappedFileInfo { + int fd_; + struct stat sbuf_; +}; + +void MappedFile::initialize() { + if (path_.exists()) { + info_ = new MappedFileInfo; + int mode = 0; + if (options_&READ_ACCESS) + if (options_&WRITE_ACCESS) + mode = O_RDWR; + else + mode = O_RDONLY; + else if (options_&WRITE_ACCESS) + mode = O_WRONLY; + info_->fd_ = ::open(path_.c_str(),mode); + + if (info_->fd_ < 0) { + delete info_; + info_ = 0; + ThrowErrno(std::string("Can't open file: ") + path_.toString()); + } + struct stat sbuf; + if(::fstat(info_->fd_, &info_->sbuf_) < 0) { + ::close(info_->fd_); + delete info_; + info_ = 0; + ThrowErrno(std::string("Can't stat file: ") + path_.toString()); + } + } else { + throw std::string("Can't open file: ") + path_.toString(); + } +} + +void MappedFile::terminate() { + assert(info_ && "MappedFile not initialized"); + if (info_->fd_ >= 0) + ::close(info_->fd_); + delete info_; + info_ = 0; +} + +void MappedFile::unmap() { + assert(info_ && "MappedFile not initialized"); + if (isMapped()) { + if (options_ & WRITE_ACCESS) + ::msync(base_, info_->sbuf_.st_size, MS_SYNC); + ::munmap(base_, info_->sbuf_.st_size); + } +} + +void* MappedFile::map() { + assert(info_ && "MappedFile not initialized"); + if (!isMapped()) { + int prot = PROT_NONE; + int flags = 0; +#ifdef MAP_FILE + flags |= MAP_FILE; +#endif + if (options_ == 0) { + prot = PROT_READ; + flags = MAP_PRIVATE; + } else { + if (options_ & READ_ACCESS) + prot |= PROT_READ; + if (options_ & WRITE_ACCESS) + prot |= PROT_WRITE; + if (options_ & EXEC_ACCESS) + prot |= PROT_EXEC; + if (options_ & SHARED_MAPPING) + flags |= MAP_SHARED; + else + flags |= MAP_PRIVATE; + } + size_t map_size = ((info_->sbuf_.st_size / Process::GetPageSize())+1) * + Process::GetPageSize(); + + base_ = ::mmap(0, map_size, prot, flags, info_->fd_, 0); + if (base_ == MAP_FAILED) + ThrowErrno(std::string("Can't map file:") + path_.toString()); + } + return base_; +} + +size_t MappedFile::size() const { + assert(info_ && "MappedFile not initialized"); + return info_->sbuf_.st_size; +} + +void MappedFile::size(size_t new_size) { + assert(info_ && "MappedFile not initialized"); + + // Take the mapping out of memory + this->unmap(); + + // Adjust the current size to a page boundary + size_t cur_size = ((info_->sbuf_.st_size / Process::GetPageSize())+1) * + Process::GetPageSize(); + + // Adjust the new_size to a page boundary + new_size = ((new_size / Process::GetPageSize())+1) * + Process::GetPageSize(); + + // If the file needs to be extended + if (new_size > cur_size) { + // Ensure we can allocate at least the idodes necessary to handle the + // file size requested. + ::lseek(info_->fd_, new_size, SEEK_SET); + ::write(info_->fd_, "\0", 1); + } + + // Seek to current end of file. + this->map(); +} + +} + diff --git a/lib/System/Unix/Memory.inc b/lib/System/Unix/Memory.inc new file mode 100644 index 0000000000..4475960e11 --- /dev/null +++ b/lib/System/Unix/Memory.inc @@ -0,0 +1,75 @@ +//===- Unix/Memory.cpp - Generic UNIX System Configuration ------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file was developed by Reid Spencer and is distributed under the +// University of Illinois Open Source License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines some functions for various memory management utilities. +// +//===----------------------------------------------------------------------===// + +#include "Unix.h" +#include "llvm/System/Process.h" + +#ifdef HAVE_SYS_MMAN_H +#include <sys/mman.h> +#endif + +namespace llvm { + +/// AllocateRWXMemory - Allocate a slab of memory with read/write/execute +/// permissions. This is typically used for JIT applications where we want +/// to emit code to the memory then jump to it. Getting this type of memory +/// is very OS specific. +/// +MemoryBlock Memory::AllocateRWX(unsigned NumBytes, const MemoryBlock* NearBlock) { + if (NumBytes == 0) return MemoryBlock(); + + long pageSize = Process::GetPageSize(); + unsigned NumPages = (NumBytes+pageSize-1)/pageSize; + + int fd = -1; +#ifdef NEED_DEV_ZERO_FOR_MMAP + static int zero_fd = open("/dev/zero", O_RDWR); + if (zero_fd == -1) { + ThrowErrno("Can't open /dev/zero device"); + } + fd = zero_fd; +#endif + + int flags = MAP_PRIVATE | +#ifdef HAVE_MMAP_ANONYMOUS + MAP_ANONYMOUS +#else + MAP_ANON +#endif + ; + + void* start = NearBlock ? (unsigned char*) NearBlock->base() + NearBlock->size() : 0; + + void *pa = ::mmap(start, pageSize*NumPages, PROT_READ|PROT_WRITE|PROT_EXEC, + flags, fd, 0); + if (pa == MAP_FAILED) { + if (NearBlock) //Try again without a near hint + return AllocateRWX(NumBytes, 0); + else + ThrowErrno("Can't allocate RWX Memory"); + } + MemoryBlock result; + result.Address = pa; + result.Size = NumPages*pageSize; + return result; +} + +void Memory::ReleaseRWX(MemoryBlock& M) { + if (M.Address == 0 || M.Size == 0) return; + if (0 != ::munmap(M.Address, M.Size)) { + ThrowErrno("Can't release RWX Memory"); + } +} + +} + diff --git a/lib/System/Unix/Mutex.inc b/lib/System/Unix/Mutex.inc new file mode 100644 index 0000000000..fa218dbb53 --- /dev/null +++ b/lib/System/Unix/Mutex.inc @@ -0,0 +1,46 @@ +//===- llvm/System/Unix/Mutex.inc - Unix Mutex Implementation ---*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file was developed by Reid Spencer and is distributed under the +// University of Illinois Open Source License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the Unix specific (non-pthread) Mutex class. +// +//===----------------------------------------------------------------------===// + +//===----------------------------------------------------------------------===// +//=== WARNING: Implementation here must contain only generic UNIX code that +//=== is guaranteed to work on *all* UNIX variants. +//===----------------------------------------------------------------------===// + +namespace llvm +{ +using namespace sys; + +Mutex::Mutex( bool recursive) +{ +} + +Mutex::~Mutex() +{ +} + +bool +Mutex::acquire() +{ +} + +bool +Mutex::release() +{ +} + +bool +Mutex::tryacquire( void ) +{ +} + +} diff --git a/lib/System/Unix/Path.inc b/lib/System/Unix/Path.inc new file mode 100644 index 0000000000..2da76e8ad1 --- /dev/null +++ b/lib/System/Unix/Path.inc @@ -0,0 +1,747 @@ +//===- llvm/System/Unix/Path.cpp - Unix Path Implementation -----*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file was developed by Reid Spencer and is distributed under the +// University of Illinois Open Source License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the Unix specific portion of the Path class. +// +//===----------------------------------------------------------------------===// + +//===----------------------------------------------------------------------===// +//=== WARNING: Implementation here must contain only generic UNIX code that +//=== is guaranteed to work on *all* UNIX variants. +//===----------------------------------------------------------------------===// + +#include "llvm/Config/alloca.h" +#include "Unix.h" +#if HAVE_SYS_STAT_H +#include <sys/stat.h> +#endif +#if HAVE_FCNTL_H +#include <fcntl.h> +#endif +#if HAVE_UTIME_H +#include <utime.h> +#endif +#if HAVE_TIME_H +#include <time.h> +#endif +#if HAVE_DIRENT_H +# include <dirent.h> +# define NAMLEN(dirent) strlen((dirent)->d_name) +#else +# define dirent direct +# define NAMLEN(dirent) (dirent)->d_namlen +# if HAVE_SYS_NDIR_H +# include <sys/ndir.h> +# endif +# if HAVE_SYS_DIR_H +# include <sys/dir.h> +# endif +# if HAVE_NDIR_H +# include <ndir.h> +# endif +#endif + +// Put in a hack for Cygwin which falsely reports that the mkdtemp function +// is available when it is not. +#ifdef __CYGWIN__ +# undef HAVE_MKDTEMP +#endif + +namespace { +inline bool lastIsSlash(const std::string& path) { + return !path.empty() && path[path.length() - 1] == '/'; +} + +} + +namespace llvm { +using namespace sys; + +Path::Path(const std::string& unverified_path) : path(unverified_path) { + if (unverified_path.empty()) + return; + if (this->isValid()) + return; + // oops, not valid. + path.clear(); + ThrowErrno(unverified_path + ": path is not valid"); +} + +bool +Path::isValid() const { + // Check some obvious things + if (path.empty()) + return false; + else if (path.length() >= MAXPATHLEN) + return false; + + // Check that the characters are ascii chars + size_t len = path.length(); + unsigned i = 0; + while (i < len && isascii(path[i])) + ++i; + return i >= len; +} + +Path +Path::GetRootDirectory() { + Path result; + result.set("/"); + return result; +} + +Path +Path::GetTemporaryDirectory() { +#if defined(HAVE_MKDTEMP) + // The best way is with mkdtemp but that's not available on many systems, + // Linux and FreeBSD have it. Others probably won't. + char pathname[MAXPATHLEN]; + strcpy(pathname,"/tmp/llvm_XXXXXX"); + if (0 == mkdtemp(pathname)) + ThrowErrno(std::string(pathname) + ": can't create temporary directory"); + Path result; + result.set(pathname); + assert(result.isValid() && "mkdtemp didn't create a valid pathname!"); + return result; +#elif defined(HAVE_MKSTEMP) + // If no mkdtemp is available, mkstemp can be used to create a temporary file + // which is then removed and created as a directory. We prefer this over + // mktemp because of mktemp's inherent security and threading risks. We still + // have a slight race condition from the time the temporary file is created to + // the time it is re-created as a directoy. + char pathname[MAXPATHLEN]; + strcpy(pathname, "/tmp/llvm_XXXXXX"); + int fd = 0; + if (-1 == (fd = mkstemp(pathname))) + ThrowErrno(std::string(pathname) + ": can't create temporary directory"); + ::close(fd); + ::unlink(pathname); // start race condition, ignore errors + if (-1 == ::mkdir(pathname, S_IRWXU)) // end race condition + ThrowErrno(std::string(pathname) + ": can't create temporary directory"); + Path result; + result.set(pathname); + assert(result.isValid() && "mkstemp didn't create a valid pathname!"); + return result; +#elif defined(HAVE_MKTEMP) + // If a system doesn't have mkdtemp(3) or mkstemp(3) but it does have + // mktemp(3) then we'll assume that system (e.g. AIX) has a reasonable + // implementation of mktemp(3) and doesn't follow BSD 4.3's lead of replacing + // the XXXXXX with the pid of the process and a letter. That leads to only + // twenty six temporary files that can be generated. + char pathname[MAXPATHLEN]; + strcpy(pathname, "/tmp/llvm_XXXXXX"); + char *TmpName = ::mktemp(pathname); + if (TmpName == 0) + ThrowErrno(std::string(TmpName) + ": can't create unique directory name"); + if (-1 == ::mkdir(TmpName, S_IRWXU)) + ThrowErrno(std::string(TmpName) + ": can't create temporary directory"); + Path result; + result.set(TmpName); + assert(result.isValid() && "mktemp didn't create a valid pathname!"); + return result; +#else + // This is the worst case implementation. tempnam(3) leaks memory unless its + // on an SVID2 (or later) system. On BSD 4.3 it leaks. tmpnam(3) has thread + // issues. The mktemp(3) function doesn't have enough variability in the + // temporary name generated. So, we provide our own implementation that + // increments an integer from a random number seeded by the current time. This + // should be sufficiently unique that we don't have many collisions between + // processes. Generally LLVM processes don't run very long and don't use very + // many temporary files so this shouldn't be a big issue for LLVM. + static time_t num = ::time(0); + char pathname[MAXPATHLEN]; + do { + num++; + sprintf(pathname, "/tmp/llvm_%010u", unsigned(num)); + } while ( 0 == access(pathname, F_OK ) ); + if (-1 == ::mkdir(pathname, S_IRWXU)) + ThrowErrno(std::string(pathname) + ": can't create temporary directory"); + Path result; + result.set(pathname); + assert(result.isValid() && "mkstemp didn't create a valid pathname!"); + return result; +#endif +} + +static void getPathList(const char*path, std::vector<sys::Path>& Paths) { + const char* at = path; + const char* delim = strchr(at, ':'); + Path tmpPath; + while( delim != 0 ) { + std::string tmp(at, size_t(delim-at)); + if (tmpPath.set(tmp)) + if (tmpPath.canRead()) + Paths.push_back(tmpPath); + at = delim + 1; + delim = strchr(at, ':'); + } + if (*at != 0) + if (tmpPath.set(std::string(at))) + if (tmpPath.canRead()) + Paths.push_back(tmpPath); + +} + +void +Path::GetSystemLibraryPaths(std::vector<sys::Path>& Paths) { +#ifdef LTDL_SHLIBPATH_VAR + char* env_var = getenv(LTDL_SHLIBPATH_VAR); + if (env_var != 0) { + getPathList(env_var,Paths); + } +#endif + // FIXME: Should this look at LD_LIBRARY_PATH too? + Paths.push_back(sys::Path("/usr/local/lib/")); + Paths.push_back(sys::Path("/usr/X11R6/lib/")); + Paths.push_back(sys::Path("/usr/lib/")); + Paths.push_back(sys::Path("/lib/")); +} + +void +Path::GetBytecodeLibraryPaths(std::vector<sys::Path>& Paths) { + char * env_var = getenv("LLVM_LIB_SEARCH_PATH"); + if (env_var != 0) { + getPathList(env_var,Paths); + } +#ifdef LLVM_LIBDIR + { + Path tmpPath; + if (tmpPath.set(LLVM_LIBDIR)) + if (tmpPath.canRead()) + Paths.push_back(tmpPath); + } +#endif + GetSystemLibraryPaths(Paths); +} + +Path +Path::GetLLVMDefaultConfigDir() { + return Path("/etc/llvm/"); +} + +Path +Path::GetUserHomeDirectory() { + const char* home = getenv("HOME"); + if (home) { + Path result; + if (result.set(home)) + return result; + } + return GetRootDirectory(); +} + +bool +Path::isFile() const { + if (!exists()) + return false; + struct stat buf; + if (0 != stat(path.c_str(), &buf)) { + ThrowErrno(path + ": can't determine type of path object: "); + } + return S_ISREG(buf.st_mode); +} + +bool +Path::isDirectory() const { + if (!exists()) + return false; + struct stat buf; + if (0 != stat(path.c_str(), &buf)) { + ThrowErrno(path + ": can't determine type of path object: "); + } + return S_ISDIR(buf.st_mode); +} + +bool +Path::isHidden() const { + if (!exists()) + return false; + size_t slash = path.rfind('/'); + return (slash != std::string::npos && + slash < path.length()-1 && + path[slash+1] == '.') || + (!path.empty() && slash == std::string::npos && path[0] == '.'); +} + +std::string +Path::getBasename() const { + // Find the last slash + size_t slash = path.rfind('/'); + if (slash == std::string::npos) + slash = 0; + else + slash++; + + size_t dot = path.rfind('.'); + if (dot == std::string::npos || dot < slash) + return path.substr(slash); + else + return path.substr(slash, dot - slash); +} + +bool Path::hasMagicNumber(const std::string &Magic) const { + if (!isFile()) + return false; + size_t len = Magic.size(); + assert(len < 1024 && "Request for magic string too long"); + char* buf = (char*) alloca(1 + len); + int fd = ::open(path.c_str(),O_RDONLY); + if (fd < 0) + return false; + size_t read_len = ::read(fd, buf, len); + close(fd); + if (len != read_len) + return false; + buf[len] = '\0'; + return Magic == buf; +} + +bool Path::getMagicNumber(std::string& Magic, unsigned len) const { + if (!isFile()) + return false; + assert(len < 1024 && "Request for magic string too long"); + char* buf = (char*) alloca(1 + len); + int fd = ::open(path.c_str(),O_RDONLY); + if (fd < 0) + return false; + ssize_t bytes_read = ::read(fd, buf, len); + ::close(fd); + if (ssize_t(len) != bytes_read) { + Magic.clear(); + return false; + } + Magic.assign(buf,len); + return true; +} + +bool +Path::isBytecodeFile() const { + if (!isFile()) + return false; + char buffer[ 4]; + buffer[0] = 0; + int fd = ::open(path.c_str(),O_RDONLY); + if (fd < 0) + return false; + ssize_t bytes_read = ::read(fd, buffer, 4); + ::close(fd); + if (4 != bytes_read) + return false; + + return (buffer[0] == 'l' && buffer[1] == 'l' && buffer[2] == 'v' && + (buffer[3] == 'c' || buffer[3] == 'm')); +} + +bool +Path::exists() const { + return 0 == access(path.c_str(), F_OK ); +} + +bool +Path::canRead() const { + return 0 == access(path.c_str(), F_OK | R_OK ); +} + +bool +Path::canWrite() const { + return 0 == access(path.c_str(), F_OK | W_OK ); +} + +bool +Path::canExecute() const { + if (0 != access(path.c_str(), R_OK | X_OK )) + return false; + struct stat st; + int r = stat(path.c_str(), &st); + if (r != 0 || !S_ISREG(st.st_mode)) + return false; + return true; +} + +std::string +Path::getLast() const { + // Find the last slash + size_t pos = path.rfind('/'); + + // Handle the corner cases + if (pos == std::string::npos) + return path; + + // If the last character is a slash + if (pos == path.length()-1) { + // Find the second to last slash + size_t pos2 = path.rfind('/', pos-1); + if (pos2 == std::string::npos) + return path.substr(0,pos); + else + return path.substr(pos2+1,pos-pos2-1); + } + // Return everything after the last slash + return path.substr(pos+1); +} + +void +Path::getStatusInfo(StatusInfo& info) const { + struct stat buf; + if (0 != stat(path.c_str(), &buf)) { + ThrowErrno(path + ": can't determine type of path object: "); + } + info.fileSize = buf.st_size; + info.modTime.fromEpochTime(buf.st_mtime); + info.mode = buf.st_mode; + info.user = buf.st_uid; + info.group = buf.st_gid; + info.isDir = S_ISDIR(buf.st_mode); +} + +static bool AddPermissionBits(const std::string& Filename, int bits) { + // Get the umask value from the operating system. We want to use it + // when changing the file's permissions. Since calling umask() sets + // the umask and returns its old value, we must call it a second + // time to reset it to the user's preference. + int mask = umask(0777); // The arg. to umask is arbitrary. + umask(mask); // Restore the umask. + + // Get the file's current mode. + struct stat st; + if ((stat(Filename.c_str(), &st)) == -1) + return false; + + // Change the file to have whichever permissions bits from 'bits' + // that the umask would not disable. + if ((chmod(Filename.c_str(), (st.st_mode | (bits & ~mask)))) == -1) + return false; + + return true; +} + +void Path::makeReadableOnDisk() { + if (!AddPermissionBits(path,0444)) + ThrowErrno(path + ": can't make file readable"); +} + +void Path::makeWriteableOnDisk() { + if (!AddPermissionBits(path,0222)) + ThrowErrno(path + ": can't make file writable"); +} + +void Path::makeExecutableOnDisk() { + if (!AddPermissionBits(path,0111)) + ThrowErrno(path + ": can't make file executable"); +} + +bool +Path::getDirectoryContents(std::set<Path>& result) const { + if (!isDirectory()) + return false; + DIR* direntries = ::opendir(path.c_str()); + if (direntries == 0) + ThrowErrno(path + ": can't open directory"); + + std::string dirPath = path; + if (!lastIsSlash(dirPath)) + dirPath += '/'; + + result.clear(); + struct dirent* de = ::readdir(direntries); + for ( ; de != 0; de = ::readdir(direntries)) { + if (de->d_name[0] != '.') { + Path aPath(dirPath + (const char*)de->d_name); + struct stat buf; + if (0 != stat(aPath.path.c_str(), &buf)) { + int stat_errno = errno; + struct stat st; + if (0 == lstat(aPath.path.c_str(), &st) && S_ISLNK(st.st_mode)) + continue; // dangling symlink -- ignore + ThrowErrno(aPath.path + + ": can't determine file object type", stat_errno); + } + result.insert(aPath); + } + } + + closedir(direntries); + return true; +} + +bool +Path::set(const std::string& a_path) { + if (a_path.empty()) + return false; + std::string save(path); + path = a_path; + if (!isValid()) { + path = save; + return false; + } + return true; +} + +bool +Path::appendComponent(const std::string& name) { + if (name.empty()) + return false; + std::string save(path); + if (!lastIsSlash(path)) + path += '/'; + path += name; + if (!isValid()) { + path = save; + return false; + } + return true; +} + +bool +Path::eraseComponent() { + size_t slashpos = path.rfind('/',path.size()); + if (slashpos == 0 || slashpos == std::string::npos) { + path.erase(); + return true; + } + if (slashpos == path.size() - 1) + slashpos = path.rfind('/',slashpos-1); + if (slashpos == std::string::npos) { + path.erase(); + return true; + } + path.erase(slashpos); + return true; +} + +bool +Path::appendSuffix(const std::string& suffix) { + std::string save(path); + path.append("."); + path.append(suffix); + if (!isValid()) { + path = save; + return false; + } + return true; +} + +bool +Path::eraseSuffix() { + std::string save = path; + size_t dotpos = path.rfind('.',path.size()); + size_t slashpos = path.rfind('/',path.size()); + if (dotpos != std::string::npos) { + if (slashpos == std::string::npos || dotpos > slashpos+1) { + path.erase(dotpos, path.size()-dotpos); + return true; + } + } + if (!isValid()) + path = save; + return false; +} + +bool +Path::createDirectoryOnDisk( bool create_parents) { + // Get a writeable copy of the path name + char pathname[MAXPATHLEN]; + path.copy(pathname,MAXPATHLEN); + + // Null-terminate the last component + int lastchar = path.length() - 1 ; + if (pathname[lastchar] == '/') + pathname[lastchar] = 0; + else + pathname[lastchar+1] = 0; + + // If we're supposed to create intermediate directories + if ( create_parents ) { + // Find the end of the initial name component + char * next = strchr(pathname,'/'); + if ( pathname[0] == '/') + next = strchr(&pathname[1],'/'); + + // Loop through the directory components until we're done + while ( next != 0 ) { + *next = 0; + if (0 != access(pathname, F_OK | R_OK | W_OK)) + if (0 != mkdir(pathname, S_IRWXU | S_IRWXG)) + ThrowErrno(std::string(pathname) + ": can't create directory"); + char* save = next; + next = strchr(next+1,'/'); + *save = '/'; + } + } + + if (0 != access(pathname, F_OK | R_OK)) + if (0 != mkdir(pathname, S_IRWXU | S_IRWXG)) + ThrowErrno(std::string(pathname) + ": can't create directory"); + return true; +} + +bool +Path::createFileOnDisk() { + // Create the file + int fd = ::creat(path.c_str(), S_IRUSR | S_IWUSR); + if (fd < 0) + ThrowErrno(path + ": can't create file"); + ::close(fd); + + return true; +} + +bool +Path::createTemporaryFileOnDisk(bool reuse_current) { + // Make this into a unique file name + makeUnique( reuse_current ); + + // create the file + int outFile = ::open(path.c_str(), O_WRONLY|O_CREAT|O_TRUNC, 0666); + if (outFile != -1) { + ::close(outFile); + return true; + } + return false; +} + +bool +Path::eraseFromDisk(bool remove_contents) const { + // Make sure we're dealing with a directory + if (isFile()) { + if (0 != unlink(path.c_str())) + ThrowErrno(path + ": can't destroy file"); + } else if (isDirectory()) { + if (remove_contents) { + // Recursively descend the directory to remove its content + std::string cmd("/bin/rm -rf "); + cmd += path; + system(cmd.c_str()); + } else { + // Otherwise, try to just remove the one directory + char pathname[MAXPATHLEN]; + path.copy(pathname,MAXPATHLEN); + int lastchar = path.length() - 1 ; + if (pathname[lastchar] == '/') + pathname[lastchar] = 0; + else + pathname[lastchar+1] = 0; + if ( 0 != rmdir(pathname)) + ThrowErrno(std::string(pathname) + ": can't destroy directory"); + } + } + else + return false; + return true; +} + +bool +Path::renamePathOnDisk(const Path& newName) { + if (0 != ::rename(path.c_str(), newName.c_str())) + ThrowErrno(std::string("can't rename '") + path + "' as '" + + newName.toString() + "' "); + return true; +} + +bool +Path::setStatusInfoOnDisk(const StatusInfo& si) const { + struct utimbuf utb; + utb.actime = si.modTime.toPosixTime(); + utb.modtime = utb.actime; + if (0 != ::utime(path.c_str(),&utb)) + ThrowErrno(path + ": can't set file modification time"); + if (0 != ::chmod(path.c_str(),si.mode)) + ThrowErrno(path + ": can't set mode"); + return true; +} + +void +sys::CopyFile(const sys::Path &Dest, const sys::Path &Src) { + int inFile = -1; + int outFile = -1; + try { + inFile = ::open(Src.c_str(), O_RDONLY); + if (inFile == -1) + ThrowErrno(Src.toString() + ": can't open source file to copy: "); + + outFile = ::open(Dest.c_str(), O_WRONLY|O_CREAT, 0666); + if (outFile == -1) + ThrowErrno(Dest.toString() +": can't create destination file for copy: "); + + char Buffer[16*1024]; + while (ssize_t Amt = ::read(inFile, Buffer, 16*1024)) { + if (Amt == -1) { + if (errno != EINTR && errno != EAGAIN) + ThrowErrno(Src.toString()+": can't read source file: "); + } else { + char *BufPtr = Buffer; + while (Amt) { + ssize_t AmtWritten = ::write(outFile, BufPtr, Amt); + if (AmtWritten == -1) { + if (errno != EINTR && errno != EAGAIN) + ThrowErrno(Dest.toString() + ": can't write destination file: "); + } else { + Amt -= AmtWritten; + BufPtr += AmtWritten; + } + } + } + } + ::close(inFile); + ::close(outFile); + } catch (...) { + if (inFile != -1) + ::close(inFile); + if (outFile != -1) + ::close(outFile); + throw; + } +} + +void +Path::makeUnique(bool reuse_current) { + if (reuse_current && !exists()) + return; // File doesn't exist already, just use it! + + // Append an XXXXXX pattern to the end of the file for use with mkstemp, + // mktemp or our own implementation. + char *FNBuffer = (char*) alloca(path.size()+8); + path.copy(FNBuffer,path.size()); + strcpy(FNBuffer+path.size(), "-XXXXXX"); + +#if defined(HAVE_MKSTEMP) + int TempFD; + if ((TempFD = mkstemp(FNBuffer)) == -1) { + ThrowErrno(path + ": can't make unique filename"); + } + + // We don't need to hold the temp file descriptor... we will trust that no one + // will overwrite/delete the file before we can open it again. + close(TempFD); + + // Save the name + path = FNBuffer; +#elif defined(HAVE_MKTEMP) + // If we don't have mkstemp, use the old and obsolete mktemp function. + if (mktemp(FNBuffer) == 0) { + ThrowErrno(path + ": can't make unique filename"); + } + + // Save the name + path = FNBuffer; +#else + // Okay, looks like we have to do it all by our lonesome. + static unsigned FCounter = 0; + unsigned offset = path.size() + 1; + while ( FCounter < 999999 && exists()) { + sprintf(FNBuffer+offset,"%06u",++FCounter); + path = FNBuffer; + } + if (FCounter > 999999) + throw std::string(path + ": can't make unique filename: too many files"); +#endif + +} +} + diff --git a/lib/System/Unix/Process.inc b/lib/System/Unix/Process.inc new file mode 100644 index 0000000000..e5a93786aa --- /dev/null +++ b/lib/System/Unix/Process.inc @@ -0,0 +1,159 @@ +//===- Unix/Process.cpp - Unix Process Implementation --------- -*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file was developed by Reid Spencer and is distributed under the +// University of Illinois Open Source License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file provides the generic Unix implementation of the Process class. +// +//===----------------------------------------------------------------------===// + +#include "Unix.h" +#ifdef HAVE_SYS_TIME_H +#include <sys/time.h> +#endif +#ifdef HAVE_SYS_RESOURCE_H +#include <sys/resource.h> +#endif +#ifdef HAVE_MALLOC_H +#include <malloc.h> +#endif + +//===----------------------------------------------------------------------===// +//=== WARNING: Implementation here must contain only generic UNIX code that +//=== is guaranteed to work on *all* UNIX variants. +//===----------------------------------------------------------------------===// + +namespace llvm { +using namespace sys; + +unsigned +Process::GetPageSize() +{ +#if defined(HAVE_GETPAGESIZE) + static const int page_size = ::getpagesize(); +#elif defined(HAVE_SYSCONF) + static long page_size = ::sysconf(_SC_PAGE_SIZE); +#else +#warning Cannot get the page size on this machine +#endif + return static_cast<unsigned>(page_size); +} + +#if defined(HAVE_SBRK) +static char* som = reinterpret_cast<char*>(::sbrk(0)); +#endif + +size_t +Process::GetMallocUsage() +{ +#if defined(HAVE_MALLINFO) + struct mallinfo mi; + mi = ::mallinfo(); + return mi.uordblks; +#elif defined(HAVE_SBRK) + // Note this is only an approximation and more closely resembles + // the value returned by mallinfo in the arena field. + char * eom = (char*) sbrk(0); + if (eom != ((char*)-1) && som != ((char*)-1)) + return eom - som; + else + return 0; +#else +#warning Cannot get malloc info on this platform + return 0; +#endif +} + +size_t +Process::GetTotalMemoryUsage() +{ +#if defined(HAVE_MALLINFO) + struct mallinfo mi = ::mallinfo(); + return mi.uordblks + mi.hblkhd; +#elif defined(HAVE_GETRUSAGE) + struct rusage usage; + ::getrusage(RUSAGE_SELF, &usage); + return usage.ru_maxrss; +#else +#warning Cannot get total memory size on this platform + return 0; +#endif +} + +void +Process::GetTimeUsage(TimeValue& elapsed, TimeValue& user_time, + TimeValue& sys_time) +{ + elapsed = TimeValue::now(); +#if defined(HAVE_GETRUSAGE) + struct rusage usage; + ::getrusage(RUSAGE_SELF, &usage); + user_time = TimeValue( + static_cast<TimeValue::SecondsType>( usage.ru_utime.tv_sec ), + static_cast<TimeValue::NanoSecondsType>( usage.ru_utime.tv_usec * + TimeValue::NANOSECONDS_PER_MICROSECOND ) ); + sys_time = TimeValue( + static_cast<TimeValue::SecondsType>( usage.ru_stime.tv_sec ), + static_cast<TimeValue::NanoSecondsType>( usage.ru_stime.tv_usec * + TimeValue::NANOSECONDS_PER_MICROSECOND ) ); +#else +#warning Cannot get usage times on this platform + user_time.seconds(0); + user_time.microseconds(0); + sys_time.seconds(0); + sys_time.microseconds(0); +#endif +} + +int Process::GetCurrentUserId() +{ + return getuid(); +} + +int Process::GetCurrentGroupId() +{ + return getgid(); +} + +// Some LLVM programs such as bugpoint produce core files as a normal part of +// their operation. To prevent the disk from filling up, this function +// does what's necessary to prevent their generation. +void Process::PreventCoreFiles() { +#if HAVE_SETRLIMIT + struct rlimit rlim; + rlim.rlim_cur = rlim.rlim_max = 0; + int res = setrlimit(RLIMIT_CORE, &rlim); + if (res != 0) + ThrowErrno("Can't prevent core file generation"); +#endif +} + +bool Process::StandardInIsUserInput() { +#if HAVE_ISATTY + return isatty(0); +#endif + // If we don't have isatty, just return false. + return false; +} + +bool Process::StandardOutIsDisplayed() { +#if HAVE_ISATTY + return isatty(1); +#endif + // If we don't have isatty, just return false. + return false; +} + +bool Process::StandardErrIsDisplayed() { +#if HAVE_ISATTY + return isatty(2); +#endif + // If we don't have isatty, just return false. + return false; +} + +} diff --git a/lib/System/Unix/Program.inc b/lib/System/Unix/Program.inc new file mode 100644 index 0000000000..8aa0705726 --- /dev/null +++ b/lib/System/Unix/Program.inc @@ -0,0 +1,225 @@ +//===- llvm/System/Unix/Program.cpp -----------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file was developed by Reid Spencer and is distributed under the +// University of Illinois Open Source License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the Unix specific portion of the Program class. +// +//===----------------------------------------------------------------------===// + +//===----------------------------------------------------------------------===// +//=== WARNING: Implementation here must contain only generic UNIX code that +//=== is guaranteed to work on *all* UNIX variants. +//===----------------------------------------------------------------------===// + +#include <llvm/Config/config.h> +#include "Unix.h" +#include <iostream> +#if HAVE_SYS_STAT_H +#include <sys/stat.h> +#endif +#if HAVE_SIGNAL_H +#include <signal.h> +#endif +#if HAVE_FCNTL_H +#include <fcntl.h> +#endif + +extern char** environ; + +namespace llvm { +using namespace sys; + +// This function just uses the PATH environment variable to find the program. +Path +Program::FindProgramByName(const std::string& progName) { + + // Check some degenerate cases + if (progName.length() == 0) // no program + return Path(); + Path temp; + if (!temp.set(progName)) // invalid name + return Path(); + // FIXME: have to check for absolute filename - we cannot assume anything + // about "." being in $PATH + if (temp.canExecute()) // already executable as is + return temp; + + // At this point, the file name is valid and its not executable + + // Get the path. If its empty, we can't do anything to find it. + const char *PathStr = getenv("PATH"); + if (PathStr == 0) + return Path(); + + // Now we have a colon separated list of directories to search; try them. + unsigned PathLen = strlen(PathStr); + while (PathLen) { + // Find the first colon... + const char *Colon = std::find(PathStr, PathStr+PathLen, ':'); + + // Check to see if this first directory contains the executable... + Path FilePath; + if (FilePath.set(std::string(PathStr,Colon))) { + FilePath.appendComponent(progName); + if (FilePath.canExecute()) + return FilePath; // Found the executable! + } + + // Nope it wasn't in this directory, check the next path in the list! + PathLen -= Colon-PathStr; + PathStr = Colon; + + // Advance past duplicate colons + while (*PathStr == ':') { + PathStr++; + PathLen--; + } + } + return Path(); +} + +static void RedirectFD(const std::string &File, int FD) { + if (File.empty()) return; // Noop + + // Open the file + int InFD = open(File.c_str(), FD == 0 ? O_RDONLY : O_WRONLY|O_CREAT, 0666); + if (InFD == -1) { + ThrowErrno("Cannot open file '" + File + "' for " + + (FD == 0 ? "input" : "output") + "!\n"); + } + + dup2(InFD, FD); // Install it as the requested FD + close(InFD); // Close the original FD +} + +static bool Timeout = false; +static void TimeOutHandler(int Sig) { + Timeout = true; +} + +int +Program::ExecuteAndWait(const Path& path, + const char** args, + const char** envp, + const Path** redirects, + unsigned secondsToWait +) { + if (!path.canExecute()) + throw path.toString() + " is not executable"; + +#ifdef HAVE_SYS_WAIT_H + // Create a child process. + int child = fork(); + switch (child) { + // An error occured: Return to the caller. + case -1: + ThrowErrno(std::string("Couldn't execute program '") + path.toString() + + "'"); + break; + + // Child process: Execute the program. + case 0: { + // Redirect file descriptors... + if (redirects) { + if (redirects[0]) + if (redirects[0]->isEmpty()) + RedirectFD("/dev/null",0); + else + RedirectFD(redirects[0]->toString(), 0); + if (redirects[1]) + if (redirects[1]->isEmpty()) + RedirectFD("/dev/null",1); + else + RedirectFD(redirects[1]->toString(), 1); + if (redirects[1] && redirects[2] && + *(redirects[1]) != *(redirects[2])) { + if (redirects[2]->isEmpty()) + RedirectFD("/dev/null",2); + else + RedirectFD(redirects[2]->toString(), 2); + } else { + dup2(1, 2); + } + } + + // Set up the environment + char** env = environ; + if (envp != 0) + env = (char**) envp; + + // Execute! + execve (path.c_str(), (char** const)args, env); + // If the execve() failed, we should exit and let the parent pick up + // our non-zero exit status. + exit (errno); + } + + // Parent process: Break out of the switch to do our processing. + default: + break; + } + + // Make sure stderr and stdout have been flushed + std::cerr << std::flush; + std::cout << std::flush; + fsync(1); + fsync(2); + + struct sigaction Act, Old; + + // Install a timeout handler. + if (secondsToWait) { + Timeout = false; + Act.sa_sigaction = 0; + Act.sa_handler = TimeOutHandler; + sigemptyset(&Act.sa_mask); + Act.sa_flags = 0; + sigaction(SIGALRM, &Act, &Old); + alarm(secondsToWait); + } + + // Parent process: Wait for the child process to terminate. + int status; + while (wait(&status) != child) + if (secondsToWait && errno == EINTR) { + // Kill the child. + kill(child, SIGKILL); + + // Turn off the alarm and restore the signal handler + alarm(0); + sigaction(SIGALRM, &Old, 0); + + // Wait for child to die + if (wait(&status) != child) + ThrowErrno("Child timedout but wouldn't die"); + + return -1; // Timeout detected + } else { + ThrowErrno("Error waiting for child process"); + } + + // We exited normally without timeout, so turn off the timer. + if (secondsToWait) { + alarm(0); + sigaction(SIGALRM, &Old, 0); + } + + // If the program exited normally with a zero exit status, return success! + if (WIFEXITED (status)) + return WEXITSTATUS(status); + else if (WIFSIGNALED(status)) + return 1; + +#else + throw std::string( + "Program::ExecuteAndWait not implemented on this platform!\n"); +#endif + return 0; +} + +} diff --git a/lib/System/Unix/README.txt b/lib/System/Unix/README.txt new file mode 100644 index 0000000000..b3bace483e --- /dev/null +++ b/lib/System/Unix/README.txt @@ -0,0 +1,16 @@ +llvm/lib/System/Unix README +=========================== + +This directory provides implementations of the lib/System classes that +are common to two or more variants of UNIX. For example, the directory +structure underneath this directory could look like this: + +Unix - only code that is truly generic to all UNIX platforms + Posix - code that is specific to Posix variants of UNIX + SUS - code that is specific to the Single Unix Specification + SysV - code that is specific to System V variants of UNIX + +As a rule, only those directories actually needing to be created should be +created. Also, further subdirectories could be created to reflect versions of +the various standards. For example, under SUS there could be v1, v2, and v3 +subdirectories to reflect the three major versions of SUS. diff --git a/lib/System/Unix/SUS/Process.cpp b/lib/System/Unix/SUS/Process.cpp new file mode 100644 index 0000000000..fb462b4a8b --- /dev/null +++ b/lib/System/Unix/SUS/Process.cpp @@ -0,0 +1,30 @@ +//===- Unix/SUS/Process.cpp - Linux Process Implementation ---- -*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file was developed by Reid Spencer and is distributed under the +// University of Illinois Open Source License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file provides the Linux specific implementation of the Process class. +// +//===----------------------------------------------------------------------===// + +#include <unistd.h> + +//===----------------------------------------------------------------------===// +//=== WARNING: Implementation here must contain only code specific to the +//=== SUS (Single Unix Specification). +//===----------------------------------------------------------------------===// + +namespace llvm { +using namespace sys; + +unsigned +Process::GetPageSize() { + static const long page_size = sysconf(_SC_PAGE_SIZE); + return static_cast<unsigned>(page_size); +} + +} diff --git a/lib/System/Unix/Signals.inc b/lib/System/Unix/Signals.inc new file mode 100644 index 0000000000..a643dbf972 --- /dev/null +++ b/lib/System/Unix/Signals.inc @@ -0,0 +1,185 @@ +//===- Signals.cpp - Generic Unix Signals Implementation -----*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file was developed by the LLVM research group and is distributed under +// the University of Illinois Open Source License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines some helpful functions for dealing with the possibility of +// Unix signals occuring while your program is running. +// +//===----------------------------------------------------------------------===// + +#include "Unix.h" +#include <vector> +#include <algorithm> +#if HAVE_EXECINFO_H +# include <execinfo.h> // For backtrace(). +#endif +#if HAVE_SIGNAL_H +#include <signal.h> +#endif + +namespace { + +/// InterruptFunction - The function to call if ctrl-c is pressed. +void (*InterruptFunction)() = 0; + +std::vector<std::string> *FilesToRemove = 0 ; +std::vector<llvm::sys::Path> *DirectoriesToRemove = 0; + +// IntSigs - Signals that may interrupt the program at any time. +const int IntSigs[] = { + SIGHUP, SIGINT, SIGQUIT, SIGPIPE, SIGTERM, SIGUSR1, SIGUSR2 +}; +const int *IntSigsEnd = IntSigs + sizeof(IntSigs)/sizeof(IntSigs[0]); + +// KillSigs - Signals that are synchronous with the program that will cause it +// to die. +const int KillSigs[] = { + SIGILL, SIGTRAP, SIGABRT, SIGFPE, SIGBUS, SIGSEGV, SIGSYS, SIGXCPU, SIGXFSZ +#ifdef SIGEMT + , SIGEMT +#endif +}; +const int *KillSigsEnd = KillSigs + sizeof(KillSigs)/sizeof(KillSigs[0]); + +#ifdef HAVE_BACKTRACE +void* StackTrace[256]; +#endif + +// PrintStackTrace - In the case of a program crash or fault, print out a stack +// trace so that the user has an indication of why and where we died. +// +// On glibc systems we have the 'backtrace' function, which works nicely, but +// doesn't demangle symbols. In order to backtrace symbols, we fork and exec a +// 'c++filt' process to do the demangling. This seems like the simplest and +// most robust solution when we can't allocate memory (such as in a signal +// handler). If we can't find 'c++filt', we fallback to printing mangled names. +// +void PrintStackTrace() { +#ifdef HAVE_BACKTRACE + // Use backtrace() to output a backtrace on Linux systems with glibc. + int depth = backtrace(StackTrace, sizeof(StackTrace)/sizeof(StackTrace[0])); + + // Create a one-way unix pipe. The backtracing process writes to PipeFDs[1], + // the c++filt process reads from PipeFDs[0]. + int PipeFDs[2]; + if (pipe(PipeFDs)) { + backtrace_symbols_fd(StackTrace, depth, STDERR_FILENO); + return; + } + + switch (pid_t ChildPID = fork()) { + case -1: // Error forking, print mangled stack trace + close(PipeFDs[0]); + close(PipeFDs[1]); + backtrace_symbols_fd(StackTrace, depth, STDERR_FILENO); + return; + default: // backtracing process + close(PipeFDs[0]); // Close the reader side. + + // Print the mangled backtrace into the pipe. + backtrace_symbols_fd(StackTrace, depth, PipeFDs[1]); + close(PipeFDs[1]); // We are done writing. + while (waitpid(ChildPID, 0, 0) == -1) + if (errno != EINTR) break; + return; + + case 0: // c++filt process + close(PipeFDs[1]); // Close the writer side. + dup2(PipeFDs[0], 0); // Read from standard input + close(PipeFDs[0]); // Close the old descriptor + dup2(2, 1); // Revector stdout -> stderr + + // Try to run c++filt or gc++filt. If neither is found, call back on 'cat' + // to print the mangled stack trace. If we can't find cat, just exit. + execlp("c++filt", "c++filt", (char*)NULL); + execlp("gc++filt", "gc++filt", (char*)NULL); + execlp("cat", "cat", (char*)NULL); + execlp("/bin/cat", "cat", (char*)NULL); + exit(0); + } +#endif +} + +// SignalHandler - The signal handler that runs... +RETSIGTYPE SignalHandler(int Sig) { + if (FilesToRemove != 0) + while (!FilesToRemove->empty()) { + std::remove(FilesToRemove->back().c_str()); + FilesToRemove->pop_back(); + } + + if (DirectoriesToRemove != 0) + while (!DirectoriesToRemove->empty()) { + DirectoriesToRemove->back().eraseFromDisk(true); + DirectoriesToRemove->pop_back(); + } + + if (std::find(IntSigs, IntSigsEnd, Sig) != IntSigsEnd) { + if (InterruptFunction) { + void (*IF)() = InterruptFunction; + InterruptFunction = 0; + IF(); // run the interrupt function. + return; + } else { + exit(1); // If this is an interrupt signal, exit the program + } + } + + // Otherwise if it is a fault (like SEGV) output the stacktrace to + // STDERR (if we can) and reissue the signal to die... + PrintStackTrace(); + signal(Sig, SIG_DFL); +} + +// Just call signal +void RegisterHandler(int Signal) { + signal(Signal, SignalHandler); +} + +} + +namespace llvm { + +void sys::SetInterruptFunction(void (*IF)()) { + InterruptFunction = IF; + RegisterHandler(SIGINT); +} + +// RemoveFileOnSignal - The public API +void sys::RemoveFileOnSignal(const sys::Path &Filename) { + if (FilesToRemove == 0) + FilesToRemove = new std::vector<std::string>; + + FilesToRemove->push_back(Filename.toString()); + + std::for_each(IntSigs, IntSigsEnd, RegisterHandler); + std::for_each(KillSigs, KillSigsEnd, RegisterHandler); +} + +// RemoveDirectoryOnSignal - The public API +void sys::RemoveDirectoryOnSignal(const llvm::sys::Path& path) { + if (!path.isDirectory()) + return; + + if (DirectoriesToRemove == 0) + DirectoriesToRemove = new std::vector<sys::Path>; + + DirectoriesToRemove->push_back(path); + + std::for_each(IntSigs, IntSigsEnd, RegisterHandler); + std::for_each(KillSigs, KillSigsEnd, RegisterHandler); +} + +/// PrintStackTraceOnErrorSignal - When an error signal (such as SIBABRT or +/// SIGSEGV) is delivered to the process, print a stack trace and then exit. +void sys::PrintStackTraceOnErrorSignal() { + std::for_each(KillSigs, KillSigsEnd, RegisterHandler); +} + +} + diff --git a/lib/System/Unix/TimeValue.inc b/lib/System/Unix/TimeValue.inc new file mode 100644 index 0000000000..8c8dfcc3b7 --- /dev/null +++ b/lib/System/Unix/TimeValue.inc @@ -0,0 +1,51 @@ +//===- Unix/TimeValue.cpp - Unix TimeValue Implementation -------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file was developed by Reid Spencer and is distributed under the +// University of Illinois Open Source License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the Unix specific portion of the TimeValue class. +// +//===----------------------------------------------------------------------===// + +//===----------------------------------------------------------------------===// +//=== WARNING: Implementation here must contain only generic UNIX code that +//=== is guaranteed to work on *all* UNIX variants. +//===----------------------------------------------------------------------===// + +#include "Unix.h" + +namespace llvm { + using namespace sys; + +std::string TimeValue::toString() const { + char buffer[32]; + + time_t ourTime = time_t(this->toEpochTime()); +#ifdef __hpux +// note that the following line needs -D_REENTRANT on HP-UX to be picked up + asctime_r(localtime(&ourTime), buffer); +#else + ::asctime_r(::localtime(&ourTime), buffer); +#endif + + std::string result(buffer); + return result.substr(0,24); +} + +TimeValue TimeValue::now() { + struct timeval the_time; + timerclear(&the_time); + if (0 != ::gettimeofday(&the_time,0)) + ThrowErrno("Couldn't obtain time of day"); + + return TimeValue( + static_cast<TimeValue::SecondsType>( the_time.tv_sec ), + static_cast<TimeValue::NanoSecondsType>( the_time.tv_usec * + NANOSECONDS_PER_MICROSECOND ) ); +} + +} diff --git a/lib/System/Unix/Unix.h b/lib/System/Unix/Unix.h new file mode 100644 index 0000000000..32609f2215 --- /dev/null +++ b/lib/System/Unix/Unix.h @@ -0,0 +1,93 @@ +//===- llvm/System/Unix/Unix.h - Common Unix Include File -------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file was developed by Reid Spencer and is distributed under the +// University of Illinois Open Source License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines things specific to Unix implementations. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_SYSTEM_UNIX_UNIX_H +#define LLVM_SYSTEM_UNIX_UNIX_H + +//===----------------------------------------------------------------------===// +//=== WARNING: Implementation here must contain only generic UNIX code that +//=== is guaranteed to work on all UNIX variants. +//===----------------------------------------------------------------------===// + +#include "llvm/Config/config.h" // Get autoconf configuration settings +#include <cstdlib> +#include <cstdio> +#include <cstring> +#include <cerrno> +#include <string> +#include <algorithm> + +#ifdef HAVE_UNISTD_H +#include <unistd.h> +#endif + +#ifdef HAVE_SYS_TYPES_H +#include <sys/types.h> +#endif + +#ifdef HAVE_SYS_PARAM_H +#include <sys/param.h> +#endif + +#ifdef HAVE_ASSERT_H +#include <assert.h> +#endif + +#ifdef TIME_WITH_SYS_TIME +# include <sys/time.h> +# include <time.h> +#else +# ifdef HAVE_SYS_TIME_H +# include <sys/time.h> +# else +# include <time.h> +# endif +#endif + +#ifdef HAVE_SYS_WAIT_H +# include <sys/wait.h> +#endif + +#ifndef WEXITSTATUS +# define WEXITSTATUS(stat_val) ((unsigned)(stat_val) >> 8) +#endif + +#ifndef WIFEXITED +# define WIFEXITED(stat_val) (((stat_val) & 255) == 0) +#endif + +inline void ThrowErrno(const std::string& prefix, int errnum = -1) { + char buffer[MAXPATHLEN]; + buffer[0] = 0; + if (errnum == -1) + errnum = errno; +#ifdef HAVE_STRERROR_R + // strerror_r is thread-safe. + if (errnum) + strerror_r(errnum,buffer,MAXPATHLEN-1); +#elif HAVE_STRERROR + // Copy the thread un-safe result of strerror into + // the buffer as fast as possible to minimize impact + // of collision of strerror in multiple threads. + if (errnum) + strncpy(buffer,strerror(errnum),MAXPATHLEN-1); + buffer[MAXPATHLEN-1] = 0; +#else + // Strange that this system doesn't even have strerror + // but, oh well, just use a generic message + sprintf(buffer, "Error #%d", errnum); +#endif + throw prefix + ": " + buffer; +} + +#endif |