From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 9761 invoked by alias); 7 Nov 2015 19:01:11 -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 9744 invoked by uid 89); 7 Nov 2015 19:01:09 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=0.2 required=5.0 tests=AWL,BAYES_20,RCVD_IN_DNSWL_NONE,SPF_PASS autolearn=ham version=3.3.2 X-HELO: gproxy7-pub.mail.unifiedlayer.com Received: from gproxy7-pub.mail.unifiedlayer.com (HELO gproxy7-pub.mail.unifiedlayer.com) (70.40.196.235) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with SMTP; Sat, 07 Nov 2015 19:01:06 +0000 Received: (qmail 15819 invoked by uid 0); 7 Nov 2015 19:01:02 -0000 Received: from unknown (HELO cmgw2) (10.0.90.83) by gproxy7.mail.unifiedlayer.com with SMTP; 7 Nov 2015 19:01:02 -0000 Received: from box522.bluehost.com ([74.220.219.122]) by cmgw2 with id ej0u1r00f2f2jeq01j0xBC; Sat, 07 Nov 2015 12:01:00 -0700 X-Authority-Analysis: v=2.1 cv=Jv9i8qIC 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=W0c_u08tbxPzIfKHOTwA:9 Received: from [174.16.156.173] (port=57615 helo=bapiya) by box522.bluehost.com with esmtpsa (TLSv1.2:AES128-GCM-SHA256:128) (Exim 4.84) (envelope-from ) id 1Zv8jQ-0004OF-6j; Sat, 07 Nov 2015 12:00:56 -0700 From: Tom Tromey To: Richard Henderson Cc: Tom Tromey , libffi-discuss Subject: Re: documentation patch, oddities, and proposals References: <87d1vqe3e0.fsf@tromey.com> <5639B430.2010807@redhat.com> Date: Sat, 07 Nov 2015 19:01:00 -0000 In-Reply-To: <5639B430.2010807@redhat.com> (Richard Henderson's message of "Wed, 4 Nov 2015 08:30:56 +0100") Message-ID: <87wpttd47v.fsf@tromey.com> User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/25.0.50 (gnu/linux) 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/msg00095.txt.bz2 rth> Indeed. It would be very nice to require a separate layout call, rth> rather than imply it from ffi_prep_cif. This would also nicely fix rth> the problem that libgo encountered wrt zero-sized structures. What was that problem btw? If it's something users might encounter I could update the docs to account for it. rth> I'll have a look at the actual doc changes later. Here's a newer version of the patch. I've expanded the section on ffi_arg use a bit. I also updated the closure docs to note that this behavior is not needed there. I did a test to see what return pointer is passed to a closure declared as returning void, since the docs had: @c FIXME: is this NULL for void-returning functions? Experimentally it is not null, so I imagine it is just garbage... ? I stuck another comment in there, maybe this is worth a bug report. I'm not sure the thread safety section is correct. It depends on what parts of a CIF are referred to after it has bee prepped. For example if ffi_call refers to the alignment, then thread safety is hard to achieve when also using multiple ABIs -- I think you'd have to re-prep the CIF before each call and also only allow one call at a time (or, really, just one ABI to be in use at a time). Tom diff --git a/doc/libffi.texi b/doc/libffi.texi index ff72e58..50fc103 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,29 @@ to ensure this. If @var{cif} declares that the function returns @code{void} (using @code{ffi_type_void}), then @var{rvalue} is ignored. +In most situations, @samp{libffi} will handle promotion according to +the ABI. However, for historical reasons, there is a special case +with return values that must be handled by your code. In particular, +for integral (not @code{struct}) types that are narrower than the +system register size, the return value will be widened by +@samp{libffi}. @samp{libffi} provides a type, @code{ffi_arg}, that +can be used as the return type. For example, if the CIF was defined +with a return type of @code{char}, @samp{libffi} will try to store a +full @code{ffi_arg} into the return value. + @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 +264,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 +390,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 +410,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; +@dots{} +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 +778,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. @@ -652,8 +796,12 @@ The @code{ffi_cif} passed to @code{ffi_prep_closure_loc}. @item ret A pointer to the memory used for the function's return value. @var{fun} must fill this, unless the function is declared as returning -@code{void}. +@code{void}. Note that this points to memory that is exactly the size +of the type given as the return type when initializing the CIF. In +particular, closures do not have the special promotion behavior of +@code{ffi_call}. @c FIXME: is this NULL for void-returning functions? +@c (experimentally it is not, but it seems like a good idea) @item args A vector of pointers to memory holding the arguments to the function. @@ -664,8 +812,7 @@ The same @var{user_data} that was passed to @end table @code{ffi_prep_closure_loc} will return @code{FFI_OK} if everything -went ok, and something else on error. -@c FIXME: what? +went ok, and one of the other @code{ffi_status} values on error. After calling @code{ffi_prep_closure_loc}, you can cast @var{codeloc} to the appropriate pointer-to-function type. @@ -733,6 +880,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,9 +918,10 @@ There is no support for bit fields in structures. @item The ``raw'' API is undocumented. -@c argument promotion? -@c unions? @c anything else? + +@item +The Go API is undocumented. @end itemize Note that variadic support is very new and tested on a relatively