aboutsummaryrefslogtreecommitdiff
path: root/util
diff options
context:
space:
mode:
authorSimon Ser <contact@emersion.fr>2021-08-07 13:46:38 +0200
committerKenny Levinsen <kl@kl.wtf>2021-09-05 22:06:25 +0200
commit55ca93469cfaa5ca1d9b6e4c164b23ef55763eb5 (patch)
tree158288ab6e0fc11a01e4eb98ed6716954ed36101 /util
parent38cd1b4f4fa8f82944fb0d378bcde3242e0a69ff (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.c44
1 files changed, 39 insertions, 5 deletions
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 <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;
+}