smalltalk
/
osmo-st-core
Archived
1
0
Fork 0

timer: Try to avoid copying the entire timerlist all the timer

Make sure that we only remove from one process, this way we can
check if the list is empty without having a lock. The list is sorted
so even if we get interrupted between the [condition] whileFalse: [res]
and someone adds an older timer, it is okay to use this timer.
This commit is contained in:
Holger Hans Peter Freyther 2011-07-06 16:56:09 +02:00
parent 6f2c4e98c7
commit 22f6836925
1 changed files with 15 additions and 20 deletions

View File

@ -56,7 +56,13 @@ Object subclass: Timer [
cancel [
<category: 'management'>
schedule removeTimer: self.
"Remember that the timer is gone."
schedule := nil.
]
isCanceled [
<category: 'management'>
^ schedule == nil.
]
]
@ -111,13 +117,6 @@ bit difficult to do this race free.'>
^ sched
]
removeTimer: aSched [
<category: 'schedule'>
sem critical: [
queue remove: aSched ifAbsent: [].
].
]
runTimers [
<category: 'delay_loop'>
@ -131,24 +130,20 @@ bit difficult to do this race free.'>
fireTimers: now [
<category: 'private'>
| copy |
"Create a shallow copy of the data"
copy := sem critical: [queue copy].
"Now execute the timers. One way or another this is crazy. If we have
a long blocking application or a deadlock the timer queue will get
stuck. But if we run this in a new process a later process might be run
before this process, changing the order of the timers."
copy do: [:each |
each timeout > now ifTrue: [^true].
sem critical: [queue remove: each].
[
each fire
] on: Error do: [:e |
"Only this process will remove items, this is why we can check isEmpty
without having the lock"
[queue isEmpty or: [queue first timeout > now]] whileFalse: [ | each |
each := sem critical: [queue removeFirst].
each isCanceled ifFalse: [
[each fire] on: Error do: [:e |
e logException: 'Execution of timer failed: %1' % {e tag} area: #timer.
].
].
]].
]
]
]