[POLL] Process>>terminate

Gary Chambers gazzaguru2 at btinternet.com
Mon Oct 15 19:05:22 UTC 2007


That seems like the correct solution to me.

> -----Original Message-----
> From: squeak-dev-bounces at lists.squeakfoundation.org
> [mailto:squeak-dev-bounces at lists.squeakfoundation.org]On Behalf Of Igor
> Stasenko
> Sent: 15 October 2007 7:55 PM
> To: The general-purpose Squeak developers list
> Subject: Re: [POLL] Process>>terminate
> 
> 
> Lukas Renggli:
> 
> - #terminate can badly harm system if two processes concurrently try
> to terminate a third process.
> 
> Yes, and that means that #terminate must be enclosed by semaphore to
> ensure that termination code evaluated only once.
> And moreover, things must be harvested to see, what is happening when
> process which causes other process to terminate terminating too ..
> like:
> 
> proc := [ ... ] fork.
> [ proc terminate ] fork terminate.
> 
> 
> On 15/10/2007, Paolo Bonzini <bonzini at gnu.org> wrote:
> > > 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
> >
> 
> For cases, when my process is terminated and i need to execute some
> code before(or at the moment) when this happens, better, i think is to
> provide a #onTerminated: method for Process, where you can put a
> hadler which will be executed whenever process is going to be
> terminated. In normal conditions, if process finished w/o explicit
> call to #terminate, this code should not be invoked.
> 
> So, you can just write something like that:
> 
> [ ... ] fork onTerminate: [ :p | Transcript show: 'Ouch, i terminated
> by..' , p name ]
> 
> or even #addOnTerminate: block , which will add a block to a list of
> blocks which will be evaluated when process is terminating.
> 
> Also, i not agree that terminate must be connected with exceptions.
> Process provides a ways how to control its execution flow, and its not
> an exceptional behavior, its a part of its interface. And i think that
> exceptions framework must not be involved here.
> Of course, its just my humble opinion :)
> 
> -- 
> Best regards,
> Igor Stasenko AKA sig.
> 




More information about the Squeak-dev mailing list