[squeak-dev] Some gotchas with #terminate and #critical:

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

[squeak-dev] Some gotchas with #terminate and #critical:

Igor Stasenko
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?

--
Best regards,
Igor Stasenko AKA sig.

Reply | Threaded
Open this post in threaded view
|

[squeak-dev] Re: Some gotchas with #terminate and #critical:

Igor Stasenko
2009/4/30 Igor Stasenko <[hidden email]>:

> 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.
>



--
Best regards,
Igor Stasenko AKA sig.

Reply | Threaded
Open this post in threaded view
|

[squeak-dev] Re: Some gotchas with #terminate and #critical:

Andreas.Raab
In reply to this post by Igor Stasenko
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

Reply | Threaded
Open this post in threaded view
|

Re: [squeak-dev] Re: Some gotchas with #terminate and #critical:

Igor Stasenko
2009/4/30 Andreas Raab <[hidden email]>:

> 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.

Reply | Threaded
Open this post in threaded view
|

Re: [squeak-dev] Re: Some gotchas with #terminate and #critical:

Igor Stasenko
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 <[hidden email]>:

> 2009/4/30 Andreas Raab <[hidden email]>:
>> 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.
>



--
Best regards,
Igor Stasenko AKA sig.