Currently i replacing all calls which affect the scheduling to redirecting them to Processor, i.e. instead: self primitiveDoSomething
do: Processor doSomethingWith: self.
This is to ensure, that no code, in rest of classes , except ProcessorScheduler deals with scheduling directly.
If i change the Semaphore>>wait method in that way, then it breaks the trick which sitting in #terminate method :
"Figure out if we are terminating the process while waiting in Semaphore>>critical: In this case, pop the suspendedContext so that we leave the ensure: block inside Semaphore>>critical: without signaling the semaphore." (inSema == true and:[ suspendedContext method == (Semaphore compiledMethodAt: #critical:)]) ifTrue:[ suspendedContext := suspendedContext home. ].
What you think is following alternative implementation:
critical: mutuallyExcludedBlock | blockValue caught | caught := false. [ caught := true. [self wait.] ifCurtailed: [ caught:=false ]. blockValue := mutuallyExcludedBlock value ] ensure: [caught ifTrue: [self signal]]. ^blockValue
avoids the need in having tricks in #terminate?
2009/4/30 Igor Stasenko siguctua@gmail.com:
Currently i replacing all calls which affect the scheduling to redirecting them to Processor, i.e. instead: self primitiveDoSomething
do: Processor doSomethingWith: self.
This is to ensure, that no code, in rest of classes , except ProcessorScheduler deals with scheduling directly.
If i change the Semaphore>>wait method in that way, then it breaks the trick which sitting in #terminate method :
"Figure out if we are terminating the process while waiting in Semaphore>>critical: In this case, pop the suspendedContext so that we leave the ensure: block inside Semaphore>>critical: without signaling the semaphore." (inSema == true and:[ suspendedContext method == (Semaphore compiledMethodAt: #critical:)]) ifTrue:[ suspendedContext := suspendedContext home. ].
What you think is following alternative implementation:
critical: mutuallyExcludedBlock | blockValue caught | caught := false. [ caught := true. [self wait.] ifCurtailed: [ caught:=false ]. blockValue := mutuallyExcludedBlock value ] ensure: [caught ifTrue: [self signal]]. ^blockValue
avoids the need in having tricks in #terminate?
the test code:
| result | result := 0. [ [ result := 5. [Processor terminateActive] ifCurtailed: [ result := 10 ]. ] ensure: [ result := 1 -> result ]. ] forkAt: Processor highestPriority. result
returns result == (1->10)
and:
| result sema | sema := Semaphore new. result := 0. ([ [ result := 5. [sema wait] ifCurtailed: [ result := 10 ]. ] ensure: [ result := 1 -> result ]. ] forkAt: Processor highestPriority) terminate. result
returns result == (1->10) as well.
-- Best regards, Igor Stasenko AKA sig.
Igor Stasenko wrote:
What you think is following alternative implementation:
critical: mutuallyExcludedBlock | blockValue caught | caught := false. [ caught := true. [self wait.] ifCurtailed: [ caught:=false ]. blockValue := mutuallyExcludedBlock value ] ensure: [caught ifTrue: [self signal]]. ^blockValue
avoids the need in having tricks in #terminate?
It doesn't. For example:
sema := Semaphore forMutualExclusion. p := [sema critical:[]] forkAt: Processor activePriority - 1. sema critical:[( Delay forMilliseconds: 100) wait]. p terminate. self assert: sema isSignaled.
Cheers, - Andreas
2009/4/30 Andreas Raab andreas.raab@gmx.de:
Igor Stasenko wrote:
What you think is following alternative implementation:
critical: mutuallyExcludedBlock | blockValue caught | caught := false. [ caught := true. [self wait.] ifCurtailed: [ caught:=false ]. blockValue := mutuallyExcludedBlock value ] ensure: [caught ifTrue: [self signal]]. ^blockValue
avoids the need in having tricks in #terminate?
It doesn't. For example:
sema := Semaphore forMutualExclusion. p := [sema critical:[]] forkAt: Processor activePriority - 1. sema critical:[( Delay forMilliseconds: 100) wait]. p terminate. self assert: sema isSignaled.
Ok, any ideas how to ensure expected behavior without poking the context stack? Because in new scheduler, a #wait implemented differently.
Cheers, - Andreas
With implementation of TerminateProcess exception, i now solved this issue.
sema := Semaphore forMutualExclusion. p := [sema testCritical:[]] forkAt: Processor activePriority - 1. sema testCritical:[( Delay forMilliseconds: 100) wait]. p terminate. self assert: sema isSignaled.
now works w/o failure in new scheduler.
A code for critical section now looks like:
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 | caught := false. [ caught := true. [self wait] on: TerminateProcess do: [:ex | caught := ex abandonedSemaphore ~~ self ]. blockValue := mutuallyExcludedBlock value ] ensure: [caught ifTrue: [self signal]]. ^blockValue
2009/4/30 Igor Stasenko siguctua@gmail.com:
2009/4/30 Andreas Raab andreas.raab@gmx.de:
Igor Stasenko wrote:
What you think is following alternative implementation:
critical: mutuallyExcludedBlock | blockValue caught | caught := false. [ caught := true. [self wait.] ifCurtailed: [ caught:=false ]. blockValue := mutuallyExcludedBlock value ] ensure: [caught ifTrue: [self signal]]. ^blockValue
avoids the need in having tricks in #terminate?
It doesn't. For example:
sema := Semaphore forMutualExclusion. p := [sema critical:[]] forkAt: Processor activePriority - 1. sema critical:[( Delay forMilliseconds: 100) wait]. p terminate. self assert: sema isSignaled.
Ok, any ideas how to ensure expected behavior without poking the context stack? Because in new scheduler, a #wait implemented differently.
Cheers, - Andreas
-- Best regards, Igor Stasenko AKA sig.
squeak-dev@lists.squeakfoundation.org