diff --git a/rktwebview_qt/shm.cpp b/rktwebview_qt/shm.cpp new file mode 100644 index 0000000..1360fcc --- /dev/null +++ b/rktwebview_qt/shm.cpp @@ -0,0 +1,352 @@ +#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); +} diff --git a/rktwebview_qt/shm.h b/rktwebview_qt/shm.h new file mode 100644 index 0000000..05793f9 --- /dev/null +++ b/rktwebview_qt/shm.h @@ -0,0 +1,60 @@ +#ifndef SHM_H +#define SHM_H + +#include + +class ShmApi; +typedef int ShmPlace; +typedef int ShmSlot; + +#define SHM_MAX_SLOTS 100 +#define SHM_NULL -1 + +class ShmSem { +private: + void *_sem; + char *_name; + bool _owner; + +public: + void post(); + void wait(); + bool trywait(); + +public: + ShmSem(const char *n, bool owner); + ~ShmSem(); +}; + +class Shm +{ +private: + ShmApi *_shm_api; + +public: + ShmPlace alloc(size_t mem); + void free(ShmPlace place); + void lock(); + void unlock(); + +public: + ShmPlace slot(ShmSlot s); + void setSlot(ShmSlot s, ShmPlace pl); + +public: + ShmSem *sem(const char *name, bool owner); + +public: + const char *name(); + +public: + void *ref(int place); + +public: + Shm(const char *name, size_t bytes, bool owner); + ~Shm(); +}; + +template void ref(Shm *shm, int place, T **p); + +#endif // SHM_H diff --git a/rktwebview_qt/shmqueue.cpp b/rktwebview_qt/shmqueue.cpp new file mode 100644 index 0000000..ece7412 --- /dev/null +++ b/rktwebview_qt/shmqueue.cpp @@ -0,0 +1,106 @@ +#include "shmqueue.h" + +ShmQueue::ShmQueue(Shm *shm, ShmSlot slot, bool owner) +{ + _shm = shm; + _owner = owner; + + if (owner) { + ShmPlace queue_place = shm->alloc(sizeof(ShmQueueStart)); + shm->setSlot(slot, queue_place); + ref(shm, queue_place, &_queue); + _queue->first = SHM_NULL; + _queue->last = SHM_NULL; + _queue->count = 0; + } else { + ShmPlace queue_start = shm->slot(slot); + ref(shm, queue_start, &_queue); + } + + char buf[1024]; + sprintf(buf, "sem_%s_%d", shm->name(), slot); + _queue_sem = shm->sem(buf, owner); +} + +ShmQueue::~ShmQueue() +{ + if (_owner) { + cleanup(); + } +} + +void ShmQueue::cleanup() +{ + // does currently nothing + delete _queue_sem; +} + +int ShmQueue::depth() +{ + _shm->lock(); + int d = _queue->count; + _shm->unlock(); + return d; +} + +void ShmQueue::enqueue(int cmd, const QString &json_data) +{ + QByteArray b(json_data.toUtf8()); + + int str_place = _shm->alloc(b.size() + 1); + char *s; + ref(_shm, str_place, &s); + memcpy(s, b.constData(), b.size()); + s[b.size()] = '\0'; + + int item_place = _shm->alloc(sizeof(ShmQueueItem)); + ShmQueueItem *item; + ref(_shm, item_place, &item); + item->cmd = cmd; + item->data_place = str_place; + item->prev = _queue->last; + item->next = SHM_NULL; + + _shm->lock(); + _queue->last = item_place; + if (_queue->first == SHM_NULL) { + _queue->first = _queue->last; + } + _queue->count += 1; + _shm->unlock(); + _queue_sem->post(); +} + +bool ShmQueue::dequeue(int &cmd, QString &json_data, bool wait) +{ + if (wait) { + _queue_sem->wait(); + } else { + if (!_queue_sem->trywait()) { + return false; + } + } + _shm->lock(); + + ShmPlace item_place = _queue->first; + ShmQueueItem *item; + ref(_shm, item_place, &item); + _queue->first = item->next; + if (_queue->first == SHM_NULL) { + _queue->last = SHM_NULL; + } + _queue->count -= 1; + + _shm->unlock(); + + ShmPlace data_place = item->data_place; + char *data; + ref(_shm, data_place, &data); + json_data = QString::fromUtf8(data, strlen(data)); + + _shm->free(data_place); + cmd = item->cmd; + + _shm->free(item_place); + return true; +} diff --git a/rktwebview_qt/shmqueue.h b/rktwebview_qt/shmqueue.h new file mode 100644 index 0000000..21f59f1 --- /dev/null +++ b/rktwebview_qt/shmqueue.h @@ -0,0 +1,51 @@ +#ifndef SHMQUEUE_H +#define SHMQUEUE_H + +#include "shm.h" +#include + +#define COMMAND_SLOT 1 +#define EVENT_SLOT 2 + +typedef struct __ShmQueueItem__ +{ + int cmd; + ShmPlace data_place; + ShmPlace next; + ShmPlace prev; +} ShmQueueItem; + +typedef struct __ShmQueue_ +{ + ShmPlace first; + ShmPlace last; + int count; +} ShmQueueStart; + + +class ShmQueue +{ +private: + Shm *_shm; + +private: + ShmQueueStart *_queue; + ShmSem *_queue_sem; + bool _owner; + +private: + void cleanup(); + +public: + int depth(); + +public: + bool dequeue(int &cmd, QString &json_data, bool wait = false); + void enqueue(int cmd, const QString &json_data); + +public: + ShmQueue(Shm *shm, ShmSlot slot, bool owner); + ~ShmQueue(); +}; + +#endif // SHMQUEUE_H