packages feed

wireform-core-0.2.0.0: cbits/magic_ring_posix.c

#include <sys/mman.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <stdint.h>
#include <stdlib.h>
#include <stdio.h>
#include <stdatomic.h>
#include "magic_ring.h"

static long cached_page_size = 0;

long hs_page_size(void) {
    if (cached_page_size == 0) {
        cached_page_size = sysconf(_SC_PAGESIZE);
    }
    return cached_page_size;
}

static size_t next_pow2(size_t val) {
    val--;
    val |= val >> 1;
    val |= val >> 2;
    val |= val >> 4;
    val |= val >> 8;
    val |= val >> 16;
    val |= val >> 32;
    val++;
    return val;
}

#if !defined(__FreeBSD__) || !defined(SHM_ANON)
static _Atomic long shm_counter = 0;
#endif

int hs_ring_create(size_t requested, struct hs_ring *out) {
    long ps = hs_page_size();
    size_t size;
    int fd;
    void *base, *m1, *m2;
    int saved_errno;

    if (requested < (size_t)ps)
        requested = (size_t)ps;

    size = (requested + (size_t)ps - 1) & ~((size_t)ps - 1);
    size = next_pow2(size);

#if defined(__FreeBSD__) && defined(SHM_ANON)
    fd = shm_open(SHM_ANON, O_RDWR, 0600);
#else
    {
        char name[64];
        snprintf(name, sizeof(name), "/wfring.%d.%ld",
                 getpid(), atomic_fetch_add(&shm_counter, 1));
        fd = shm_open(name, O_RDWR | O_CREAT | O_EXCL, 0600);
        if (fd >= 0)
            shm_unlink(name);
    }
#endif

    if (fd < 0)
        return -1;

    if (ftruncate(fd, (off_t)size) != 0) {
        saved_errno = errno;
        close(fd);
        errno = saved_errno;
        return -1;
    }

    base = mmap(NULL, size * 2, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
    if (base == MAP_FAILED) {
        saved_errno = errno;
        close(fd);
        errno = saved_errno;
        return -1;
    }

    m1 = mmap(base, size, PROT_READ | PROT_WRITE,
              MAP_SHARED | MAP_FIXED, fd, 0);
    if (m1 == MAP_FAILED) {
        saved_errno = errno;
        munmap(base, size * 2);
        close(fd);
        errno = saved_errno;
        return -1;
    }

    m2 = mmap((char *)base + size, size, PROT_READ | PROT_WRITE,
              MAP_SHARED | MAP_FIXED, fd, 0);
    if (m2 == MAP_FAILED) {
        saved_errno = errno;
        munmap(base, size * 2);
        close(fd);
        errno = saved_errno;
        return -1;
    }

    close(fd);
    memset(base, 0, size);

    out->base = base;
    out->size = size;
    return 0;
}

void hs_ring_destroy(struct hs_ring *ring) {
    if (ring && ring->base) {
        munmap(ring->base, ring->size * 2);
        ring->base = NULL;
        ring->size = 0;
    }
}