The Trunk: Morphic-jcg.302.mcz

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
1 message Options
Reply | Threaded
Open this post in threaded view
|

The Trunk: Morphic-jcg.302.mcz

commits-2
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.
- ]!