This is the binary distribution of racket-webview
This commit is contained in:
652
shm.cpp
Normal file
652
shm.cpp
Normal file
@@ -0,0 +1,652 @@
|
||||
#include "shm.h"
|
||||
#include "utils.h"
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#ifdef __linux
|
||||
#define _strdup strdup
|
||||
#endif
|
||||
|
||||
typedef struct __shm_item__ {
|
||||
|
||||
ShmPlace next;
|
||||
ShmPlace prev;
|
||||
int size;
|
||||
int alloc_size;
|
||||
} ShmItem;
|
||||
|
||||
|
||||
class ShmApiBase
|
||||
{
|
||||
protected:
|
||||
char *_mem;
|
||||
|
||||
int *_used;
|
||||
ShmPlace *_slots;
|
||||
ShmPlace *_first;
|
||||
ShmPlace *_free_list;
|
||||
|
||||
char *_mem_name;
|
||||
char *_sem_name;
|
||||
|
||||
int _in_critical;
|
||||
size_t _size;
|
||||
bool _owner;
|
||||
|
||||
public:
|
||||
virtual void enterCritical() = 0;
|
||||
virtual void leaveCritical() = 0;
|
||||
|
||||
public:
|
||||
int slot(int s) {
|
||||
return _slots[s];
|
||||
}
|
||||
|
||||
void setSlot(int s, ShmPlace place) {
|
||||
_slots[s] = place;
|
||||
}
|
||||
|
||||
public:
|
||||
const char *name() {
|
||||
return _mem_name;
|
||||
}
|
||||
|
||||
public:
|
||||
template <class T> void ref(int place, T** p) {
|
||||
if (place == SHM_NULL) {
|
||||
*p = nullptr;
|
||||
} else {
|
||||
*p = reinterpret_cast<T *>(_mem + place);
|
||||
}
|
||||
}
|
||||
|
||||
inline void *ref(int place)
|
||||
{
|
||||
if (place == SHM_NULL) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return _mem + place;
|
||||
}
|
||||
|
||||
public:
|
||||
void info(int &usage, int &free_depth, int &free_size, int &item_depth, int &item_size, double &usage_factor) {
|
||||
enterCritical();
|
||||
|
||||
usage = *_used;
|
||||
|
||||
auto count = [this](ShmPlace *l, int &depth, int &size, double &factor) {
|
||||
depth = 0;
|
||||
size = 0;
|
||||
int alloc_size = 0;
|
||||
ShmPlace p = *l;
|
||||
while (p != SHM_NULL) {
|
||||
//p -= sizeof(ShmItem);
|
||||
ShmItem *i;
|
||||
ref(p, &i);
|
||||
size += i->size;
|
||||
alloc_size += i->alloc_size;
|
||||
depth += 1;
|
||||
p = i->next;
|
||||
}
|
||||
if (size > 0) {
|
||||
factor = (static_cast<double>(alloc_size) / static_cast<double>(size));
|
||||
} else {
|
||||
factor = 1.0;
|
||||
}
|
||||
};
|
||||
|
||||
double x;
|
||||
count(_free_list, free_depth, free_size, x);
|
||||
count(_first, item_depth, item_size, usage_factor);
|
||||
|
||||
leaveCritical();
|
||||
}
|
||||
|
||||
public:
|
||||
int alloc(size_t bytes) {
|
||||
enterCritical();
|
||||
|
||||
ShmPlace p_i = *_free_list;
|
||||
ShmItem *i;
|
||||
ref(p_i, &i);
|
||||
|
||||
while (i != nullptr && i->size < bytes) {
|
||||
p_i = i->next;
|
||||
ref(p_i, &i);
|
||||
}
|
||||
|
||||
int place;
|
||||
if (i != nullptr) {
|
||||
if (i->prev != SHM_NULL) {
|
||||
ShmItem *prev_i;
|
||||
ref(i->prev, &prev_i);
|
||||
prev_i->next = i->next;
|
||||
}
|
||||
if (i->next != SHM_NULL) {
|
||||
ShmItem *next_i;
|
||||
ref(i->next, &next_i);
|
||||
next_i->prev = i->prev;
|
||||
}
|
||||
if (i->prev == SHM_NULL) {
|
||||
*_free_list = i->next;
|
||||
}
|
||||
i->next = *_first;
|
||||
if (*_first != SHM_NULL) {
|
||||
ShmItem *first_i;
|
||||
ref(*_first, &first_i);
|
||||
first_i->prev = p_i;
|
||||
}
|
||||
i->prev = SHM_NULL;
|
||||
i->alloc_size = bytes;
|
||||
|
||||
*_first = p_i;
|
||||
place = p_i + sizeof(ShmItem);
|
||||
} else {
|
||||
ShmPlace p_i = *_used;
|
||||
i = reinterpret_cast<ShmItem *>(reinterpret_cast<char *>(_mem) + p_i);
|
||||
int u = static_cast<int>(*_used + sizeof(ShmItem) + bytes);
|
||||
|
||||
if (u >= _size) {
|
||||
place = SHM_NULL;
|
||||
} else {
|
||||
*_used = u;
|
||||
i->prev = SHM_NULL;
|
||||
i->size = bytes;
|
||||
i->alloc_size = bytes;
|
||||
i->next = *_first;
|
||||
if (*_first != SHM_NULL) {
|
||||
ShmItem *first_i;
|
||||
ref(*_first, &first_i);
|
||||
first_i->prev = p_i;
|
||||
}
|
||||
|
||||
*_first = p_i;
|
||||
place = p_i + sizeof(ShmItem);
|
||||
}
|
||||
}
|
||||
|
||||
leaveCritical();
|
||||
return place;
|
||||
}
|
||||
|
||||
void free(ShmPlace place) {
|
||||
if (place == SHM_NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
enterCritical();
|
||||
|
||||
ShmPlace p_i = place - sizeof(ShmItem);
|
||||
ShmItem *i;
|
||||
ref(p_i, &i);
|
||||
|
||||
if (i->prev != SHM_NULL) {
|
||||
ShmItem *prev_i;
|
||||
ref(i->prev, &prev_i);
|
||||
prev_i->next = i->next;
|
||||
}
|
||||
if (i->next != SHM_NULL) {
|
||||
ShmItem *next_i;
|
||||
ref(i->next, &next_i);
|
||||
next_i->prev = i->prev;
|
||||
}
|
||||
if (i->prev == SHM_NULL) {
|
||||
*_first = i->next;
|
||||
}
|
||||
i->next = *_free_list;
|
||||
if (*_free_list != SHM_NULL) {
|
||||
ShmItem *fl;
|
||||
ref(*_free_list, &fl);
|
||||
fl->prev = p_i;
|
||||
}
|
||||
i->prev = SHM_NULL;
|
||||
*_free_list = p_i;
|
||||
|
||||
leaveCritical();
|
||||
}
|
||||
|
||||
public:
|
||||
ShmSem *makeSem(const char *name, bool owner) {
|
||||
return new ShmSem(name, owner);
|
||||
}
|
||||
|
||||
public:
|
||||
ShmApiBase(const char *name, size_t size, bool owner) {
|
||||
char *buf = reinterpret_cast<char *>(malloc(strlen(name) + 50));
|
||||
sprintf(buf, "sem_%s", name);
|
||||
_sem_name = _strdup(buf);
|
||||
_mem_name = _strdup(name);
|
||||
::free(buf);
|
||||
|
||||
_owner = owner;
|
||||
|
||||
_size = size;
|
||||
|
||||
_used = nullptr;
|
||||
_slots = nullptr;
|
||||
_first = nullptr;
|
||||
_free_list = nullptr;
|
||||
_mem = nullptr;
|
||||
|
||||
_in_critical = 0;
|
||||
}
|
||||
|
||||
virtual ~ShmApiBase()
|
||||
{
|
||||
::free(_sem_name);
|
||||
::free(_mem_name);
|
||||
}
|
||||
};
|
||||
|
||||
#ifdef __linux
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/shm.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/mman.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <semaphore.h>
|
||||
|
||||
|
||||
class ShmApi : public ShmApiBase
|
||||
{
|
||||
private:
|
||||
int _shm_fd;
|
||||
sem_t *_sem;
|
||||
|
||||
private:
|
||||
void cleanup() {
|
||||
// We don't need to do anything here.
|
||||
|
||||
}
|
||||
|
||||
public:
|
||||
void enterCritical() {
|
||||
if (_in_critical > 0) {
|
||||
_in_critical++;
|
||||
} else {
|
||||
sem_wait(_sem);
|
||||
_in_critical = 1;
|
||||
}
|
||||
}
|
||||
|
||||
void leaveCritical() {
|
||||
if (_in_critical > 1) {
|
||||
_in_critical--;
|
||||
} else {
|
||||
_in_critical = 0;
|
||||
sem_post(_sem);
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
bool isValid() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public:
|
||||
ShmApi(const char *name, size_t size, bool owner) : ShmApiBase(name, size, owner)
|
||||
{
|
||||
size_t slots_size = sizeof(ShmPlace) * SHM_MAX_SLOTS;
|
||||
size += slots_size;
|
||||
|
||||
if (_owner) {
|
||||
_sem = sem_open(_sem_name, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR, 0);
|
||||
_shm_fd = shm_open(name, O_CREAT | O_RDWR, 0600);
|
||||
ftruncate(_shm_fd, size);
|
||||
} else {
|
||||
_sem = sem_open(_sem_name, O_RDWR, S_IRUSR | S_IWUSR, 0);
|
||||
_shm_fd = shm_open(name, O_RDWR, 0600);
|
||||
}
|
||||
_mem = reinterpret_cast<char *>(mmap(nullptr, _size, PROT_READ|PROT_WRITE, MAP_SHARED, _shm_fd, 0));
|
||||
|
||||
_slots = reinterpret_cast <ShmPlace *>(_mem + sizeof(int) + sizeof(ShmPlace) + sizeof(ShmPlace));
|
||||
_used = reinterpret_cast<int *>(_mem);
|
||||
|
||||
_first = reinterpret_cast<ShmPlace *>(_mem + sizeof(int));
|
||||
_free_list = reinterpret_cast<ShmPlace *>(_mem + sizeof(int) + sizeof(ShmPlace));
|
||||
|
||||
if (_owner) {
|
||||
*_first = SHM_NULL;
|
||||
*_free_list = SHM_NULL;
|
||||
*_used = sizeof(int) + sizeof(ShmItem *) + sizeof(ShmItem *) + slots_size;
|
||||
sem_post(_sem);
|
||||
}
|
||||
|
||||
_in_critical = 0;
|
||||
}
|
||||
|
||||
~ShmApi() {
|
||||
cleanup();
|
||||
munmap(_mem, _size);
|
||||
close(_shm_fd);
|
||||
sem_close(_sem);
|
||||
if (_owner) {
|
||||
shm_unlink(_mem_name);
|
||||
sem_unlink(_sem_name);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
class ShmSemApi {
|
||||
private:
|
||||
sem_t *_sem;
|
||||
char *_name;
|
||||
bool _owner;
|
||||
|
||||
public:
|
||||
void post() {
|
||||
sem_post(_sem);
|
||||
}
|
||||
|
||||
void wait() {
|
||||
int r = sem_wait(_sem);
|
||||
if (r != 0) {
|
||||
ERROR2("sem_wait error: %d, %s\n", errno, strerror(errno));
|
||||
}
|
||||
}
|
||||
|
||||
bool trywait() {
|
||||
int r = sem_trywait(reinterpret_cast<sem_t *>(_sem));
|
||||
if (r != 0 && r != EAGAIN) {
|
||||
ERROR2("sem_wait error: %d, %s\n", errno, strerror(errno));
|
||||
}
|
||||
|
||||
return (r == 0);
|
||||
}
|
||||
|
||||
public:
|
||||
ShmSemApi(const char *n, bool owner) {
|
||||
_name = strdup(n);
|
||||
|
||||
sem_t *s;
|
||||
if (owner) {
|
||||
s = sem_open(n, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR, 0);
|
||||
} else {
|
||||
s = sem_open(n, O_RDWR, S_IRUSR | S_IWUSR, 0);
|
||||
}
|
||||
_sem = s;
|
||||
_owner = owner;
|
||||
}
|
||||
|
||||
virtual ~ShmSemApi() {
|
||||
sem_close(_sem);
|
||||
if (_owner) {
|
||||
sem_unlink(_name);
|
||||
}
|
||||
free(_name);
|
||||
}
|
||||
};
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <windows.h>
|
||||
|
||||
class ShmApi : public ShmApiBase
|
||||
{
|
||||
private:
|
||||
HANDLE _shm_handle;
|
||||
HANDLE _sem_handle;
|
||||
bool _valid;
|
||||
|
||||
public:
|
||||
ShmApi(const char *name, size_t size, bool owner) : ShmApiBase(name, size, owner)
|
||||
{
|
||||
size_t slots_size = sizeof(ShmPlace) * SHM_MAX_SLOTS;
|
||||
size += slots_size;
|
||||
|
||||
_valid = true;
|
||||
if (_owner) {
|
||||
_shm_handle = CreateFileMappingA(INVALID_HANDLE_VALUE,
|
||||
NULL,
|
||||
PAGE_READWRITE,
|
||||
0,
|
||||
static_cast<DWORD>(size), // size must be smaller < 2GB
|
||||
name);
|
||||
|
||||
if (_shm_handle == NULL) {
|
||||
ERROR2("Cannot create shared memory with name %s and size %lld\n", name, size);
|
||||
_valid = false;
|
||||
}
|
||||
} else {
|
||||
_shm_handle = OpenFileMappingA(FILE_MAP_ALL_ACCESS,
|
||||
FALSE,
|
||||
name);
|
||||
if (_shm_handle == NULL) {
|
||||
ERROR1("Cannot open shared memory with name %s\n", name);
|
||||
_valid = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (_valid) {
|
||||
_mem = static_cast<LPSTR>(MapViewOfFile(_shm_handle,
|
||||
FILE_MAP_ALL_ACCESS,
|
||||
0,
|
||||
0,
|
||||
size));
|
||||
if (_mem == NULL) {
|
||||
ERROR1("Cannot map shared memory, errorcode = %ld\n", GetLastError());
|
||||
_valid = false;
|
||||
CloseHandle(_shm_handle);
|
||||
}
|
||||
}
|
||||
|
||||
if (_valid) {
|
||||
if (_owner) {
|
||||
_sem_handle = CreateSemaphoreA(NULL,
|
||||
1,
|
||||
10000,
|
||||
_sem_name
|
||||
);
|
||||
} else {
|
||||
_sem_handle = OpenSemaphoreA(SYNCHRONIZE|SEMAPHORE_MODIFY_STATE, FALSE, _sem_name);
|
||||
}
|
||||
if (_sem_handle == NULL) {
|
||||
ERROR2("Cannot create or open semaphore with name '%s' (%ld)\n", _sem_name, GetLastError());
|
||||
UnmapViewOfFile(_mem);
|
||||
CloseHandle(_shm_handle);
|
||||
_valid = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (_valid) {
|
||||
_slots = reinterpret_cast <ShmPlace *>(_mem + sizeof(int) + sizeof(ShmPlace) + sizeof(ShmPlace));
|
||||
_used = reinterpret_cast<int *>(_mem);
|
||||
|
||||
_first = reinterpret_cast<ShmPlace *>(_mem + sizeof(int));
|
||||
_free_list = reinterpret_cast<ShmPlace *>(_mem + sizeof(int) + sizeof(ShmPlace));
|
||||
|
||||
if (_owner) {
|
||||
*_first = SHM_NULL;
|
||||
*_free_list = SHM_NULL;
|
||||
*_used = sizeof(int) + sizeof(ShmItem *) + sizeof(ShmItem *) + slots_size;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
~ShmApi()
|
||||
{
|
||||
if (_valid) {
|
||||
UnmapViewOfFile(_mem);
|
||||
CloseHandle(_shm_handle);
|
||||
CloseHandle(_sem_handle);
|
||||
}
|
||||
}
|
||||
|
||||
bool isValid() {
|
||||
return _valid;
|
||||
}
|
||||
|
||||
void enterCritical()
|
||||
{
|
||||
if (_in_critical > 0) {
|
||||
_in_critical++;
|
||||
} else {
|
||||
WaitForSingleObject(_sem_handle, INFINITE);
|
||||
_in_critical = 1;
|
||||
}
|
||||
}
|
||||
|
||||
void leaveCritical()
|
||||
{
|
||||
if (_in_critical > 1) {
|
||||
_in_critical--;
|
||||
} else {
|
||||
_in_critical = 0;
|
||||
ReleaseSemaphore(_sem_handle, 1, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
ShmSem *sem(const char *name, bool owner)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
class ShmSemApi {
|
||||
private:
|
||||
HANDLE _sem;
|
||||
char *_name;
|
||||
bool _owner;
|
||||
|
||||
public:
|
||||
void post() {
|
||||
ReleaseSemaphore(_sem, 1, NULL);
|
||||
}
|
||||
|
||||
void wait() {
|
||||
DWORD r = WaitForSingleObject(_sem, INFINITE);
|
||||
if (r != WAIT_OBJECT_0) {
|
||||
ERROR1("sem_wait error: %ld\n", r);
|
||||
}
|
||||
}
|
||||
|
||||
bool trywait() {
|
||||
DWORD r = WaitForSingleObject(_sem , 0);
|
||||
if (r != WAIT_OBJECT_0 && r != WAIT_TIMEOUT) {
|
||||
ERROR1("sem_wait error: %ld\n", r);
|
||||
}
|
||||
return r == WAIT_OBJECT_0;
|
||||
}
|
||||
|
||||
public:
|
||||
ShmSemApi(const char *n, bool owner) {
|
||||
_name = _strdup(n);
|
||||
|
||||
if (owner) {
|
||||
_sem = CreateSemaphoreA(NULL,
|
||||
0,
|
||||
10000,
|
||||
_name);
|
||||
} else {
|
||||
_sem = OpenSemaphoreA(SYNCHRONIZE|SEMAPHORE_MODIFY_STATE, FALSE, _name);
|
||||
}
|
||||
|
||||
if (_sem == NULL) {
|
||||
ERROR1("Cannot create or open semaphore with name '%s'\n", _name);
|
||||
}
|
||||
_owner = owner;
|
||||
}
|
||||
|
||||
virtual ~ShmSemApi() {
|
||||
if (_sem != NULL) {
|
||||
CloseHandle(_sem);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
ShmPlace Shm::alloc(size_t mem)
|
||||
{
|
||||
return _shm_api->alloc(mem);
|
||||
}
|
||||
|
||||
void Shm::free(ShmPlace place)
|
||||
{
|
||||
_shm_api->free(place);
|
||||
}
|
||||
|
||||
void Shm::unlock()
|
||||
{
|
||||
_shm_api->leaveCritical();
|
||||
}
|
||||
|
||||
ShmPlace Shm::slot(ShmSlot s)
|
||||
{
|
||||
return _shm_api->slot(s);
|
||||
}
|
||||
|
||||
void Shm::setSlot(ShmSlot s, ShmPlace pl)
|
||||
{
|
||||
_shm_api->setSlot(s, pl);
|
||||
}
|
||||
|
||||
ShmSem *Shm::sem(const char *name, bool owner)
|
||||
{
|
||||
return _shm_api->makeSem(name, owner);
|
||||
}
|
||||
|
||||
bool Shm::isValid()
|
||||
{
|
||||
return _shm_api->isValid();
|
||||
}
|
||||
|
||||
const char *Shm::name()
|
||||
{
|
||||
return _shm_api->name();
|
||||
}
|
||||
|
||||
void *Shm::ref(int place)
|
||||
{
|
||||
return _shm_api->ref(place);
|
||||
}
|
||||
|
||||
void Shm::info(int &usage, int &free_depth, int &free_size, int &item_depth, int &item_size, double &usage_factor)
|
||||
{
|
||||
_shm_api->info(usage, free_depth, free_size, item_depth, item_size, usage_factor);
|
||||
}
|
||||
|
||||
void Shm::lock()
|
||||
{
|
||||
_shm_api->enterCritical();
|
||||
}
|
||||
|
||||
Shm::Shm(const char *name, size_t bytes, bool owner)
|
||||
{
|
||||
_shm_api = new ShmApi(name, bytes, owner);
|
||||
}
|
||||
|
||||
Shm::~Shm()
|
||||
{
|
||||
delete _shm_api;
|
||||
}
|
||||
|
||||
|
||||
void ShmSem::post() {
|
||||
_api->post();
|
||||
}
|
||||
|
||||
void ShmSem::wait() {
|
||||
_api->wait();
|
||||
}
|
||||
|
||||
bool ShmSem::trywait() {
|
||||
return _api->trywait();
|
||||
}
|
||||
|
||||
ShmSem::ShmSem(const char *n, bool owner) {
|
||||
_api = new ShmSemApi(n, owner);
|
||||
}
|
||||
|
||||
ShmSem::~ShmSem() {
|
||||
delete _api;
|
||||
}
|
||||
Reference in New Issue
Block a user