[Openmcl-devel] objc exception handling

Yannick Versley yversley at gmx.de
Mon Feb 24 02:43:43 PST 2003


>  1) A lisp error in code called from ObjC (especially when called as part
> of the ObjC event-dispatching mechanism) should ideally not interfere with
> that event-dispatching mechanism.  I think that any behavior like trying
> to enter a break loop in the main event dispatching thread counts as
> interfering with event-dispatching.  It may be that the best that can
> be done in cases like this is to (somehow) log an error message, cause
> the event-handling thread to believe that the current event's been handled,
> and let it go process the next event.
I agree. This would probably involve writing a lispapplication
sendEvent: method to catch errors, log them and continue in the hope that
everything is right.

> > Normal exception handling in ObjC works using _setjmp/_longjmp in
> > conjunction with NSAddHandler/NSRemoveHandler. Is it possible to use
> > _setjmp with lisp code?
>
> I think that there may be a bit more to ObjC exception handling than
> _setjmp/_longjmp; I've stepped through some code in -[NSApplication run]
> that seemed to be doing something like HANDLER-CASE.  I don't know what
> would be involved in integrating ObjC's exception handling with lisp's,
> but Apple's Java, AppleScript, FScript, and something called Joy (don't
> have the URL handy) all integrate themselves into the ObjC exception
> signalling/handling machinery in some mostly reasonable way (and all
> of these environments have somewhat different exception models.)

Here is a piece of ObjC code that shows how exceptions are handled there:
NS_DURING
  doUsefulStuff();
NS_HANDLER
 cleanUp();
NS_ENDHANDLER
These are really macros and get expanded to
(1) { NSHandler _localHandler; _NSAddHandler2(&_localHandler);
(1) if (!_setjmp(_localHandler._state)) {
       doUsefulStuff();
(2) _NSRemoveHandler2(&_localHandler); } else {
(2) NSException *localException=
(2)                      _NSExceptionObjectFromHandler2(&_localHandler);
       cleanUp();
(3) localException=0; } }
(the numbers are just to mark the expanded parts).

So, yes, it's a bit more, but _setjmp is the hard part.
[NSException raise] just has to look at some stack to find a pointer to a
NSHandler and does a _longjmp to the _state member of that after storing
a pointer to self in an appropriate location.

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.

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.


_______________________________________________
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