summaryrefslogtreecommitdiff
path: root/src/lib/shm_rdrbuff.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib/shm_rdrbuff.c')
-rw-r--r--src/lib/shm_rdrbuff.c617
1 files changed, 0 insertions, 617 deletions
diff --git a/src/lib/shm_rdrbuff.c b/src/lib/shm_rdrbuff.c
deleted file mode 100644
index 5cdeba9e..00000000
--- a/src/lib/shm_rdrbuff.c
+++ /dev/null
@@ -1,617 +0,0 @@
-/*
- * Ouroboros - Copyright (C) 2016 - 2024
- *
- * Random Deletion Ring Buffer for Data Units
- *
- * Dimitri Staessens <dimitri@ouroboros.rocks>
- * Sander Vrijders <sander@ouroboros.rocks>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public License
- * version 2.1 as published by the Free Software Foundation.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., http://www.fsf.org/about/contact/.
- */
-
-#define _POSIX_C_SOURCE 200809L
-
-#include "config.h"
-
-#include <ouroboros/errno.h>
-#include <ouroboros/pthread.h>
-#include <ouroboros/shm_rdrbuff.h>
-
-#include <assert.h>
-#include <fcntl.h>
-#include <signal.h>
-#include <stdbool.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <sys/mman.h>
-#include <sys/stat.h>
-
-#define SHM_BLOCKS_SIZE ((SHM_BUFFER_SIZE) * SHM_RDRB_BLOCK_SIZE)
-#define SHM_FILE_SIZE (SHM_BLOCKS_SIZE + 2 * sizeof(size_t) \
- + sizeof(pthread_mutex_t) + 2 * sizeof(pthread_cond_t) \
- + sizeof(pid_t))
-#define DU_BUFF_OVERHEAD (DU_BUFF_HEADSPACE + DU_BUFF_TAILSPACE)
-
-#define get_head_ptr(rdrb) \
- idx_to_du_buff_ptr(rdrb, *rdrb->head)
-
-#define get_tail_ptr(rdrb) \
- idx_to_du_buff_ptr(rdrb, *rdrb->tail)
-
-#define idx_to_du_buff_ptr(rdrb, idx) \
- ((struct shm_du_buff *) (rdrb->shm_base + idx * SHM_RDRB_BLOCK_SIZE))
-
-#define shm_rdrb_used(rdrb) \
- (((*rdrb->head + (SHM_BUFFER_SIZE) - *rdrb->tail) + 1) \
- & ((SHM_BUFFER_SIZE) - 1))
-
-#define shm_rdrb_free(rdrb, i) \
- (shm_rdrb_used(rdrb) + i < (SHM_BUFFER_SIZE))
-
-#define shm_rdrb_empty(rdrb) \
- (*rdrb->tail == *rdrb->head)
-
-struct shm_du_buff {
- size_t size;
-#ifdef SHM_RDRB_MULTI_BLOCK
- size_t blocks;
-#endif
- size_t du_head;
- size_t du_tail;
- size_t refs;
- size_t idx;
-};
-
-struct shm_rdrbuff {
- uint8_t * shm_base; /* start of blocks */
- size_t * head; /* start of ringbuffer head */
- size_t * tail; /* start of ringbuffer tail */
- pthread_mutex_t * lock; /* lock all free space in shm */
- pthread_cond_t * healthy; /* flag when packet is read */
- pid_t * pid; /* pid of the irmd owner */
-};
-
-static void garbage_collect(struct shm_rdrbuff * rdrb)
-{
-#ifdef SHM_RDRB_MULTI_BLOCK
- struct shm_du_buff * sdb;
- while (!shm_rdrb_empty(rdrb) &&
- (sdb = get_tail_ptr(rdrb))->refs == 0)
- *rdrb->tail = (*rdrb->tail + sdb->blocks)
- & ((SHM_BUFFER_SIZE) - 1);
-#else
- while (!shm_rdrb_empty(rdrb) && get_tail_ptr(rdrb)->refs == 0)
- *rdrb->tail = (*rdrb->tail + 1) & ((SHM_BUFFER_SIZE) - 1);
-#endif
- pthread_cond_broadcast(rdrb->healthy);
-}
-
-#ifdef HAVE_ROBUST_MUTEX
-static void sanitize(struct shm_rdrbuff * rdrb)
-{
- --get_head_ptr(rdrb)->refs;
- garbage_collect(rdrb);
- pthread_mutex_consistent(rdrb->lock);
-}
-#endif
-
-static char * rdrb_filename(void)
-{
- char * str;
-
- str = malloc(strlen(SHM_RDRB_NAME) + 1);
- if (str == NULL)
- return NULL;
-
- sprintf(str, "%s", SHM_RDRB_NAME);
-
- return str;
-}
-
-void shm_rdrbuff_close(struct shm_rdrbuff * rdrb)
-{
- assert(rdrb);
-
- munmap(rdrb->shm_base, SHM_FILE_SIZE);
- free(rdrb);
-}
-
-void shm_rdrbuff_destroy(struct shm_rdrbuff * rdrb)
-{
- char * shm_rdrb_fn;
-
- assert(rdrb);
-
- if (getpid() != *rdrb->pid && kill(*rdrb->pid, 0) == 0) {
- free(rdrb);
- return;
- }
-
- shm_rdrbuff_close(rdrb);
-
- shm_rdrb_fn = rdrb_filename();
- if (shm_rdrb_fn == NULL)
- return;
-
- shm_unlink(shm_rdrb_fn);
- free(shm_rdrb_fn);
-}
-
-#define MM_FLAGS (PROT_READ | PROT_WRITE)
-
-static struct shm_rdrbuff * rdrb_create(int flags)
-{
- struct shm_rdrbuff * rdrb;
- int fd;
- uint8_t * shm_base;
- char * shm_rdrb_fn;
-
- shm_rdrb_fn = rdrb_filename();
- if (shm_rdrb_fn == NULL)
- goto fail_fn;
-
- rdrb = malloc(sizeof *rdrb);
- if (rdrb == NULL)
- goto fail_rdrb;
-
- fd = shm_open(shm_rdrb_fn, flags, 0666);
- if (fd == -1)
- goto fail_open;
-
- if ((flags & O_CREAT) && ftruncate(fd, SHM_FILE_SIZE) < 0)
- goto fail_truncate;
-
- shm_base = mmap(NULL, SHM_FILE_SIZE, MM_FLAGS, MAP_SHARED, fd, 0);
- if (shm_base == MAP_FAILED)
- goto fail_truncate;
-
- close(fd);
-
- rdrb->shm_base = shm_base;
- rdrb->head = (size_t *) ((uint8_t *) rdrb->shm_base + SHM_BLOCKS_SIZE);
- rdrb->tail = rdrb->head + 1;
- rdrb->lock = (pthread_mutex_t *) (rdrb->tail + 1);
- rdrb->healthy = (pthread_cond_t *) (rdrb->lock + 1);
- rdrb->pid = (pid_t *) (rdrb->healthy + 1);
-
- free(shm_rdrb_fn);
-
- return rdrb;
-
- fail_truncate:
- close(fd);
- if (flags & O_CREAT)
- shm_unlink(shm_rdrb_fn);
- fail_open:
- free(rdrb);
- fail_rdrb:
- free(shm_rdrb_fn);
- fail_fn:
- return NULL;
-}
-
-struct shm_rdrbuff * shm_rdrbuff_create(void)
-{
- struct shm_rdrbuff * rdrb;
- mode_t mask;
- pthread_mutexattr_t mattr;
- pthread_condattr_t cattr;
-
- mask = umask(0);
-
- rdrb = rdrb_create(O_CREAT | O_EXCL | O_RDWR);
-
- umask(mask);
-
- if (rdrb == NULL)
- goto fail_rdrb;
-
- if (pthread_mutexattr_init(&mattr))
- goto fail_mattr;
-
- pthread_mutexattr_setpshared(&mattr, PTHREAD_PROCESS_SHARED);
-#ifdef HAVE_ROBUST_MUTEX
- pthread_mutexattr_setrobust(&mattr, PTHREAD_MUTEX_ROBUST);
-#endif
- if (pthread_mutex_init(rdrb->lock, &mattr))
- goto fail_mutex;
-
- if (pthread_condattr_init(&cattr))
- goto fail_cattr;
-
- pthread_condattr_setpshared(&cattr, PTHREAD_PROCESS_SHARED);
-#ifndef __APPLE__
- pthread_condattr_setclock(&cattr, PTHREAD_COND_CLOCK);
-#endif
- if (pthread_cond_init(rdrb->healthy, &cattr))
- goto fail_healthy;
-
- *rdrb->head = 0;
- *rdrb->tail = 0;
-
- *rdrb->pid = getpid();
-
- pthread_mutexattr_destroy(&mattr);
- pthread_condattr_destroy(&cattr);
-
- return rdrb;
-
- fail_healthy:
- pthread_condattr_destroy(&cattr);
- fail_cattr:
- pthread_mutex_destroy(rdrb->lock);
- fail_mutex:
- pthread_mutexattr_destroy(&mattr);
- fail_mattr:
- shm_rdrbuff_destroy(rdrb);
- fail_rdrb:
- return NULL;
-}
-
-struct shm_rdrbuff * shm_rdrbuff_open(void)
-{
- return rdrb_create(O_RDWR);
-}
-
-void shm_rdrbuff_purge(void)
-{
- char * shm_rdrb_fn;
-
- shm_rdrb_fn = rdrb_filename();
- if (shm_rdrb_fn == NULL)
- return;
-
- shm_unlink(shm_rdrb_fn);
- free(shm_rdrb_fn);
-}
-
-int shm_rdrbuff_mlock(struct shm_rdrbuff * rdrb)
-{
- assert(rdrb != NULL);
-
- return mlock(rdrb->shm_base, SHM_FILE_SIZE);
-}
-
-ssize_t shm_rdrbuff_alloc(struct shm_rdrbuff * rdrb,
- size_t len,
- uint8_t ** ptr,
- struct shm_du_buff ** psdb)
-{
- struct shm_du_buff * sdb;
- size_t size = DU_BUFF_OVERHEAD + len;
-#ifdef SHM_RDRB_MULTI_BLOCK
- size_t blocks = 0;
- size_t padblocks = 0;
-#endif
- ssize_t sz = size + sizeof(*sdb);
-
- assert(rdrb);
- assert(psdb);
-
-#ifndef SHM_RDRB_MULTI_BLOCK
- if (sz > SHM_RDRB_BLOCK_SIZE)
- return -EMSGSIZE;
-#else
- while (sz > 0) {
- sz -= SHM_RDRB_BLOCK_SIZE;
- ++blocks;
- }
-#endif
-#ifndef HAVE_ROBUST_MUTEX
- pthread_mutex_lock(rdrb->lock);
-#else
- if (pthread_mutex_lock(rdrb->lock) == EOWNERDEAD)
- sanitize(rdrb);
-#endif
-#ifdef SHM_RDRB_MULTI_BLOCK
- if (blocks + *rdrb->head > (SHM_BUFFER_SIZE))
- padblocks = (SHM_BUFFER_SIZE) - *rdrb->head;
-
- if (!shm_rdrb_free(rdrb, blocks + padblocks)) {
-#else
- if (!shm_rdrb_free(rdrb, 1)) {
-#endif
- pthread_mutex_unlock(rdrb->lock);
- return -EAGAIN;
- }
-
-#ifdef SHM_RDRB_MULTI_BLOCK
- if (padblocks) {
- sdb = get_head_ptr(rdrb);
- sdb->size = 0;
- sdb->blocks = padblocks;
- sdb->refs = 0;
- sdb->du_head = 0;
- sdb->du_tail = 0;
- sdb->idx = *rdrb->head;
-
- *rdrb->head = 0;
- }
-#endif
- sdb = get_head_ptr(rdrb);
- sdb->refs = 1;
- sdb->idx = *rdrb->head;
-#ifdef SHM_RDRB_MULTI_BLOCK
- sdb->blocks = blocks;
-
- *rdrb->head = (*rdrb->head + blocks) & ((SHM_BUFFER_SIZE) - 1);
-#else
- *rdrb->head = (*rdrb->head + 1) & ((SHM_BUFFER_SIZE) - 1);
-#endif
- pthread_mutex_unlock(rdrb->lock);
-
- sdb->size = size;
- sdb->du_head = DU_BUFF_HEADSPACE;
- sdb->du_tail = sdb->du_head + len;
-
- *psdb = sdb;
- if (ptr != NULL)
- *ptr = (uint8_t *) (sdb + 1) + sdb->du_head;
-
- return sdb->idx;
-}
-
-ssize_t shm_rdrbuff_alloc_b(struct shm_rdrbuff * rdrb,
- size_t len,
- uint8_t ** ptr,
- struct shm_du_buff ** psdb,
- const struct timespec * abstime)
-{
- struct shm_du_buff * sdb;
- size_t size = DU_BUFF_OVERHEAD + len;
-#ifdef SHM_RDRB_MULTI_BLOCK
- size_t blocks = 0;
- size_t padblocks = 0;
-#endif
- ssize_t sz = size + sizeof(*sdb);
- int ret = 0;
-
- assert(rdrb);
- assert(psdb);
-
-#ifndef SHM_RDRB_MULTI_BLOCK
- if (sz > SHM_RDRB_BLOCK_SIZE)
- return -EMSGSIZE;
-#else
- while (sz > 0) {
- sz -= SHM_RDRB_BLOCK_SIZE;
- ++blocks;
- }
-#endif
-#ifndef HAVE_ROBUST_MUTEX
- pthread_mutex_lock(rdrb->lock);
-#else
- if (pthread_mutex_lock(rdrb->lock) == EOWNERDEAD)
- sanitize(rdrb);
-#endif
- pthread_cleanup_push(__cleanup_mutex_unlock, rdrb->lock);
-
-#ifdef SHM_RDRB_MULTI_BLOCK
- if (blocks + *rdrb->head > (SHM_BUFFER_SIZE))
- padblocks = (SHM_BUFFER_SIZE) - *rdrb->head;
-
- while (!shm_rdrb_free(rdrb, blocks + padblocks) && ret != ETIMEDOUT) {
-#else
- while (!shm_rdrb_free(rdrb, 1) && ret != ETIMEDOUT) {
-#endif
- ret = __timedwait(rdrb->healthy, rdrb->lock, abstime);
-#ifdef SHM_RDRB_MULTI_BLOCK
- if (blocks + *rdrb->head > (SHM_BUFFER_SIZE))
- padblocks = (SHM_BUFFER_SIZE) - *rdrb->head;
-#endif
- }
-
- if (ret != ETIMEDOUT) {
-#ifdef SHM_RDRB_MULTI_BLOCK
- if (padblocks) {
- sdb = get_head_ptr(rdrb);
- sdb->size = 0;
- sdb->blocks = padblocks;
- sdb->refs = 0;
- sdb->du_head = 0;
- sdb->du_tail = 0;
- sdb->idx = *rdrb->head;
-
- *rdrb->head = 0;
- }
-#endif
- sdb = get_head_ptr(rdrb);
- sdb->refs = 1;
- sdb->idx = *rdrb->head;
-#ifdef SHM_RDRB_MULTI_BLOCK
- sdb->blocks = blocks;
-
- *rdrb->head = (*rdrb->head + blocks) & ((SHM_BUFFER_SIZE) - 1);
-#else
- *rdrb->head = (*rdrb->head + 1) & ((SHM_BUFFER_SIZE) - 1);
-#endif
- }
-
- pthread_cleanup_pop(true);
-
- if (ret == ETIMEDOUT)
- return -ETIMEDOUT;
-
- sdb->size = size;
- sdb->du_head = DU_BUFF_HEADSPACE;
- sdb->du_tail = sdb->du_head + len;
-
- *psdb = sdb;
- if (ptr != NULL)
- *ptr = (uint8_t *) (sdb + 1) + sdb->du_head;
-
- return sdb->idx;
-}
-
-ssize_t shm_rdrbuff_read(uint8_t ** dst,
- struct shm_rdrbuff * rdrb,
- size_t idx)
-{
- struct shm_du_buff * sdb;
-
- assert(dst);
- assert(rdrb);
- assert(idx < (SHM_BUFFER_SIZE));
-
- sdb = idx_to_du_buff_ptr(rdrb, idx);
- *dst = ((uint8_t *) (sdb + 1)) + sdb->du_head;
-
- return (ssize_t) (sdb->du_tail - sdb->du_head);
-}
-
-struct shm_du_buff * shm_rdrbuff_get(struct shm_rdrbuff * rdrb,
- size_t idx)
-{
- assert(rdrb);
- assert(idx < (SHM_BUFFER_SIZE));
-
- return idx_to_du_buff_ptr(rdrb, idx);
-}
-
-int shm_rdrbuff_remove(struct shm_rdrbuff * rdrb,
- size_t idx)
-{
- struct shm_du_buff * sdb;
-
- assert(rdrb);
- assert(idx < (SHM_BUFFER_SIZE));
-
-#ifndef HAVE_ROBUST_MUTEX
- pthread_mutex_lock(rdrb->lock);
-#else
- if (pthread_mutex_lock(rdrb->lock) == EOWNERDEAD)
- sanitize(rdrb);
-#endif
- /* assert(!shm_rdrb_empty(rdrb)); */
-
- sdb = idx_to_du_buff_ptr(rdrb, idx);
-
- if (sdb->refs == 1) { /* only stack needs it, can be removed */
- sdb->refs = 0;
- if (idx == *rdrb->tail)
- garbage_collect(rdrb);
- }
-
- pthread_mutex_unlock(rdrb->lock);
-
- return 0;
-}
-
-size_t shm_du_buff_get_idx(struct shm_du_buff * sdb)
-{
- assert(sdb);
-
- return sdb->idx;
-}
-
-uint8_t * shm_du_buff_head(struct shm_du_buff * sdb)
-{
- assert(sdb);
-
- return (uint8_t *) (sdb + 1) + sdb->du_head;
-}
-
-uint8_t * shm_du_buff_tail(struct shm_du_buff * sdb)
-{
- assert(sdb);
-
- return (uint8_t *) (sdb + 1) + sdb->du_tail;
-}
-
-size_t shm_du_buff_len(struct shm_du_buff * sdb)
-{
- assert(sdb);
-
- return sdb->du_tail - sdb->du_head;
-}
-
-uint8_t * shm_du_buff_head_alloc(struct shm_du_buff * sdb,
- size_t size)
-{
- assert(sdb);
-
- if (sdb->du_head < size)
- return NULL;
-
- sdb->du_head -= size;
-
- return (uint8_t *) (sdb + 1) + sdb->du_head;
-}
-
-uint8_t * shm_du_buff_tail_alloc(struct shm_du_buff * sdb,
- size_t size)
-{
- uint8_t * buf;
-
- assert(sdb);
-
- if (sdb->du_tail + size >= sdb->size)
- return NULL;
-
- buf = (uint8_t *) (sdb + 1) + sdb->du_tail;
-
- sdb->du_tail += size;
-
- return buf;
-}
-
-uint8_t * shm_du_buff_head_release(struct shm_du_buff * sdb,
- size_t size)
-{
- uint8_t * buf;
-
- assert(sdb);
- assert(!(size > sdb->du_tail - sdb->du_head));
-
- buf = (uint8_t *) (sdb + 1) + sdb->du_head;
-
- sdb->du_head += size;
-
- return buf;
-}
-
-uint8_t * shm_du_buff_tail_release(struct shm_du_buff * sdb,
- size_t size)
-{
- assert(sdb);
- assert(!(size > sdb->du_tail - sdb->du_head));
-
- sdb->du_tail -= size;
-
- return (uint8_t *) (sdb + 1) + sdb->du_tail;
-}
-
-void shm_du_buff_truncate(struct shm_du_buff * sdb,
- size_t len)
-{
- assert(sdb);
- assert(len <= sdb->size);
-
- sdb->du_tail = sdb->du_head + len;
-}
-
-int shm_du_buff_wait_ack(struct shm_du_buff * sdb)
-{
- __sync_add_and_fetch(&sdb->refs, 1);
-
- return 0;
-}
-
-int shm_du_buff_ack(struct shm_du_buff * sdb)
-{
- __sync_sub_and_fetch(&sdb->refs, 1);
- return 0;
-}