summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPeter Hutterer <peter.hutterer@who-t.net>2013-10-16 10:08:46 +1000
committerPeter Hutterer <peter.hutterer@who-t.net>2013-10-17 13:18:37 +1000
commit2a91d8d28a44b71864afbf3fc71b8bdaf2580775 (patch)
tree2ac60f72cb04977b115ef0ca0ac3baae91e0ffd9
parent4960bf8f53f5ef396d1e9b9c7822da544e259ee2 (diff)
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>
-rw-r--r--Xext/sync.c32
-rw-r--r--dix/events.c38
-rw-r--r--include/dix.h6
3 files changed, 69 insertions, 7 deletions
diff --git a/Xext/sync.c b/Xext/sync.c
index ed891b169..1bb7733eb 100644
--- a/Xext/sync.c
+++ b/Xext/sync.c
@@ -2686,6 +2686,15 @@ IdleTimeBlockHandler(pointer pCounter, struct timeval **wt, pointer LastSelectMa
}
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
IdleTimeWakeupHandler(pointer pCounter, int rc, pointer LastSelectMask)
{
SyncCounter *counter = pCounter;
@@ -2699,10 +2708,24 @@ IdleTimeWakeupHandler(pointer pCounter, int rc, pointer LastSelectMask)
IdleTimeQueryValue(pCounter, &idle);
- if ((greater && XSyncValueGreaterOrEqual(idle, *greater)) ||
- (less && XSyncValueLessOrEqual(idle, *less))) {
- SyncChangeCounter(counter, 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
@@ -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 c803721f3..ca0c085d9 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 fd2490fbd..f0c0d14dc 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 */ ,