exceptions (was Re: blahblahblah)



since my last message on this subject i took a good hit to the head with the clue bat.

here's what's going into 0.96. comments are welcome, as are complaints. given that sf's anoncvs is chronically behind and thus rarely used, i figured that rather than hope people will test this code, i'll go ahead and put it into the release and see what breaks. :-/

- signal and event handlers are now run in an eval context, i.e., they
are no longer fatal.
- a dedicated mechanism in Glib handles the exceptions in signal and
event handlers.
- exceptions do not cross main loop boundaries. effectively, event
loops create their own exception-handling contexts.

some effects of these changes:

- if you are relying on gtk2-perl's current behavior on exceptions
for the control flow of your program, you will need to re-evaluate
your code. this is not likely, since gtk2-perl is currently broken
with respect to exceptions, but i have to warn you.
note that things like trapping the file-not-found exception that
comes from a Gtk2::Gdk::Pixbuf->new_from_file within a subroutine
have *not* been changed.
- if you do not register any exception handlers with Glib, unhandled
exceptions will be reported noisily through warn() and then forgotten.
this is how the Event and Tk modules behave, and even pygtk, for
that matter.



rationale:

callbacks attached to signals are not part of the flow of the code that emits the signals. that is, the emission of a clicked signal on a button should not fail (and be responsible for cleaning up after) things that go wrong in the callbacks connected to it.


details:

this is implemented by adding the G_EVAL flag to call_sv() in gperl_closure_marshal(), and then calling gperl_run_exception_handlers() if ERRSV (that is, $@) is true after the call. that means that anything that uses GPerlClosures will have its exceptions trapped.

currently, the things that use GPerlClosures are signal handlers, event handlers (Timeout, Idle, and IO watches), and the new exception handlers. GPerlCallback, which is used for most of the remaining callbacks in Gtk2, has not been touched; these are typically "immediate" callbacks, so the above philosophy doesn't apply so neatly.

Glib implements its exception handling mechanism because a) it can be run only for exceptions trapped by us, b) $SIG{__DIE__} brings a bit of controversy (it was intended to be used to clean up as a program exits on a die, not for run-time exception hooks), and c) you can install a bunch of them.

the exception handlers add two methods to the perl API:

TAG = Glib->install_exception_handler (FUNC, DATA); # data is optional
Glib->remove_exception_handler (TAG);

the handlers run in the order in which they are installed, and are passed the trapped $@ value (passed by value) and the installed user data, if any. the handler is expected to return a boolean value; if FALSE, the handler is removed, if true, the handler stays installed.



i previously said:
always running callback handlers in G_EVAL is a no-no, as it hides broken code
when no eval block is present in your program.

i still despise hiding exceptions, which is why Glib will now spit out something to the effect of

*** unhandled exception in callback:
*** No such file or directory at test.pl line 25.
*** ignoring at test.pl line 99.

it's marked obnoxiously with the "***" prefix so you're sure to see it; the full text of $@ from the exception is included (this particular one happened at line 25); and the final line tells you that it's being ignored from line 99, which in this program happens to be the line containing Gtk2->main.

this message is suppressed if you have any exception handler callbacks installed.

[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]