Joshua Gargus uploaded a new version of Morphic to project The Trunk:
http://source.squeak.org/trunk/Morphic-jcg.302.mcz ==================== Summary ==================== Name: Morphic-jcg.302 Author: jcg Time: 9 January 2010, 3:04:38 am UUID: 93a25230-2da7-463c-b82c-cdd8fee1b12d Ancestors: Morphic-jcg.301 After version 301, sending #future from a non-UI thread is no longer thread-safe, because accesses to the MorphicAlarmQueue were not synchronized. Now they are, for all uses of Morphic alarms (i.e. even non-future-send users can now safely use Morphic alarms from other threads). =============== Diff against Morphic-jcg.301 =============== Item was changed: ----- Method: WorldState>>addAlarm:withArguments:for:at: (in category 'alarms') ----- addAlarm: aSelector withArguments: argArray for: aTarget at: scheduledTime "Add a new alarm with the given set of parameters" + self lockAlarmsDuring: [:locked | + locked add: (MorphicAlarm + scheduledAt: scheduledTime + receiver: aTarget + selector: aSelector + arguments: argArray). + ]! - self alarms add: - (MorphicAlarm - scheduledAt: scheduledTime - receiver: aTarget - selector: aSelector - arguments: argArray).! Item was changed: ----- Method: WorldState>>triggerAlarmsBefore: (in category 'alarms') ----- triggerAlarmsBefore: nowTime "Trigger all pending alarms that are to be executed before nowTime." - | pending | lastAlarmTime ifNil:[lastAlarmTime := nowTime]. (nowTime < lastAlarmTime or:[nowTime - lastAlarmTime > 10000]) ifTrue:[self adjustAlarmTimes: nowTime]. + self lockAlarmsDuring: [:pending | + [pending isEmpty not and:[pending first scheduledTime < nowTime]] + whileTrue:[pending removeFirst value: nowTime]. + ]. - pending := self alarms. - [pending isEmpty not and:[pending first scheduledTime < nowTime]] - whileTrue:[pending removeFirst value: nowTime]. lastAlarmTime := nowTime.! Item was changed: Heap subclass: #MorphicAlarmQueue + instanceVariableNames: 'mutex sequenceNumber' - instanceVariableNames: 'sequenceNumber' classVariableNames: '' poolDictionaries: '' category: 'Morphic-Events'! + !MorphicAlarmQueue commentStamp: 'jcg 1/9/2010 13:34' prior: 0! - !MorphicAlarmQueue commentStamp: '<historical>' prior: 0! MorphicAlarmQueue is a specialized Heap. The main change is to stamp each added MorphicAlarm with a sequence number to ensure that alarms scheduled for the same time are executed in the order that they were added.! Item was changed: ----- Method: WorldState>>adjustAlarmTimes: (in category 'alarms') ----- adjustAlarmTimes: nowTime "Adjust the alarm times after some clock weirdness (such as roll-over, image-startup etc)" | deltaTime | deltaTime := nowTime - lastAlarmTime. + self lockAlarmsDuring: [:locked | + locked do:[:alarm| alarm scheduledTime: alarm scheduledTime + deltaTime]. + ]! - self alarms do:[:alarm| alarm scheduledTime: alarm scheduledTime + deltaTime].! Item was added: + ----- Method: WorldState>>lockAlarmsDuring: (in category 'alarms') ----- + lockAlarmsDuring: actionBlock + "All accesses to the alarms queue is synchronized by a mutex. Answer the result of evaluating the 1-argument 'actionBlock'." + alarms ifNil: [alarms := MorphicAlarmQueue new]. + ^alarms mutex critical: [ + actionBlock value: alarms + ]! Item was added: + ----- Method: MorphicAlarmQueue>>mutex (in category 'accessing') ----- + mutex + ^mutex ifNil: [mutex := Mutex new]! Item was changed: ----- Method: WorldState>>cleanseStepListForWorld: (in category 'stepping') ----- cleanseStepListForWorld: aWorld "Remove morphs from the step list that are not in this World. Often were in a flap that has moved on to another world." | deletions morphToStep | deletions := nil. stepList do: [:entry | morphToStep := entry receiver. morphToStep world == aWorld ifFalse:[ deletions ifNil: [deletions := OrderedCollection new]. deletions addLast: entry]]. deletions ifNotNil:[ deletions do: [:entry| self stopStepping: entry receiver]]. + self lockAlarmsDuring: [:locked | + locked copy do: [:entry | + morphToStep := entry receiver. + (morphToStep isMorph and:[morphToStep world == aWorld]) + ifFalse:[self removeAlarm: entry selector for: entry receiver]] + ].! - self alarms copy do:[:entry| - morphToStep := entry receiver. - (morphToStep isMorph and:[morphToStep world == aWorld]) - ifFalse:[self removeAlarm: entry selector for: entry receiver]].! Item was changed: ----- Method: WorldState>>removeAlarm:for: (in category 'alarms') ----- removeAlarm: aSelector for: aTarget "Remove the alarm with the given selector" + self lockAlarmsDuring: [:locked | + | alarm | + alarm := locked + detect: [:any | any receiver == aTarget and: [any selector == aSelector]] + ifNone: [nil]. + alarm ifNotNil: [locked remove: alarm] + ]. + ! - - | alarm | - alarm := self alarms - detect: [:any | any receiver == aTarget and: [any selector == aSelector]] - ifNone: [nil]. - alarm isNil ifFalse: [self alarms remove: alarm]! Item was removed: - ----- Method: WorldState>>alarmSortBlock (in category 'alarms') ----- - alarmSortBlock - ^[ :alarm1 :alarm2 | - alarm1 scheduledTime < alarm2 scheduledTime. - ]! |
Free forum by Nabble | Edit this page |