I've dug more into the code and came up with something a bit nicer than what I originally described. Feel free to look at the changeshttps://github.com/ffilozov/cffi/commit/e35e949891a0fe5faeca2a0a44050edff99b9f3c (comments and suggestions are always welcome).
My basic assumption is that the underlying CFFI-SYS functions like %foreign-funcall and defcfun-helper-forms would return two values whenever defcfun or foreign-funcall is configured to return errno. The first value is the foreign call return value, and the second is errno. errno is then captured to be passed to the user's structure, and the foreign call return value is propagated further.
Here's a sample of how it looks:
CL-USER> (defparameter errno-object (cffi:make-errno :value 0)) ERRNO-OBJECT
CL-USER> (cffi:defcfun ("socket" :errno t) :int (a :int) (b :int) (c :int)) Warning: :call-direct ignored because :error-value specified. SOCKET
CL-USER> (socket errno-object -1 -1 -1) -1
CL-USER> errno-object #S(CFFI::ERRNO :VALUE 22)
More:
CL-USER> (defparameter errno-object (cffi:make-errno :value 0)) ERRNO-OBJECT
CL-USER> (cffi:foreign-funcall ("getenv" :errno errno-object) :string "SHELL" :string+ptr) ("/bin/bash" 140735646882874)
CL-USER> errno-object #S(CFFI::ERRNO :VALUE 0)
Last one:
CL-USER> (defparameter errno-object (cffi:make-errno :value 0)) ERRNO-OBJECT
CL-USER> (cffi:defcfun ("printf" :errno t) :int (control :string) &rest) PRINTF
CL-USER> (printf errno-object "%s %s" :string "hi" :string "bob") 6
CL-USER> errno-object #S(CFFI::ERRNO :VALUE 0)
On Thu, Aug 8, 2013 at 11:37 PM, Luís Oliveira luismbo@gmail.com wrote:
Felix Filozov ffilozov@gmail.com writes:
Looking into Allegro CL SMP's manual, there's a macro called with-delayed-interrupts, which should prevent interrupts and GC from running. However, the wrong errno was still returned when I used this macro. I will ask Franz if such a macro exists.
What's your test case like?
I started exploring your second suggestion. I created an errno defstruct (this is what the user passes), in the CFFI package, and I tried passing that structure to the CFFI-SYS layer to be modified, but then I realized that CFFI-SYS doesn't know anything about the CFFI package so it can't modify the structure. So I'm passing a function to CFFI-SYS, which gets called with the returned errno value as an argument. I don't know if I like this callback mechanism.
Seems a bit heavy handed, yeah. We can split cffi-sys in two files: a shared file (with the package define and perhaps that structure definition) and an implementation-specific file.
Also, while reading through the code I noticed that there's some edge cases that would need to be handled. For example %defcfun may make a call to foreign-funcall if the argument types and the returns types are considered call-by-value. What does that mean?
We've recently added support for passing structures by value. When that functionality is needed, we use libffi for invoking the foreign function. I have no idea how we can reliably get errno in that case.
I also don't quite understand what entry-vec is, if that's something that can be ignored for now.
I don't remember the details, but doc/allegro-internals.txt has some info about it.
Cheers,
-- Luís Oliveira http://kerno.org/~luis