This makes the shared memory visible only for the Xephyr and the X server to which it is connected.
Signed-off-by: Alexander Volkov <[email protected]> --- hw/kdrive/ephyr/ephyr.h | 1 + hw/kdrive/ephyr/hostx.c | 165 +++++++++++++++++++++++++++++++++++------------- 2 files changed, 121 insertions(+), 45 deletions(-) diff --git a/hw/kdrive/ephyr/ephyr.h b/hw/kdrive/ephyr/ephyr.h index d44dbc17e..604823955 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; + uint32_t shmsize; KdScreenInfo *screen; int mynum; /* Screen number */ diff --git a/hw/kdrive/ephyr/hostx.c b/hw/kdrive/ephyr/hostx.c index ef8541673..0af32d8d9 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,6 +419,109 @@ 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 +#if (XCB_SHM_MAJOR_VERSION == 1 && XCB_SHM_MINOR_VERSION >= 2) || XCB_SHM_MAJOR_VERSION > 1 + { + 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); + } +#else + { + HostX.have_shm = TRUE; + HostX.have_shm_fd_passing = FALSE; + } +#endif +} + +static Bool +hostx_create_shm_segment(xcb_shm_segment_info_t *shminfo, size_t size) +{ + shminfo->shmaddr = NULL; + +#if (XCB_SHM_MAJOR_VERSION == 1 && XCB_SHM_MINOR_VERSION >= 2) || XCB_SHM_MAJOR_VERSION > 1 + 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 +#endif + { + shminfo->shmid = shmget(IPC_PRIVATE, size, IPC_CREAT|0600); + if (shminfo->shmid != -1) { + shminfo->shmaddr = shmat(shminfo->shmid, 0, 0); + if (shminfo->shmaddr == (void *)-1) + shminfo->shmaddr = NULL; + if (shminfo->shmaddr) { + 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); + + if (error) { + free(error); + shmdt(shminfo->shmaddr); + shminfo->shmaddr = NULL; + } + } + } + } + return shminfo->shmaddr != NULL; +} + +static void +hostx_destroy_shm_segment(xcb_shm_segment_info_t *shminfo, size_t size) +{ +#if (XCB_SHM_MAJOR_VERSION == 1 && XCB_SHM_MINOR_VERSION >= 2) || XCB_SHM_MAJOR_VERSION > 1 + if (HostX.have_shm_fd_passing) { + munmap(shminfo->shmaddr, size); + } else +#endif + { + shmdt(shminfo->shmaddr); + shmctl(shminfo->shmid, IPC_RMID, 0); + } + shminfo->shmaddr = NULL; +} + int hostx_init(void) { @@ -638,36 +743,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; - xcb_generic_error_t *e; - xcb_void_cookie_t cookie; - xcb_shm_seg_t shmseg; - - HostX.have_shm = TRUE; - - shminfo.shmid = shmget(IPC_PRIVATE, 1, IPC_CREAT|0777); - shminfo.shmaddr = shmat(shminfo.shmid,0,0); - - shmseg = xcb_generate_id(HostX.conn); - cookie = xcb_shm_attach_checked(HostX.conn, shmseg, shminfo.shmid, - TRUE); - e = xcb_request_check(HostX.conn, cookie); - - if (e) { - fprintf(stderr, "\nXephyr unable to use SHM XImages\n"); + if (!hostx_create_shm_segment(&shminfo, 1)) { HostX.have_shm = FALSE; - free(e); + fprintf(stderr, "\nXephyr unable to use SHM XImages\n"); + } else { + hostx_destroy_shm_segment(&shminfo, 1); } - - shmdt(shminfo.shmaddr); - shmctl(shminfo.shmid, IPC_RMID, 0); + } else { + fprintf(stderr, "\nXephyr unable to use SHM XImages\n"); } xcb_flush(HostX.conn); @@ -814,8 +901,7 @@ hostx_screen_init(KdScreenInfo *screen, if (HostX.have_shm) { xcb_shm_detach(HostX.conn, scrpriv->shminfo.shmseg); xcb_image_destroy(scrpriv->ximg); - shmdt(scrpriv->shminfo.shmaddr); - shmctl(scrpriv->shminfo.shmid, IPC_RMID, 0); + hostx_destroy_shm_segment(&scrpriv->shminfo, scrpriv->shmsize); } else { free(scrpriv->ximg->data); @@ -835,27 +921,16 @@ hostx_screen_init(KdScreenInfo *screen, ~0, NULL); - scrpriv->shminfo.shmid = - shmget(IPC_PRIVATE, - scrpriv->ximg->stride * buffer_height, - IPC_CREAT | 0777); - scrpriv->ximg->data = shmat(scrpriv->shminfo.shmid, 0, 0); - scrpriv->shminfo.shmaddr = scrpriv->ximg->data; - - if (scrpriv->ximg->data == (uint8_t *) -1) { + scrpriv->shmsize = scrpriv->ximg->stride * buffer_height; + if (!hostx_create_shm_segment(&scrpriv->shminfo, + scrpriv->shmsize)) { EPHYR_DBG ("Can't attach SHM Segment, falling back to plain XImages"); HostX.have_shm = FALSE; - xcb_image_destroy (scrpriv->ximg); - shmctl(scrpriv->shminfo.shmid, IPC_RMID, 0); - } - else { + xcb_image_destroy(scrpriv->ximg); + } else { EPHYR_DBG("SHM segment attached %p", scrpriv->shminfo.shmaddr); - scrpriv->shminfo.shmseg = xcb_generate_id(HostX.conn); - xcb_shm_attach(HostX.conn, - scrpriv->shminfo.shmseg, - scrpriv->shminfo.shmid, - FALSE); + scrpriv->ximg->data = scrpriv->shminfo.shmaddr; shm_success = TRUE; } } -- 2.11.0 _______________________________________________ [email protected]: X.Org development Archives: http://lists.x.org/archives/xorg-devel Info: https://lists.x.org/mailman/listinfo/xorg-devel
