777c761
From 4db4a1313e2992ffb77949f4fbd7fff16ffceaee Mon Sep 17 00:00:00 2001
777c761
From: Adam Jackson <ajax@redhat.com>
777c761
Date: Wed, 10 Dec 2008 16:13:20 -0500
777c761
Subject: [PATCH] xsync: Fix wakeup storm in idletime counter.
777c761
777c761
Wakeup scheduling only considered the threshold values, and not whether
777c761
the trigger was edge or level.
777c761
---
777c761
 Xext/sync.c |   51 +++++++++++++++++++++++++++++++++++++++++----------
777c761
 1 files changed, 41 insertions(+), 10 deletions(-)
777c761
777c761
diff --git a/Xext/sync.c b/Xext/sync.c
777c761
index d6b8c27..4d159d2 100644
777c761
--- a/Xext/sync.c
777c761
+++ b/Xext/sync.c
777c761
@@ -2323,7 +2323,7 @@ SyncInitServerTime(void)
777c761
  * IDLETIME implementation
777c761
  */
777c761
 
777c761
-static pointer IdleTimeCounter;
777c761
+static SyncCounter *IdleTimeCounter;
777c761
 static XSyncValue *pIdleTimeValueLess;
777c761
 static XSyncValue *pIdleTimeValueGreater;
777c761
 
777c761
@@ -2335,38 +2335,69 @@ IdleTimeQueryValue (pointer pCounter, CARD64 *pValue_return)
777c761
 }
777c761
 
777c761
 static void
777c761
-IdleTimeBlockHandler (pointer env,
777c761
-                      struct timeval **wt,
777c761
-                      pointer LastSelectMask)
777c761
+IdleTimeBlockHandler(pointer env, struct timeval **wt, pointer LastSelectMask)
777c761
 {
777c761
-    XSyncValue idle;
777c761
+    XSyncValue idle, old_idle;
777c761
+    SyncTriggerList *list = IdleTimeCounter->pTriglist;
777c761
+    SyncTrigger *trig;
777c761
 
777c761
     if (!pIdleTimeValueLess && !pIdleTimeValueGreater)
777c761
 	return;
777c761
 
777c761
+    old_idle = IdleTimeCounter->value;
777c761
     IdleTimeQueryValue (NULL, &idle);
777c761
+    IdleTimeCounter->value = idle; /* push, so CheckTrigger works */
777c761
 
777c761
     if (pIdleTimeValueLess &&
777c761
         XSyncValueLessOrEqual (idle, *pIdleTimeValueLess))
777c761
     {
777c761
-	AdjustWaitForDelay (wt, 0);
777c761
+	/*
777c761
+	 * We've been idle for less than the threshold value, and someone
777c761
+	 * wants to know about that, but now we need to know whether they
777c761
+	 * want level or edge trigger.  Check the trigger list against the
777c761
+	 * current idle time, and if any succeed, bomb out of select()
777c761
+	 * immediately so we can reschedule.
777c761
+	 */
777c761
+
777c761
+	for (list = IdleTimeCounter->pTriglist; list; list = list->next) {
777c761
+	    trig = list->pTrigger;
777c761
+	    if (trig->CheckTrigger(trig, old_idle)) {
777c761
+		AdjustWaitForDelay(wt, 0);
777c761
+		break;
777c761
+	    }
777c761
+	}
777c761
     }
777c761
     else if (pIdleTimeValueGreater)
777c761
     {
777c761
-	unsigned long timeout = 0;
777c761
+	/*
777c761
+	 * There's a threshold in the positive direction.  If we've been
777c761
+	 * idle less than it, schedule a wakeup for sometime in the future.
777c761
+	 * If we've been idle more than it, and someone wants to know about
777c761
+	 * that level-triggered, schedule an immediate wakeup.
777c761
+	 */
777c761
+	unsigned long timeout = -1;
777c761
 
777c761
-	if (XSyncValueLessThan (idle, *pIdleTimeValueGreater))
777c761
-	{
777c761
+	if (XSyncValueLessThan (idle, *pIdleTimeValueGreater)) {
777c761
 	    XSyncValue value;
777c761
 	    Bool overflow;
777c761
 
777c761
 	    XSyncValueSubtract (&value, *pIdleTimeValueGreater,
777c761
 	                        idle, &overflow);
777c761
-	    timeout = XSyncValueLow32 (value);
777c761
+	    timeout = min(timeout, XSyncValueLow32 (value));
777c761
+	} else {
777c761
+	    for (list = IdleTimeCounter->pTriglist; list; list = list->next) {
777c761
+		trig = list->pTrigger;
777c761
+		if (trig->CheckTrigger(trig, old_idle)) {
777c761
+		    timeout = min(timeout, 0);
777c761
+		    break;
777c761
+		}
777c761
+	    }
777c761
 	}
777c761
 
777c761
 	AdjustWaitForDelay (wt, timeout);
777c761
     }
777c761
+
777c761
+    IdleTimeCounter->value = old_idle; /* pop */
777c761
 }
777c761
 
777c761
 static void
777c761
-- 
777c761
1.6.0.3
777c761