'From Squeak3.10beta of 22 July 2007 [latest update: #7136] on 28 July 2007 at 7:07:06 am'! "Reporter: andreas Summary: 0006576: Delay is not thread-safe Description: Delay is not thread-safe since currently the calling process updates the internal Delay structure itself. If the process gets terminated while doing this (e.g., adding/removing from SuspendedDelays) the whole system is left in an inconsistent state and breaks. Attached changes fix the problem. Additional Information: It is *very* hard to recreate this problem under controlled circumstances which is the reason why there are no tests accompanying the changes. I've not been able to create the problem on a single machine but we have seen it for months on our servers and with these changes the problem simply went away. "! !Semaphore methodsFor: 'mutual exclusion' stamp: 'ar 7/27/2007 18:19'! critical: mutuallyExcludedBlock "Evaluate mutuallyExcludedBlock only if the receiver is not currently in the process of running the critical: message. If the receiver is, evaluate mutuallyExcludedBlock after the other critical: message is finished." | blockValue caught | "We need to catch eventual interruptions very carefully. The naive approach of just doing, e.g.,: self wait. aBlock ensure:[self signal]. will fail if the active process gets terminated while in the wait. However, the equally naive: [self wait. aBlock value] ensure:[self signal]. will fail too, since the active process may get interrupted while entering the ensured block and leave the semaphore signaled twice. To avoid both problems we make use of the fact that interrupts only occur on sends (or backward jumps) and use an assignment (bytecode) right before we go into the wait primitive (which is not a real send and therefore not interruptable either)." caught := false. [ caught := true. self wait. blockValue := mutuallyExcludedBlock value ] ensure: [ caught ifTrue: [self signal]. ]. ^blockValue ! ! !Semaphore methodsFor: 'mutual exclusion' stamp: 'ar 7/27/2007 18:19'! critical: mutuallyExcludedBlock ifCurtailed: terminationBlock "Evaluate mutuallyExcludedBlock only if the receiver is not currently in the process of running the critical: message. If the receiver is, evaluate mutuallyExcludedBlock after the other critical: message is finished." | blockValue caught | caught := false. "See comment in Semaphore>>critical:" [ caught := true. self wait. [blockValue := mutuallyExcludedBlock value] ifCurtailed: terminationBlock ] ensure: [ caught ifTrue:[self signal]. ]. ^blockValue! ! !Semaphore methodsFor: 'mutual exclusion' stamp: 'ar 7/27/2007 18:20'! critical: mutuallyExcludedBlock ifError: errorBlock "Evaluate mutuallyExcludedBlock only if the receiver is not currently in the process of running the critical: message. If the receiver is, evaluate mutuallyExcludedBlock after the other critical: message is finished." | blockValue hasError errMsg errRcvr caught | caught := false. "See comment in Semaphore>>critical:" [ caught := true. self wait. hasError := false. blockValue := [mutuallyExcludedBlock value] ifError:[:msg :rcvr| hasError := true. errMsg := msg. errRcvr := rcvr ]. ] ensure: [ caught ifTrue:[self signal]. ]. hasError ifTrue:[ ^errorBlock value: errMsg value: errRcvr]. ^blockValue! ! !Semaphore methodsFor: 'mutual exclusion' stamp: 'ar 7/27/2007 18:20'! critical: mutuallyExcludedBlock ifLocked: alternativeBlock "Evaluate mutuallyExcludedBlock only if the receiver is not currently in the process of running the critical: message. If the receiver is, evaluate alternativeBlock." | blockValue caught | "Note: The following is tricky and depends on the fact that the VM will not switch between processes while executing byte codes (process switches happen only in real sends). The following test is written carefully so that it will result in bytecodes only." excessSignals == 0 ifTrue:[ "If we come here, then the semaphore was locked when the test executed. Evaluate the alternative block and answer its result." ^alternativeBlock value ]. caught := false. "See comment in Semaphore>>critical:" [ caught := true. self wait. blockValue := mutuallyExcludedBlock value. ] ensure: [ caught ifTrue:[self signal]. ]. ^blockValue! ! !Semaphore reorganize! ('initialize-release' initSignals terminateProcess) ('communication' signal waitTimeoutMSecs: waitTimeoutSeconds:) ('mutual exclusion' critical: critical:ifCurtailed: critical:ifError: critical:ifLocked:) ('comparing' = hash) ('testing' isSignaled) ('*Scripting-Preload' primitiveWait) ('*Scripting-override' wait) ! ReleaseBuilderFor3dot10 new updatePackages: 'Kernel-edc.163(162).mcd' !