This is the mail archive of the libffi-discuss@sourceware.org mailing list for the libffi project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: documentation patch, oddities, and proposals


On Wed, Nov 4, 2015 at 1:32 PM, Tom Tromey <tom@tromey.com> 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
>


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]