[PATCH 5/7] sync: if the idle time was reset, force alarms to trigger (#70476)
Peter Hutterer
peter.hutterer at who-t.net
Wed Oct 16 20:58:18 PDT 2013
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 at who-t.net>
---
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
More information about the xorg-devel
mailing list