I've managed (accidentally) to get a 7.4 Process to be deadlocked with
itself. The key is to send #terminate to the Process when it's at just the wrong point. This is clearly not desirable behavior. However, I'm not sure what the desirable behavior is. I'm interested in hearing your opinions on the subject. Here's the sequence the Process follows: * Sends #critical: aBlock to a Semaphore. * The Semaphore does a #wait. * aBlock is evaluated, and completes. * The Semaphore should now signal itself. This signal is in an #ensure: block. * Just before the #ensure: block is entered, the Process is sent #terminate. * The #terminate causes the stack to unwind and all unwind blocks to run. HOWEVER, because we've already entered #valueAsUnwindBlockFrom: for the #ensure: block, it is *not* evaluated. The Semaphore is not signaled. * All unwind blocks deeper on the stack are evaluated. * One of these unwind blocks sends #critical: to our Semaphore. * Since the Semaphore has not been signaled, the Process hangs at this point. The core of this problem seems to be that unwind blocks should not be executed in response to an error inside the unwind block, but that creates a hole in unwind block behavior when #terminate (and possibly #interruptWith:) are sent. So my question right now is whether there's a way to improve this. Putting a marker on the stack when interrupting a Process could be used to complete an interrupted unwind block on unwind, while unwind blocks that raise an exception during their own execution would not be completed. However, this could make it difficult to terminate processes that had misbehaving and long-running unwind blocks. What do you think? Thanks, -Martin For the curious, here's a stack excerpt. Full stack available on request. Debug process GbxRecursionLock(Semaphore)>>waitIfCurtailedSignal GbxRecursionLock(Semaphore)>>critical: ... GbsSession>>logout optimized [] in GbsSession>>loginLinked: BlockClosure>>valueAsUnwindBlockFrom: BlockClosure>>evaluateUnwindBlockFor: MethodContext>>evaluateUnwind TerminateException(GenericException)>>unwind TerminateException(GenericException)>>return: TerminateException(GenericException)>>return optimized [] in [] in Process class>>forBlock:priority: TerminateException(GenericException)>>performHandler: TerminateException(GenericException)>>propagatePrivateFrom: TerminateException(GenericException)>>propagateFrom: TerminateException(GenericException)>>propagate TerminateException(GenericException)>>raiseSignal TerminateException class(GenericException class)>>raise optimized [] in Process>>terminate BlockClosure>>on:do: Process>>terminate optimized [] in [] in Process>>terminate BlockClosure>>valueAsUnwindBlockFrom: BlockClosure>>ensure: GbxRecursionLock(Semaphore)>>critical: ... |
Martin McClure wrote:
> The core of this problem seems to be that unwind blocks should not be > executed in response to an error inside the unwind block, but that > creates a hole in unwind block behavior when #terminate (and possibly > #interruptWith:) are sent. I guess we need to differentiate between exceptions risen in-process (possibly in a broken unwind block) and those risen by an other process. IOW it seems only #interruptWith: needs special treatment. R - |
Free forum by Nabble | Edit this page |