diff options
author | Simon Ser <contact@emersion.fr> | 2021-08-07 13:46:38 +0200 |
---|---|---|
committer | Kenny Levinsen <kl@kl.wtf> | 2021-09-05 22:06:25 +0200 |
commit | 55ca93469cfaa5ca1d9b6e4c164b23ef55763eb5 (patch) | |
tree | 158288ab6e0fc11a01e4eb98ed6716954ed36101 /util | |
parent | 38cd1b4f4fa8f82944fb0d378bcde3242e0a69ff (diff) |
util/shm: add allocate_shm_file_pair
This function behaves like allocate_shm_file, except it also
returns a read-only FD. This is useful to share the same segment
of memory with many Wayland clients.
Diffstat (limited to 'util')
-rw-r--r-- | util/shm.c | 44 |
1 files changed, 39 insertions, 5 deletions
@@ -8,6 +8,8 @@ #include <wlr/config.h> #include "util/shm.h" +#define RANDNAME_PATTERN "/wlroots-XXXXXX" + static void randname(char *buf) { struct timespec ts; clock_gettime(CLOCK_REALTIME, &ts); @@ -18,17 +20,15 @@ static void randname(char *buf) { } } -int create_shm_file(void) { +static int excl_shm_open(char *name) { int retries = 100; do { - char name[] = "/wlroots-XXXXXX"; - randname(name + strlen(name) - 6); + randname(name + strlen(RANDNAME_PATTERN) - 6); --retries; // CLOEXEC is guaranteed to be set by shm_open int fd = shm_open(name, O_RDWR | O_CREAT | O_EXCL, 0600); if (fd >= 0) { - shm_unlink(name); return fd; } } while (retries > 0 && errno == EEXIST); @@ -37,10 +37,12 @@ int create_shm_file(void) { } int allocate_shm_file(size_t size) { - int fd = create_shm_file(); + char name[] = RANDNAME_PATTERN; + int fd = excl_shm_open(name); if (fd < 0) { return -1; } + shm_unlink(name); int ret; do { @@ -53,3 +55,35 @@ int allocate_shm_file(size_t size) { return fd; } + +bool allocate_shm_file_pair(size_t size, int *rw_fd_ptr, int *ro_fd_ptr) { + char name[] = RANDNAME_PATTERN; + int rw_fd = excl_shm_open(name); + if (rw_fd < 0) { + return false; + } + + // CLOEXEC is guaranteed to be set by shm_open + int ro_fd = shm_open(name, O_RDONLY, 0); + if (ro_fd < 0) { + shm_unlink(name); + close(rw_fd); + return false; + } + + shm_unlink(name); + + int ret; + do { + ret = ftruncate(rw_fd, size); + } while (ret < 0 && errno == EINTR); + if (ret < 0) { + close(rw_fd); + close(ro_fd); + return false; + } + + *rw_fd_ptr = rw_fd; + *ro_fd_ptr = ro_fd; + return true; +} |