mirror of
https://github.com/gnustep/libs-base.git
synced 2025-04-22 16:33:29 +00:00
make timers more robust
git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/base/trunk@28656 72102866-910b-0410-8b05-ffd578937521
This commit is contained in:
parent
55a63e4299
commit
0836fd9bd7
3 changed files with 67 additions and 18 deletions
|
@ -5,7 +5,11 @@
|
|||
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.
|
||||
tweak. I also made incrementing repeated timers a bit more robust,
|
||||
checking that they provide a valid increment time interval and
|
||||
removing them from the loop if they don't.
|
||||
* Source/NSTimer.m: slightly tidy/clarify initialisation code and
|
||||
documentation.
|
||||
|
||||
2009-09-08 Richard Frith-Macdonald <rfm@gnu.org>
|
||||
|
||||
|
|
|
@ -62,6 +62,7 @@
|
|||
#ifdef HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
#include <math.h>
|
||||
#include <time.h>
|
||||
#include <limits.h>
|
||||
#include <string.h> /* for memset() */
|
||||
|
@ -813,6 +814,20 @@ static inline BOOL timerInvalidated(NSTimer *t)
|
|||
GSIArray timers;
|
||||
unsigned i;
|
||||
|
||||
if ([timer isKindOfClass: [NSTimer class]] == NO
|
||||
|| [timer isProxy] == YES)
|
||||
{
|
||||
[NSException raise: NSInvalidArgumentException
|
||||
format: @"[%@-%@] not a valid timer",
|
||||
NSStringFromClass([self class]), NSStringFromSelector(_cmd)];
|
||||
}
|
||||
if ([mode isKindOfClass: [NSString class]] == NO)
|
||||
{
|
||||
[NSException raise: NSInvalidArgumentException
|
||||
format: @"[%@-%@] not a valid mode",
|
||||
NSStringFromClass([self class]), NSStringFromSelector(_cmd)];
|
||||
}
|
||||
|
||||
NSDebugMLLog(@"NSRunLoop", @"add timer for %f in %@",
|
||||
[[timer fireDate] timeIntervalSinceReferenceDate], mode);
|
||||
|
||||
|
@ -875,10 +890,38 @@ updateTimer(NSTimer *t, NSDate *d, NSTimeInterval now)
|
|||
NSTimeInterval ti = [d timeIntervalSinceReferenceDate];
|
||||
NSTimeInterval increment = [t timeInterval];
|
||||
|
||||
ti += increment;
|
||||
while (ti < now)
|
||||
if (increment <= 0.0)
|
||||
{
|
||||
ti += increment;
|
||||
/* Should never get here ... unless a subclass is returning
|
||||
* a bad interval ... we return NO so that the timer gets
|
||||
* removed from the loop.
|
||||
*/
|
||||
NSLog(@"WARNING timer %@ had bad interval ... removed", t);
|
||||
return NO;
|
||||
}
|
||||
|
||||
ti += increment; // Hopefully a single increment will do.
|
||||
|
||||
if (ti < now)
|
||||
{
|
||||
NSTimeInterval add;
|
||||
|
||||
/* Just incrementing the date was insufficieint to bring it to
|
||||
* the current time, so we must have missed one or more fire
|
||||
* opportunities, or the fire date has been set on the timer.
|
||||
* If a fire date long ago has been set and the increment value
|
||||
* is really small, we might need to increment very many times
|
||||
* to get the new fire date. To avoid looping for ages, we
|
||||
* calculate the number of increments needed and do them in one
|
||||
* go.
|
||||
*/
|
||||
add = floor((now - ti) / increment);
|
||||
ti += (increment * add);
|
||||
if (ti < now)
|
||||
{
|
||||
add++;
|
||||
ti += increment;
|
||||
}
|
||||
}
|
||||
d = [[NSDate alloc] initWithTimeIntervalSinceReferenceDate: ti];
|
||||
[t setFireDate: d];
|
||||
|
|
|
@ -69,22 +69,21 @@ static Class NSDate_class;
|
|||
return nil;
|
||||
}
|
||||
|
||||
/**
|
||||
* <init />
|
||||
/** <init />
|
||||
* Initialise the receive, a newly allocated NSTimer object.<br />
|
||||
* The fd argument specifies an initial fire date ... if it is not
|
||||
* supplied (a nil object) then the ti argument is used to create
|
||||
* a start date relative to the current time.<br />
|
||||
* The ti argument specifies the time (in seconds) between the firing.
|
||||
* If it is less than or equal to 0.0 then a small interval is chosen
|
||||
* automatically.<br />
|
||||
* The fd argument specifies an initial fire date copied by the timer...
|
||||
* if it is not supplied (a nil object) then the ti argument is used to
|
||||
* create a start date relative to the current time.<br />
|
||||
* The f argument specifies whether the timer will fire repeatedly
|
||||
* or just once.<br />
|
||||
* If the selector argument is zero, then then object is an invocation
|
||||
* to be used when the timer fires. otherwise, the object is sent the
|
||||
* message specified by the selector and with the timer as an argument.<br />
|
||||
* The fd, object and info arguments will be retained until the timer is
|
||||
* invalidated.<br />
|
||||
* The object and info arguments will be retained until the timer is
|
||||
* invalidated.
|
||||
*/
|
||||
- (id) initWithFireDate: (NSDate*)fd
|
||||
interval: (NSTimeInterval)ti
|
||||
|
@ -93,26 +92,30 @@ static Class NSDate_class;
|
|||
userInfo: (id)info
|
||||
repeats: (BOOL)f
|
||||
{
|
||||
if (ti <= 0)
|
||||
if (ti <= 0.0)
|
||||
{
|
||||
ti = 0.0001;
|
||||
}
|
||||
_interval = ti;
|
||||
if (fd == nil)
|
||||
{
|
||||
_date = [[NSDate_class allocWithZone: NSDefaultMallocZone()]
|
||||
initWithTimeIntervalSinceNow: _interval];
|
||||
initWithTimeIntervalSinceNow: ti];
|
||||
}
|
||||
else
|
||||
{
|
||||
_date = [fd copy];
|
||||
_date = [fd copyWithZone: NSDefaultMallocZone()];
|
||||
}
|
||||
_target = RETAIN(object);
|
||||
_selector = selector;
|
||||
_info = RETAIN(info);
|
||||
_repeats = f;
|
||||
if (_repeats == NO)
|
||||
if (f == YES)
|
||||
{
|
||||
_repeats = YES;
|
||||
_interval = ti;
|
||||
}
|
||||
else
|
||||
{
|
||||
_repeats = NO;
|
||||
_interval = 0.0;
|
||||
}
|
||||
return self;
|
||||
|
@ -266,7 +269,6 @@ static Class NSDate_class;
|
|||
- (void) invalidate
|
||||
{
|
||||
/* OPENSTEP allows this method to be called multiple times. */
|
||||
//NSAssert(_invalidated == NO, NSInternalInconsistencyException);
|
||||
_invalidated = YES;
|
||||
if (_target != nil)
|
||||
{
|
||||
|
|
Loading…
Reference in a new issue