Skip to content

Commit d059d1c

Browse files
committed
[runloop] Ensure timing arithmetic is done in ns.
Fixes SR-14288.
1 parent f97d23c commit d059d1c

File tree

1 file changed

+20
-11
lines changed

1 file changed

+20
-11
lines changed

CoreFoundation/RunLoop.subproj/CFRunLoop.c

Lines changed: 20 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,15 @@ extern void objc_terminate(void);
4141
#define USE_DISPATCH_SOURCE_FOR_TIMERS 0
4242
#endif
4343

44+
static inline uint64_t __CFNanosecondsToTSR(uint64_t ns) {
45+
#if TARGET_OS_MAC || TARGET_OS_LINUX
46+
return ns;
47+
#else
48+
CFTimeInterval ti = ns / 1.0E9;
49+
return __CFTimeIntervalToTSR(ti);
50+
#endif
51+
}
52+
4453
#if USE_DISPATCH_SOURCE_FOR_TIMERS
4554
#if !TARGET_OS_MAC
4655
typedef uint32_t mach_port_t;
@@ -2353,10 +2362,10 @@ static void __CFArmNextTimerInMode(CFRunLoopModeRef rlm, CFRunLoopRef rl) {
23532362

23542363
if (nextSoftDeadline < UINT64_MAX && (nextHardDeadline != rlm->_timerHardDeadline || nextSoftDeadline != rlm->_timerSoftDeadline)) {
23552364
if (CFRUNLOOP_NEXT_TIMER_ARMED_ENABLED()) {
2356-
CFRUNLOOP_NEXT_TIMER_ARMED((unsigned long)(nextSoftDeadline - mach_absolute_time()));
2365+
CFRUNLOOP_NEXT_TIMER_ARMED((unsigned long)(nextSoftDeadline - __CFNanosecondsToTSR(mach_absolute_time())));
23572366
}
23582367

2359-
cf_trace(KDEBUG_EVENT_CFRL_NEXT_TIMER_ARMED, rl, rlm, (nextSoftDeadline - mach_absolute_time()), 0);
2368+
cf_trace(KDEBUG_EVENT_CFRL_NEXT_TIMER_ARMED, rl, rlm, (nextSoftDeadline - __CFNanosecondsToTSR(mach_absolute_time())), 0);
23602369
#if USE_DISPATCH_SOURCE_FOR_TIMERS
23612370
// We're going to hand off the range of allowable timer fire date to dispatch and let it fire when appropriate for the system.
23622371
uint64_t leeway = __CFTSRToNanoseconds(nextHardDeadline - nextSoftDeadline);
@@ -2453,7 +2462,7 @@ static Boolean __CFRunLoopDoTimer(CFRunLoopRef rl, CFRunLoopModeRef rlm, CFRunLo
24532462
CFRetain(rlt);
24542463
__CFRunLoopTimerLock(rlt);
24552464

2456-
if (__CFIsValid(rlt) && rlt->_fireTSR <= mach_absolute_time() && !__CFRunLoopTimerIsFiring(rlt) && rlt->_runLoop == rl) {
2465+
if (__CFIsValid(rlt) && rlt->_fireTSR <= __CFNanosecondsToTSR(mach_absolute_time()) && !__CFRunLoopTimerIsFiring(rlt) && rlt->_runLoop == rl) {
24572466
void *context_info = NULL;
24582467
void (*context_release)(const void *) = NULL;
24592468
if (rlt->_context.retain) {
@@ -2528,7 +2537,7 @@ static Boolean __CFRunLoopDoTimer(CFRunLoopRef rl, CFRunLoopModeRef rlm, CFRunLo
25282537
CRSetCrashLogMessage("A CFRunLoopTimer with an interval of 0 is set to repeat");
25292538
HALT;
25302539
}
2531-
uint64_t currentTSR = mach_absolute_time();
2540+
uint64_t currentTSR = __CFNanosecondsToTSR(mach_absolute_time());
25322541
nextFireTSR = oldFireTSR;
25332542
while (nextFireTSR <= currentTSR) {
25342543
nextFireTSR += intervalTSR;
@@ -2872,7 +2881,7 @@ static void __CFRunLoopTimeout(void *arg) {
28722881

28732882
/* rl, rlm are locked on entrance and exit */
28742883
static int32_t __CFRunLoopRun(CFRunLoopRef rl, CFRunLoopModeRef rlm, CFTimeInterval seconds, Boolean stopAfterHandle, CFRunLoopModeRef previousMode) {
2875-
uint64_t startTSR = mach_absolute_time();
2884+
uint64_t startTSR = __CFNanosecondsToTSR(mach_absolute_time());
28762885

28772886
if (__CFRunLoopIsStopped(rl)) {
28782887
__CFRunLoopUnsetStopped(rl);
@@ -3128,18 +3137,18 @@ static int32_t __CFRunLoopRun(CFRunLoopRef rl, CFRunLoopModeRef rlm, CFTimeInter
31283137
else if (modeQueuePort != MACH_PORT_NULL && livePort == modeQueuePort) {
31293138
CFRUNLOOP_WAKEUP_FOR_TIMER();
31303139
cf_trace(KDEBUG_EVENT_CFRL_DID_WAKEUP_FOR_TIMER, rl, rlm, livePort, 0);
3131-
if (!__CFRunLoopDoTimers(rl, rlm, mach_absolute_time())) {
3140+
if (!__CFRunLoopDoTimers(rl, rlm, __CFNanosecondsToTSR(mach_absolute_time()))) {
31323141
// Re-arm the next timer, because we apparently fired early
31333142
__CFArmNextTimerInMode(rlm, rl);
31343143
}
31353144
}
31363145
#endif
31373146
#endif
3138-
else if (rlm->_timerPort != MACH_PORT_NULL && livePort == rlm->_timerPort) {
3147+
else if (rlm->_timerPort != CFPORT_NULL && livePort == rlm->_timerPort) {
31393148
CFRUNLOOP_WAKEUP_FOR_TIMER();
31403149
// On Windows, we have observed an issue where the timer port is set before the time which we requested it to be set. For example, we set the fire time to be TSR 167646765860, but it is actually observed firing at TSR 167646764145, which is 1715 ticks early. The result is that, when __CFRunLoopDoTimers checks to see if any of the run loop timers should be firing, it appears to be 'too early' for the next timer, and no timers are handled.
31413150
// In this case, the timer port has been automatically reset (since it was returned from MsgWaitForMultipleObjectsEx), and if we do not re-arm it, then no timers will ever be serviced again unless something adjusts the timer list (e.g. adding or removing timers). The fix for the issue is to reset the timer here if CFRunLoopDoTimers did not handle a timer itself. 9308754
3142-
if (!__CFRunLoopDoTimers(rl, rlm, mach_absolute_time())) {
3151+
if (!__CFRunLoopDoTimers(rl, rlm, __CFNanosecondsToTSR(mach_absolute_time()))) {
31433152
// Re-arm the next timer
31443153
// Since we'll be resetting the same timer as before
31453154
// with the same deadlines, we need to reset these
@@ -3215,7 +3224,7 @@ static int32_t __CFRunLoopRun(CFRunLoopRef rl, CFRunLoopModeRef rlm, CFTimeInter
32153224

32163225
if (sourceHandledThisLoop && stopAfterHandle) {
32173226
retVal = kCFRunLoopRunHandledSource;
3218-
} else if (timeout_context->termTSR < mach_absolute_time()) {
3227+
} else if (timeout_context->termTSR < __CFNanosecondsToTSR(mach_absolute_time())) {
32193228
retVal = kCFRunLoopRunTimedOut;
32203229
} else if (__CFRunLoopIsStopped(rl)) {
32213230
__CFRunLoopUnsetStopped(rl);
@@ -4382,7 +4391,7 @@ CFRunLoopTimerRef CFRunLoopTimerCreate(CFAllocatorRef allocator, CFAbsoluteTime
43824391
memory->_tolerance = 0.0;
43834392
if (TIMER_DATE_LIMIT < fireDate) fireDate = TIMER_DATE_LIMIT;
43844393
memory->_nextFireDate = fireDate;
4385-
uint64_t now2 = mach_absolute_time();
4394+
uint64_t now2 = __CFNanosecondsToTSR(mach_absolute_time());
43864395
CFAbsoluteTime now1 = CFAbsoluteTimeGetCurrent();
43874396
if (fireDate < now1) {
43884397
memory->_fireTSR = now2;
@@ -4441,7 +4450,7 @@ void CFRunLoopTimerSetNextFireDate(CFRunLoopTimerRef rlt, CFAbsoluteTime fireDat
44414450
if (!__CFIsValid(rlt)) return;
44424451
if (TIMER_DATE_LIMIT < fireDate) fireDate = TIMER_DATE_LIMIT;
44434452
uint64_t nextFireTSR = 0ULL;
4444-
uint64_t now2 = mach_absolute_time();
4453+
uint64_t now2 = __CFNanosecondsToTSR(mach_absolute_time());
44454454
CFAbsoluteTime now1 = CFAbsoluteTimeGetCurrent();
44464455
if (fireDate < now1) {
44474456
nextFireTSR = now2;

0 commit comments

Comments
 (0)