[PATCH] dix: switch the syncEvent queue to a struct list

Peter Hutterer peter.hutterer at who-t.net
Thu Dec 1 15:09:19 PST 2011


No effective functionality change, just cleanup to make this code slightly
more sane.

Signed-off-by: Peter Hutterer <peter.hutterer at who-t.net>
---
Chase started with this, necessary for some multitouch patch. His original
patch changed pendtail from double to single-pointer only. But with the
two struct list API additions, it's much easier to switch this to a linked
list implementation instead of yet another open-coded one.

 dix/events.c       |   46 ++++++++++++++++--------------------
 include/dix.h      |    1 +
 include/inputstr.h |    6 ++--
 test/input.c       |   65 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 90 insertions(+), 28 deletions(-)

diff --git a/dix/events.c b/dix/events.c
index b43b0c5..1317514 100644
--- a/dix/events.c
+++ b/dix/events.c
@@ -1128,12 +1128,14 @@ NoticeEventTime(InternalEvent *ev)
 void
 EnqueueEvent(InternalEvent *ev, DeviceIntPtr device)
 {
-    QdEventPtr	tail = *syncEvents.pendtail;
+    QdEventPtr	tail;
     QdEventPtr	qe;
     SpritePtr	pSprite = device->spriteInfo->sprite;
     int		eventlen;
     DeviceEvent *event = &ev->device_event;
 
+    tail = list_last_entry(&syncEvents.pending, QdEventRec, next);
+
     NoticeTime((InternalEvent*)event);
 
     /* Fix for key repeating bug. */
@@ -1192,15 +1194,13 @@ EnqueueEvent(InternalEvent *ev, DeviceIntPtr device)
     qe = malloc(sizeof(QdEventRec) + eventlen);
     if (!qe)
 	return;
-    qe->next = (QdEventPtr)NULL;
+    list_init(&qe->next);
     qe->device = device;
     qe->pScreen = pSprite->hotPhys.pScreen;
     qe->months = currentTime.months;
     qe->event = (InternalEvent *)(qe + 1);
     memcpy(qe->event, event, eventlen);
-    if (tail)
-	syncEvents.pendtail = &tail->next;
-    *syncEvents.pendtail = qe;
+    list_append(&qe->next, &syncEvents.pending);
 }
 
 /**
@@ -1212,22 +1212,20 @@ EnqueueEvent(InternalEvent *ev, DeviceIntPtr device)
  * If there is none, we're done. If there is at least one device that is not
  * frozen, then re-run from the beginning of the event queue.
  */
-static void
+void
 PlayReleasedEvents(void)
 {
-    QdEventPtr *prev, qe;
+    QdEventPtr tmp;
+    QdEventPtr qe;
     DeviceIntPtr dev;
     DeviceIntPtr pDev;
 
-    prev = &syncEvents.pending;
-    while ( (qe = *prev) )
-    {
+restart:
+    list_for_each_entry_safe(qe, tmp, &syncEvents.pending, next) {
 	if (!qe->device->deviceGrab.sync.frozen)
 	{
-	    *prev = qe->next;
-            pDev = qe->device;
-	    if (*syncEvents.pendtail == *prev)
-		syncEvents.pendtail = prev;
+	    list_del(&qe->next);
+	    pDev = qe->device;
 	    if (qe->event->any.type == ET_Motion)
 		CheckVirtualMotion(pDev, qe, NullWindow);
 	    syncEvents.time.months = qe->months;
@@ -1264,12 +1262,11 @@ PlayReleasedEvents(void)
 		;
 	    if (!dev)
 		break;
+
 	    /* Playing the event may have unfrozen another device. */
 	    /* So to play it safe, restart at the head of the queue */
-	    prev = &syncEvents.pending;
+	    goto restart;
 	}
-	else
-	    prev = &qe->next;
     }
 }
 
@@ -1310,7 +1307,8 @@ ComputeFreezes(void)
     for (dev = inputInfo.devices; dev; dev = dev->next)
 	FreezeThaw(dev, dev->deviceGrab.sync.other ||
                 (dev->deviceGrab.sync.state >= FROZEN));
-    if (syncEvents.playingEvents || (!replayDev && !syncEvents.pending))
+    if (syncEvents.playingEvents ||
+        (!replayDev && list_is_empty(&syncEvents.pending)))
 	return;
     syncEvents.playingEvents = TRUE;
     if (replayDev)
@@ -5266,6 +5264,7 @@ void
 InitEvents(void)
 {
     int i;
+    QdEventPtr qe, tmp;
 
     inputInfo.numDevices = 0;
     inputInfo.devices = (DeviceIntPtr)NULL;
@@ -5279,13 +5278,10 @@ InitEvents(void)
 
     syncEvents.replayDev = (DeviceIntPtr)NULL;
     syncEvents.replayWin = NullWindow;
-    while (syncEvents.pending)
-    {
-	QdEventPtr next = syncEvents.pending->next;
-	free(syncEvents.pending);
-	syncEvents.pending = next;
-    }
-    syncEvents.pendtail = &syncEvents.pending;
+    if (syncEvents.pending.next)
+        list_for_each_entry_safe(qe, tmp, &syncEvents.pending, next)
+            free(qe);
+    list_init(&syncEvents.pending);
     syncEvents.playingEvents = FALSE;
     syncEvents.time.months = 0;
     syncEvents.time.milliseconds = 0;	/* hardly matters */
diff --git a/include/dix.h b/include/dix.h
index a78005a..3dc28d0 100644
--- a/include/dix.h
+++ b/include/dix.h
@@ -339,6 +339,7 @@ extern _X_EXPORT void NoticeEventTime(InternalEvent *ev);
 extern void EnqueueEvent(
     InternalEvent * /* ev */,
     DeviceIntPtr  /* device */);
+extern void PlayReleasedEvents(void);
 
 extern void ActivatePointerGrab(
     DeviceIntPtr /* mouse */,
diff --git a/include/inputstr.h b/include/inputstr.h
index 1692c1a..e3a9213 100644
--- a/include/inputstr.h
+++ b/include/inputstr.h
@@ -630,7 +630,7 @@ extern _X_EXPORT InputInfo inputInfo;
 /* for keeping the events for devices grabbed synchronously */
 typedef struct _QdEvent *QdEventPtr;
 typedef struct _QdEvent {
-    QdEventPtr		next;
+    struct list		next;
     DeviceIntPtr	device;
     ScreenPtr		pScreen;	/* what screen the pointer was on */
     unsigned long	months;		/* milliseconds is in the event */
@@ -646,8 +646,8 @@ typedef struct _QdEvent {
  * replayed and processed as if they would come from the device directly.
  */
 typedef struct _EventSyncInfo {
-    QdEventPtr          pending, /**<  list of queued events */
-                        *pendtail; /**< last event in list */
+    struct list         pending;
+
     /** The device to replay events for. Only set in AllowEvents(), in which
      * case it is set to the device specified in the request. */
     DeviceIntPtr        replayDev;      /* kludgy rock to put flag for */
diff --git a/test/input.c b/test/input.c
index 5b4c8c1..7d079f2 100644
--- a/test/input.c
+++ b/test/input.c
@@ -1674,8 +1674,73 @@ mieq_test(void) {
     mieqFini();
 }
 
+/* Simple check that we're replaying events in-order */
+static void
+process_input_proc(InternalEvent *ev, DeviceIntPtr device)
+{
+    static int last_evtype = -1;
+
+    if (ev->any.header == 0xac)
+        last_evtype = -1;
+
+    assert(ev->any.type == ++last_evtype);
+}
+
+static void
+dix_enqueue_events(void) {
+#define NEVENTS 5
+    DeviceIntRec dev;
+    InternalEvent ev[NEVENTS];
+    SpriteInfoRec spriteInfo;
+    SpriteRec sprite;
+    QdEventPtr qe;
+    int i;
+
+    memset(&dev, 0, sizeof(dev));
+    dev.public.processInputProc = process_input_proc;
+
+    memset(&spriteInfo, 0, sizeof(spriteInfo));
+    memset(&sprite, 0, sizeof(sprite));
+    dev.spriteInfo = &spriteInfo;
+    spriteInfo.sprite = &sprite;
+
+    InitEvents();
+    assert(list_is_empty(&syncEvents.pending));
+
+    /* this way PlayReleasedEvents really runs through all events in the
+     * queue */
+    inputInfo.devices = &dev;
+
+    /* to reset process_input_proc */
+    ev[0].any.header = 0xac;
+
+    for (i = 0; i < NEVENTS; i++)
+    {
+        ev[i].any.length = sizeof(*ev);
+        ev[i].any.type = i;
+        EnqueueEvent(&ev[i], &dev);
+        assert(!list_is_empty(&syncEvents.pending));
+        qe = list_last_entry(&syncEvents.pending, QdEventRec, next);
+        assert(memcmp(qe->event, &ev[i], ev[i].any.length) == 0);
+        qe = list_first_entry(&syncEvents.pending, QdEventRec, next);
+        assert(memcmp(qe->event, &ev[0], ev[i].any.length) == 0);
+    }
+
+    /* calls process_input_proc */
+    dev.deviceGrab.sync.frozen = 1;
+    PlayReleasedEvents();
+    assert(!list_is_empty(&syncEvents.pending));
+
+
+    dev.deviceGrab.sync.frozen = 0;
+    PlayReleasedEvents();
+    assert(list_is_empty(&syncEvents.pending));
+}
+
+
 int main(int argc, char** argv)
 {
+    dix_enqueue_events();
     dix_double_fp_conversion();
     dix_input_valuator_masks();
     dix_input_attributes();
-- 
1.7.7.1


More information about the xorg-devel mailing list