Data-HashMap-Shared
view release on metacpan or search on metacpan
shm_generic.h view on Meta::CPAN
/* Allocate the process-local ShmHandle given an already-mmap'd base and
* a computed layout. Shared by shm_create_map, shm_create_memfd and
* shm_open_fd_map; all three differ only in how they acquire `base`. */
static ShmHandle *shm_alloc_handle(void *base, uint64_t total_size,
int has_arena, int has_lru, int has_ttl,
const ShmLayout *lo,
const char *path, int backing_fd, char *errbuf) {
ShmHeader *hdr = (ShmHeader *)base;
ShmHandle *h = (ShmHandle *)calloc(1, sizeof(ShmHandle));
if (!h) {
if (errbuf) snprintf(errbuf, SHM_ERR_BUFLEN, "calloc: out of memory");
munmap(base, (size_t)total_size);
if (backing_fd >= 0) close(backing_fd);
return NULL;
}
h->hdr = hdr;
h->nodes = (char *)hdr + hdr->nodes_off;
h->states = (uint8_t *)((char *)hdr + hdr->states_off);
h->arena = hdr->arena_off ? (char *)hdr + hdr->arena_off : NULL;
h->lru_prev = has_lru ? (uint32_t *)((char *)hdr + lo->lru_prev_off) : NULL;
h->lru_next = has_lru ? (uint32_t *)((char *)hdr + lo->lru_next_off) : NULL;
h->lru_accessed = has_lru ? (uint8_t *)((char *)hdr + lo->lru_accessed_off) : NULL;
h->expires_at = has_ttl ? (uint32_t *)((char *)hdr + lo->expires_off) : NULL;
h->reader_slots = (ShmReaderSlot *)((char *)hdr + lo->reader_slots_off);
/* Slot claimed lazily on first lock â see shm_claim_reader_slot. */
h->my_slot_idx = UINT32_MAX;
h->cached_pid = 0;
h->mmap_size = (size_t)total_size;
h->max_mask = hdr->max_table_cap - 1;
h->iter_pos = 0;
h->backing_fd = backing_fd;
/* Hash lookups are random-access: hint the kernel to skip
* read-ahead. Best-effort â failure (e.g., MADV_RANDOM not
* supported) is harmless. */
(void)madvise(base, (size_t)total_size, MADV_RANDOM);
if (path) {
h->path = strdup(path);
if (!h->path) {
if (errbuf) snprintf(errbuf, SHM_ERR_BUFLEN, "strdup: out of memory");
munmap(base, (size_t)total_size);
if (backing_fd >= 0) close(backing_fd);
free(h);
return NULL;
}
}
/* Pre-size copy_buf for string variants to avoid realloc on first access */
if (has_arena) {
h->copy_buf = (char *)malloc(256);
if (h->copy_buf) h->copy_buf_size = 256;
}
return h;
}
/* Securely obtain a fd: create exclusively (O_CREAT|O_EXCL|O_NOFOLLOW at
* file_mode, default 0600 = owner-only), or attach an existing file
* (O_RDWR|O_NOFOLLOW, no O_CREAT). Blocks a symlink swap or a pre-seeded/
* hard-linked backing file; cross-user sharing is opt-in via a wider file_mode. */
static int shm_secure_open(const char *path, mode_t file_mode, char *errbuf) {
for (int attempt = 0; attempt < 100; attempt++) {
int fd = open(path, O_RDWR|O_CREAT|O_EXCL|O_NOFOLLOW|O_CLOEXEC, file_mode);
if (fd >= 0) { (void)fchmod(fd, file_mode); return fd; } /* exact mode: umask narrowed the O_EXCL create */
if (errno != EEXIST) {
if (errbuf) snprintf(errbuf, SHM_ERR_BUFLEN, "create(%s): %s", path, strerror(errno));
return -1;
}
fd = open(path, O_RDWR|O_NOFOLLOW|O_CLOEXEC);
if (fd >= 0) return fd;
if (errno == ENOENT) continue; /* creator unlinked between our two opens; retry */
if (errbuf) snprintf(errbuf, SHM_ERR_BUFLEN, "open(%s): %s", path, strerror(errno));
return -1;
}
if (errbuf) snprintf(errbuf, SHM_ERR_BUFLEN, "open(%s): create/attach kept racing", path);
return -1;
}
static ShmHandle *shm_create_map(const char *path, uint32_t max_entries,
uint32_t node_size, uint32_t variant_id,
int has_arena, uint32_t max_size,
uint32_t default_ttl, uint32_t lru_skip,
uint64_t arena_cap_override, mode_t file_mode, char *errbuf) {
if (errbuf) errbuf[0] = '\0';
uint32_t max_tcap = shm_max_tcap_from_entries(max_entries);
int has_lru = (max_size > 0);
int has_ttl = (default_ttl > 0);
ShmLayout lo;
shm_compute_layout(&lo, max_tcap, node_size, has_lru, has_ttl, has_arena, max_entries, arena_cap_override);
#define SHM_ERR(fmt, ...) do { if (errbuf) snprintf(errbuf, SHM_ERR_BUFLEN, fmt, ##__VA_ARGS__); } while(0)
int anonymous = (path == NULL);
int fd = -1;
int is_new;
struct stat st = { 0 };
void *base;
if (anonymous) {
base = mmap(NULL, lo.total_size, PROT_READ | PROT_WRITE,
MAP_SHARED | MAP_ANONYMOUS, -1, 0);
if (base == MAP_FAILED) { SHM_ERR("mmap(anon): %s", strerror(errno)); return NULL; }
is_new = 1;
} else {
fd = shm_secure_open(path, file_mode, errbuf);
if (fd < 0) return NULL;
while (flock(fd, LOCK_EX) < 0) {
if (errno == EINTR) continue; /* retry: a signal interrupted the blocking lock */
SHM_ERR("flock(%s): %s", path, strerror(errno)); close(fd); return NULL;
}
if (fstat(fd, &st) < 0) { SHM_ERR("fstat(%s): %s", path, strerror(errno)); flock(fd, LOCK_UN); close(fd); return NULL; }
is_new = (st.st_size == 0);
if (!is_new && (uint64_t)st.st_size < sizeof(ShmHeader)) {
SHM_ERR("%s: file too small (%lld bytes, need %zu)", path,
(long long)st.st_size, sizeof(ShmHeader));
flock(fd, LOCK_UN); close(fd); return NULL;
}
( run in 3.680 seconds using v1.01-cache-2.11-cpan-600a1bdf6e4 )