[Openmcl-devel] objc exception handling
Gary Byers
gb at clozure.com
Mon Feb 24 12:24:14 PST 2003
On Mon, 24 Feb 2003, Yannick Versley wrote:
>
> If I try to use _setjmp and _longjmp in Lisp code, it does not do what I
> would want it to do:
>
> (defun test-setjmp ()
> (let ((result))
> (rlet ((env :jmp_buf))
> (setq result (external-call "_setjmp" :address env :signed-fullword))
> (if (= result 0)
> (progn
> (format t "in DURING branch, result=~w~%" result)
> (external-call "_longjmp" :address env :signed-fullword 42)
> (format t "longjmp returned?")
> )
> (format t "in HANDLER branch, result=~w" result)))))
>
> In C, the call to _longjmp would jump back to the point where _setjmp has
> returned, with 42 as new result. Here, execution just continues past
> the call of _longjmp.
What's happening is something like:
(funcall #'ff-call #'(lambda () (setjmp ...)))
followed by
(funcall #'ff-call #'(lambda () (longjmp ...)))
The longjmp is returning to the place from which setjmp is called;
that "place" is returning to its caller. (There really isn't a lisp
FF-CALL -function- involved here, but there's some code in the lisp
kernel that handles the transition between the lisp world and the
foreign world. It's a non-trivial transition, and there are good
(GC-related) reasons for that intermediate layer.)
It doesn't sound like we can use setjmp/longjmp from lisp. What we
-might- be able to do (if we need to) is setup a jmp_buf (manually)
and arrange that when that's longjmp'ed to from foreign code some
specified lisp code is invoked in the right dynamic context. That
sounds doable (more doable than making ffcall deal with setjmp/longjmp);
there would still be issues related to getting setjmp/longjmp and
catch/throw/unwind-protect to work together, and the best way of
"getting them to work together" may be to refrain from using them
at the same time.
>
> I looked at JIGS (a Java/ObjectiveC wrapper from the GNUstep project), and
> the way they do exception handling is checking in each wrapper if there
> was an exception (with NS_DURING on the ObjC side or looking into the
> JNIEnv object on the java side) and throwing/raising a corresponding
> exception on the other side. Apple's Java probably does similar things.
>
> What we would do is wrap a lisp equivalent of NS_DURING / NS_HANDLER /
> NS_ENDHANDLER around the external-call in objc-message-send on one side
> and using handler-case or ignore-errors in define-objc-method.
>
Another approach would be to install an "uncaught exception handler"
that does nothing (the default uncaught exception handler aborts the
application.) In the Cocoa event-handling thread, we basically want
to handle all lisp/objc exceptions by (maybe) logging something, then
transferring control back to the loop in -[NSApplication run]. That
loop seems to do something like:
(loop
NS_DURING
fetch-and-dispatch-an-event
NS_HANDLER
cleanup-some-window-state
do-default-handling-for-uncaught-exceptions
NS_ENDHANDLER)
The thing that I'm referring to as
"do-default-handling-for-uncaught-exceptions" calls an NSApplication
method to report the exception, then calls the uncaught exception
handler. If that handler returns, the event loop repeats.
This seems to be almost exactly what we want (at least for exceptions
that occur in the event handling thread.) It -almost- works in 0.13.x,
but the fact that lisp threads aren't native threads confuses the issue.
It seems to work fine in the development version of 0.14.
If an ObjC exception happens in some other (native) thread - such as
when typing something into a listener - I -think- that what we want
to do is intercept it at the point where it's being raised, map it
to a lisp condition, and let lisp's condition-handling mechanisms
try to deal with it.
_______________________________________________
Openmcl-devel mailing list
Openmcl-devel at clozure.com
http://clozure.com/cgi-bin/mailman/listinfo/openmcl-devel
More information about the Openmcl-devel
mailing list