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