[squeak-dev] Re: [Pharo-project] #ensure: issues

Eliot Miranda eliot.miranda at gmail.com
Thu Mar 4 01:52:52 UTC 2010


On Wed, Mar 3, 2010 at 5:35 PM, Andreas Raab <andreas.raab at gmx.de> wrote:

> On 3/3/2010 5:23 PM, Eliot Miranda wrote:
>
>>
>>
>> On Wed, Mar 3, 2010 at 5:07 PM, Andreas Raab <andreas.raab at gmx.de
>> <mailto:andreas.raab at gmx.de>> wrote:
>>
>>    What do you guys think about this? It behaves no worse than the
>>    current implementation if it encountered a problematic ensure: block
>>    in #terminate but it does try to complete one when it finds it. I
>>    think that short of changing the overall terminate semantics this is
>>    pretty close to as good as it gets. The test illustrates the problem.
>>
>>    Eliot - could you check that my usage of findContextSuchThat /
>>    closures / runUntilErrorOrReturn: looks reasonable? I'm still
>>    relatively new to closure land in these areas.
>>
>>
>> That's fine.  But running unwinds in a different process is, I think,
>> unwise.  Process identity is important and unwinds should be run in the
>> context of the process itself.
>>
>
> I said "short of changing the overall termination semantics" :-)
>

But running unwinds in anything other than the owning process is /broken/
and arranging that a process runs its own unwinds on termination is
straight-forward.  The VW code does a few other things, but the way it
transfers control from one process to another is easy to do in Squeak.


>
> Cheers,
>  - Andreas
>
>
>  Here's the VisualWorks code:
>
>>
>> terminate
>> "Terminate the receiver process, by sending the Process terminateSignal.
>> Allow all unwind blocks to run, even if they are currently in progress."
>>
>> "If the receiver is the active process then raise the terminateSignal
>>  which should be
>> caught by the handler in Process class>>forBlock:priority:.  The handler
>> will return,
>> causing all unwind blocks to run, and then will invoke finalTerminate,
>> actually terminating the receiver."
>> Processor activeProcess == self ifTrue:
>> [ [ Process terminateSignal raise ] on: Signal noHandlerSignal do:
>> [ :ex |
>> "Usually, this can only happen if a Process was terminated unnaturally.
>> Try to recover gracefully."
>> Process terminateSignal == ex unhandledException class
>> ifTrue: [ ex return ]
>> ifFalse: [ ex pass ].
>> ].
>> ^self finalTerminate
>> ].
>>
>> "If the receiver is not the active process and its suspendedContext is
>> nil then
>> it is already suspended."
>> suspendedContext == nil ifTrue: [^self].
>>
>> "Suspend the receiver, then place a block atop the receiver's stack to
>> invoke this method as the active process, and resume the receiver."
>> interruptProtect critical:
>> [| savedContext interruptContext outerMostUnwind curr |
>> myList == nil ifFalse: [self suspend].
>> curr := suspendedContext.
>> [curr == nil] whileFalse:
>> [curr method isMarkedForUnwindInAction
>> ifTrue: [outerMostUnwind := curr.
>> curr := curr skipOverUnwindingBlocks].
>> curr := curr findNextMarkedUpTo: nil].
>> (outerMostUnwind ~~ nil and: [outerMostUnwind method numTempsOnly > 0])
>> ifTrue:
>> [outerMostUnwind localAt: outerMostUnwind method numArgs+1 put: true]
>> ifFalse:
>> [savedContext := suspendedContext.
>> interruptContext := [self terminate] newContext.
>> interruptContext sender: savedContext.
>> suspendedContext := interruptContext].
>> self resume]
>>
>> So...
>> - it only runs unwinds in the context of the process, pushing a block
>> that will run terminate if other than the current process tries to
>> terminate it
>> - it tried to discover whether the attempt to terminate from another
>> process was made while unwind blocks are being run and marks any such
>> block as having completed (i.e. it'll short-circuit an already-executing
>> unwind block).
>>
>>
>>
>> P.S. Here's the identification of an unwind in action:
>>
>> BlockClosure>>valueAsUnwindBlockFrom: aContextOrNil
>> "Unwind blocks are evaluated using this wrapper.
>> This method is marked as special.  When the
>> system searches for unwind blocks, it skips over
>> all contexts between this context and the context
>> passed in as an argument.  If the argument is
>> nil, it skips over the sender of this context.
>>
>> The purpose of this is that errors inside an
>> unwind block should not evaluate that unwind
>> block, and they should not circumvent the
>> running of other unwind blocks lower on the
>> stack."
>>
>> <exception: #unwindInAction>
>>
>> | shouldTerminate |
>> "The first temporary variable in this method is treated specially by
>> Process>>terminate,
>> which may set it to true. If that happens, terminate the process at the
>> end of the unwind action.
>> Normally we should be able to take for granted that shouldTerminate has
>> nil as its initial
>> value, but since this variable is modified by another process, it's
>> possible that the other
>> process could set the value to true when this process is waiting at the
>> initial PC of the method.
>> In that case, when this process resumes, it needs to make sure that it
>> doesn't overwrite
>> the true with a false.
>>
>> On a purely theoretical level, there's still room for a race condition
>> between testing for nil
>> and assigning false to the variable, but in practise our execution
>> technology doesn't allow
>> for a process switch between the test and the assignment, so the only
>> way it could be a
>> problem in practise is if the method were being debugged or run by a VI
>> level interpreter
>> at the time that some other process wanted to terminate it. At this
>> time, the risk of that kind
>> of situation seems so much smaller thatn the risk of a process switch at
>> the initial PC, that
>> we're willing to fix only the initial PC case."
>> shouldTerminate == nil ifTrue: [shouldTerminate := false].
>> self value.
>> shouldTerminate
>> ifTrue:
>> [Processor activeProcess terminate].
>>
>> CompiledCode>>isMarkedForUnwindInAction
>> "Answer true if marked for unwind in action."
>>
>> ^false
>>
>> MarkedMethod>>isMarkedForUnwindInAction
>> "Answer true if method is marked for unwinding in action."
>>
>> ^markType == #unwindInAction
>> and I can spell practice ;)
>>
>>
>> HTH
>> Eliot
>>
>>
>>    Cheers,
>>      - Andreas
>>
>>
>>
>>
>>
>>
>>
>>
>>
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://lists.squeakfoundation.org/pipermail/squeak-dev/attachments/20100303/5c74208a/attachment.htm


More information about the Squeak-dev mailing list