skip to content
==> src/shm.c <==
1/* shm.rs: memfd_create (Linux) / shm_open + unlink (macOS), ftruncate, mmap. */
2#include "mesh/shm.h"
3#include "mesh/text.h"
4
5#include "mesh/abi/base.h"
6
7#include <errno.h>
8#include <fcntl.h>
9#include <stdatomic.h>
10#include <stdlib.h>
11#include <string.h>
12#include <sys/mman.h>
13#include <unistd.h>
14
15static char *os_error(int e) { return mesh_fmt("%s (os error %d)", strerror(e), e); }
16
17static int create(char **err) {
18#if defined(__linux__)
19    int fd = memfd_create("meshd-mailbox", MFD_CLOEXEC);
20    if (fd < 0) {
21        char *e = os_error(errno);
22        mesh_errf(err, "mailbox: memfd_create: %s", e);
23        free(e);
24    }
25    return fd;
26#else
27    static atomic_uint n;
28    /* Names are at most 31 bytes on macOS (PSHMNAMLEN). */
29    char name[32];
30    snprintf(name, sizeof name, "/meshd.%d.%u", (int)getpid(), atomic_fetch_add(&n, 1));
31    int fd = shm_open(name, O_CREAT | O_EXCL | O_RDWR, 0600);
32    if (fd < 0) {
33        char *e = os_error(errno);
34        mesh_errf(err, "mailbox: shm_open \"%s\": %s", name, e);
35        free(e);
36        return -1;
37    }
38    shm_unlink(name);
39    fcntl(fd, F_SETFD, FD_CLOEXEC);
40    return fd;
41#endif
42}
43
44bool mesh_shm_with_len(size_t len, mesh_shm *out, char **err) {
45    int fd = create(err);
46    if (fd < 0) return false;
47    if (ftruncate(fd, (off_t)len) != 0) {
48        char *e = os_error(errno);
49        close(fd);
50        mesh_errf(err, "mailbox: ftruncate %zu: %s", len, e);
51        free(e);
52        return false;
53    }
54    void *p = mmap(NULL, len, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
55    if (p == MAP_FAILED) {
56        char *e = os_error(errno);
57        close(fd);
58        mesh_errf(err, "mailbox: mmap: %s", e);
59        free(e);
60        return false;
61    }
62    *out = (mesh_shm){p, len, fd};
63    return true;
64}
65
66bool mesh_shm_new(mesh_shm *out, char **err) { return mesh_shm_with_len(MESH_MAILBOX_BYTES, out, err); }
67
68char *mesh_shm_path(const mesh_shm *s) { return mesh_fmt("/proc/%d/fd/%d", (int)getpid(), s->fd); }
69
70void mesh_shm_close(mesh_shm *s) {
71    if (s->base) munmap(s->base, s->len);
72    if (s->fd >= 0) close(s->fd);
73    *s = (mesh_shm){NULL, 0, -1};
74}