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:
rfm 2007-12-08 19:56:39 +00:00
parent c04361b3d6
commit 33691693fa
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> 2007-12-07 Richard Frith-Macdonald <rfm@gnu.org>
* Headers/Additions/GNUstepBase/GSConfig.h.in: * Headers/Additions/GNUstepBase/GSConfig.h.in:

View file

@ -860,26 +860,55 @@ static inline BOOL timerInvalidated(NSTimer *t)
d = timerDate(t); d = timerDate(t);
if ([d timeIntervalSinceReferenceDate] > now) if ([d timeIntervalSinceReferenceDate] > now)
{ {
when = [timerDate(t) copy]; when = [d copy];
break; 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]; [t fire];
GSPrivateNotifyASAP(); /* Post notifications. */ GSPrivateNotifyASAP(); /* Post notifications. */
IF_NO_GC([arp emptyPool]); IF_NO_GC([arp emptyPool]);
now = GSTimeNow(); now = GSTimeNow();
/* Increment fire date unless timer is invalidated or the /* The -fire method could have re-run the current run loop
* timeout handler has already updated it. * 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] i = GSIArrayCount(timers);
initWithTimeIntervalSinceReferenceDate: }
now + [t timeInterval]]; if (timerInvalidated(t) == NO)
[t setFireDate: d]; {
RELEASE(d); /* 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; _currentMode = savedMode;