Fix for mutation of timers array during firing of a timer.

git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/base/trunk@25706 72102866-910b-0410-8b05-ffd578937521
This commit is contained in:
Richard Frith-MacDonald 2007-12-08 19:56:39 +00:00
parent 357314fb8e
commit b0aed5aebb
2 changed files with 44 additions and 10 deletions

View file

@ -1,3 +1,8 @@
2007-12-08 Richard Frith-Macdonald <rfm@gnu.org>
* Source/NSRunLoop.m: Deal with mutation of timers array during
firing of a timer.
2007-12-07 Richard Frith-Macdonald <rfm@gnu.org>
* Headers/Additions/GNUstepBase/GSConfig.h.in:

View file

@ -860,26 +860,55 @@ static inline BOOL timerInvalidated(NSTimer *t)
d = timerDate(t);
if ([d timeIntervalSinceReferenceDate] > now)
{
when = [timerDate(t) copy];
when = [d copy];
break;
}
/* Firing will also increment its fireDate, if it is repeating. */
/* 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]);
now = GSTimeNow();
/* Increment fire date unless timer is invalidated or the
* timeout handler has already updated it.
/* The -fire method could have re-run the current run loop
* and caused timers to have been added (not a problem),
* or invalidated and/or removed. In the latter case the
* timers array could have shrunk, so we must check that
* our loop index is not too large.
*/
if (timerInvalidated(t) == NO && timerDate(t) == d)
if (i > GSIArrayCount(timers))
{
d = [[NSDate alloc]
initWithTimeIntervalSinceReferenceDate:
now + [t timeInterval]];
[t setFireDate: d];
RELEASE(d);
i = GSIArrayCount(timers);
}
if (timerInvalidated(t) == NO)
{
/* Increment fire date unless the timeout handler
* has already updated it. Then put the timer back
* in the array so that it can fire again next
* time this method is called.
*/
if (timerDate(t) == d)
{
d = [[NSDate alloc]
initWithTimeIntervalSinceReferenceDate:
now + [t timeInterval]];
[t setFireDate: d];
RELEASE(d);
}
GSIArrayInsertItemNoRetain(timers, (GSIArrayItem)((id)t), i);
}
else
{
/* The timer was invalidated, so we can release it as we
* aren't p[utting it back in the array.
*/
RELEASE(t);
}
}
_currentMode = savedMode;