[perl #57610] [PATCH] Resumable exceptions

2008-09-07 Thread Christoph Otto via RT
On Tue Aug 05 04:09:14 2008, tene wrote:
 pdd23:
 
 Exception handlers can resume execution immediately after the
 throw opcode by invoking the resume continuation which is stored
 in the exception object.  That continuation must be invoked with no
 parameters; in other words, throw never returns a value.
 
 Exception.pmc has the following attributes:
 
 ATTR INTVALid;   /* The task ID in the scheduler. */
 ATTR FLOATVAL  birthtime;/* The creation time stamp of the
 exception. */
 ATTR STRING   *message;  /* The exception message. */
 ATTR PMC  *payload;  /* The payload for the exception. */
 ATTR INTVALseverity; /* The severity of the exception. */
 ATTR INTVALtype; /* The type of the exception. */
 ATTR INTVALexit_code;/* The exit code of the exception. */
 ATTR PMC  *stacktrace;   /* The stacktrace of an exception. */
 ATTR INTVALhandled;  /* Whether the exception has been
 handled. */
 ATTR PMC  *handler_iter; /* An iterator of handlers (for
 rethrow). */
 ATTR Parrot_Context *handler_ctx; /* A stored context for handler
 iterator. */
 
 None of these is a continuation.
 
 The throw opcode passes the address of the next opcode to
 Parrot_ex_throw_from_op, but Petfo only uses it in:
 
 address= VTABLE_invoke(interp, handler, dest);
 
 and the ExceptionHandler PMC's invoke() does not use that parameter
 at all.
 
 
 This first draft of a patch adds an attribute to the exception pmc to
 hold a return continuation, creates a retcontinuation pmc in the throw
 opcode and assigns it to that attribute, and patches
 new_ret_continuation to initialize the new continuation's from_ctx
 attribute in the same way new_continuation does.
 
 This last item is there to fix a segfault.  I don't understand
 parrot's
 continuations well enough yet to have any idea why they were
 different,
 so I just guessed.  I don't know if it's wrong, but it doesn't seem to
 fail any extra tests.
 
 Added a simple test case.

It looks like Allison applied your patch in r30123 but forgot to close
this ticket.  Now seems like a good time to resolve it.
Thanks for the patch.



Re: Resumable exceptions

2008-08-21 Thread Stephen Weeks
Not long ago, Patrick R. Michaud proclaimed...
 Here's a simple test for resumable exceptions that I'm trying
 to get to work.  I'm probably coding/understanding something wrong, 
 so any suggestions or pointers would be greatly appreciated.
 
 .sub main :main
 push_eh catcher
 'foo'()
 pop_eh
 say 'ok 4'
 .return ()
   catcher:
 .get_results ($P0, $S0)
 $P1 = $P0['retcont']
 $P1()
 .end
 
 .sub 'foo'
 say 'ok 1'
 $P0 = new 'Exception'
 throw $P0
 say 'ok 2'
 $P0 = new 'Exception'
 throw $P0
 say 'ok 3'
 .end
 
 What I'm trying to do is to test the ability to resume after
 exceptions thrown by Cfoo.  The Cmain sub above sets up
 a handler to catch exceptions, then calls Cfoo.  The handler
 simply resumes any exception that is caught.  The Cfoo sub
 prints 'ok 1', throws an exception, prints 'ok 2', throws another
 exception, and prints 'ok 3'.
 
 I can resume the first exception but not the second:
 
 $ ./parrot x.pir
 ok 1
 ok 2
 No exception handler and no message
 current instr.: 'foo' pc 46 (x.pir:20)
 called from Sub 'main' pc 29 (x.pir:10)
 $
 
 Suggestions and corrections to my code welcomed.

Check RT #58170 for this.  Let me know if you need more detail on what's
happening.


Resumable exceptions

2008-08-20 Thread Patrick R. Michaud
Here's a simple test for resumable exceptions that I'm trying
to get to work.  I'm probably coding/understanding something wrong, 
so any suggestions or pointers would be greatly appreciated.

.sub main :main
push_eh catcher
'foo'()
pop_eh
say 'ok 4'
.return ()
  catcher:
.get_results ($P0, $S0)
$P1 = $P0['retcont']
$P1()
.end

.sub 'foo'
say 'ok 1'
$P0 = new 'Exception'
throw $P0
say 'ok 2'
$P0 = new 'Exception'
throw $P0
say 'ok 3'
.end

What I'm trying to do is to test the ability to resume after
exceptions thrown by Cfoo.  The Cmain sub above sets up
a handler to catch exceptions, then calls Cfoo.  The handler
simply resumes any exception that is caught.  The Cfoo sub
prints 'ok 1', throws an exception, prints 'ok 2', throws another
exception, and prints 'ok 3'.

I can resume the first exception but not the second:

$ ./parrot x.pir
ok 1
ok 2
No exception handler and no message
current instr.: 'foo' pc 46 (x.pir:20)
called from Sub 'main' pc 29 (x.pir:10)
$

Suggestions and corrections to my code welcomed.

Pm


Re: Resumable exceptions

2008-08-20 Thread Allison Randal

Patrick R. Michaud wrote:


What I'm trying to do is to test the ability to resume after
exceptions thrown by Cfoo.  The Cmain sub above sets up
a handler to catch exceptions, then calls Cfoo.  The handler
simply resumes any exception that is caught.  The Cfoo sub
prints 'ok 1', throws an exception, prints 'ok 2', throws another
exception, and prints 'ok 3'.

I can resume the first exception but not the second:

$ ./parrot x.pir
ok 1
ok 2
No exception handler and no message
current instr.: 'foo' pc 46 (x.pir:20)
called from Sub 'main' pc 29 (x.pir:10)
$

Suggestions and corrections to my code welcomed.


The old exception system deleted a handler as soon as it was retrieved 
for an exception. For backward-compatibility, the new exception system 
replicates that mis-feature. The problem is, if you end up throwing an 
exception in the middle of handling another one, and didn't mark the 
handler somehow, you can easily get an infinite loop of thrown 
exceptions (when the handler gets some data it didn't expect from the 
second exception, and so throws another exception).


In an ideal world:

a) every exception handler would first check the type of the exception 
it was passed, and rethrow any exceptions it can't handle.


b) exception handlers would only be deleted by 'pop_eh', and otherwise 
would simply pass out of scope after leaving the context where they were 
defined.


Since (a) has to be in place before (b) can work, it was delayed.

(And I just changed the name of the 'retcont' attribute to 'resume', to 
make it a little clearer.)


Allison


[perl #57610] [PATCH] Resumable exceptions

2008-08-05 Thread via RT
, CONST_STRING(INTERP, retcont)) 
== 0) {
+GET_ATTR_retcont(interp, SELF, value);
+}
 else if (string_equal(INTERP, name, CONST_STRING(INTERP, 
stacktrace)) == 0) {
 GET_ATTR_stacktrace(interp, SELF, value);
 }
@@ -579,6 +586,9 @@ Set an attribute value for the exception object.
 else if (string_equal(INTERP, name, CONST_STRING(INTERP, payload)) 
== 0) {
 SET_ATTR_payload(interp, SELF, value);
 }
+else if (string_equal(INTERP, name, CONST_STRING(INTERP, retcont)) 
== 0) {
+SET_ATTR_retcont(interp, SELF, value);
+}
 else if (string_equal(INTERP, name, CONST_STRING(INTERP, 
stacktrace)) == 0) {
 SET_ATTR_stacktrace(interp, SELF, value);
 }
diff --git a/src/sub.c b/src/sub.c
index bcc7bdb..529ddc0 100644
--- a/src/sub.c
+++ b/src/sub.c
@@ -191,7 +191,7 @@ new_ret_continuation(PARROT_INTERP)
 Parrot_cont * const cc = mem_allocate_typed(Parrot_cont);
 
 cc-to_ctx  = CONTEXT(interp);
-cc-from_ctx= NULL;/* filled in during a call */
+cc-from_ctx= CONTEXT(interp);/* filled in during a call */
 cc-dynamic_state   = NULL;
 cc-runloop_id  = 0;
 cc-seg = interp-code;
diff --git a/t/op/exceptions.t b/t/op/exceptions.t
index e49f647..1c4aa1f 100644
--- a/t/op/exceptions.t
+++ b/t/op/exceptions.t
@@ -6,7 +6,7 @@ use strict;
 use warnings;
 use lib qw( . lib ../lib ../../lib );
 use Test::More;
-use Parrot::Test tests = 29;
+use Parrot::Test tests = 30;
 
 =head1 NAME
 
@@ -608,6 +608,29 @@ Exception message: Class Foo already registered!
 after compile
 OUTPUT
 
+pir_output_is( 'CODE', 'OUTPUT', Resumable exceptions );
+.sub main :main
+push_eh _handler
+new $P1, 'Exception'
+say 'Before throwing'
+throw $P1
+say 'After throwing'
+end
+_handler:
+.local pmc e
+.local string s
+.local pmc c
+.get_results (e, s)
+say 'In the exception handler'
+c = e['retcont']
+c()
+.end
+CODE
+Before throwing
+In the exception handler
+After throwing
+OUTPUT
+
 # Local Variables:
 #   mode: cperl
 #   cperl-indent-level: 4
-- 
1.5.5.1



resumable exceptions and LEAVE/KEEP/UNDO blocks

2007-03-05 Thread Daniel Hulme
What happens if a resumable exception is propagated through a block with
a LEAVE, KEEP, or UNDO block? S04 seems to be a bit vague on this point.
It strikes me that what we want it to do is not execute them when the
exception is propagated, because we don't know whether it's going to be
resumed or not. If the exception is resumed by its handler, then that's
fine, as we can call the blocks at the usual time (when the blocks they
are attached to exit). If the exception is caught and handled and not
resumed, that would leave us with having to find all the LEAVE c.
blocks and call them in the right order when the exception handler
exits.

In either case, it looks like you have a problem. LEAVE c. blocks will
often be used for things like database transactions, where we want to
ensure that some lock obtained on entering the block is released
promptly regardless of how the control flow jumps about. In such a
context, throwing a resumable exception that skips the LEAVE block,
farts about doing some potentially long computation in a higher-up
scope, and only calls the LEAVE block to release the lock at some later
date, seems to be far from the best choice. Sure, we can warn
programmers to make their resumable-exception handlers short, or to only
throw non-resumable exceptions from blocks that are likely to be called
in such circumstances. I suppose that would be an acceptable resolution,
but it has an aura of non--re-entrant signal handlers about it, so it
seems like the sort of thing I would like to avoid if anyone is clever
enough to think of something else to do.

BTW, if one is handling a resumable exception, how does one resume it? I
couldn't find anything explaining how. Having a .resume method (or some
cutesier name) on the Resumable role would seem to make sense.

-- 
Customer Waiter, waiter! There's a fly in my soup!
Waiter That's not a bug, it's a feature.
http://surreal.istic.org/  The Answer of the Oracle Is Always Death.


signature.asc
Description: Digital signature


Re: resumable exceptions and LEAVE/KEEP/UNDO blocks

2007-03-05 Thread Larry Wall
On Mon, Mar 05, 2007 at 01:06:46PM +, Daniel Hulme wrote:
: What happens if a resumable exception is propagated through a block with
: a LEAVE, KEEP, or UNDO block? S04 seems to be a bit vague on this point.
: It strikes me that what we want it to do is not execute them when the
: exception is propagated, because we don't know whether it's going to be
: resumed or not. If the exception is resumed by its handler, then that's
: fine, as we can call the blocks at the usual time (when the blocks they
: are attached to exit). If the exception is caught and handled and not
: resumed, that would leave us with having to find all the LEAVE c.
: blocks and call them in the right order when the exception handler
: exits.
: 
: In either case, it looks like you have a problem. LEAVE c. blocks will
: often be used for things like database transactions, where we want to
: ensure that some lock obtained on entering the block is released
: promptly regardless of how the control flow jumps about. In such a
: context, throwing a resumable exception that skips the LEAVE block,
: farts about doing some potentially long computation in a higher-up
: scope, and only calls the LEAVE block to release the lock at some later
: date, seems to be far from the best choice. Sure, we can warn
: programmers to make their resumable-exception handlers short, or to only
: throw non-resumable exceptions from blocks that are likely to be called
: in such circumstances. I suppose that would be an acceptable resolution,
: but it has an aura of non--re-entrant signal handlers about it, so it
: seems like the sort of thing I would like to avoid if anyone is clever
: enough to think of something else to do.

I don't see a problem here.  I think you maybe missed the bit that says:

A CCATCH block sees the lexical scope in which it was defined, but
its caller is the dynamic location that threw the exception.  That is,
the stack is not unwound until some exception handler chooses to
unwind it by handling the exception in question.

Exiting blocks are not run until the decision is made to unwind the stack,
which is *after* the exception handlers are run.  So all the exception
trampoline has to do to resume is just return; the resume continuation
doesn't really have to be a real continuation in this case.

: BTW, if one is handling a resumable exception, how does one resume it? I
: couldn't find anything explaining how. Having a .resume method (or some
: cutesier name) on the Resumable role would seem to make sense.

To resume a resumable exception the correct thing to do is very
likely nothing.  The outermost warning handler is what generally
resumes otherwise uncaught resumables.  If you catch a warning,
it defaults to resuming when handled unless you rethrow it as fatal.

Larry


Re: resumable exceptions and LEAVE/KEEP/UNDO blocks

2007-03-05 Thread Daniel Hulme
On Mon, Mar 05, 2007 at 09:01:13AM -0800, Larry Wall wrote:
 I don't see a problem here.  I think you maybe missed the bit that says:
 
 A CCATCH block sees the lexical scope in which it was defined, but
 its caller is the dynamic location that threw the exception.  That is,
 the stack is not unwound until some exception handler chooses to
 unwind it by handling the exception in question.

Yes, I did. I was grepping specifically for the bit on resumable
exceptions and the quoted bit is 80 lines up so I missed it completely.
Thanks for pointing me at it.

[...]
 To resume a resumable exception the correct thing to do is very
 likely nothing.  The outermost warning handler is what generally
 resumes otherwise uncaught resumables.  If you catch a warning,
 it defaults to resuming when handled unless you rethrow it as fatal.

OK, that makes sense.

The reason that came up was because on Friday I had a good idea for a
language feature that would have made a task I had been doing that day
much easier. When I checked the spec, though, I found out it was already
in. This is happening increasingly often, which should be reassuring to
all concerned.

-- 
Listen to your users, but ignore what they say. - Nathaniel Borenstein
http://surreal.istic.org/  Calm down, it's only ones and zeroes.


signature.asc
Description: Digital signature


Re: [unclassified] Re: resumable exceptions

2006-06-17 Thread John M. Dlugosz
I was involved in the C++ standardization process, and argued for 
resumption as opposed to termination only in exceptions.  I was somewhat 
of a pioneer, implementing C++ exceptions for my team to use before 
commercial compilers had them.  After all, why start a new project with 
an old paradigm?


Anyway, as passionate as I was about resumption, or at least making it 
not impossible to implement resumption, at the next ANSI meeting the 
terminate-only camp made compelling arguments. 

I don't remember what the killer argument was.  But I do remember bits 
and pieces:  people with real-world experience on systems that have 
resumable exceptions in some form ended up never using them; it 
complicates the implementation; it is not necessary since callbacks fill 
that role already (e.g. new_handler instead of resuming from the 
bad_alloc exception); and the semantic concepts of what an exception 
means.  To elaborate, the code throws when it can't deal with the 
situation.  What does it mean if the throw worked like a function call 
and returned?  Code would have to watch out for that, which defeats the 
point of making the exception a clean get-away.  Really, after fixing 
something the function has to start over at the top; e.g. try allocating 
again... that's what a loop around the whole try/catch does, and is 
today common practice! 

So on providing different places to jump to depending on whether the 
exception is fixed or not fixed, how is that different from a normal 
catch block which can re-throw or drop out?


Consider the error upon trying to open a file.  If the open command 
contains a callback handler as part of itself, it can try again and 
eventually return, transparantly to the caller who just sees that the 
file was (eventually) opened.  But what if the caller needs to back up 
and repeat some steps because of that failure, to get another running 
start at the command so to speak?  That's what you can do with a 
mechanism more elaborate than the callback built into the command.  But 
you can do that with a try/catch now, having termination semantics, 
already.  Besides syntactic sugar, how is resuming different from that?


--John

Larry Wall wrote:


On Wed, Jun 14, 2006 at 08:59:02PM -0700, Chip Salzenberg wrote:
: Are Parrot exceptions now, in fact, resumable?  If they are, is that
: important?  Is anyone actually resuming execution after exception handlers
: are called?  I think we _can_ keep resumability, but I'm not sure I want us
: to, and I definitely don't want to bother if no one wants it.

The current thought for Perl 6 is that warnings are essentially just
resumable control exceptions that by default are caught only by the
outermost exception handler, which by default resumes them.  But any
exception handler in the dynamic scope may then catch one and turn
it fatal.  This gives us dynamic as well as lexical control of warnings
without inventing a mechanism separate from existing control exceptions.

On the other hand, I think we've also said that exceptions are
resumable only if the thrower includes as part of the exception
object a continuation to resume at, which presumably warn() does.
So maybe you don't need to do anything special to make exceptions
resumable for Perl 6, assuming throwing the exception doesn't clobber
the continuation somehow.

On the gripping hand, it looks like this is missing from the specs...

Larry

 






Re: [unclassified] Re: resumable exceptions

2006-06-17 Thread Larry Wall
On Fri, Jun 16, 2006 at 10:51:24PM -0500, John M. Dlugosz wrote:
: Anyway, as passionate as I was about resumption, or at least making it 
: not impossible to implement resumption, at the next ANSI meeting the 
: terminate-only camp made compelling arguments. 

Well, interestingly, I used to be in the terminate-only camp.

: I don't remember what the killer argument was.  But I do remember bits 
: and pieces:  people with real-world experience on systems that have 
: resumable exceptions in some form ended up never using them; it 
: complicates the implementation; it is not necessary since callbacks fill 
: that role already (e.g. new_handler instead of resuming from the 
: bad_alloc exception); and the semantic concepts of what an exception 
: means.  To elaborate, the code throws when it can't deal with the 
: situation.  What does it mean if the throw worked like a function call 
: and returned?

In general, it would simply mean that you called warn() instead
of fail().  If you call warn() you're expecting to gamely attempt
to continue.  If you call fail(), you're not expecting to return.
Warning is all about expressing misgivings when you're not sure.
If we throw a warning like we throw an exception, then someone in
the dynamic context may well be more sure than we are whether the
warning should be suppressed or fatalized.

: Code would have to watch out for that, which defeats the 
: point of making the exception a clean get-away.  Really, after fixing 
: something the function has to start over at the top; e.g. try allocating 
: again... that's what a loop around the whole try/catch does, and is 
: today common practice! 
: 
: So on providing different places to jump to depending on whether the 
: exception is fixed or not fixed, how is that different from a normal 
: catch block which can re-throw or drop out?

It doesn't give the code in question the option of raising objections
without giving up.  How would you like it if the only way you could
complain to your management was by turning in a letter of resignation
and hoping they'll rehire you immediately?  Instead, we use office
memos/email that can convey either warnings or resignations.

: Consider the error upon trying to open a file.  If the open command 
: contains a callback handler as part of itself, it can try again and 
: eventually return, transparantly to the caller who just sees that the 
: file was (eventually) opened.  But what if the caller needs to back up 
: and repeat some steps because of that failure, to get another running 
: start at the command so to speak?  That's what you can do with a 
: mechanism more elaborate than the callback built into the command.  But 
: you can do that with a try/catch now, having termination semantics, 
: already.  Besides syntactic sugar, how is resuming different from that?

Sure, and that's what fatal exceptions are good for.  If you are giving
up, throwing a terminate-only exception is exactly what you want to do.

But look at this from the other direction--how do we unify warnings
with exceptions such that people aren't forced to invent out-of-band
warning systems that duplicate most of what throwing exceptions
already does?

In a sense, the whole idea of resumably exception is looking at
it sideways from what you really want.  An exception is just some
bad news that you're trying to pass up the dynamic stack to get more
direction on.  Even if you don't define resumably exceptions at all, in
a language where continuations are first class objects, the *throwing*
code can install one of those into any exception that can hold one,
and bang, you've got resumable exceptions whether you want them or not.

The point you made earlier is one that I agree with, which is that the
*user* interface has to be clear at the point of the throw.  You don't
want to define your interface so that fail() ever returns.  It's like
a return: it documents that the following statement is not reached.
But we can treat warn() as a variant that does document the fact that
it installs a resume continuation, and then attempts to throw a kind of
exception that will be resumed by default.

We could go as far as to have another variant, despair() or some such,
that throws a resumable exception that is not expected to resume
by default, but someone in the dynamic scope might call our resume
continuation anyway.  So that function call would document that we
*probably* won't resume here but don't count on it.  If we do resume,
we'll still try to carry on somehow.

Note also that this cleans up the local $SIG{__WARN__} mess of Perl 5.
Perl 5 compartmentalized warnings from exceptions, but we're just not
gonna do that anymore.  It makes much more sense to unify them, I think.

The latest version of S04 documents how all this is expected to work,
in particular the notion that warnings are just considered control
exceptions so that they bypass most CATCH blocks but can be managed
via CONTROL blocks.

Larry


Re: resumable exceptions

2006-06-15 Thread Larry Wall
On Wed, Jun 14, 2006 at 08:59:02PM -0700, Chip Salzenberg wrote:
: Are Parrot exceptions now, in fact, resumable?  If they are, is that
: important?  Is anyone actually resuming execution after exception handlers
: are called?  I think we _can_ keep resumability, but I'm not sure I want us
: to, and I definitely don't want to bother if no one wants it.

The current thought for Perl 6 is that warnings are essentially just
resumable control exceptions that by default are caught only by the
outermost exception handler, which by default resumes them.  But any
exception handler in the dynamic scope may then catch one and turn
it fatal.  This gives us dynamic as well as lexical control of warnings
without inventing a mechanism separate from existing control exceptions.

On the other hand, I think we've also said that exceptions are
resumable only if the thrower includes as part of the exception
object a continuation to resume at, which presumably warn() does.
So maybe you don't need to do anything special to make exceptions
resumable for Perl 6, assuming throwing the exception doesn't clobber
the continuation somehow.

On the gripping hand, it looks like this is missing from the specs...

Larry


resumable exceptions

2006-06-14 Thread Chip Salzenberg
Are Parrot exceptions now, in fact, resumable?  If they are, is that
important?  Is anyone actually resuming execution after exception handlers
are called?  I think we _can_ keep resumability, but I'm not sure I want us
to, and I definitely don't want to bother if no one wants it.
-- 
Chip Salzenberg [EMAIL PROTECTED]