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-21 17:06:22 +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>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <semaphore.h>
|
|
|
|
#include <time.h>
|
|
|
|
#include <assert.h>
|
|
|
|
#include <errno.h>
|
|
|
|
#include <signal.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-03-19 22:08:36 +00:00
|
|
|
#include <sys/stat.h> /* For mode constants */
|
|
|
|
#include <fcntl.h> /* For O_* constants */
|
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;
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
int checked(int result, const char* expr) {
|
|
|
|
if (result == -1) {
|
|
|
|
std::cerr << "FAIL errno=" << errno << " in |" << expr << "|" << std::endl;
|
|
|
|
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-19 22:08:36 +00:00
|
|
|
std::cout << "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
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2017-03-16 01:39:28 +00:00
|
|
|
#undef CHECKED
|
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-21 17:06:22 +00:00
|
|
|
#endif
|