[POLL] Process>>terminate
Paolo Bonzini
bonzini at gnu.org
Mon Oct 15 12:03:44 UTC 2007
> Well, I must *personally* say that I always associated #ensure: and
> friends with the exception framework - thus, yes, I also want my ensure:
> blocks to run - when there are *exceptions* thrown - but also when the
> Process is *terminated*?
That's the source of the misunderstanding. #ensure: is completely
detached from the exception framework. In fact, you can implement
exceptions only with thisContext, but it's really hard to implement
#ensure: correctly without support in the virtual machine. #ensure: and
#ifCurtailed: blocks, for example, are run also when a block performs a
non-local return, as in
^[ ^#outer ] ensure: [ Transcript show: 'executed' ]
^[ ^#outer ] ifCurtailed: [ Transcript show: 'executed' ]
Note that #ifCurtailed: and #ensure: are equally powerful. Here is
#ifCurtailed: implemented with #ensure: and vice versa:
BlockClosure>>ifCurtailed: curtailedBlock
| result |
curtailed := true.
^[ result := aBlock value. curtailed := false. result ]
ensure: [ curtailed ifTrue: [ curtailedBlock value ] ]
BlockClosure>>ensure: ensureBlock
| result |
[ result := aBlock value ] ifCurtailed: [
ensureBlock value.
^result ].
"Don't reenter the ensureBlock if it is curtailed!"
ensureBlock value.
^result
> - #ensure: blocks are evaluated in the wrong process, that is the
> process that calls #terminate not the one that runs the process. This
> can have very strange effects, if your code depends on the current
> process.
This can be solved easily. You define a ProcessBeingTerminated
exception and wrap the process block aBlock into something like this:
BlockClosure>>newProcess
^Process
forContext: self processBlock
priority: Processor userSchedulingPriority
BlockClosure>>processBlock
^[[aBlock
on: ProcessBeingTerminated
do: [:sig |
"If we terminate in the handler, the 'ensure' blocks
are not evaluated. Instead, if the handler returns, the
unwinding is done properly."
sig return]]
ensure: [self primTerminate]]
where #primTerminate is the "hard terminate" that Igor was mentioning.
Process>>primTerminate
self isActiveProcess ifFalse: [ self error: 'booh' ].
thisContext terminateTo: nil.
self suspend
and termination becomes a matter of signaling the exception:
ProcessorScheduler>>isProcessReady: aProcess
^aProcess suspendingList ==
(quiescentProcessLists at: aProcess priority)
Process>>isReady
^Processor isProcessReady: self
Process>>terminate
| pbt |
"A while ago I explained how to use this to properly implement
Semaphore>>#critical:."
pbt := ProcessBeingTerminated new.
self isReady ifFalse: [ pbt semaphore: myList ].
self signalException: pbt.
You can do whatever you want with this code, it is not taken from GNU
Smalltalk.
Paolo
More information about the Squeak-dev
mailing list
|