The Inbox: Kernel-nice.856.mcz

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
4 messages Options
Reply | Threaded
Open this post in threaded view
|

The Inbox: Kernel-nice.856.mcz

commits-2
A new version of Kernel was added to project The Inbox:
http://source.squeak.org/inbox/Kernel-nice.856.mcz

==================== Summary ====================

Name: Kernel-nice.856
Author: nice
Time: 5 June 2014, 11:11:07.752 pm
UUID: 44668d33-00c2-4e36-b95b-69d83b0d7544
Ancestors: Kernel-cmm.855

Attempt to fix ExceptionTests>>#testHandlerFromAction.
When the handler does not handle an Exception, simply mark the handler context as inactive (self tempAt: 3 put: false).

=============== Diff against Kernel-cmm.855 ===============

Item was changed:
  ----- Method: ContextPart>>handleSignal: (in category 'private-exceptions') -----
  handleSignal: exception
  "Sent to handler (on:do:) contexts only.  If my exception class (first arg) handles exception then execute my handle block (second arg), otherwise forward this message to the next handler context.  If none left, execute exception's defaultAction (see nil>>handleSignal:)."
 
  | val |
+ ((((self tempAt: 1) handles: exception) or: [self tempAt: 3 put: false])
+ and: [self tempAt: 3]) ifFalse: [
- (((self tempAt: 1) handles: exception) and: [self tempAt: 3]) ifFalse: [
  ^ self nextHandlerContext handleSignal: exception].
 
  exception privHandlerContext: self contextTag.
  self tempAt: 3 put: false.  "disable self while executing handle block"
  val := [(self tempAt: 2) cull: exception ]
  ensure: [self tempAt: 3 put: true].
  self return: val.  "return from self if not otherwise directed in handle block"
  !


Reply | Threaded
Open this post in threaded view
|

Re: The Inbox: Kernel-nice.856.mcz

Nicolas Cellier
This change resolved the failing test for me, and I did not yet find what else it may break...
In this danger zone, more eyes are required, so up to you to refute the method :)


2014-06-05 23:11 GMT+02:00 <[hidden email]>:
A new version of Kernel was added to project The Inbox:
http://source.squeak.org/inbox/Kernel-nice.856.mcz

==================== Summary ====================

Name: Kernel-nice.856
Author: nice
Time: 5 June 2014, 11:11:07.752 pm
UUID: 44668d33-00c2-4e36-b95b-69d83b0d7544
Ancestors: Kernel-cmm.855

Attempt to fix ExceptionTests>>#testHandlerFromAction.
When the handler does not handle an Exception, simply mark the handler context as inactive (self tempAt: 3 put: false).

=============== Diff against Kernel-cmm.855 ===============

Item was changed:
  ----- Method: ContextPart>>handleSignal: (in category 'private-exceptions') -----
  handleSignal: exception
        "Sent to handler (on:do:) contexts only.  If my exception class (first arg) handles exception then execute my handle block (second arg), otherwise forward this message to the next handler context.  If none left, execute exception's defaultAction (see nil>>handleSignal:)."

        | val |
+       ((((self tempAt: 1) handles: exception) or: [self tempAt: 3 put: false])
+                and: [self tempAt: 3]) ifFalse: [
-       (((self tempAt: 1) handles: exception) and: [self tempAt: 3]) ifFalse: [
                ^ self nextHandlerContext handleSignal: exception].

        exception privHandlerContext: self contextTag.
        self tempAt: 3 put: false.  "disable self while executing handle block"
        val := [(self tempAt: 2) cull: exception ]
                ensure: [self tempAt: 3 put: true].
        self return: val.  "return from self if not otherwise directed in handle block"
  !





Reply | Threaded
Open this post in threaded view
|

Re: The Inbox: Kernel-nice.856.mcz

Nicolas Cellier

2014-06-05 23:27 GMT+02:00 Nicolas Cellier <[hidden email]>:
This change resolved the failing test for me, and I did not yet find what else it may break...
In this danger zone, more eyes are required, so up to you to refute the method :)

I think I have a refutation (theoretically): if an outer handler resumes execution in signalContext, then the inner handler context won't be re-activated and will miss the next exceptions...

Unfortunately, resuming is the default behavior for any unhandled exception (see UndefinedObject>>#handleSignal:).
So every un-caught exception (even the most harmless Notification) will deactivate all the enclosing handlers!

Definitely not a good change, I must find another way...


2014-06-05 23:11 GMT+02:00 <[hidden email]>:

A new version of Kernel was added to project The Inbox:
http://source.squeak.org/inbox/Kernel-nice.856.mcz

==================== Summary ====================

Name: Kernel-nice.856
Author: nice
Time: 5 June 2014, 11:11:07.752 pm
UUID: 44668d33-00c2-4e36-b95b-69d83b0d7544
Ancestors: Kernel-cmm.855

Attempt to fix ExceptionTests>>#testHandlerFromAction.
When the handler does not handle an Exception, simply mark the handler context as inactive (self tempAt: 3 put: false).

=============== Diff against Kernel-cmm.855 ===============

Item was changed:
  ----- Method: ContextPart>>handleSignal: (in category 'private-exceptions') -----
  handleSignal: exception
        "Sent to handler (on:do:) contexts only.  If my exception class (first arg) handles exception then execute my handle block (second arg), otherwise forward this message to the next handler context.  If none left, execute exception's defaultAction (see nil>>handleSignal:)."

        | val |
+       ((((self tempAt: 1) handles: exception) or: [self tempAt: 3 put: false])
+                and: [self tempAt: 3]) ifFalse: [
-       (((self tempAt: 1) handles: exception) and: [self tempAt: 3]) ifFalse: [
                ^ self nextHandlerContext handleSignal: exception].

        exception privHandlerContext: self contextTag.
        self tempAt: 3 put: false.  "disable self while executing handle block"
        val := [(self tempAt: 2) cull: exception ]
                ensure: [self tempAt: 3 put: true].
        self return: val.  "return from self if not otherwise directed in handle block"
  !






Reply | Threaded
Open this post in threaded view
|

Re: The Inbox: Kernel-nice.856.mcz

Nicolas Cellier

2014-06-06 0:17 GMT+02:00 Nicolas Cellier <[hidden email]>:

2014-06-05 23:27 GMT+02:00 Nicolas Cellier <[hidden email]>:

This change resolved the failing test for me, and I did not yet find what else it may break...
In this danger zone, more eyes are required, so up to you to refute the method :)

I think I have a refutation (theoretically): if an outer handler resumes execution in signalContext, then the inner handler context won't be re-activated and will miss the next exceptions...

Unfortunately, resuming is the default behavior for any unhandled exception (see UndefinedObject>>#handleSignal:).
So every un-caught exception (even the most harmless Notification) will deactivate all the enclosing handlers!

Definitely not a good change, I must find another way...


I came with a brand new strategy: the goal of the testHandlerFromAction is that one:
if an exception occurs while evaluating the handler block, we want to bypass all inner handlers (those inside the protected block).

Since #handleSignal:  is upper on the stack than the inner #on:do: handler, it could be used to intercept the handling and forward to outer handlers.
So here is an implementation of this strategy:

- mark the #handleSignal: context as a handler (<primitive: 199>) so as to intercept handling of next exception
- don't let #handleSignal: handle signal, but simply let it pass to the nextHandlerContext that we pre-recorded in (temp at: 4)
- record the nextHandlerContext in an inst var of #handleSignal: before executing the handlerBlock [(temp at: 2) cull: exception]

I tested it with this:

1) first add a fourth temp to BlockClosure on:do: for safely inquiring (temp at: 4)

on: exception do: handlerAction
    "Evaluate the receiver in the scope of an exception handler."

    | handlerActive nextHandler |
    <primitive: 199>  "just a marker, fail and execute the following"
    handlerActive := true.
    nextHandler := nil.
    ^ self value

2) modify ContextPart handleSignal: as described above

handleSignal: exception
    "Sent to handler (on:do: and handleSignal:) contexts only.  If my exception class (first arg) handles exception then execute my handle block (second arg), otherwise forward this message to the next handler context.  If none left, execute exception's defaultAction (see nil>>handleSignal:)."

    | val active nextHandler |
    <primitive: 199>
    active := false.
    (((self tempAt: 1) handles: exception) and: [self tempAt: 3]) ifFalse: [
        ^((self tempAt: 4) ifNil: [self nextHandlerContext]) handleSignal: exception].

    exception privHandlerContext: self contextTag.
    self tempAt: 3 put: false.  "disable self while executing handle block"
    nextHandler := self nextHandlerContext.
    val := [ (self tempAt: 2) cull: exception ]
        ensure: [self tempAt: 3 put: true].
    self return: val.  "return from self if not otherwise directed in handle block"

If an exception occurs while evaluating the handler block, we are first finding a #handleSignal: context down the stack,
(temp at: 1) is an Exception instance, not an Exception class, it naturally does not handles: (Object>>handles:)
Instead, it will just pass the message to the nextHandler (tempAt: 4)...
eventually this continues thru several outer handlers.

With this scheme, I have a my #testHandlerFromAction passing, but a new failure: #testHandlerReentrancy
Indeed, #testHandlerReentrancy is signalling a Notification from within an outer handler, how could it possibly search a inner handler?
That's precisely what we tried to avoid !!!

To enable such usage of #rearmHandlerDuring: we would have to annihilate the nextHandler temp...
But we don't have an access to this #handleSignal: context from within the exception (it's never the handlerContext, since it does not handles:)
I could possibly add another inst.var. in Exception and fill it with thisContext from within handleSignal:
Above proposition would have holes (even the not rearmed inner handlers would be rearmed).
I see no sender of #rearmHandlerDuring: in trunk, and I'm not sure where it could be usefull...
It seems relatively recent in Squeak (stamp 2010, no previous version).

What do you think?


2014-06-05 23:11 GMT+02:00 <[hidden email]>:

A new version of Kernel was added to project The Inbox:
http://source.squeak.org/inbox/Kernel-nice.856.mcz

==================== Summary ====================

Name: Kernel-nice.856
Author: nice
Time: 5 June 2014, 11:11:07.752 pm
UUID: 44668d33-00c2-4e36-b95b-69d83b0d7544
Ancestors: Kernel-cmm.855

Attempt to fix ExceptionTests>>#testHandlerFromAction.
When the handler does not handle an Exception, simply mark the handler context as inactive (self tempAt: 3 put: false).

=============== Diff against Kernel-cmm.855 ===============

Item was changed:
  ----- Method: ContextPart>>handleSignal: (in category 'private-exceptions') -----
  handleSignal: exception
        "Sent to handler (on:do:) contexts only.  If my exception class (first arg) handles exception then execute my handle block (second arg), otherwise forward this message to the next handler context.  If none left, execute exception's defaultAction (see nil>>handleSignal:)."

        | val |
+       ((((self tempAt: 1) handles: exception) or: [self tempAt: 3 put: false])
+                and: [self tempAt: 3]) ifFalse: [
-       (((self tempAt: 1) handles: exception) and: [self tempAt: 3]) ifFalse: [
                ^ self nextHandlerContext handleSignal: exception].

        exception privHandlerContext: self contextTag.
        self tempAt: 3 put: false.  "disable self while executing handle block"
        val := [(self tempAt: 2) cull: exception ]
                ensure: [self tempAt: 3 put: true].
        self return: val.  "return from self if not otherwise directed in handle block"
  !