summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAdam Jackson <ajax@redhat.com>2008-12-10 16:13:20 -0500
committerAdam Jackson <ajax@redhat.com>2008-12-16 09:55:27 -0500
commitca56d764d2be28c64fe15c9e37d534ef00117ad2 (patch)
tree745d9bdc25c821beeaa35bb093e3c1eb4a64b4d8
parenta82f10c5dd9fa74ff18759ab288bbd9c8b7ac4de (diff)
xsync: Fix wakeup storm in idletime counter.
Wakeup scheduling only considered the threshold values, and not whether the trigger was edge or level. See also: https://bugzilla.redhat.com/show_bug.cgi?id=474586 http://svn.gnome.org/viewvc/gnome-screensaver/trunk/src/test-idle-ext.c?view=markup (cherry picked from commit 1f4fb0225b278d1cf4145aebeb0bdd23dc8f62d5)
-rw-r--r--Xext/sync.c51
1 files changed, 41 insertions, 10 deletions
diff --git a/Xext/sync.c b/Xext/sync.c
index 63f6fa2aa..1b3736644 100644
--- a/Xext/sync.c
+++ b/Xext/sync.c
@@ -2535,3 +2535,3 @@ SyncInitServerTime(void)
-static pointer IdleTimeCounter;
+static SyncCounter *IdleTimeCounter;
static XSyncValue *pIdleTimeValueLess;
@@ -2547,7 +2547,7 @@ IdleTimeQueryValue (pointer pCounter, CARD64 *pValue_return)
static void
-IdleTimeBlockHandler (pointer env,
- struct timeval **wt,
- pointer LastSelectMask)
+IdleTimeBlockHandler(pointer env, struct timeval **wt, pointer LastSelectMask)
{
- XSyncValue idle;
+ XSyncValue idle, old_idle;
+ SyncTriggerList *list = IdleTimeCounter->pTriglist;
+ SyncTrigger *trig;
@@ -2556,3 +2556,5 @@ IdleTimeBlockHandler (pointer env,
+ old_idle = IdleTimeCounter->value;
IdleTimeQueryValue (NULL, &idle);
+ IdleTimeCounter->value = idle; /* push, so CheckTrigger works */
@@ -2561,3 +2563,17 @@ IdleTimeBlockHandler (pointer env,
{
- AdjustWaitForDelay (wt, 0);
+ /*
+ * We've been idle for less than the threshold value, and someone
+ * wants to know about that, but now we need to know whether they
+ * want level or edge trigger. Check the trigger list against the
+ * current idle time, and if any succeed, bomb out of select()
+ * immediately so we can reschedule.
+ */
+
+ for (list = IdleTimeCounter->pTriglist; list; list = list->next) {
+ trig = list->pTrigger;
+ if (trig->CheckTrigger(trig, old_idle)) {
+ AdjustWaitForDelay(wt, 0);
+ break;
+ }
+ }
}
@@ -2565,6 +2581,11 @@ IdleTimeBlockHandler (pointer env,
{
- unsigned long timeout = 0;
+ /*
+ * There's a threshold in the positive direction. If we've been
+ * idle less than it, schedule a wakeup for sometime in the future.
+ * If we've been idle more than it, and someone wants to know about
+ * that level-triggered, schedule an immediate wakeup.
+ */
+ unsigned long timeout = -1;
- if (XSyncValueLessThan (idle, *pIdleTimeValueGreater))
- {
+ if (XSyncValueLessThan (idle, *pIdleTimeValueGreater)) {
XSyncValue value;
@@ -2574,3 +2595,11 @@ IdleTimeBlockHandler (pointer env,
idle, &overflow);
- timeout = XSyncValueLow32 (value);
+ timeout = min(timeout, XSyncValueLow32 (value));
+ } else {
+ for (list = IdleTimeCounter->pTriglist; list; list = list->next) {
+ trig = list->pTrigger;
+ if (trig->CheckTrigger(trig, old_idle)) {
+ timeout = min(timeout, 0);
+ break;
+ }
+ }
}
@@ -2579,2 +2608,4 @@ IdleTimeBlockHandler (pointer env,
}
+
+ IdleTimeCounter->value = old_idle; /* pop */
}