From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 41375 invoked by alias); 4 Nov 2015 05:35:18 -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 41361 invoked by uid 89); 4 Nov 2015 05:35:17 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=2.7 required=5.0 tests=AWL,BAYES_99,BAYES_999,FREEMAIL_FROM,RCVD_IN_DNSWL_LOW,SPF_PASS,TBC autolearn=no version=3.3.2 X-HELO: mail-lb0-f176.google.com Received: from mail-lb0-f176.google.com (HELO mail-lb0-f176.google.com) (209.85.217.176) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with (AES128-GCM-SHA256 encrypted) ESMTPS; Wed, 04 Nov 2015 05:35:15 +0000 Received: by lbbwb3 with SMTP id wb3so7784664lbb.1 for ; Tue, 03 Nov 2015 21:35:11 -0800 (PST) MIME-Version: 1.0 X-Received: by 10.112.135.136 with SMTP id ps8mr14522290lbb.38.1446615311037; Tue, 03 Nov 2015 21:35:11 -0800 (PST) Received: by 10.25.208.82 with HTTP; Tue, 3 Nov 2015 21:35:10 -0800 (PST) In-Reply-To: <87d1vqe3e0.fsf@tromey.com> References: <87d1vqe3e0.fsf@tromey.com> Date: Wed, 04 Nov 2015 05:35:00 -0000 Message-ID: Subject: Re: documentation patch, oddities, and proposals From: Andrew Pinski To: Tom Tromey Cc: libffi-discuss Content-Type: text/plain; charset=UTF-8 X-IsSubscribed: yes X-SW-Source: 2015/txt/msg00091.txt.bz2 On Wed, Nov 4, 2015 at 1:32 PM, Tom Tromey wrote: > 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... Yes this would be useful as it would be nice to move libobjc away from its current mess of using GCC's internal headers too. Thanks, Andrew > > * ... 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 >