[PATCH xserver 4/5] ephyr: Process queued X events before blocking [v2]

Keith Packard keithp at keithp.com
Tue Jun 14 21:02:50 UTC 2016


If we end up reading all pending X events in the course of other server
execution, then our notify FD callback won't get invoked and we won't
process them. Fix this by noting that there are queued events in the
block handler, setting the poll timeout to zero and queuing a work
proc to clear the event queue.

v2: use a work proc to clear the event queue rather than doing it in
    the block handler directly.

Signed-off-by: Keith Packard <keithp at keithp.com>
---
 hw/kdrive/ephyr/ephyr.c | 52 +++++++++++++++++++++++++++++++------------------
 hw/kdrive/ephyr/hostx.c | 26 +++++++++++++++++++++++++
 hw/kdrive/ephyr/hostx.h |  6 ++++++
 3 files changed, 65 insertions(+), 19 deletions(-)

diff --git a/hw/kdrive/ephyr/ephyr.c b/hw/kdrive/ephyr/ephyr.c
index e5f1883..015aef5 100644
--- a/hw/kdrive/ephyr/ephyr.c
+++ b/hw/kdrive/ephyr/ephyr.c
@@ -337,6 +337,16 @@ ephyrInternalDamageRedisplay(ScreenPtr pScreen)
 }
 
 static void
+ephyrXcbProcessEvents(Bool queued_only);
+
+static Bool
+ephyrEventWorkProc(ClientPtr client, void *closure)
+{
+    ephyrXcbProcessEvents(TRUE);
+    return TRUE;
+}
+
+static void
 ephyrScreenBlockHandler(ScreenPtr pScreen, void *timeout, void *pRead)
 {
     KdScreenPriv(pScreen);
@@ -345,20 +355,16 @@ ephyrScreenBlockHandler(ScreenPtr pScreen, void *timeout, void *pRead)
 
     pScreen->BlockHandler = scrpriv->BlockHandler;
     (*pScreen->BlockHandler)(pScreen, timeout, pRead);
+    scrpriv->BlockHandler = pScreen->BlockHandler;
+    pScreen->BlockHandler = ephyrScreenBlockHandler;
 
-    if (scrpriv->pDamage) {
-
-        /* Re-wrap if we're still tracking damage
-         */
-        scrpriv->BlockHandler = pScreen->BlockHandler;
-        pScreen->BlockHandler = ephyrScreenBlockHandler;
+    if (scrpriv->pDamage)
         ephyrInternalDamageRedisplay(pScreen);
-    } else {
 
-        /* Done tracking damage, note that we've left
-         * the block handler unwrapped
-         */
-        scrpriv->BlockHandler = NULL;
+    if (hostx_has_queued_event()) {
+        if (!QueueWorkProc(ephyrEventWorkProc, NULL, NULL))
+            FatalError("cannot queue event processing in ephyr block handler");
+        AdjustWaitForDelay(timeout, 0);
     }
 }
 
@@ -374,12 +380,6 @@ ephyrSetInternalDamage(ScreenPtr pScreen)
                                     (DamageDestroyFunc) 0,
                                     DamageReportNone, TRUE, pScreen, pScreen);
 
-    /* Wrap only once */
-    if (scrpriv->BlockHandler == NULL) {
-        scrpriv->BlockHandler = pScreen->BlockHandler;
-        pScreen->BlockHandler = ephyrScreenBlockHandler;
-    }
-
     pPixmap = (*pScreen->GetScreenPixmap) (pScreen);
 
     DamageRegister(&pPixmap->drawable, scrpriv->pDamage);
@@ -682,6 +682,10 @@ ephyrInitScreen(ScreenPtr pScreen)
 Bool
 ephyrFinishInitScreen(ScreenPtr pScreen)
 {
+    KdScreenPriv(pScreen);
+    KdScreenInfo *screen = pScreenPriv->screen;
+    EphyrScrPriv *scrpriv = screen->driver;
+
     /* FIXME: Calling this even if not using shadow.
      * Seems harmless enough. But may be safer elsewhere.
      */
@@ -693,6 +697,9 @@ ephyrFinishInitScreen(ScreenPtr pScreen)
         return FALSE;
 #endif
 
+    scrpriv->BlockHandler = pScreen->BlockHandler;
+    pScreen->BlockHandler = ephyrScreenBlockHandler;
+
     return TRUE;
 }
 
@@ -1131,12 +1138,13 @@ ephyrProcessConfigureNotify(xcb_generic_event_t *xev)
 }
 
 static void
-ephyrXcbNotify(int fd, int ready, void *data)
+ephyrXcbProcessEvents(Bool queued_only)
 {
     xcb_connection_t *conn = hostx_get_xcbconn();
 
     while (TRUE) {
-        xcb_generic_event_t *xev = xcb_poll_for_event(conn);
+        xcb_generic_event_t *xev = hostx_get_event(queued_only);
+
         if (!xev) {
             /* If our XCB connection has died (for example, our window was
              * closed), exit now.
@@ -1191,6 +1199,12 @@ ephyrXcbNotify(int fd, int ready, void *data)
     }
 }
 
+static void
+ephyrXcbNotify(int fd, int ready, void *data)
+{
+    ephyrXcbProcessEvents(FALSE);
+}
+
 void
 ephyrCardFini(KdCardInfo * card)
 {
diff --git a/hw/kdrive/ephyr/hostx.c b/hw/kdrive/ephyr/hostx.c
index abe6eda..887f654 100644
--- a/hw/kdrive/ephyr/hostx.c
+++ b/hw/kdrive/ephyr/hostx.c
@@ -70,6 +70,7 @@ struct EphyrHostXVars {
     xcb_gcontext_t  gc;
     xcb_render_pictformat_t argb_format;
     xcb_cursor_t empty_cursor;
+    xcb_generic_event_t *saved_event;
     int depth;
     Bool use_sw_cursor;
     Bool use_fullscreen;
@@ -1227,6 +1228,31 @@ hostx_get_xcbconn(void)
     return HostX.conn;
 }
 
+xcb_generic_event_t *
+hostx_get_event(Bool queued_only)
+{
+    xcb_generic_event_t *xev;
+
+    if (HostX.saved_event) {
+        xev = HostX.saved_event;
+        HostX.saved_event = NULL;
+    } else {
+        if (queued_only)
+            xev = xcb_poll_for_queued_event(HostX.conn);
+        else
+            xev = xcb_poll_for_event(HostX.conn);
+    }
+    return xev;
+}
+
+Bool
+hostx_has_queued_event(void)
+{
+    if (!HostX.saved_event)
+        HostX.saved_event = xcb_poll_for_queued_event(HostX.conn);
+    return HostX.saved_event != NULL;
+}
+
 int
 hostx_get_screen(void)
 {
diff --git a/hw/kdrive/ephyr/hostx.h b/hw/kdrive/ephyr/hostx.h
index 6e0b07b..d0f3011 100644
--- a/hw/kdrive/ephyr/hostx.h
+++ b/hw/kdrive/ephyr/hostx.h
@@ -157,6 +157,12 @@ hostx_size_set_from_configure(Bool);
 xcb_connection_t *
 hostx_get_xcbconn(void);
 
+xcb_generic_event_t *
+hostx_get_event(Bool queued_only);
+
+Bool
+hostx_has_queued_event(void);
+
 int
 hostx_get_screen(void);
 
-- 
2.8.1



More information about the xorg-devel mailing list