summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKaz Kylheku <kaz@kylheku.com>2017-05-20 14:48:28 -0700
committerKaz Kylheku <kaz@kylheku.com>2017-05-20 14:48:28 -0700
commit66479625440d34dbb43b8e8a5f645dca95f9cc97 (patch)
tree7bc12b030275e4410711f4016184159d2c97f165
parent914368cbdca3a26a0e790bf47acec4a393a481c4 (diff)
downloadtxr-66479625440d34dbb43b8e8a5f645dca95f9cc97.tar.gz
txr-66479625440d34dbb43b8e8a5f645dca95f9cc97.tar.bz2
txr-66479625440d34dbb43b8e8a5f645dca95f9cc97.zip
ffi: overhaul ffi-call API and document it.
* ffi.c (ffi_call_wrap): Take struct args * parameters rather than a list. Check that number of arguments matches required number from call desc. No need to build argument array any more; we just refer to the one in args. Also, the first two parameters are reversed for consistency with other functions. (ffi_init): Update registration of ffi-call to reflect type change. * ffi.h (ffi_call_wrap): Declaration updated. * txr.1: Documented ffi-call.
-rw-r--r--ffi.c24
-rw-r--r--ffi.h2
-rw-r--r--share/txr/stdlib/ffi.tl2
-rw-r--r--txr.147
4 files changed, 66 insertions, 9 deletions
diff --git a/ffi.c b/ffi.c
index 31666020..226e1063 100644
--- a/ffi.c
+++ b/ffi.c
@@ -2140,14 +2140,13 @@ val ffi_make_call_desc(val ntotal, val nfixed, val rettype, val argtypes)
return obj;
}
-val ffi_call_wrap(val ffi_call_desc, val fptr, val args_in)
+val ffi_call_wrap(val fptr, val ffi_call_desc, struct args *args)
{
val self = lit("ffi-call");
struct txr_ffi_call_desc *tfcd = ffi_call_desc_checked(ffi_call_desc);
mem_t *fp = cptr_get(fptr);
cnum n = tfcd->ntotal;
void **values = convert(void **, alloca(sizeof *values * tfcd->ntotal));
- val args = args_in;
val types = tfcd->argtypes;
val rtype = tfcd->rettype;
struct txr_ffi_type *rtft = ffi_type_struct(rtype);
@@ -2159,9 +2158,20 @@ val ffi_call_wrap(val ffi_call_desc, val fptr, val args_in)
struct txr_ffi_type **type = convert(struct txr_ffi_type **,
alloca(n * sizeof *type));
+ if (args->argc < n) {
+ args_decl(args_copy, n);
+ args_copy_zap(args_copy, args);
+ args = args_copy;
+ }
+
+ args_normalize(args, n);
+
+ if (args->fill < n || args->list)
+ uw_throwf(error_s, lit("~a: ~s requires ~s arguments"),
+ self, ffi_call_desc, num(n), nao);
+
for (i = 0; i < n; i++) {
struct txr_ffi_type *mtft = type[i] = ffi_type_struct(pop(&types));
- arg[i] = pop(&args);
values[i] = zalloca(mtft->size);
in_pass_needed = in_pass_needed || mtft->in != 0;
}
@@ -2170,7 +2180,7 @@ val ffi_call_wrap(val ffi_call_desc, val fptr, val args_in)
for (i = 0; i < n; i++) {
struct txr_ffi_type *mtft = type[i];
- mtft->put(mtft, arg[i], convert(mem_t *, values[i]), self);
+ mtft->put(mtft, args->arg[i], convert(mem_t *, values[i]), self);
in_pass_needed = in_pass_needed || mtft->in != 0;
}
@@ -2182,7 +2192,7 @@ val ffi_call_wrap(val ffi_call_desc, val fptr, val args_in)
for (i = 0; i < nreached; i++) {
struct txr_ffi_type *mtft = type[i];
if (mtft->release != 0)
- mtft->release(mtft, arg[i], convert(mem_t *, values[i]));
+ mtft->release(mtft, args->arg[i], convert(mem_t *, values[i]));
}
}
}
@@ -2197,7 +2207,7 @@ val ffi_call_wrap(val ffi_call_desc, val fptr, val args_in)
for (i = 0; i < n; i++) {
struct txr_ffi_type *mtft = type[i];
if (mtft->in != 0)
- mtft->in(mtft, 0, convert(mem_t *, values[i]), arg[i], self);
+ mtft->in(mtft, 0, convert(mem_t *, values[i]), args->arg[i], self);
}
}
@@ -2785,7 +2795,7 @@ void ffi_init(void)
ffi_closure_s = intern(lit("ffi-closure"), user_package);
reg_fun(intern(lit("ffi-type-compile"), user_package), func_n1(ffi_type_compile));
reg_fun(intern(lit("ffi-make-call-desc"), user_package), func_n4(ffi_make_call_desc));
- reg_fun(intern(lit("ffi-call"), user_package), func_n3(ffi_call_wrap));
+ reg_fun(intern(lit("ffi-call"), user_package), func_n2v(ffi_call_wrap));
reg_fun(intern(lit("ffi-make-closure"), user_package), func_n4o(ffi_make_closure, 2));
reg_fun(intern(lit("ffi-typedef"), user_package), func_n2(ffi_typedef));
reg_fun(intern(lit("ffi-size"), user_package), func_n1(ffi_size));
diff --git a/ffi.h b/ffi.h
index 5545126e..3f415082 100644
--- a/ffi.h
+++ b/ffi.h
@@ -55,7 +55,7 @@ val ffi_type_compile(val syntax);
val ffi_make_call_desc(val ntotal, val nfixed, val rettype, val argtypes);
val ffi_make_closure(val fun, val call_desc, val safe_p_in, val abort_ret_in);
mem_t *ffi_closure_get_fptr(val closure);
-val ffi_call_wrap(val ffi_call_desc, val fptr, val args);
+val ffi_call_wrap(val fptr, val ffi_call_desc, struct args *args);
val ffi_typedef(val name, val type);
val ffi_size(val type);
val ffi_put_into(val dstbuf, val obj, val type);
diff --git a/share/txr/stdlib/ffi.tl b/share/txr/stdlib/ffi.tl
index 12f9dab6..99d76137 100644
--- a/share/txr/stdlib/ffi.tl
+++ b/share/txr/stdlib/ffi.tl
@@ -67,7 +67,7 @@
,arg-types-sym))
(defvarl ,fun-sym ,fun-ref)
(defun ,name ,args-sym
- (ffi-call ,call-desc-sym ,fun-sym ,args-sym))))))
+ (ffi-call ,fun-sym ,call-desc-sym . ,args-sym))))))
(defmacro deffi-type (name type-expr)
^(ffi-typedef ',name (ffi-type-compile ',type-expr)))
diff --git a/txr.1 b/txr.1
index 5b3614c9..f7a84073 100644
--- a/txr.1
+++ b/txr.1
@@ -54321,6 +54321,53 @@ FFI closures.
[mapcar ffi-type-compile '(str str)])) ;; args
.cble
+
+.coNP Function @ ffi-call
+.synb
+.mets (ffi-call < fun-cptr < call-desc <> { arg }*)
+.syne
+.desc
+The
+.code ffi-call
+function invokes a foreign function.
+
+The
+.meta fun-cptr
+argument which must be a
+.code cptr
+object. It is assumed to point to a foreign function.
+
+The
+.meta call-desc
+argument must be a FFI call descriptor, produced by
+.codn ffi-call-desc .
+
+The
+.meta call-desc
+must correctly describe the foreign function.
+
+The zero or more
+.meta arg
+arguments are values which are converted into foreign
+argument values. There must be exactly as many of these arguments
+as are required by
+.metn call-desc .
+
+The
+.code ffi-call
+function converts every
+.meta arg
+to a corresponding foreign object. If these conversions are
+successful, the converted foreign arguments are passed by value
+to the foreign function indicated by
+.metn fun-cptr .
+An unsuccessful conversion throws an error.
+
+When the call returns, the foreign function's return value is
+converted to a Lisp object and returned, in accordance with the
+return type that is declared inside
+.metn call-desc .
+
.coNP Function @ ffi-typedef
.synb
.mets (ffi-typedef < name << type )