[plt-scheme] FFI + errno

From: Eli Barzilay (eli at barzilay.org)
Date: Mon Dec 21 03:57:19 EST 2009

On Dec 21, Thomas Chust wrote:
> with something like
> 
>    (_fun _bytes
>          -> (res : _int) (errno : (_errno 'posix))
>          -> (if (equal? res -1)
>                 (error 'errno "~a" errno)
>                 res))
> 
> where _errno would be a special output type expression.
> 
> Of course it would be functionally equivalent, but I think this
> variant looks cleaner and is more in the Scheme spirit since it
> treats the additional error code output of the function as an output
> instead of replicating the strange behaviour of C by storing a
> function output in a thread local parameter for no added value.

I'm not sure what exactly bothers you: the fact that this is
implemented with a thread cell (which you don't really have to see)
and you prefer to avoid the global, or the fact that getting the value
is not too schemely.

If it's the former, then fixing it would involve changing C code to
accept some way to store the errno (eg, passing in a box, or a setter
function), and then changing the `_fun' interface to communicate such
a receiver.  You might also have efficiency issues, for example, if
you use a box value, then this means allocating a box for every such
call.  (Which might as well be negligible wrt the overall glue cost.)

If it's the latter (which I prefer (see below)), then the problem is
finding some convenient way to expose a more convenient interface, and
that shouldn't be difficult.  You can get close with this:

  (define-fun-syntax _errno
    (syntax-rules ()
      [(_ kind) (post: (saved-errno))])) ; `kind' is not used

  (define foo
    (get-ffi-obj 'foo "x.so"
      (_fun #:save-errno 'posix
            _int
            [e : (_errno 'posix)]
            -> [r : _int]
            -> (values r e)))) ; or whatever you want to do with e

but that doesn't make `_errno' imply the `#:save-errno' keyword.  So I
extended the "custom _fun type" interface so now you can do this:


  (define-fun-syntax _errno
    (syntax-rules ()
      [(_ kind) (post: (saved-errno) keywords: #:save-errno kind)]))

  (define foo
    (get-ffi-obj 'foo "x.so"
      (_fun _int
            [e : (_errno 'posix)]
            -> [r : _int]
            -> (values r e)))) ; or whatever you want to do with e

I didn't add this `_errno' definition, since I'm not sure if this
looks like a good way to improve this.


> To me, storing the contents of errno in a thread local location to
> be accessed by (saved-errno) seems just as sensible as modifying the
> (values ...) special form to return only the first value and to
> store a list of all remaining values in a thread local location to
> be accessed by (saved-values) — undoubtedly this approach would
> work, but I don't think it is an elegant design ;-)

IMO there's no problem with elegance here, since the foreign library
is intended to bridge the gap from C to Scheme -- which is why it
makes sense (to me, at least) to have the simplest code in C, and then
smooth out the interface in Scheme.  Because of this I'd prefer the
second approach over complicating the C code.

-- 
          ((lambda (x) (x x)) (lambda (x) (x x)))          Eli Barzilay:
                    http://barzilay.org/                   Maze is Life!


Posted on the users mailing list.