sync: if the idle time was reset, force alarms to trigger (#70476)
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 <peter.hutterer@who-t.net> Reviewed-by: Adam Jackson <ajax@redhat.com> Reviewed-by: Keith Packard <keithp@keithp.com>
This commit is contained in:
parent
efc1035ca9
commit
06b87aa528
32
Xext/sync.c
32
Xext/sync.c
|
@ -2685,6 +2685,15 @@ IdleTimeBlockHandler(pointer pCounter, struct timeval **wt, pointer LastSelectMa
|
||||||
counter->value = old_idle; /* pop */
|
counter->value = old_idle; /* pop */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
IdleTimeCheckBrackets(SyncCounter *counter, XSyncValue idle, XSyncValue *less, XSyncValue *greater)
|
||||||
|
{
|
||||||
|
if ((greater && XSyncValueGreaterOrEqual(idle, *greater)) ||
|
||||||
|
(less && XSyncValueLessOrEqual(idle, *less))) {
|
||||||
|
SyncChangeCounter(counter, idle);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
IdleTimeWakeupHandler(pointer pCounter, int rc, pointer LastSelectMask)
|
IdleTimeWakeupHandler(pointer pCounter, int rc, pointer LastSelectMask)
|
||||||
{
|
{
|
||||||
|
@ -2699,10 +2708,24 @@ IdleTimeWakeupHandler(pointer pCounter, int rc, pointer LastSelectMask)
|
||||||
|
|
||||||
IdleTimeQueryValue(pCounter, &idle);
|
IdleTimeQueryValue(pCounter, &idle);
|
||||||
|
|
||||||
if ((greater && XSyncValueGreaterOrEqual(idle, *greater)) ||
|
/*
|
||||||
(less && XSyncValueLessOrEqual(idle, *less))) {
|
There is no guarantee for the WakeupHandler to be called within a specific
|
||||||
SyncChangeCounter(counter, idle);
|
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, FALSE);
|
||||||
|
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
|
static void
|
||||||
|
@ -2720,6 +2743,9 @@ IdleTimeBracketValues(pointer pCounter, CARD64 * pbracket_less,
|
||||||
IdleTimeWakeupHandler, pCounter);
|
IdleTimeWakeupHandler, pCounter);
|
||||||
}
|
}
|
||||||
else if (!registered && (pbracket_less || pbracket_greater)) {
|
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(FALSE);
|
||||||
RegisterBlockAndWakeupHandlers(IdleTimeBlockHandler,
|
RegisterBlockAndWakeupHandlers(IdleTimeBlockHandler,
|
||||||
IdleTimeWakeupHandler, pCounter);
|
IdleTimeWakeupHandler, pCounter);
|
||||||
}
|
}
|
||||||
|
|
38
dix/events.c
38
dix/events.c
|
@ -262,7 +262,10 @@ InputInfo inputInfo;
|
||||||
|
|
||||||
EventSyncInfoRec syncEvents;
|
EventSyncInfoRec syncEvents;
|
||||||
|
|
||||||
static TimeStamp lastDeviceEventTime[MAXDEVICES];
|
static struct DeviceEventTime {
|
||||||
|
Bool reset;
|
||||||
|
TimeStamp time;
|
||||||
|
} lastDeviceEventTime[MAXDEVICES];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The root window the given device is currently on.
|
* The root window the given device is currently on.
|
||||||
|
@ -1060,8 +1063,11 @@ MonthChangedOrBadTime(CARD32 *ms)
|
||||||
void
|
void
|
||||||
NoticeTime(const DeviceIntPtr dev, TimeStamp time)
|
NoticeTime(const DeviceIntPtr dev, TimeStamp time)
|
||||||
{
|
{
|
||||||
lastDeviceEventTime[XIAllDevices] = currentTime;
|
lastDeviceEventTime[XIAllDevices].time = currentTime;
|
||||||
lastDeviceEventTime[dev->id] = currentTime;
|
lastDeviceEventTime[dev->id].time = currentTime;
|
||||||
|
|
||||||
|
LastEventTimeToggleResetFlag(dev->id, TRUE);
|
||||||
|
LastEventTimeToggleResetFlag(XIAllDevices, TRUE);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -1085,7 +1091,30 @@ NoticeEventTime(InternalEvent *ev, DeviceIntPtr dev)
|
||||||
TimeStamp
|
TimeStamp
|
||||||
LastEventTime(int deviceid)
|
LastEventTime(int deviceid)
|
||||||
{
|
{
|
||||||
return lastDeviceEventTime[deviceid];
|
return lastDeviceEventTime[deviceid].time;
|
||||||
|
}
|
||||||
|
|
||||||
|
Bool
|
||||||
|
LastEventTimeWasReset(int deviceid)
|
||||||
|
{
|
||||||
|
return lastDeviceEventTime[deviceid].reset;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
LastEventTimeToggleResetFlag(int deviceid, Bool state)
|
||||||
|
{
|
||||||
|
lastDeviceEventTime[deviceid].reset = state;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
LastEventTimeToggleResetAll(Bool state)
|
||||||
|
{
|
||||||
|
DeviceIntPtr dev;
|
||||||
|
nt_list_for_each_entry(dev, inputInfo.devices, next) {
|
||||||
|
LastEventTimeToggleResetFlag(dev->id, FALSE);
|
||||||
|
}
|
||||||
|
LastEventTimeToggleResetFlag(XIAllDevices, FALSE);
|
||||||
|
LastEventTimeToggleResetFlag(XIAllMasterDevices, FALSE);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**************************************************************************
|
/**************************************************************************
|
||||||
|
@ -5297,6 +5326,7 @@ InitEvents(void)
|
||||||
|
|
||||||
dummy.id = i;
|
dummy.id = i;
|
||||||
NoticeTime(&dummy, currentTime);
|
NoticeTime(&dummy, currentTime);
|
||||||
|
LastEventTimeToggleResetFlag(i, FALSE);
|
||||||
}
|
}
|
||||||
|
|
||||||
syncEvents.replayDev = (DeviceIntPtr) NULL;
|
syncEvents.replayDev = (DeviceIntPtr) NULL;
|
||||||
|
|
|
@ -322,6 +322,12 @@ NoticeEventTime(InternalEvent *ev,
|
||||||
DeviceIntPtr dev);
|
DeviceIntPtr dev);
|
||||||
extern _X_EXPORT TimeStamp
|
extern _X_EXPORT TimeStamp
|
||||||
LastEventTime(int deviceid);
|
LastEventTime(int deviceid);
|
||||||
|
extern _X_EXPORT Bool
|
||||||
|
LastEventTimeWasReset(int deviceid);
|
||||||
|
extern _X_EXPORT void
|
||||||
|
LastEventTimeToggleResetFlag(int deviceid, Bool state);
|
||||||
|
extern _X_EXPORT void
|
||||||
|
LastEventTimeToggleResetAll(Bool state);
|
||||||
|
|
||||||
extern void
|
extern void
|
||||||
EnqueueEvent(InternalEvent * /* ev */ ,
|
EnqueueEvent(InternalEvent * /* ev */ ,
|
||||||
|
|
Loading…
Reference in New Issue