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
This commit is contained in:
parent
1a99110f0c
commit
1f4fb0225b
51
Xext/sync.c
51
Xext/sync.c
|
@ -2281,7 +2281,7 @@ SyncInitServerTime(void)
|
|||
* IDLETIME implementation
|
||||
*/
|
||||
|
||||
static pointer IdleTimeCounter;
|
||||
static SyncCounter *IdleTimeCounter;
|
||||
static XSyncValue *pIdleTimeValueLess;
|
||||
static XSyncValue *pIdleTimeValueGreater;
|
||||
|
||||
|
@ -2293,38 +2293,69 @@ 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;
|
||||
|
||||
if (!pIdleTimeValueLess && !pIdleTimeValueGreater)
|
||||
return;
|
||||
|
||||
old_idle = IdleTimeCounter->value;
|
||||
IdleTimeQueryValue (NULL, &idle);
|
||||
IdleTimeCounter->value = idle; /* push, so CheckTrigger works */
|
||||
|
||||
if (pIdleTimeValueLess &&
|
||||
XSyncValueLessOrEqual (idle, *pIdleTimeValueLess))
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (pIdleTimeValueGreater)
|
||||
{
|
||||
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;
|
||||
Bool overflow;
|
||||
|
||||
XSyncValueSubtract (&value, *pIdleTimeValueGreater,
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
AdjustWaitForDelay (wt, timeout);
|
||||
}
|
||||
|
||||
IdleTimeCounter->value = old_idle; /* pop */
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
Loading…
Reference in New Issue
Block a user