#include "shm.h" #ifdef __linux #include #include #include #include #include #include #include #include #include typedef struct __shm_item__ { struct __shm_item__ *next; struct __shm_item__ *prev; size_t size; } ShmItem; class ShmApi { private: int _shm_fd; size_t _size; bool _owner; void *_mem; sem_t *_sem; char *_mem_name; char *_sem_name; size_t *_used; ShmItem **__first; ShmItem **__free_list; ShmPlace *_slots; int _in_critical; private: void cleanup() { // We don't need to do anything here. } public: ShmSem *makeSem(const char *name, bool owner) { return new ShmSem(name, owner); } 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: int alloc(size_t bytes) { enterCritical(); ShmItem *_free_list = *__free_list; ShmItem *_first = *__first; ShmItem *i = _free_list; while (i != nullptr && i->size < bytes) { i = i->next; } int place; if (i != nullptr) { if (i->prev != nullptr) { i->prev->next = i->next; } if (i->next != nullptr) { i->next->prev = i->prev; } if (i->prev == nullptr) { _free_list = i->next; } i->next = _first; if (_first != nullptr) { _first->prev = i; } i->prev = nullptr; _first = i; *__first = _first; *__free_list = _free_list; place = (reinterpret_cast(i) + sizeof(ShmItem)) - reinterpret_cast(_mem); } else { i = reinterpret_cast(reinterpret_cast(_mem) + *_used); size_t u = *_used + sizeof(ShmItem) + bytes; if (u >= _size) { place = -1; } else { *_used = u; i->prev = nullptr; i->size = bytes; i->next = _first; _first = i; *__first = _first; place = (reinterpret_cast(i) + sizeof(ShmItem)) - reinterpret_cast(_mem); } } leaveCritical(); return place; } void free(int place) { enterCritical(); ShmItem *i = reinterpret_cast(reinterpret_cast(_mem) + place - sizeof(ShmItem)); ShmItem *_free_list = *__free_list; ShmItem *_first = *__first; if (i->prev != nullptr) { i->prev->next = i->next; } if (i->next != nullptr) { i->next->prev = i->prev; } if (i->prev == nullptr) { _first = i->next; } i->next = _free_list; if (_free_list != nullptr) { _free_list->prev = i; } i->prev = nullptr; _free_list = i; *__first = _first; *__free_list = _free_list; leaveCritical(); } inline void *ref(int place) { return reinterpret_cast(_mem) + place; } 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: ShmApi(const char *name, size_t size, bool owner) { { char buf[strlen(name) + 50]; sprintf(buf, "sem_%s", name); _sem_name = strdup(buf); _mem_name = strdup(name); } size_t slots_size = sizeof(ShmPlace) * SHM_MAX_SLOTS; size += slots_size; _sem = sem_open(_sem_name, O_CREAT); _shm_fd = shm_open(name, O_CREAT | O_RDWR, 0600); ftruncate(_shm_fd, size); _size = size; _mem = mmap(nullptr, _size, PROT_READ|PROT_WRITE, MAP_SHARED, _shm_fd, 0); _slots = reinterpret_cast (reinterpret_cast(_mem) + sizeof(size_t) + sizeof(ShmItem *) + sizeof(ShmItem *)); _used = reinterpret_cast(_mem); __first = reinterpret_cast(reinterpret_cast(_mem) + sizeof(size_t)); __free_list = reinterpret_cast(reinterpret_cast(_mem) + sizeof(size_t) + sizeof(ShmItem *)); _owner = owner; if (_owner) { *__first = nullptr; *__free_list = nullptr; *_used = sizeof(size_t) + 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); } ::free(_mem_name); ::free(_sem_name); } }; #endif #ifdef _WIN32 class ShmApi { public: ShmApi(const char *name, size_t size, bool owner) { } ~ShmApi() { } void enterCritical() { } void leaveCritical() { } void *alloc(size_t bytes) { return malloc(bytes); } void free(void *mem) { free(mem); } } #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); } const char *Shm::name() { return _shm_api->name(); } void *Shm::ref(int place) { return _shm_api->ref(place); } 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; } template void ref(Shm *shm, int place, T **p) { *p = reinterpret_cast(shm->ref(place)); } void ShmSem::post() { sem_post(reinterpret_cast(_sem)); } void ShmSem::wait() { sem_wait(reinterpret_cast(_sem)); } bool ShmSem::trywait() { return sem_trywait(reinterpret_cast(_sem)) == 0; } ShmSem::ShmSem(const char *n, bool owner) { _name = strdup(n); _sem = reinterpret_cast(sem_open(n, O_CREAT)); _owner = owner; } ShmSem::~ShmSem() { sem_close(reinterpret_cast(_sem)); if (_owner) { sem_unlink(_name); } free(_name); }