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
|
* IDLETIME implementation
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static pointer IdleTimeCounter;
|
static SyncCounter *IdleTimeCounter;
|
||||||
static XSyncValue *pIdleTimeValueLess;
|
static XSyncValue *pIdleTimeValueLess;
|
||||||
static XSyncValue *pIdleTimeValueGreater;
|
static XSyncValue *pIdleTimeValueGreater;
|
||||||
|
|
||||||
|
@ -2293,38 +2293,69 @@ IdleTimeQueryValue (pointer pCounter, CARD64 *pValue_return)
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
IdleTimeBlockHandler (pointer env,
|
IdleTimeBlockHandler(pointer env, struct timeval **wt, pointer LastSelectMask)
|
||||||
struct timeval **wt,
|
|
||||||
pointer LastSelectMask)
|
|
||||||
{
|
{
|
||||||
XSyncValue idle;
|
XSyncValue idle, old_idle;
|
||||||
|
SyncTriggerList *list = IdleTimeCounter->pTriglist;
|
||||||
|
SyncTrigger *trig;
|
||||||
|
|
||||||
if (!pIdleTimeValueLess && !pIdleTimeValueGreater)
|
if (!pIdleTimeValueLess && !pIdleTimeValueGreater)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
old_idle = IdleTimeCounter->value;
|
||||||
IdleTimeQueryValue (NULL, &idle);
|
IdleTimeQueryValue (NULL, &idle);
|
||||||
|
IdleTimeCounter->value = idle; /* push, so CheckTrigger works */
|
||||||
|
|
||||||
if (pIdleTimeValueLess &&
|
if (pIdleTimeValueLess &&
|
||||||
XSyncValueLessOrEqual (idle, *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)
|
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;
|
XSyncValue value;
|
||||||
Bool overflow;
|
Bool overflow;
|
||||||
|
|
||||||
XSyncValueSubtract (&value, *pIdleTimeValueGreater,
|
XSyncValueSubtract (&value, *pIdleTimeValueGreater,
|
||||||
idle, &overflow);
|
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);
|
AdjustWaitForDelay (wt, timeout);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
IdleTimeCounter->value = old_idle; /* pop */
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
|
Loading…
Reference in New Issue