[Pharo-project] [squeak-dev] My solution to handling errors in system-critical processes

Igor Stasenko siguctua at gmail.com
Sat May 21 01:51:32 CEST 2011

On 20 May 2011 19:33, Eliot Miranda <eliot.miranda at gmail.com> wrote:
> Hi Igor,
>     I get the idea but I does one really need on:fork: ?  Why not add
> Exception>fork, a la Exception>pass?  So one writes
> [ self doSomething  ] on: Error do: [:ex | ex fork ].
> and if you want to specify a handler function you pass in a block:
> [ self doSomething  ] on: Error do: [:ex | ex fork: [block to handle error
> in another process here] ].

Good question.
You can implement it anywhere.
Except then how to correctly determine stack slicing point?

Exception>>fork: aBlock

  contextToSlice := thisContext sender home

see, the above is too fragile. Where the guarantees that you sending
#fork: inside a block, but not like:

Error new fork: [ .... ] ?

If you looked at implementation, i capturing the context of a method
before sending #on:do:
in this way, i know the stack slicing point beforehand.
But if i place it into exception, then correct behavior will have to
rely on developer's sanity that he using it as intended by design.
So, why putting pitfalls when we can avoid them?

My choice for stack slicing point was to let user to see the closure
context with on:do: while debugging,
otherwise it will be harder to determine the origin of code, which led
to error.

Right now, if you evaluate
[ 1/0 ] on: Error fork:[ :ex | ex pass ]

in debugger, you will see the 2nd bottom context will be an on:do: method,
and next one will contain the context for closure that is receiver of #on:do:
so in this way you can clearly see the method with exception handler,
who wanted to
handle errors in forked process.

> ?
> Further, re the finalization issue why are you so resistant to the
> tried-and-tested VW solution that's been in use for about a decade?

i am not resistant at all. I had no time to do that.
Actually, i came to this idea when looking at Henrik's code for Announcements..
and then i found that it can serve for both finalization and
Announcements (and lot of other critical places,
where you don't want to be killed by errors).
For instance , today i shown to Stef, that by placing it at single point in
WorldState>>doOneCycleNowFor: aWorld

we could avoid respawning UI process each time you open debugger.
You slicing the stack with error, putting it into forked process,
where you can do anything with it,
while UI process continues to run from known safe point.

So it solves more problems than just in finalization.

Also i think that it is more efficient: you pay the high price only
when it is necessary - when exception
happens, but if things go as expected , the overhead is minimal.
While in solution which you describing, the price was higher, since you have
to pass the finalizer to forked process and signal semaphore, and then
wait till it finish or fork another process.
And synchronization is not cheap, and moreover, you will have 1 extra
process hanging around all the time.

While now i can simply do:

executors do: [:executor |
   [ executor finalize ] on: Exception fork: [ :ex | ex pass ]

> best,
> Eliot

Best regards,
Igor Stasenko AKA sig.

More information about the Pharo-project mailing list