diff --git a/include/util/shm.h b/include/util/shm.h index fb67b711..331532fc 100644 --- a/include/util/shm.h +++ b/include/util/shm.h @@ -1,7 +1,10 @@ #ifndef UTIL_SHM_H #define UTIL_SHM_H +#include + int create_shm_file(void); int allocate_shm_file(size_t size); +bool allocate_shm_file_pair(size_t size, int *rw_fd, int *ro_fd); #endif diff --git a/util/shm.c b/util/shm.c index f7c7303e..e0d84e8e 100644 --- a/util/shm.c +++ b/util/shm.c @@ -8,6 +8,8 @@ #include #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; +}