Make setFireDate: be usable from within a timeout handler method.

git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/base/trunk@25695 72102866-910b-0410-8b05-ffd578937521
This commit is contained in:
Richard Frith-MacDonald 2007-12-07 08:35:16 +00:00
parent cbb3df3248
commit 849f4a8478
3 changed files with 58 additions and 43 deletions

View file

@ -5,6 +5,8 @@
than one run loop mode and firing in one mode could result in badly
ordered timers in another mode.
Handle resetting of time for repeating timers.
Allow timeout handler callbacks to use ([-setFireDate:]) and have
it honoured.
* Source/NSTimer.m: Remove resetting of fire date from ([-fire])
and move it to the run loop for MacOS-X compatibility.

View file

@ -26,9 +26,6 @@
#define __NSTimer_h_GNUSTEP_BASE_INCLUDE
#import <GNUstepBase/GSVersionMacros.h>
/* This class is currently thrown together. When it is cleaned up, it
may no longer be concrete. */
#import <Foundation/NSDate.h>
#if defined(__cplusplus)
@ -39,9 +36,12 @@ extern "C" {
* NB. NSRunLoop is optimised using a hack that knows about the
* class layout for the fire date and invialidation flag in NSTimer.
* These MUST remain the first two items in the class.
* Other classes must not attempt to use instance variables as
* they are subject to change.
*/
@interface NSTimer : NSObject
{
@private
NSDate *_date; /* Must be first - for NSRunLoop optimisation */
BOOL _invalidated; /* Must be 2nd - for NSRunLoop optimisation */
BOOL _repeats;
@ -76,17 +76,19 @@ extern "C" {
- (void) invalidate;
- (id) userInfo;
#if OS_API_VERSION(GS_API_MACOSX, GS_API_LATEST)
- (BOOL) isValid;
- (NSTimeInterval) timeInterval;
#endif
#if OS_API_VERSION(100200, GS_API_LATEST)
- (id) initWithFireDate: (NSDate*)fd
interval: (NSTimeInterval)ti
target: (id)object
selector: (SEL)selector
userInfo: (id)info
repeats: (BOOL)f;
- (BOOL) isValid;
- (void) setFireDate: (NSDate*)fireDate;
- (NSTimeInterval) timeInterval;
#endif
@end

View file

@ -253,11 +253,6 @@ static inline BOOL timerInvalidated(NSTimer *t)
return ((tvars)t)->_invalidated;
}
static NSComparisonResult tSort(GSIArrayItem i0, GSIArrayItem i1)
{
return [timerDate(i0.obj) compare: timerDate(i1.obj)];
}
@implementation NSObject (TimedPerformers)
@ -816,19 +811,34 @@ static NSComparisonResult tSort(GSIArrayItem i0, GSIArrayItem i1)
/*
* Fire housekeeping timer as necessary
*/
if ((t = context->housekeeper) != nil
&& ([timerDate(t) timeIntervalSinceReferenceDate] <= now))
{
NSDate *next;
if ((t = context->housekeeper) != nil)
{
if (timerInvalidated(t))
{
DESTROY(context->housekeeper);
}
else if ([timerDate(t) timeIntervalSinceReferenceDate] <= now)
{
NSDate *d = timerDate(t);
[t fire];
IF_NO_GC([arp emptyPool]);
now = GSTimeNow();
next = [[NSDate alloc] initWithTimeIntervalSinceReferenceDate:
now + [t timeInterval]];
[t setFireDate: next];
RELEASE(next);
}
[t fire];
GSPrivateNotifyASAP();
IF_NO_GC([arp emptyPool]);
now = GSTimeNow();
/* Increment fire date unless timer is invalidated or the
* timeout handler has already updated it.
*/
if (timerInvalidated(t) == NO && timerDate(t) == d)
{
d = [[NSDate alloc]
initWithTimeIntervalSinceReferenceDate:
now + [t timeInterval]];
[t setFireDate: d];
RELEASE(d);
}
}
}
/*
* Handle normal timers ... remove invalidated timers and fire any
@ -837,39 +847,40 @@ static NSComparisonResult tSort(GSIArrayItem i0, GSIArrayItem i1)
i = GSIArrayCount(timers);
while (i-- > 0)
{
NSTimer *min_timer = GSIArrayItemAtIndex(timers, i).obj;
NSDate *d;
if (timerInvalidated(min_timer) == YES)
t = GSIArrayItemAtIndex(timers, i).obj;
if (timerInvalidated(t) == YES)
{
GSIArrayRemoveItemAtIndex(timers, i);
min_timer = nil;
t = nil;
continue;
}
if ([timerDate(min_timer) timeIntervalSinceReferenceDate] > now)
d = timerDate(t);
if ([d timeIntervalSinceReferenceDate] > now)
{
when = [timerDate(min_timer) copy];
when = [timerDate(t) copy];
break;
}
/* Firing will also increment its fireDate, if it is repeating. */
[min_timer fire];
now = GSTimeNow();
if (timerInvalidated(min_timer) == NO)
{
NSDate *next;
next = [[NSDate alloc] initWithTimeIntervalSinceReferenceDate:
now + [min_timer timeInterval]];
[min_timer setFireDate: next];
RELEASE(next);
}
else
{
GSIArrayRemoveItemAtIndex(timers, i);
}
[t fire];
GSPrivateNotifyASAP(); /* Post notifications. */
IF_NO_GC([arp emptyPool]);
now = GSTimeNow();
/* Increment fire date unless timer is invalidated or the
* timeout handler has already updated it.
*/
if (timerInvalidated(t) == NO && timerDate(t) == d)
{
d = [[NSDate alloc]
initWithTimeIntervalSinceReferenceDate:
now + [t timeInterval]];
[t setFireDate: d];
RELEASE(d);
}
}
_currentMode = savedMode;
}