Stephen Compall wrote:
case of undefined behavior: (block a (block b (unwind-protect (return-from a 1) (return-from b 2)))) [1] http://www.lisp.org/HyperSpec/Issues/iss152.html
Steele had a nice text about breathing, roaming and fishing crabs in CLtL1 and II.
I would like to hear from those [...] running CFFI
This has nothing to do with CFFI. Only the underlying implementation knows the answer.
And the general answer is: don't exit non-locally across callbacks! It can always lead to unforeseen trouble.
Rationale: a) Consider jumping to a shared library written in say C++, which has its own idea of unwind-protect. If you throw out of this via Lisp, the C++ destructor will never get called. Different run-times don't mix. b) Consider code written in C. It expects a functional style, i.e. it was not written with non-local exits in mind. It may set some variables or worse, allocate resources, call some function (your Lisp callback) and reset that variable upon exit. If you throw out of this via Lisp, the variable will not be reset, the resource onot freed. Your application may cease to work as a consequence of this (been there, done that). And it will take you time to debug and understand why.
Of course, if you throw out of C:qsort(), I wouldn't expect trouble. That's no counterproof of the above. But consider calling into .NET (I think Edit Weitz has a binding to .NET). Non-local exits get you immediately out of any specified behaviour.
As an aside: would it be better for the defcallback semantics to simply say "don't exit non-locally through a C frame"?
Exactly. It's the only sensible thing to do. Ideally, every callback should contain something similar to ignore-errors (e.g. X event loops).
It would probably make callbacks (and perhaps callouts, for that matter) cheaper to call,
I don't understand that implication.
Regards, Jorg Hohle.
On Fri, 2006-01-06 at 10:30 +0100, Hoehle, Joerg-Cyril wrote:
And the general answer is: don't exit non-locally across callbacks! It can always lead to unforeseen trouble.
After writing the callbacks section (see Tutorial-Callbacks in http://csserver.evansville.edu/~sc87/cffi/tutorial.texi) I decided to explore whether CFFI could (or should, even) provide a general non-local exit prevention. The answer is, with some difficulty and an interface change, perhaps.
On Lisps with EXIT-EXTENT:MEDIUM, this can be implemented with an unwind-protect form in defcallback [1], which performs the operation posted (as undefined in MINIMAL). Lisps with built-in protection in callback definition don't need this.
As an aside: would it be better for the defcallback semantics to simply say "don't exit non-locally through a C frame"?
Exactly. It's the only sensible thing to do. Ideally, every callback should contain something similar to ignore-errors (e.g. X event loops).
The tutorial does this.
It would probably make callbacks (and perhaps callouts, for that matter) cheaper to call,
I don't understand that implication.
If CFFI is to provide general unwind prevention as stated above, the EXIT-EXTENT:MEDIUM would entail the overhead of always entering an unwind-protect. In addition, if one wanted the "other side" to signal an error indicating that Lisp tried to unwind a C frame, a flag check would have to be added to every foreign funcall. [2] I don't, but the possibility remains.
defcallback doesn't provide this now, and maybe shouldn't at all. In the tutorial, a value must be computed and returned to indicate an error; a parameter would have to be added to defcallback to do this, assuming you care whether C knows that there was some error.
[1] This does not protect you from non-local exits in the handler code, as that would entail another unwind-protect, which itself would have unprotected code ... however, it protects all of the important part -- user code.
[2] Not really important when you're doing a bunch of generic function calls under cffi-new-translators anyway, I suppose.