ccls/src/platform_linux.cc

242 lines
6.1 KiB
C++
Raw Normal View History

2017-03-19 22:06:22 +00:00
#if defined(__linux__) || defined(__APPLE__)
2017-03-04 01:45:20 +00:00
#include "platform.h"
2017-03-25 20:15:00 +00:00
#include "utils.h"
2017-03-04 01:45:20 +00:00
#include <cassert>
#include <string>
#include <pthread.h>
#include <iostream>
#include <unistd.h>
#include <stdio.h>
2017-03-28 01:47:12 +00:00
#include <limits.h>
2017-03-29 17:23:45 +00:00
#include <string.h>
2017-03-04 01:45:20 +00:00
#include <stdlib.h>
#include <semaphore.h>
#include <time.h>
#include <assert.h>
#include <errno.h>
#include <signal.h>
2017-04-18 17:21:53 +00:00
#include <dirent.h>
#include <sys/types.h> // required for stat.h
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
2017-03-19 22:08:36 +00:00
#include <fcntl.h> /* For O_* constants */
#include <sys/stat.h> /* For mode constants */
2017-03-04 01:45:20 +00:00
#include <semaphore.h>
#include <sys/mman.h>
2017-04-18 17:21:53 +00:00
#ifndef __APPLE__
#include <sys/prctl.h>
2017-04-18 17:21:53 +00:00
#endif
2017-03-04 01:45:20 +00:00
struct PlatformMutexLinux : public PlatformMutex {
sem_t* sem_ = nullptr;
PlatformMutexLinux(const std::string& name) {
2017-03-16 01:39:28 +00:00
std::cerr << "PlatformMutexLinux name=" << name << std::endl;
2017-03-19 22:08:36 +00:00
sem_ = sem_open(name.c_str(), O_CREAT, 0666 /*permission*/,
1 /*initial_value*/);
2017-03-04 01:45:20 +00:00
}
2017-03-19 22:08:36 +00:00
~PlatformMutexLinux() override { sem_close(sem_); }
2017-03-04 01:45:20 +00:00
};
struct PlatformScopedMutexLockLinux : public PlatformScopedMutexLock {
sem_t* sem_ = nullptr;
2017-03-19 22:08:36 +00:00
PlatformScopedMutexLockLinux(sem_t* sem) : sem_(sem) { sem_wait(sem_); }
2017-03-04 01:45:20 +00:00
2017-03-19 22:08:36 +00:00
~PlatformScopedMutexLockLinux() override { sem_post(sem_); }
2017-03-04 01:45:20 +00:00
};
2017-03-16 01:39:28 +00:00
void* checked(void* result, const char* expr) {
if (!result) {
std::cerr << "FAIL errno=" << errno << " in |" << expr << "|" << std::endl;
2017-03-28 02:28:45 +00:00
std::cerr << "errno => " << strerror(errno) << std::endl;
2017-03-16 01:39:28 +00:00
exit(1);
}
return result;
}
int checked(int result, const char* expr) {
if (result == -1) {
std::cerr << "FAIL errno=" << errno << " in |" << expr << "|" << std::endl;
2017-03-28 02:28:45 +00:00
std::cerr << "errno => " << strerror(errno) << std::endl;
2017-03-16 01:39:28 +00:00
exit(1);
}
return result;
}
#define CHECKED(expr) checked(expr, #expr)
2017-03-04 01:45:20 +00:00
struct PlatformSharedMemoryLinux : public PlatformSharedMemory {
std::string name_;
2017-03-21 17:06:22 +00:00
size_t size_;
2017-03-04 01:45:20 +00:00
int fd_;
2017-03-21 17:06:22 +00:00
PlatformSharedMemoryLinux(const std::string& name, size_t size)
: name_(name), size_(size) {
std::cerr << "PlatformSharedMemoryLinux name=" << name << ", size=" << size << std::endl;
2017-03-16 01:39:28 +00:00
// Try to create shared memory but only if it does not already exist. Since
// we created the memory, we need to initialize it.
fd_ = shm_open(name_.c_str(), O_RDWR | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR);
if (fd_ >= 0) {
std::cerr << "Calling ftruncate fd_=" << fd_ << std::endl;
2017-03-21 17:06:22 +00:00
CHECKED(ftruncate(fd_, size));
2017-03-16 01:39:28 +00:00
}
// Otherwise, we just open existing shared memory. We don't need to
// create or initialize it.
else {
2017-03-19 22:08:36 +00:00
fd_ = CHECKED(shm_open(
name_.c_str(), O_RDWR, /* memory is read/write, create if needed */
S_IRUSR | S_IWUSR /* user read/write */));
2017-03-16 01:39:28 +00:00
}
// Map the shared memory to an address.
2017-03-21 17:06:22 +00:00
data =
CHECKED(mmap(nullptr /*kernel assigned starting address*/, size,
2017-03-19 22:08:36 +00:00
PROT_READ | PROT_WRITE, MAP_SHARED, fd_, 0 /*offset*/));
2017-03-21 17:06:22 +00:00
capacity = size;
2017-03-16 01:39:28 +00:00
2017-03-28 01:04:37 +00:00
std::cerr << "Open shared memory name=" << name << ", fd=" << fd_
2017-03-21 17:06:22 +00:00
<< ", shared=" << data << ", capacity=" << capacity << std::endl;
2017-03-04 01:45:20 +00:00
}
~PlatformSharedMemoryLinux() override {
2017-03-21 17:06:22 +00:00
CHECKED(munmap(data, size_));
2017-03-16 01:39:28 +00:00
CHECKED(shm_unlink(name_.c_str()));
2017-03-21 17:06:22 +00:00
data = nullptr;
2017-03-04 01:45:20 +00:00
}
};
std::unique_ptr<PlatformMutex> CreatePlatformMutex(const std::string& name) {
std::string name2 = "/" + name;
return MakeUnique<PlatformMutexLinux>(name2);
}
2017-03-19 22:08:36 +00:00
std::unique_ptr<PlatformScopedMutexLock> CreatePlatformScopedMutexLock(
PlatformMutex* mutex) {
return MakeUnique<PlatformScopedMutexLockLinux>(
static_cast<PlatformMutexLinux*>(mutex)->sem_);
2017-03-04 01:45:20 +00:00
}
2017-03-19 22:08:36 +00:00
std::unique_ptr<PlatformSharedMemory> CreatePlatformSharedMemory(
2017-03-21 17:06:22 +00:00
const std::string& name, size_t size) {
2017-03-04 01:45:20 +00:00
std::string name2 = "/" + name;
2017-03-21 17:06:22 +00:00
return MakeUnique<PlatformSharedMemoryLinux>(name2, size);
2017-03-04 01:45:20 +00:00
}
2017-03-28 01:47:12 +00:00
void PlatformInit() {
}
std::string NormalizePath(const std::string& path) {
errno = 0;
char name[PATH_MAX + 1];
realpath(path.c_str(), name);
if (errno)
return path;
return name;
}
bool TryMakeDirectory(const std::string& absolute_path) {
const mode_t kMode = 0777; // UNIX style permissions
if (mkdir(absolute_path.c_str(), kMode) == -1) {
// Success if the directory exists.
return errno == EEXIST;
}
return true;
}
void SetCurrentThreadName(const std::string& thread_name) {
2017-04-18 17:21:53 +00:00
#ifndef __APPLE__
prctl(PR_SET_NAME, thread_name.c_str(), 0, 0, 0);
2017-04-18 17:21:53 +00:00
#endif
}
int64_t GetLastModificationTime(const std::string& absolute_path) {
struct stat buf;
if (stat(absolute_path.c_str(), &buf) != 0) {
switch (errno) {
case ENOENT:
std::cerr << "GetLastModificationTime: unable to find file " << absolute_path << std::endl;
break;
case EINVAL:
std::cerr << "GetLastModificationTime: invalid param to _stat for file file " << absolute_path << std::endl;
break;
default:
std::cerr << "GetLastModificationTime: unhandled for " << absolute_path << std::endl;
exit(1);
break;
}
}
return buf.st_mtime;
}
// See http://stackoverflow.com/q/13198627
void CopyFileTo(const std::string& dest, const std::string& source) {
int fd_from = open(source.c_str(), O_RDONLY);
if (fd_from < 0)
return;
int fd_to = open(dest.c_str(), O_WRONLY | O_CREAT | O_EXCL, 0666);
if (fd_to < 0)
goto out_error;
2017-04-21 17:00:36 +00:00
char buf[4096];
ssize_t nread;
while (nread = read(fd_from, buf, sizeof buf), nread > 0) {
char *out_ptr = buf;
ssize_t nwritten;
do {
nwritten = write(fd_to, out_ptr, nread);
if (nwritten >= 0) {
nread -= nwritten;
out_ptr += nwritten;
}
else if (errno != EINTR)
goto out_error;
} while (nread > 0);
}
if (nread == 0) {
if (close(fd_to) < 0) {
fd_to = -1;
goto out_error;
}
close(fd_from);
return;
}
out_error:
close(fd_from);
if (fd_to >= 0)
close(fd_to);
}
2017-03-29 06:33:38 +00:00
std::vector<std::string> GetPlatformClangArguments() {
// TODO: use install config variable for path?
return {
"-stdlib=libc++",
"-nostdinc++",
2017-03-29 17:12:00 +00:00
//"-I/usr/local/Cellar/llvm/3.9.1/include",
"-I/Users/jdufault/Personal/super-clang-index/libcxx/include"
2017-03-29 06:33:38 +00:00
};
}
2017-03-28 01:47:12 +00:00
#undef CHECKED
2017-03-21 17:06:22 +00:00
#endif