Subject: Re: bug#18592: FFI should have portable access to‘errno’

From: Nala Ginrut <[email-masked]>
Date: Thu, 31 Dec 2015 20:33:49 +0800

Hi folks!
Here're patches (based on stable-2.0) to fix this issue according to
proposal 1.

Please review them, I'm going to write a new CFFI parser with nyacc, so
these patches is important for this plan. 

Thanks!

On Sat, 2015-01-24 at 11:33 +0100, Ludovic Courtès wrote:
> Mark H Weaver <[email-masked]> skribis:
> 
> > [email-masked] (Ludovic Courtès) writes:
> >
> >> Chaos Eternal <[email-masked]> skribis:
> >>
> >>> Proposals to solve this bug:
> >>>
> >>> Proposal 1.
> >>>
> >>> Adding a keyword argument to pointer->procedure, if set to true, the
> >>> generated wrapper will check 'errno' immediately after ffi_call and
> >>> return the errno as second value.
> >>>
> >>> the proposed pointer->procedure maybe like this:
> >>> pointer->procedure return_type func_ptr arg_types #:return-errno

> I agree #1 is now the best option so far.
> 
> Ludo’.

>From 88a99af4b5db9096c3cde51c72eb371b6be76754 Mon Sep 17 00:00:00 2001
From: Nala Ginrut <[email-masked]>
Date: Thu, 31 Dec 2015 20:27:59 +0800
Subject: [PATCH 1/2] Add option to pointer->procedure to return errno if
 necessary

---
 libguile/foreign.c |   33 ++++++++++++++++++++++++---------
 libguile/foreign.h |    2 +-
 2 files changed, 25 insertions(+), 10 deletions(-)

diff --git a/libguile/foreign.c b/libguile/foreign.c
index 29cfc73..6909023 100644
--- a/libguile/foreign.c
+++ b/libguile/foreign.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2010-2015  Free Software Foundation, Inc.
+/* Copyright (C) 2010-2016  Free Software Foundation, Inc.
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public License
@@ -85,7 +85,7 @@ null_pointer_error (const char *func_name)
 }
 
 
-static SCM cif_to_procedure (SCM cif, SCM func_ptr);
+static SCM cif_to_procedure (SCM cif, SCM func_ptr, SCM return_errno);

 static SCM pointer_weak_refs = SCM_BOOL_F;
@@ -753,24 +753,29 @@ make_cif (SCM return_type, SCM arg_types, const char *caller)
 }
 #undef FUNC_NAME
 
-SCM_DEFINE (scm_pointer_to_procedure, "pointer->procedure", 3, 0, 0,
-            (SCM return_type, SCM func_ptr, SCM arg_types),
+SCM_DEFINE (scm_pointer_to_procedure, "pointer->procedure", 3, 1, 0,
+            (SCM return_type, SCM func_ptr, SCM arg_types, SCM return_errno),
             "Make a foreign function.\n\n"
             "Given the foreign void pointer @var{func_ptr}, its argument and\n"
             "return types @var{arg_types} and @var{return_type}, return a\n"
             "procedure that will pass arguments to the foreign function\n"
             "and return appropriate values.\n\n"
             "@var{arg_types} should be a list of foreign types.\n"
-            "@code{return_type} should be a foreign type.")
+            "@code{return_type} should be a foreign type.\n"
+	    "@var{return_errno} is @code{#f} in default, if set to #t, then\n"
+	    "the @var{errno} will be returned as the second value.")
 #define FUNC_NAME s_scm_pointer_to_procedure
 {
   ffi_cif *cif;
 
   SCM_VALIDATE_POINTER (2, func_ptr);
 
+  if (SCM_UNLIKELY (SCM_UNBNDP (return_errno)))
+    return_errno = SCM_BOOL_F;
+
   cif = make_cif (return_type, arg_types, FUNC_NAME);
 
-  return cif_to_procedure (scm_from_pointer (cif, NULL), func_ptr);
+  return cif_to_procedure (scm_from_pointer (cif, NULL), func_ptr, return_errno);
 }
 #undef FUNC_NAME
 
@@ -940,7 +945,7 @@ get_objcode_trampoline (unsigned int nargs)
 }
 
 static SCM
-cif_to_procedure (SCM cif, SCM func_ptr)
+cif_to_procedure (SCM cif, SCM func_ptr, SCM return_errno)
 {
   ffi_cif *c_cif;
   SCM objcode, table, ret;
@@ -949,7 +954,8 @@ cif_to_procedure (SCM cif, SCM func_ptr)
   objcode = get_objcode_trampoline (c_cif->nargs);
   
   table = scm_c_make_vector (2, SCM_UNDEFINED);
-  SCM_SIMPLE_VECTOR_SET (table, 0, scm_cons (cif, func_ptr));
+  SCM_SIMPLE_VECTOR_SET (table, 0,
+			 scm_cons (cif, scm_cons (func_ptr, return_errno)));
   SCM_SIMPLE_VECTOR_SET (table, 1, SCM_BOOL_F); /* name */
   ret = scm_make_program (objcode, table, SCM_BOOL_F);
   
@@ -1116,9 +1122,11 @@ scm_i_foreign_call (SCM foreign, const SCM *argv)
   unsigned i;
   size_t arg_size;
   scm_t_ptrdiff off;
+  SCM return_errno;
 
   cif = SCM_POINTER_VALUE (SCM_CAR (foreign));
-  func = SCM_POINTER_VALUE (SCM_CDR (foreign));
+  func = SCM_POINTER_VALUE (SCM_CADR (foreign));
+  return_errno = SCM_CDDR (foreign);
 
   /* Argument pointers.  */
   args = alloca (sizeof (void *) * cif->nargs);
@@ -1153,9 +1161,16 @@ scm_i_foreign_call (SCM foreign, const SCM *argv)
   rvalue = (void *) ROUND_UP ((scm_t_uintptr) data + off,
 			      max (sizeof (void *), cif->rtype->alignment));
 
+  errno = 0;
   /* off we go! */
   ffi_call (cif, func, rvalue, args);
 
+  if (SCM_LIKELY (scm_is_true (return_errno)))
+    {
+      return scm_values (scm_list_2 (pack (cif->rtype, rvalue, 1),
+				     scm_from_int (errno)));
+    }
+
   return pack (cif->rtype, rvalue, 1);
 }
 
diff --git a/libguile/foreign.h b/libguile/foreign.h
index 41c0b65..8541526 100644
--- a/libguile/foreign.h
+++ b/libguile/foreign.h
@@ -93,7 +93,7 @@ SCM_INTERNAL SCM scm_pointer_to_string (SCM pointer, SCM length, SCM encoding);
  */
 
 SCM_API SCM scm_pointer_to_procedure (SCM return_type, SCM func_ptr,
-				      SCM arg_types);
+				      SCM arg_types, SCM return_errno);
 SCM_API SCM scm_procedure_to_pointer (SCM return_type, SCM func_ptr,
 				      SCM arg_types);
 SCM_INTERNAL SCM scm_i_foreign_call (SCM foreign, const SCM *argv);
-- 
1.7.10.4

>From 71151759513f8163e45c328e5bcae8e89ebbf614 Mon Sep 17 00:00:00 2001
From: Nala Ginrut <[email-masked]>
Date: Thu, 31 Dec 2015 20:28:36 +0800
Subject: [PATCH 2/2] updated pointer->procedure in document

---
 doc/ref/api-foreign.texi |    7 +++++--
 1 file changed, 5 insertions(+), 2 deletions(-)

diff --git a/doc/ref/api-foreign.texi b/doc/ref/api-foreign.texi
index c2c49ec..9fd09f5 100644
--- a/doc/ref/api-foreign.texi
+++ b/doc/ref/api-foreign.texi
@@ -813,8 +813,8 @@ tightly packed structs and unions by hand. See the code for
 Of course, the land of C is not all nouns and no verbs: there are
 functions too, and Guile allows you to call them.
 
-@deffn {Scheme Procedure} pointer->procedure return_type func_ptr arg_types
-@deffnx {C Procedure} scm_pointer_to_procedure (return_type, func_ptr, arg_types)
+@deffn {Scheme Procedure} pointer->procedure return_type func_ptr arg_types [return_errno=#f]
+@deffnx {C Procedure} scm_pointer_to_procedure (return_type, func_ptr, arg_types, return_errno)
 Make a foreign function.
 
 Given the foreign void pointer @var{func_ptr}, its argument and
@@ -825,6 +825,9 @@ and return appropriate values.
 @var{arg_types} should be a list of foreign types.
 @code{return_type} should be a foreign type. @xref{Foreign Types}, for
 more information on foreign types.
+@var{return_errno} is @code{#f} in default, if set to @code{#t}, then @var{errno}
+will be returned as the second value.
+
 @end deffn
 
 Here is a better definition of @code{(math bessel)}:
-- 
1.7.10.4