diff options
author | Kaz Kylheku <kaz@kylheku.com> | 2017-05-20 14:48:28 -0700 |
---|---|---|
committer | Kaz Kylheku <kaz@kylheku.com> | 2017-05-20 14:48:28 -0700 |
commit | 66479625440d34dbb43b8e8a5f645dca95f9cc97 (patch) | |
tree | 7bc12b030275e4410711f4016184159d2c97f165 | |
parent | 914368cbdca3a26a0e790bf47acec4a393a481c4 (diff) | |
download | txr-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.c | 24 | ||||
-rw-r--r-- | ffi.h | 2 | ||||
-rw-r--r-- | share/txr/stdlib/ffi.tl | 2 | ||||
-rw-r--r-- | txr.1 | 47 |
4 files changed, 66 insertions, 9 deletions
@@ -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)); @@ -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))) @@ -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 ) |