From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 39651 invoked by alias); 4 Nov 2015 05:32:26 -0000 Mailing-List: contact libffi-discuss-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: libffi-discuss-owner@sourceware.org Received: (qmail 39636 invoked by uid 89); 4 Nov 2015 05:32:22 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=0.5 required=5.0 tests=AWL,BAYES_20,RCVD_IN_DNSWL_NONE,SPF_PASS,TBC autolearn=no version=3.3.2 X-HELO: gproxy4-pub.mail.unifiedlayer.com Received: from gproxy4-pub.mail.unifiedlayer.com (HELO gproxy4-pub.mail.unifiedlayer.com) (69.89.23.142) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with SMTP; Wed, 04 Nov 2015 05:32:20 +0000 Received: (qmail 23832 invoked by uid 0); 4 Nov 2015 05:32:17 -0000 Received: from unknown (HELO cmgw3) (10.0.90.84) by gproxy4.mail.unifiedlayer.com with SMTP; 4 Nov 2015 05:32:17 -0000 Received: from box522.bluehost.com ([74.220.219.122]) by cmgw3 with id dPYA1r00c2f2jeq01PYDpF; Wed, 04 Nov 2015 04:32:15 -0700 X-Authority-Analysis: v=2.1 cv=Zs1+dbLG c=1 sm=1 tr=0 a=GsOEXm/OWkKvwdLVJsfwcA==:117 a=GsOEXm/OWkKvwdLVJsfwcA==:17 a=cNaOj0WVAAAA:8 a=f5113yIGAAAA:8 a=zstS-IiYAAAA:8 a=PnD2wP_eR3oA:10 a=q5Y1GWT81MIA:10 a=qtqOOiqGOCEA:10 a=NEAV23lmAAAA:8 a=W0c_u08tbxPzIfKHOTwA:9 Received: from [174.16.156.173] (port=47588 helo=bapiya) by box522.bluehost.com with esmtpsa (TLSv1.2:AES128-GCM-SHA256:128) (Exim 4.84) (envelope-from ) id 1Ztqg8-0001P2-El; Tue, 03 Nov 2015 22:32:12 -0700 From: Tom Tromey To: libffi-discuss Subject: documentation patch, oddities, and proposals Date: Wed, 04 Nov 2015 05:32:00 -0000 Message-ID: <87d1vqe3e0.fsf@tromey.com> MIME-Version: 1.0 Content-Type: text/plain X-Identified-User: {36111:box522.bluehost.com:elynrobi:tromey.com} {sentby:smtp auth 174.16.156.173 authed with tom+tromey.com} X-SW-Source: 2015/txt/msg00090.txt.bz2 Hi! [ I tried to send this once before but I don't know that it went through, so trying again... ] I've been working on an FFI: https://github.com/tromey/emacs-ffi While doing so I refreshed my memory of some of the oddities of libffi, and discovered some I had never run across before. I found a few things that weren't documented. I wrote a documentation patch that I think covers them all. It is appended. If you like it I can write a ChangeLog entry and submit a pull request. Some questions, observations, and proposals: * The ffi_arg business for return values I (re-)learned from reading the archvies. I still haven't fixed my own code to deal with this yet. I wasn't sure -- is this needed in some way for the closure API as well? If so, and someone can explain where (that is, arguments, return values, or both), I will write a documentation patch. * I wanted to compute the layout of a struct. libffi does this internally but doesn't expose the results. I think it would be great to have a new function to do this. In fact I wrote one, but... * ... this lead me to the discovery that ffi_prep_types modifies some of the libffi globals, meaning that libffi is not type-safe when using multiple ABIs. Currently, AFAICT, this only affects long doubles on PPC. So, not quite as bad as it seems -- but still it is a bug. * Also due to ffi_prep_types, you can't really use the size and alignment fields of an ffi_type unless you know that the ABI hasn't changed. And, because of this, you also can't share structure types across ABIs. (Maybe that is obvious? It was a bit of a surprise to me.) * As you can see from the docs, I also had to resort to some shenanigans to get arrays and unions working. I think it would be preferable to have FFI_TYPE_ARRAY and FFI_TYPE_UNION directly in the library. * This doesn't impact the docs, but ffi.h.in is a mix of public and private stuff. I think it would be nice to separate these. * I didn't write docs for the raw or java APIs. It's probably time for those to die. * Someone who understands what it does should perhaps write documentation for the Go closure code. Or, if this is only for use by gccgo, then maybe it should be relegated to the aforementioned internal-only header. Tom diff --git a/doc/libffi.texi b/doc/libffi.texi index ff72e58..16c1b53 100644 --- a/doc/libffi.texi +++ b/doc/libffi.texi @@ -107,6 +107,7 @@ values passed between the two languages. * Multiple ABIs:: Different passing styles on one platform. * The Closure API:: Writing a generic function. * Closure Example:: A closure example. +* Thread Safety:: Thread safety. @end menu @@ -190,12 +191,23 @@ to ensure this. If @var{cif} declares that the function returns @code{void} (using @code{ffi_type_void}), then @var{rvalue} is ignored. +For types like @code{char} that are narrower than the system register +size, @samp{libffi} provides a type, @code{ffi_arg}, that can be used +as the return type. + @var{avalues} is a vector of @code{void *} pointers that point to the memory locations holding the argument values for a call. If @var{cif} declares that the function has no arguments (i.e., @var{nargs} was 0), then @var{avalues} is ignored. Note that argument values may be modified by the callee (for instance, structs passed by value); the burden of copying pass-by-value arguments is placed on the caller. + +Note that while the return value must be register-sized, arguments +should exactly match their declared type. For example, if an argument +is a @code{short}, then the entry is @var{avalues} should point to an +object declared as @code{short}; but if the return type is +@code{short}, then @var{rvalue} should point to an object declared as +a larger type -- usually @code{ffi_arg}. @end defun @@ -246,6 +258,8 @@ int main() @menu * Primitive Types:: Built-in types. * Structures:: Structure types. +* Size and Alignment:: Size and alignment of types. +* Arrays and Unions:: Arrays and unions. * Type Example:: Structure type example. * Complex:: Complex types. * Complex Type Example:: Complex type example. @@ -370,8 +384,7 @@ when passing to @code{ffi_prep_cif}. @node Structures @subsection Structures -Although @samp{libffi} has no special support for unions or -bit-fields, it is perfectly happy passing structures back and forth. +@samp{libffi} is perfectly happy passing structures back and forth. You must first describe the structure to @samp{libffi} by creating a new @code{ffi_type} object for it. @@ -391,9 +404,132 @@ For a structure, this should be set to @code{FFI_TYPE_STRUCT}. @item ffi_type **elements This is a @samp{NULL}-terminated array of pointers to @code{ffi_type} objects. There is one element per field of the struct. + +Note that @samp{libffi} has no special support for bit-fields. You +must manage these manually. @end table @end deftp +The @code{size} and @code{alignment} fields will be filled in by +@code{ffi_prep_cif} or @code{ffi_prep_cif_var}, as needed. + +@node Size and Alignment +@subsection Size and Alignment + +@code{libffi} will set the @code{size} and @code{alignment} fields of +an @code{ffi_type} object for you. It does so using its knowledge of +the ABI. + +You might expect that you can simply read these fields for a type that +has been laid out by @code{libffi}. However, there are some caveats. + +@itemize @bullet +@item +The size or alignment of some of the built-in types may vary depending +on the chosen ABI. + +@item +The size and alignment of a new structure type will not be set by +@code{libffi} until it has been passed to @code{ffi_prep_cif}. + +@item +A structure type cannot be shared across ABIs. Instead each ABI needs +its own copy of the structure type. +@end itemize + +So, before examining these fields, it is safest to pass the +@code{ffi_type} object to @code{ffi_prep_cif} first. This function +will do all the needed setup. + +@example +ffi_type *desired_type; +ffi_abi desired_abi; +... +ffi_cif cif; +if (ffi_prep_cif (&cif, desired_abi, 0, desired_type, NULL) == FFI_OK) + @{ + size_t size = desired_type->size; + unsigned short alignment = desired_type->alignment; + @} +@end example + +@node Arrays and Unions +@subsection Arrays and Unions + +@subsubsection Arrays + +@samp{libffi} does not have direct support for arrays or unions. +However, they can be emulated using structures. + +To emulate an array, simply create an @code{ffi_type} using +@code{FFI_TYPE_STRUCT} with as many members as there are elements in +the array. + +@example +ffi_type array_type; +ffi_type **elements +int i; + +elements = malloc ((n + 1) * sizeof (ffi_type *)); +for (i = 0; i < n; ++i) + elements[i] = array_element_type; +elements[n] = NULL; + +array_type.size = array_type.alignment = 0; +array_type.type = FFI_TYPE_STRUCT; +array_type.elements = elements; +@end example + +Note that arrays cannot be passed or returned by value in C -- +structure types created like this should only be used to refer to +members of real @code{FFI_TYPE_STRUCT} objects. + +However, a phony array type like this will not cause any errors from +@samp{libffi} if you use it as an argument or return type. This may +be confusing. + +@subsubsection Unions + +A union can also be emulated using @code{FFI_TYPE_STRUCT}. In this +case, however, you must make sure that the size and alignment match +the real requirements of the union. + +One simple way to do this is to ensue that each element type is laid +out. Then, give the new structure type a single element; the size of +the largest element; and the largest alignment seen as well. + +This example uses the @code{ffi_prep_cif} trick to ensure that each +element type is laid out. + +@example +ffi_abi desired_abi; +ffi_type union_type; +ffi_type **union_elements; + +int i; +ffi_type element_types[2]; + +element_types[1] = NULL; + +union_type.size = union_type.alignment = 0; +union_type.type = FFI_TYPE_STRUCT; +union_type.elements = element_types; + +for (i = 0; union_elements[i]; ++i) + @{ + ffi_cif cif; + if (ffi_prep_cif (&cif, desired_abi, 0, union_elements[i], NULL) == FFI_OK) + @{ + if (union_elements[i]->size > union_type.size) + @{ + union_type.size = union_elements[i]; + size = union_elements[i]->size; + @} + if (union_elements[i]->alignment > union_type.alignment) + union_type.alignment = union_elements[i]->alignment; + @} + @} +@end example @node Type Example @subsection Type Example @@ -636,6 +772,8 @@ Prepare a closure function. the writable address returned by @code{ffi_closure_alloc}. @var{cif} is the @code{ffi_cif} describing the function parameters. +Note that this object, and the types to which it refers, must be kept +alive until the closure itself is freed. @var{user_data} is an arbitrary datum that is passed, uninterpreted, to your closure function. @@ -733,6 +871,28 @@ int main() @end example +@node Thread Safety +@section Thread Safety + +@code{libffi} is not completely thread-safe. However, many parts are, +and if you follow some simple rules, you can use it safely in a +multi-threaded program. + +@itemize @bullet +@item +@code{ffi_prep_cif} may modify the @code{ffi_type} objects passed to +it. It is best to ensure that only a single thread prepares a given +@code{ffi_cif} at a time. + +@item +On some platforms, @code{ffi_prep_cif} may modify the size and +alignment of some types, depending on the chosen ABI. On these +platforms, if you switch between ABIs, you must ensure that there is +only one call to @code{ffi_prep_cif} at a time. + +Currently the only affected platform is PowerPC and the only affected +type is @code{long double}. +@end itemize @node Missing Features @chapter Missing Features @@ -749,8 +909,6 @@ There is no support for bit fields in structures. @item The ``raw'' API is undocumented. -@c argument promotion? -@c unions? @c anything else? @end itemize