The time between the idle reset and the IdleTimeWakeupHandler to be called is indeterminate. Clients with an PositiveTransition or NegativeTransition alarm on a low threshold may miss an alarm.
Work around this by keeping a reset flag for each device. When the WakeupHandler triggers and the reset flag is set, we force a re-calculation of everything and pretend the current idle time is zero. Immediately after is the next calculation with the real idle time. Relatively reproducible test case: Set up a XSyncNegativeTransition alarm for a threshold of 1 ms. May trigger, may not. X.Org Bug 70476 <http://bugs.freedesktop.org/show_bug.cgi?id=70476> Signed-off-by: Peter Hutterer <[email protected]> --- Xext/sync.c | 50 ++++++++++++++++++++++++++++++++++++++------------ dix/events.c | 38 ++++++++++++++++++++++++++++++++++---- include/dix.h | 6 ++++++ 3 files changed, 78 insertions(+), 16 deletions(-) diff --git a/Xext/sync.c b/Xext/sync.c index ed891b1..1bb7733 100644 --- a/Xext/sync.c +++ b/Xext/sync.c @@ -2686,19 +2686,8 @@ IdleTimeBlockHandler(pointer pCounter, struct timeval **wt, pointer LastSelectMa } static void -IdleTimeWakeupHandler(pointer pCounter, int rc, pointer LastSelectMask) +IdleTimeCheckBrackets(SyncCounter *counter, XSyncValue idle, XSyncValue *less, XSyncValue *greater) { - SyncCounter *counter = pCounter; - IdleCounterPriv *priv = SysCounterGetPrivate(counter); - XSyncValue *less = priv->value_less, - *greater = priv->value_greater; - XSyncValue idle; - - if (!less && !greater) - return; - - IdleTimeQueryValue(pCounter, &idle); - if ((greater && XSyncValueGreaterOrEqual(idle, *greater)) || (less && XSyncValueLessOrEqual(idle, *less))) { SyncChangeCounter(counter, idle); @@ -2706,6 +2695,40 @@ IdleTimeWakeupHandler(pointer pCounter, int rc, pointer LastSelectMask) } static void +IdleTimeWakeupHandler(pointer pCounter, int rc, pointer LastSelectMask) +{ + SyncCounter *counter = pCounter; + IdleCounterPriv *priv = SysCounterGetPrivate(counter); + XSyncValue *less = priv->value_less, + *greater = priv->value_greater; + XSyncValue idle; + + if (!less && !greater) + return; + + IdleTimeQueryValue(pCounter, &idle); + + /* + There is no guarantee for the WakeupHandler to be called within a specific + timeframe. Idletime may go to 0, but by the time we get here, it may be + non-zero and alarms for a pos. transition on 0 won't get triggered. + https://bugs.freedesktop.org/show_bug.cgi?id=70476 + */ + if (LastEventTimeWasReset(priv->deviceid)) { + LastEventTimeToggleResetFlag(priv->deviceid, 0); + if (!XSyncValueIsZero(idle)) { + XSyncValue zero; + XSyncIntsToValue(&zero, 0, 0); + IdleTimeCheckBrackets(counter, zero, less, greater); + less = priv->value_less; + greater = priv->value_greater; + } + } + + IdleTimeCheckBrackets(counter, idle, less, greater); +} + +static void IdleTimeBracketValues(pointer pCounter, CARD64 * pbracket_less, CARD64 * pbracket_greater) { @@ -2720,6 +2743,9 @@ IdleTimeBracketValues(pointer pCounter, CARD64 * pbracket_less, IdleTimeWakeupHandler, pCounter); } else if (!registered && (pbracket_less || pbracket_greater)) { + /* Reset flag must be zero so we don't force a idle timer reset on + the first wakeup */ + LastEventTimeToggleResetAll(0); RegisterBlockAndWakeupHandlers(IdleTimeBlockHandler, IdleTimeWakeupHandler, pCounter); } diff --git a/dix/events.c b/dix/events.c index c803721..ca0c085 100644 --- a/dix/events.c +++ b/dix/events.c @@ -262,7 +262,10 @@ InputInfo inputInfo; EventSyncInfoRec syncEvents; -static TimeStamp lastDeviceEventTime[MAXDEVICES]; +static struct DeviceEventTime { + int reset; + TimeStamp time; +} lastDeviceEventTime[MAXDEVICES]; /** * The root window the given device is currently on. @@ -1060,8 +1063,11 @@ MonthChangedOrBadTime(CARD32 *ms) void NoticeTime(const DeviceIntPtr dev, TimeStamp time) { - lastDeviceEventTime[XIAllDevices] = currentTime; - lastDeviceEventTime[dev->id] = currentTime; + lastDeviceEventTime[XIAllDevices].time = currentTime; + lastDeviceEventTime[dev->id].time = currentTime; + + LastEventTimeToggleResetFlag(dev->id, 1); + LastEventTimeToggleResetFlag(XIAllDevices, 1); } static void @@ -1085,7 +1091,30 @@ NoticeEventTime(InternalEvent *ev, DeviceIntPtr dev) TimeStamp LastEventTime(int deviceid) { - return lastDeviceEventTime[deviceid]; + return lastDeviceEventTime[deviceid].time; +} + +int +LastEventTimeWasReset(int deviceid) +{ + return lastDeviceEventTime[deviceid].reset; +} + +void +LastEventTimeToggleResetFlag(int deviceid, int state) +{ + lastDeviceEventTime[deviceid].reset = state; +} + +void +LastEventTimeToggleResetAll(int state) +{ + DeviceIntPtr dev; + nt_list_for_each_entry(dev, inputInfo.devices, next) { + LastEventTimeToggleResetFlag(dev->id, 0); + } + LastEventTimeToggleResetFlag(XIAllDevices, 0); + LastEventTimeToggleResetFlag(XIAllMasterDevices, 0); } /************************************************************************** @@ -5297,6 +5326,7 @@ InitEvents(void) dummy.id = i; NoticeTime(&dummy, currentTime); + LastEventTimeToggleResetFlag(i, 0); } syncEvents.replayDev = (DeviceIntPtr) NULL; diff --git a/include/dix.h b/include/dix.h index fd2490f..f0c0d14 100644 --- a/include/dix.h +++ b/include/dix.h @@ -322,6 +322,12 @@ NoticeEventTime(InternalEvent *ev, DeviceIntPtr dev); extern _X_EXPORT TimeStamp LastEventTime(int deviceid); +extern _X_EXPORT int +LastEventTimeWasReset(int deviceid); +extern _X_EXPORT void +LastEventTimeToggleResetFlag(int deviceid, int state); +extern _X_EXPORT void +LastEventTimeToggleResetAll(int state); extern void EnqueueEvent(InternalEvent * /* ev */ , -- 1.8.3.1 _______________________________________________ [email protected]: X.Org development Archives: http://lists.x.org/archives/xorg-devel Info: http://lists.x.org/mailman/listinfo/xorg-devel
