diff options
author | Adam Jackson <ajax@redhat.com> | 2008-12-10 16:13:20 -0500 |
---|---|---|
committer | Adam Jackson <ajax@redhat.com> | 2008-12-11 10:31:48 -0500 |
commit | 1f4fb0225b278d1cf4145aebeb0bdd23dc8f62d5 (patch) | |
tree | 56ccd03a85d24c8d715f56c404dcbe464fff35f7 | |
parent | 1a99110f0c221b79045ea26d61c4a1ec1e0d7341 (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
-rw-r--r-- | Xext/sync.c | 51 |
1 files changed, 41 insertions, 10 deletions
diff --git a/Xext/sync.c b/Xext/sync.c index 88fc03d03..d9e66b3f4 100644 --- a/Xext/sync.c +++ b/Xext/sync.c | |||
@@ -2281,7 +2281,7 @@ SyncInitServerTime(void) | |||
2281 | * IDLETIME implementation | 2281 | * IDLETIME implementation |
2282 | */ | 2282 | */ |
2283 | 2283 | ||
2284 | static pointer IdleTimeCounter; | 2284 | static SyncCounter *IdleTimeCounter; |
2285 | static XSyncValue *pIdleTimeValueLess; | 2285 | static XSyncValue *pIdleTimeValueLess; |
2286 | static XSyncValue *pIdleTimeValueGreater; | 2286 | static XSyncValue *pIdleTimeValueGreater; |
2287 | 2287 | ||
@@ -2293,38 +2293,69 @@ IdleTimeQueryValue (pointer pCounter, CARD64 *pValue_return) | |||
2293 | } | 2293 | } |
2294 | 2294 | ||
2295 | static void | 2295 | static void |
2296 | IdleTimeBlockHandler (pointer env, | 2296 | IdleTimeBlockHandler(pointer env, struct timeval **wt, pointer LastSelectMask) |
2297 | struct timeval **wt, | ||
2298 | pointer LastSelectMask) | ||
2299 | { | 2297 | { |
2300 | XSyncValue idle; | 2298 | XSyncValue idle, old_idle; |
2299 | SyncTriggerList *list = IdleTimeCounter->pTriglist; | ||
2300 | SyncTrigger *trig; | ||
2301 | 2301 | ||
2302 | if (!pIdleTimeValueLess && !pIdleTimeValueGreater) | 2302 | if (!pIdleTimeValueLess && !pIdleTimeValueGreater) |
2303 | return; | 2303 | return; |
2304 | 2304 | ||
2305 | old_idle = IdleTimeCounter->value; | ||
2305 | IdleTimeQueryValue (NULL, &idle); | 2306 | IdleTimeQueryValue (NULL, &idle); |
2307 | IdleTimeCounter->value = idle; /* push, so CheckTrigger works */ | ||
2306 | 2308 | ||
2307 | if (pIdleTimeValueLess && | 2309 | if (pIdleTimeValueLess && |
2308 | XSyncValueLessOrEqual (idle, *pIdleTimeValueLess)) | 2310 | XSyncValueLessOrEqual (idle, *pIdleTimeValueLess)) |
2309 | { | 2311 | { |
2310 | AdjustWaitForDelay (wt, 0); | 2312 | /* |
2313 | * We've been idle for less than the threshold value, and someone | ||
2314 | * wants to know about that, but now we need to know whether they | ||
2315 | * want level or edge trigger. Check the trigger list against the | ||
2316 | * current idle time, and if any succeed, bomb out of select() | ||
2317 | * immediately so we can reschedule. | ||
2318 | */ | ||
2319 | |||
2320 | for (list = IdleTimeCounter->pTriglist; list; list = list->next) { | ||
2321 | trig = list->pTrigger; | ||
2322 | if (trig->CheckTrigger(trig, old_idle)) { | ||
2323 | AdjustWaitForDelay(wt, 0); | ||
2324 | break; | ||
2325 | } | ||
2326 | } | ||
2311 | } | 2327 | } |
2312 | else if (pIdleTimeValueGreater) | 2328 | else if (pIdleTimeValueGreater) |
2313 | { | 2329 | { |
2314 | unsigned long timeout = 0; | 2330 | /* |
2331 | * There's a threshold in the positive direction. If we've been | ||
2332 | * idle less than it, schedule a wakeup for sometime in the future. | ||
2333 | * If we've been idle more than it, and someone wants to know about | ||
2334 | * that level-triggered, schedule an immediate wakeup. | ||
2335 | */ | ||
2336 | unsigned long timeout = -1; | ||
2315 | 2337 | ||
2316 | if (XSyncValueLessThan (idle, *pIdleTimeValueGreater)) | 2338 | if (XSyncValueLessThan (idle, *pIdleTimeValueGreater)) { |
2317 | { | ||
2318 | XSyncValue value; | 2339 | XSyncValue value; |
2319 | Bool overflow; | 2340 | Bool overflow; |
2320 | 2341 | ||
2321 | XSyncValueSubtract (&value, *pIdleTimeValueGreater, | 2342 | XSyncValueSubtract (&value, *pIdleTimeValueGreater, |
2322 | idle, &overflow); | 2343 | idle, &overflow); |
2323 | timeout = XSyncValueLow32 (value); | 2344 | timeout = min(timeout, XSyncValueLow32 (value)); |
2345 | } else { | ||
2346 | for (list = IdleTimeCounter->pTriglist; list; list = list->next) { | ||
2347 | trig = list->pTrigger; | ||
2348 | if (trig->CheckTrigger(trig, old_idle)) { | ||
2349 | timeout = min(timeout, 0); | ||
2350 | break; | ||
2351 | } | ||
2352 | } | ||
2324 | } | 2353 | } |
2325 | 2354 | ||
2326 | AdjustWaitForDelay (wt, timeout); | 2355 | AdjustWaitForDelay (wt, timeout); |
2327 | } | 2356 | } |
2357 | |||
2358 | IdleTimeCounter->value = old_idle; /* pop */ | ||
2328 | } | 2359 | } |
2329 | 2360 | ||
2330 | static void | 2361 | static void |