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.
This commit is contained in:
Simon Ser 2021-08-07 13:46:38 +02:00 committed by Kenny Levinsen
parent 38cd1b4f4f
commit 55ca93469c
2 changed files with 42 additions and 5 deletions

View file

@ -1,7 +1,10 @@
#ifndef UTIL_SHM_H
#define UTIL_SHM_H
#include <stdbool.h>
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

View file

@ -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;
}