with shared memory
This commit is contained in:
352
rktwebview_qt/shm.cpp
Normal file
352
rktwebview_qt/shm.cpp
Normal file
@@ -0,0 +1,352 @@
|
|||||||
|
#include "shm.h"
|
||||||
|
|
||||||
|
#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 <semaphore.h>
|
||||||
|
|
||||||
|
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<char *>(i) + sizeof(ShmItem)) - reinterpret_cast<char *>(_mem);
|
||||||
|
} else {
|
||||||
|
i = reinterpret_cast<ShmItem *>(reinterpret_cast<char *>(_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<char *>(i) + sizeof(ShmItem)) - reinterpret_cast<char *>(_mem);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
leaveCritical();
|
||||||
|
return place;
|
||||||
|
}
|
||||||
|
|
||||||
|
void free(int place) {
|
||||||
|
enterCritical();
|
||||||
|
ShmItem *i = reinterpret_cast<ShmItem *>(reinterpret_cast<char *>(_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<char *>(_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 <ShmPlace *>(reinterpret_cast<char *>(_mem) + sizeof(size_t) + sizeof(ShmItem *) + sizeof(ShmItem *));
|
||||||
|
|
||||||
|
_used = reinterpret_cast<size_t *>(_mem);
|
||||||
|
|
||||||
|
__first = reinterpret_cast<ShmItem **>(reinterpret_cast<char *>(_mem) + sizeof(size_t));
|
||||||
|
|
||||||
|
__free_list = reinterpret_cast<ShmItem **>(reinterpret_cast<char *>(_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<class T> void ref(Shm *shm, int place, T **p)
|
||||||
|
{
|
||||||
|
*p = reinterpret_cast<T *>(shm->ref(place));
|
||||||
|
}
|
||||||
|
|
||||||
|
void ShmSem::post() {
|
||||||
|
sem_post(reinterpret_cast<sem_t *>(_sem));
|
||||||
|
}
|
||||||
|
|
||||||
|
void ShmSem::wait() {
|
||||||
|
sem_wait(reinterpret_cast<sem_t *>(_sem));
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ShmSem::trywait() {
|
||||||
|
return sem_trywait(reinterpret_cast<sem_t *>(_sem)) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
ShmSem::ShmSem(const char *n, bool owner) {
|
||||||
|
_name = strdup(n);
|
||||||
|
_sem = reinterpret_cast<void *>(sem_open(n, O_CREAT));
|
||||||
|
_owner = owner;
|
||||||
|
}
|
||||||
|
|
||||||
|
ShmSem::~ShmSem() {
|
||||||
|
sem_close(reinterpret_cast<sem_t *>(_sem));
|
||||||
|
if (_owner) {
|
||||||
|
sem_unlink(_name);
|
||||||
|
}
|
||||||
|
free(_name);
|
||||||
|
}
|
||||||
60
rktwebview_qt/shm.h
Normal file
60
rktwebview_qt/shm.h
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
#ifndef SHM_H
|
||||||
|
#define SHM_H
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
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 <class T> void ref(Shm *shm, int place, T **p);
|
||||||
|
|
||||||
|
#endif // SHM_H
|
||||||
106
rktwebview_qt/shmqueue.cpp
Normal file
106
rktwebview_qt/shmqueue.cpp
Normal file
@@ -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;
|
||||||
|
}
|
||||||
51
rktwebview_qt/shmqueue.h
Normal file
51
rktwebview_qt/shmqueue.h
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
#ifndef SHMQUEUE_H
|
||||||
|
#define SHMQUEUE_H
|
||||||
|
|
||||||
|
#include "shm.h"
|
||||||
|
#include <QString>
|
||||||
|
|
||||||
|
#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
|
||||||
Reference in New Issue
Block a user