mirror of
https://github.com/gnustep/libs-base.git
synced 2025-05-31 16:50:58 +00:00
OSX compatibility tweak
git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/base/trunk@28653 72102866-910b-0410-8b05-ffd578937521
This commit is contained in:
parent
82bde6a773
commit
7c8e06d58e
2 changed files with 131 additions and 154 deletions
|
@ -1,3 +1,12 @@
|
||||||
|
2009-09-10 Richard Frith-Macdonald <rfm@gnu.org>
|
||||||
|
|
||||||
|
* Source/NSRunLoop.m: ([-limitDateForMode:]) on OSX it seems that only
|
||||||
|
one timer fires each time this method is invoked ... so I rewrote this
|
||||||
|
method to only fire one timer (excluding the private housekeeping one).
|
||||||
|
Changing to only fire one timer actually allows the code to be simpler
|
||||||
|
so it's a good update in its own right, not just a OSX compatibility
|
||||||
|
tweak.
|
||||||
|
|
||||||
2009-09-08 Richard Frith-Macdonald <rfm@gnu.org>
|
2009-09-08 Richard Frith-Macdonald <rfm@gnu.org>
|
||||||
|
|
||||||
* configure.ac:
|
* configure.ac:
|
||||||
|
|
|
@ -858,6 +858,35 @@ static inline BOOL timerInvalidated(NSTimer *t)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* Ensure that the fire date has been updated either by the timeout handler
|
||||||
|
* updating it or by incrementing it ourselves.<br />
|
||||||
|
* Return YES if it was updated, NO if it was invalidated.
|
||||||
|
*/
|
||||||
|
static BOOL
|
||||||
|
updateTimer(NSTimer *t, NSDate *d, NSTimeInterval now)
|
||||||
|
{
|
||||||
|
if (timerInvalidated(t) == YES)
|
||||||
|
{
|
||||||
|
return NO;
|
||||||
|
}
|
||||||
|
if (timerDate(t) == d)
|
||||||
|
{
|
||||||
|
NSTimeInterval ti = [d timeIntervalSinceReferenceDate];
|
||||||
|
NSTimeInterval increment = [t timeInterval];
|
||||||
|
|
||||||
|
ti += increment;
|
||||||
|
while (ti < now)
|
||||||
|
{
|
||||||
|
ti += increment;
|
||||||
|
}
|
||||||
|
d = [[NSDate alloc] initWithTimeIntervalSinceReferenceDate: ti];
|
||||||
|
[t setFireDate: d];
|
||||||
|
RELEASE(d);
|
||||||
|
}
|
||||||
|
return YES;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Fires timers whose fire date has passed, and checks timers and limit dates
|
* Fires timers whose fire date has passed, and checks timers and limit dates
|
||||||
* for input sources, determining the earliest time that any future timeout
|
* for input sources, determining the earliest time that any future timeout
|
||||||
|
@ -883,11 +912,12 @@ static inline BOOL timerInvalidated(NSTimer *t)
|
||||||
extern NSTimeInterval GSTimeNow(void);
|
extern NSTimeInterval GSTimeNow(void);
|
||||||
GSIArray timers = context->timers;
|
GSIArray timers = context->timers;
|
||||||
NSTimeInterval now;
|
NSTimeInterval now;
|
||||||
NSDate *earliest = nil;
|
NSDate *earliest;
|
||||||
BOOL recheck = YES;
|
NSTimer *et;
|
||||||
NSTimeInterval ei = 0;
|
NSDate *d;
|
||||||
NSTimer *t;
|
NSTimer *t;
|
||||||
NSTimeInterval ti;
|
NSTimeInterval ti;
|
||||||
|
NSTimeInterval ei;
|
||||||
unsigned i;
|
unsigned i;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -910,169 +940,107 @@ static inline BOOL timerInvalidated(NSTimer *t)
|
||||||
{
|
{
|
||||||
DESTROY(context->housekeeper);
|
DESTROY(context->housekeeper);
|
||||||
}
|
}
|
||||||
else if ([timerDate(t) timeIntervalSinceReferenceDate] <= now)
|
else if ([(d=timerDate(t)) timeIntervalSinceReferenceDate] <= now)
|
||||||
{
|
{
|
||||||
NSDate *d = timerDate(t);
|
|
||||||
|
|
||||||
[t fire];
|
[t fire];
|
||||||
GSPrivateNotifyASAP();
|
GSPrivateNotifyASAP();
|
||||||
IF_NO_GC([arp emptyPool]);
|
IF_NO_GC([arp emptyPool]);
|
||||||
|
updateTimer(t, d, now);
|
||||||
/* Increment fire date unless timer is invalidated or the
|
|
||||||
* timeout handler has already updated it.
|
|
||||||
*/
|
|
||||||
if (timerInvalidated(t) == NO && timerDate(t) == d)
|
|
||||||
{
|
|
||||||
ti = [d timeIntervalSinceReferenceDate];
|
|
||||||
ti += [t timeInterval];
|
|
||||||
while (ti < now)
|
|
||||||
{
|
|
||||||
ti += [t timeInterval];
|
|
||||||
}
|
|
||||||
d = [[NSDate alloc]
|
|
||||||
initWithTimeIntervalSinceReferenceDate: ti];
|
|
||||||
[t setFireDate: d];
|
|
||||||
RELEASE(d);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Handle normal timers ... remove invalidated timers and fire any
|
* Handle normal timers ... remove invalidated timers and fire one
|
||||||
* whose date has passed.
|
* whose date has passed.
|
||||||
*/
|
*/
|
||||||
while (recheck == YES)
|
earliest = nil;
|
||||||
{
|
et = nil;
|
||||||
recheck = NO;
|
i = GSIArrayCount(timers);
|
||||||
earliest = nil;
|
while (i-- > 0)
|
||||||
|
{
|
||||||
|
t = GSIArrayItemAtIndex(timers, i).obj;
|
||||||
|
if (timerInvalidated(t) == YES)
|
||||||
|
{
|
||||||
|
GSIArrayRemoveItemAtIndex(timers, i);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
d = timerDate(t);
|
||||||
|
ti = [d timeIntervalSinceReferenceDate];
|
||||||
|
if (earliest == nil || ti < ei)
|
||||||
|
{
|
||||||
|
earliest = d;
|
||||||
|
ei = ti;
|
||||||
|
et = t;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
i = GSIArrayCount(timers);
|
/* If the earliest date is in the past, we should fire the timer.
|
||||||
while (i-- > 0)
|
*/
|
||||||
{
|
if (et != nil && ei < now)
|
||||||
t = GSIArrayItemAtIndex(timers, i).obj;
|
{
|
||||||
if (timerInvalidated(t) == YES)
|
/* When firing the timer we must remove it from
|
||||||
{
|
* the loop so that if the -fire methods re-runs
|
||||||
GSIArrayRemoveItemAtIndex(timers, i);
|
* the loop we do not get recursive entry into
|
||||||
}
|
* the timer. This appears to be the behavior
|
||||||
}
|
* in MacOS-X also.
|
||||||
for (i = 0; i < GSIArrayCount(timers); i++)
|
*/
|
||||||
{
|
i = GSIArrayCount(timers);
|
||||||
NSDate *d;
|
while (i-- > 0)
|
||||||
|
{
|
||||||
t = GSIArrayItemAtIndex(timers, i).obj;
|
t = GSIArrayItemAtIndex(timers, i).obj;
|
||||||
d = timerDate(t);
|
if (t == et)
|
||||||
ti = [d timeIntervalSinceReferenceDate];
|
{
|
||||||
if (ti <= now)
|
|
||||||
{
|
|
||||||
/* When firing the timer we must remove it from
|
|
||||||
* the loop so that if the -fire methods re-runs
|
|
||||||
* the loop we do not get recursive entry into
|
|
||||||
* the timer. This appears to be the behavior
|
|
||||||
* in MacOS-X also.
|
|
||||||
*/
|
|
||||||
GSIArrayRemoveItemAtIndexNoRelease(timers, i);
|
|
||||||
[t fire];
|
|
||||||
GSPrivateNotifyASAP(); /* Post notifications. */
|
|
||||||
IF_NO_GC([arp emptyPool]);
|
|
||||||
|
|
||||||
if (timerInvalidated(t) == YES)
|
|
||||||
{
|
|
||||||
/* The timer was invalidated, so we can
|
|
||||||
* release it as we aren't putting it back
|
|
||||||
* in the array.
|
|
||||||
*/
|
|
||||||
RELEASE(t);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
NSDate *next = timerDate(t);
|
|
||||||
BOOL shouldSetFireDate = NO;
|
|
||||||
|
|
||||||
if (next == d)
|
|
||||||
{
|
|
||||||
/* The timeout handler has not updated
|
|
||||||
* the fire date, so we increment it.
|
|
||||||
*/
|
|
||||||
shouldSetFireDate = YES;
|
|
||||||
ti = [d timeIntervalSinceReferenceDate];
|
|
||||||
ti += [t timeInterval];
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
ti = [next timeIntervalSinceReferenceDate];
|
|
||||||
if (ti <= now)
|
|
||||||
{
|
|
||||||
/* The timeout handler updated the fire
|
|
||||||
* date to some time in the past, so we
|
|
||||||
* need to override that value.
|
|
||||||
*/
|
|
||||||
shouldSetFireDate = YES;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (shouldSetFireDate == YES)
|
|
||||||
{
|
|
||||||
NSTimeInterval increment = [t timeInterval];
|
|
||||||
|
|
||||||
/* First we ensure that the new fire date is
|
|
||||||
* in the future, then we set it in the timer.
|
|
||||||
*/
|
|
||||||
while (ti < now)
|
|
||||||
{
|
|
||||||
ti += increment;
|
|
||||||
}
|
|
||||||
next = [[NSDate alloc]
|
|
||||||
initWithTimeIntervalSinceReferenceDate: ti];
|
|
||||||
[t setFireDate: next];
|
|
||||||
RELEASE(next);
|
|
||||||
}
|
|
||||||
GSIArrayAddItemNoRetain(timers,
|
|
||||||
(GSIArrayItem)((id)t));
|
|
||||||
}
|
|
||||||
|
|
||||||
/* As a timer was fired, it's possible that the
|
|
||||||
* array of valid timers in this context has changed
|
|
||||||
* so we must recheck the dates in case a timer we
|
|
||||||
* already checked has had its start date set back
|
|
||||||
* earlier than the point at which we checked it.
|
|
||||||
* It's also possible that the incremented date of
|
|
||||||
* a repeating timer is still the earliest date in
|
|
||||||
* the context.
|
|
||||||
*/
|
|
||||||
recheck = YES;
|
|
||||||
/* It's possible that the system time was changed
|
|
||||||
* while we have been running, and that the timer
|
|
||||||
* which just fired caused another timer to be
|
|
||||||
* scheduled using a time in the past relative to
|
|
||||||
* 'now'. If we checked it again, we would fire it
|
|
||||||
* again and could in this way end up repeatedly
|
|
||||||
* firing a timer as fast as we possibly can until
|
|
||||||
* the system time in in sync with 'now'.
|
|
||||||
* To prevent this, we re-cache 'now' with the
|
|
||||||
* current system time if that time is in the past.
|
|
||||||
* We can't do that unconditionally though, because
|
|
||||||
* doing so would defeat the whole point of caching
|
|
||||||
* 'now' ... to prevent a repeated slow timed event
|
|
||||||
* from continually firing.
|
|
||||||
*/
|
|
||||||
ti = GSTimeNow();
|
|
||||||
if (ti < now)
|
|
||||||
{
|
|
||||||
fprintf(stderr, "WARNING, we appear to have jumped back in time %g seconds.\n", now - ti);
|
|
||||||
now = ti;
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
else
|
}
|
||||||
{
|
GSIArrayRemoveItemAtIndexNoRelease(timers, i);
|
||||||
if (earliest == nil || ti < ei)
|
[et fire];
|
||||||
{
|
GSPrivateNotifyASAP(); /* Post notifications. */
|
||||||
ei = ti;
|
IF_NO_GC([arp emptyPool]);
|
||||||
earliest = d;
|
if (updateTimer(et, earliest, now) == YES)
|
||||||
}
|
{
|
||||||
}
|
/* Updated ... replace in array.
|
||||||
}
|
*/
|
||||||
}
|
GSIArrayAddItemNoRetain(timers, (GSIArrayItem)((id)et));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* The timer was invalidated, so we can
|
||||||
|
* release it as we aren't putting it back
|
||||||
|
* in the array.
|
||||||
|
*/
|
||||||
|
RELEASE(et);
|
||||||
|
}
|
||||||
|
earliest = nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Now, if we have no earliest date it may be because a timer fired,
|
||||||
|
* in which case we must look again to see what the new earliest
|
||||||
|
* date is.
|
||||||
|
*/
|
||||||
|
if (earliest == nil && (i = GSIArrayCount(timers)) > 0)
|
||||||
|
{
|
||||||
|
while (i-- > 0)
|
||||||
|
{
|
||||||
|
t = GSIArrayItemAtIndex(timers, i).obj;
|
||||||
|
if (timerInvalidated(t) == YES)
|
||||||
|
{
|
||||||
|
GSIArrayRemoveItemAtIndex(timers, i);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
d = timerDate(t);
|
||||||
|
ti = [d timeIntervalSinceReferenceDate];
|
||||||
|
if (earliest == nil || ti < ei)
|
||||||
|
{
|
||||||
|
earliest = d;
|
||||||
|
ei = ti;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* The earliest date of a valid timeout is copied into 'when'
|
/* The earliest date of a valid timeout is copied into 'when'
|
||||||
* and used as our limit date.
|
* and used as our limit date.
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue