[PATCH xserver 2/2] Xephyr: Prefer using MIT-SHM FD-passing when possible

Alexander Volkov a.volkov at rusbitech.ru
Wed Jan 31 12:36:36 UTC 2018


This makes the shared memory visible only for the Xephyr
and the X server to which it is connected.

Signed-off-by: Alexander Volkov <a.volkov at rusbitech.ru>
---
 configure.ac            |   2 +-
 hw/kdrive/ephyr/ephyr.h |   1 +
 hw/kdrive/ephyr/hostx.c | 109 +++++++++++++++++++++++++++++++++++-------------
 3 files changed, 83 insertions(+), 29 deletions(-)

diff --git a/configure.ac b/configure.ac
index 01fa26c87..180334d99 100644
--- a/configure.ac
+++ b/configure.ac
@@ -2305,7 +2305,7 @@ XEPHYR_INCS=
 AM_CONDITIONAL(KDRIVE, [test x$KDRIVE = xyes])
 
 if test "$KDRIVE" = yes; then
-    XEPHYR_REQUIRED_LIBS="xau xdmcp xcb xcb-shape xcb-render xcb-renderutil xcb-aux xcb-image xcb-icccm xcb-shm xcb-keysyms xcb-randr xcb-xkb"
+    XEPHYR_REQUIRED_LIBS="xau xdmcp xcb xcb-shape xcb-render xcb-renderutil xcb-aux xcb-image xcb-icccm xcb-shm >= 1.9 xcb-keysyms xcb-randr xcb-xkb"
     if test "x$XV" = xyes; then
         XEPHYR_REQUIRED_LIBS="$XEPHYR_REQUIRED_LIBS xcb-xv"
     fi
diff --git a/hw/kdrive/ephyr/ephyr.h b/hw/kdrive/ephyr/ephyr.h
index d44dbc17e..fe01661dc 100644
--- a/hw/kdrive/ephyr/ephyr.h
+++ b/hw/kdrive/ephyr/ephyr.h
@@ -79,6 +79,7 @@ typedef struct _ephyrScrPriv {
     const char *output;         /* Set via -output option */
     unsigned char *fb_data;     /* only used when host bpp != server bpp */
     xcb_shm_segment_info_t shminfo;
+    size_t shmsize;
 
     KdScreenInfo *screen;
     int mynum;                  /* Screen number */
diff --git a/hw/kdrive/ephyr/hostx.c b/hw/kdrive/ephyr/hostx.c
index 04a8de0b1..23e1cd3bf 100644
--- a/hw/kdrive/ephyr/hostx.c
+++ b/hw/kdrive/ephyr/hostx.c
@@ -41,6 +41,7 @@
 #include <sys/ipc.h>
 #include <sys/shm.h>
 #include <sys/time.h>
+#include <sys/mman.h>
 
 #include <X11/keysym.h>
 #include <xcb/xcb.h>
@@ -75,6 +76,7 @@ struct EphyrHostXVars {
     Bool use_sw_cursor;
     Bool use_fullscreen;
     Bool have_shm;
+    Bool have_shm_fd_passing;
 
     int n_screens;
     KdScreenInfo **screens;
@@ -417,29 +419,77 @@ hostx_set_title(char *title)
 #pragma does_not_return(exit)
 #endif
 
+static void
+hostx_init_shm(void)
+{
+    /* Try to get share memory ximages for a little bit more speed */
+    if (!hostx_has_extension(&xcb_shm_id) || getenv("XEPHYR_NO_SHM")) {
+        HostX.have_shm = FALSE;
+    } else {
+        xcb_generic_error_t *error = NULL;
+        xcb_shm_query_version_cookie_t cookie;
+        xcb_shm_query_version_reply_t *reply;
+
+        HostX.have_shm = TRUE;
+        HostX.have_shm_fd_passing = FALSE;
+        cookie = xcb_shm_query_version(HostX.conn);
+        reply = xcb_shm_query_version_reply(HostX.conn, cookie, &error);
+        if (reply) {
+            HostX.have_shm_fd_passing =
+                    (reply->major_version == 1 && reply->minor_version >= 2) ||
+                    reply->major_version > 1;
+            free(reply);
+        }
+        free(error);
+    }
+}
+
 static Bool
 hostx_create_shm_segment(xcb_shm_segment_info_t *shminfo, size_t size)
 {
     shminfo->shmaddr = NULL;
-    shminfo->shmid = shmget(IPC_PRIVATE, size, IPC_CREAT|0666);
-    if (shminfo->shmid != -1) {
-        shminfo->shmaddr = shmat(shminfo->shmid, 0, 0);
-        if (shminfo->shmaddr == (void *)-1) {
-            shminfo->shmaddr = NULL;
-        } else {
-            xcb_generic_error_t *error = NULL;
-            xcb_void_cookie_t cookie;
 
-            shmctl(shminfo->shmid, IPC_RMID, 0);
+    if (HostX.have_shm_fd_passing) {
+        xcb_generic_error_t *error = NULL;
+        xcb_shm_create_segment_cookie_t cookie;
+        xcb_shm_create_segment_reply_t *reply;
+
+        shminfo->shmseg = xcb_generate_id(HostX.conn);
+        cookie = xcb_shm_create_segment(HostX.conn, shminfo->shmseg, size, TRUE);
+        reply = xcb_shm_create_segment_reply(HostX.conn, cookie, &error);
+        if (!error && reply && reply->nfd == 1) {
+            int *fds = xcb_shm_create_segment_reply_fds(HostX.conn, reply);
+            if (fds) {
+                shminfo->shmaddr =
+                        (uint8_t *)mmap(0, size, PROT_READ|PROT_WRITE, MAP_SHARED, fds[0], 0);
+                close(fds[0]);
+                if (shminfo->shmaddr == MAP_FAILED)
+                    shminfo->shmaddr = NULL;
+            }
+        }
+        free(error);
+        free(reply);
+    } else {
+        shminfo->shmid = shmget(IPC_PRIVATE, size, IPC_CREAT|0666);
+        if (shminfo->shmid != -1) {
+            shminfo->shmaddr = shmat(shminfo->shmid, 0, 0);
+            if (shminfo->shmaddr == (void *)-1) {
+                shminfo->shmaddr = NULL;
+            } else {
+                xcb_generic_error_t *error = NULL;
+                xcb_void_cookie_t cookie;
+
+                shmctl(shminfo->shmid, IPC_RMID, 0);
 
-            shminfo->shmseg = xcb_generate_id(HostX.conn);
-            cookie = xcb_shm_attach_checked(HostX.conn, shminfo->shmseg, shminfo->shmid, TRUE);
-            error = xcb_request_check(HostX.conn, cookie);
+                shminfo->shmseg = xcb_generate_id(HostX.conn);
+                cookie = xcb_shm_attach_checked(HostX.conn, shminfo->shmseg, shminfo->shmid, TRUE);
+                error = xcb_request_check(HostX.conn, cookie);
 
-            if (error) {
-                free(error);
-                shmdt(shminfo->shmaddr);
-                shminfo->shmaddr = NULL;
+                if (error) {
+                    free(error);
+                    shmdt(shminfo->shmaddr);
+                    shminfo->shmaddr = NULL;
+                }
             }
         }
     }
@@ -448,10 +498,15 @@ hostx_create_shm_segment(xcb_shm_segment_info_t *shminfo, size_t size)
 }
 
 static void
-hostx_destroy_shm_segment(xcb_shm_segment_info_t *shminfo)
+hostx_destroy_shm_segment(xcb_shm_segment_info_t *shminfo, size_t size)
 {
     xcb_shm_detach(HostX.conn, shminfo->shmseg);
-    shmdt(shminfo->shmaddr);
+
+    if (HostX.have_shm_fd_passing)
+        munmap(shminfo->shmaddr, size);
+    else
+        shmdt(shminfo->shmaddr);
+
     shminfo->shmaddr = NULL;
 }
 
@@ -676,21 +731,18 @@ hostx_init(void)
         }
     }
 
-    /* Try to get share memory ximages for a little bit more speed */
-    if (!hostx_has_extension(&xcb_shm_id) || getenv("XEPHYR_NO_SHM")) {
-        fprintf(stderr, "\nXephyr unable to use SHM XImages\n");
-        HostX.have_shm = FALSE;
-    }
-    else {
+    hostx_init_shm();
+    if (HostX.have_shm) {
         /* Really really check we have shm - better way ?*/
         xcb_shm_segment_info_t shminfo;
-        HostX.have_shm = TRUE;
         if (!hostx_create_shm_segment(&shminfo, 1)) {
             fprintf(stderr, "\nXephyr unable to use SHM XImages\n");
             HostX.have_shm = FALSE;
         } else {
-            hostx_destroy_shm_segment(&shminfo);
+            hostx_destroy_shm_segment(&shminfo, 1);
         }
+    } else {
+        fprintf(stderr, "\nXephyr unable to use SHM XImages\n");
     }
 
     xcb_flush(HostX.conn);
@@ -837,7 +889,7 @@ hostx_screen_init(KdScreenInfo *screen,
         if (HostX.have_shm) {
             xcb_shm_detach(HostX.conn, scrpriv->shminfo.shmseg);
             xcb_image_destroy(scrpriv->ximg);
-            hostx_destroy_shm_segment(&scrpriv->shminfo);
+            hostx_destroy_shm_segment(&scrpriv->shminfo, scrpriv->shmsize);
         }
         else {
             free(scrpriv->ximg->data);
@@ -857,8 +909,9 @@ hostx_screen_init(KdScreenInfo *screen,
                                                 ~0,
                                                 NULL);
 
+        scrpriv->shmsize = scrpriv->ximg->stride * buffer_height;
         if (!hostx_create_shm_segment(&scrpriv->shminfo,
-                                      scrpriv->ximg->stride * buffer_height)) {
+                                      scrpriv->shmsize)) {
             EPHYR_DBG
                 ("Can't create SHM Segment, falling back to plain XImages");
             HostX.have_shm = FALSE;
-- 
2.11.0



More information about the xorg-devel mailing list