Introduce xcb_aux_alloc_shm() to create anonymous files in RAM

Submitted by Alexander Volkov on Feb. 15, 2019, 4:08 p.m.

Details

Message ID 20190215160824.29974-1-avolkov@astralinux.ru
State New
Headers show
Series "Introduce xcb_aux_alloc_shm() to create anonymous files in RAM" ( rev: 3 ) in XCB

Not browsing as part of any series.

Commit Message

Alexander Volkov Feb. 15, 2019, 4:08 p.m.
From: Alexander Volkov <a.volkov@rusbitech.ru>

... which then can be mapped with mmap().
It is intended to be used in conjunction with xcb_shm_attach_fd()
to access the created shared memory from a client and the X server.

The implementation is based on the code of shm_tmpfile()
from X.Org Server.

Signed-off-by: Alexander Volkov <a.volkov@rusbitech.ru>
---
 configure.ac  |  4 +++
 src/xcb_aux.c | 91 +++++++++++++++++++++++++++++++++++++++++++++++++++
 src/xcb_aux.h |  3 ++
 3 files changed, 98 insertions(+)

Patch hide | download patch | download mbox

diff --git a/configure.ac b/configure.ac
index 1fe1561..8e31ada 100644
--- a/configure.ac
+++ b/configure.ac
@@ -7,10 +7,14 @@  AC_CONFIG_HEADERS([config.h])
 AC_CONFIG_MACRO_DIR([m4])
 AM_INIT_AUTOMAKE([foreign dist-bzip2])
 
+AC_USE_SYSTEM_EXTENSIONS
+
 XCB_UTIL_COMMON([1.4], [1.6])
 
 AC_CHECK_FUNCS_ONCE(vasprintf)
 
+AC_CHECK_FUNCS(memfd_create mkostemp)
+
 AC_CONFIG_FILES([Makefile
 		src/Makefile
 		xcb-atom.pc
diff --git a/src/xcb_aux.c b/src/xcb_aux.c
index b6f64f8..bb407fb 100644
--- a/src/xcb_aux.c
+++ b/src/xcb_aux.c
@@ -33,9 +33,16 @@ 
 #include "config.h"
 #endif
 
+#include <unistd.h>
+#if HAVE_MEMFD_CREATE
+#include <sys/mman.h>
+#endif
+
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#include <fcntl.h>
+#include <limits.h>
 
 #include <xcb/xcb.h>
 #include "xcb_aux.h"
@@ -376,3 +383,87 @@  xcb_aux_clear_window(xcb_connection_t *  dpy,
 {
     return xcb_clear_area(dpy, 0, w, 0, 0, 0, 0);
 }
+
+/* SHM related functions */
+
+static int
+shm_tmpfile(void)
+{
+    const char *shmdirs[] = {
+        "/run/shm",
+        "/var/tmp",
+        "/tmp",
+    };
+    const int shmdirs_count = sizeof(shmdirs) / sizeof(shmdirs[0]);
+    int fd;
+
+#ifdef HAVE_MEMFD_CREATE
+    fd = memfd_create("xcb", MFD_CLOEXEC|MFD_ALLOW_SEALING);
+    if (fd != -1)
+        return fd;
+#endif
+
+#ifdef O_TMPFILE
+    for (int i = 0; i < shmdirs_count; i++) {
+        fd = open(shmdirs[i], O_TMPFILE|O_RDWR|O_CLOEXEC|O_EXCL, 0666);
+        if (fd >= 0)
+            return fd;
+    }
+#endif
+
+    for (int i = 0; i < shmdirs_count; i++) {
+        char template[PATH_MAX];
+        snprintf(template, sizeof(template), "%s/shmfd-XXXXXX", shmdirs[i]);
+#ifdef HAVE_MKOSTEMP
+        fd = mkostemp(template, O_CLOEXEC);
+#else
+        fd = mkstemp(template);
+#endif
+        if (fd < 0)
+            continue;
+        unlink(template);
+#ifndef HAVE_MKOSTEMP
+        int flags = fcntl(fd, F_GETFD);
+        if (flags != -1) {
+            flags |= FD_CLOEXEC;
+            (void) fcntl(fd, F_SETFD, &flags);
+        }
+#endif
+        return fd;
+    }
+
+    return -1;
+}
+
+/**
+ * xcb_aux_alloc_shm:
+ *
+ * Creates an anonymous file of the required size in RAM.
+ * It enables the close-on-exec flag for the file
+ * descriptor. The F_SEAL_SHRINK seal is set when
+ * possible, thus the file cannot be reduced in size.
+ * This function is intended for use in conjunction with
+ * xcb_shm_attach_fd().
+ *
+ * Return value: the file descriptor, or -1 on failure
+ * (in which case, errno will be set as appropriate).
+ **/
+
+int
+xcb_aux_alloc_shm(size_t size)
+{
+    int fd;
+
+    fd = shm_tmpfile();
+    if (fd < 0)
+        return -1;
+#if defined(F_ADD_SEALS) && defined(F_SEAL_SHRINK)
+    (void) fcntl(fd, F_ADD_SEALS, F_SEAL_SHRINK);
+#endif
+    if (ftruncate(fd, size) < 0) {
+        close(fd);
+        return -1;
+    }
+
+    return fd;
+}
diff --git a/src/xcb_aux.h b/src/xcb_aux.h
index da4fb85..75b6e66 100644
--- a/src/xcb_aux.h
+++ b/src/xcb_aux.h
@@ -206,6 +206,9 @@  xcb_void_cookie_t
 xcb_aux_clear_window(xcb_connection_t *  dpy,
 		     xcb_window_t        w);
 
+int
+xcb_aux_alloc_shm(size_t size);
+
 #ifdef __cplusplus
 }
 #endif