Login  Register

Re: binding a C functions that allocates two chunks of memory and returns an integer

Posted by Sven Gothel on Nov 30, 2011; 1:08pm
URL: https://forum.jogamp.org/binding-a-C-functions-that-allocates-two-chunks-of-memory-and-returns-an-integer-tp3547863p3548229.html

On Wednesday, November 30, 2011 11:23:46 AM a001 [via jogamp] wrote:

>
> Thanks for all the great work with JogAmp and GlueGen.
>
> I have a C library (to be called from Java) and I would be happy to use
> GlueGen to automate the generation of the necessary Java and JNI code.
>
> However, after looking to the GlueGen manual, I'm afraid I'm still missing
> something. I've noticed the examples you provide about how to manage ingoing
> and outgoing structs, array of structs, and array of pointers. They are
> great.
>
> Still, I have not understood how to bind API like the following:
>
>   struct foo_s;                        /* forward decl */
>   typedef struct foo_s foo_t;
>
>   int foo(foo_t **a, foo_t **b);
>
> foo allocates two variables of type foo_t and places the addresses of
> allocated memory respectively in *a and *b. Returns zero on success, or one
> of the applicable error values on failure.
>
> Please, can you tell me how to generate the glue code for this?

Since 'struct foo_s' is opaque, ie. a 'void *', it shall be opaque for GlueGen as well.

Your 2 arguments refer to a _writable_ pointer array of these opaque type,
hence the PointerType shall be generated.

We have similar tests in GlueGen's unit tests, and it works quite well, eg:

  http://jogamp.org/git/?p=gluegen.git;a=blob;f=src/junit/com/jogamp/gluegen/test/junit/generation/test1.h;hb=HEAD

  30 typedef uint64_t foo; // similar to your 'struct foo' if opaque

  44 /** Returns a copy of the passed array, each element incr by 1 */
  45 MYAPI foo * MYAPIENTRY arrayTestFoo2(const foo * array );
  46
  47 /** Increments each element of the passed array by 1 - IDENTITY */
  48 MYAPI void MYAPIENTRY arrayTestFoo3(foo * array );
  49
  50 /** Returns a array-array of the passed array, split at ARRAY size - IDENTITY! */
  51 MYAPI foo * * MYAPIENTRY arrayTestFoo3ArrayToPtrPtr(const foo * array);
  52
  53 /** Fills dest array ptr of ARRAY size with arrays (allocs) and copies content of src to it - COPY! */
  54 MYAPI void MYAPIENTRY arrayTestFoo3CopyPtrPtrA(foo * * dest, const foo * * src);

A 'mapped' structure w/ an anonymous / opaque type here:
  http://jogamp.org/git/?p=gluegen.git;a=blob;f=src/junit/com/jogamp/gluegen/test/junit/generation/test1.h;hb=HEAD#l132

The configuration here:
 Dynamic (function lookup, library loading at runtime) - RECOMMENDED:
    http://jogamp.org/git/?p=gluegen.git;a=blob;f=src/junit/com/jogamp/gluegen/test/junit/generation/test1p2-gluegen.cfg;hb=HEAD
 Static:
    http://jogamp.org/git/?p=gluegen.git;a=blob;f=src/junit/com/jogamp/gluegen/test/junit/generation/test1p1-gluegen.cfg;hb=HEAD
 Base:
    http://jogamp.org/git/?p=gluegen.git;a=blob;f=src/junit/com/jogamp/gluegen/test/junit/generation/test1-common.cfg;hb=HEAD

Note the return size definition in test1-common.cfg:
  11 ReturnValueCapacity arrayTestFoo2 ARRAY_SIZE * sizeof(foo)
  12 ReturnValueCapacity arrayTestFoo3ArrayToPtrPtr ARRAY_SIZE * sizeof(foo *)
  13 ReturnValueCapacity arrayTestFoo3PtrPtr ARRAY_SIZE * sizeof(foo *)
  14 ReturnValueCapacity typeTestAnonPointer ARRAY_SIZE * sizeof(MYAPIConfig)

GlueGen generates:

  /** Interface to C language function: <br> <code> foo *  arrayTestFoo2(const foo *  array); </code>    */
  public LongBuffer arrayTestFoo2(LongBuffer array);

  /** Interface to C language function: <br> <code> foo *  arrayTestFoo2(const foo *  array); </code>    */
  public LongBuffer arrayTestFoo2(long[] array, int array_offset);

  /** Interface to C language function: <br> <code> void arrayTestFoo3(foo *  array); </code>    */
  public void arrayTestFoo3(LongBuffer array);

  /** Interface to C language function: <br> <code> void arrayTestFoo3(foo *  array); </code>    */
  public void arrayTestFoo3(long[] array, int array_offset);

  /** Interface to C language function: <br> <code> foo *  *  arrayTestFoo3ArrayToPtrPtr(const foo *  array); </code>    */
  public PointerBuffer arrayTestFoo3ArrayToPtrPtr(LongBuffer array);

  /** Interface to C language function: <br> <code> foo *  *  arrayTestFoo3ArrayToPtrPtr(const foo *  array); </code>    */
  public PointerBuffer arrayTestFoo3ArrayToPtrPtr(long[] array, int array_offset);

  /** Interface to C language function: <br> <code> void arrayTestFoo3CopyPtrPtrA(foo *  *  dest, const foo *  *  src); </code>    */
  public void arrayTestFoo3CopyPtrPtrA(PointerBuffer dest, PointerBuffer src);

  /** Interface to C language function: <br> <code> foo *  *  arrayTestFoo3PtrPtr(foo *  *  array); </code>    */
  public PointerBuffer arrayTestFoo3PtrPtr(PointerBuffer array);

The tests for above bindings is here:
  http://jogamp.org/git/?p=gluegen.git;a=blob;f=src/junit/com/jogamp/gluegen/test/junit/generation/BaseClass.java;hb=HEAD#l271

>
> In the examples you provide I've noticed that all functions allocating
> memory return a pointer to some static storage and how the
> ReturnValueCapacity directive is used to specify the size of the returned
> memory.

Not 'static storage' it's all dynamic.
The ReturnValueCapacity is described above .. see configuration.

Let's see the Java impl .. :

  /** Entry point (through function pointer) to C language function: <br> <code> foo *  *  arrayTestFoo3ArrayToPtrPtr(const foo *  array); </code>    */
  public PointerBuffer arrayTestFoo3ArrayToPtrPtr(long[] array, int array_offset)  {
    // REMOVED CHECKS ..

    ByteBuffer _res;
    _res = dispatch_arrayTestFoo3ArrayToPtrPtr1(array, Buffers.SIZEOF_LONG * array_offset, false, __addr_);
    if (_res == null) return null;
    Buffers.nativeOrder(_res);
    return PointerBuffer.wrap(_res);
  }

The native method returns the nio Buffer like this:
  return (*env)->NewDirectByteBuffer(env, _res, ARRAY_SIZE * sizeof(foo *));

I hope this elaboration helps a little bit and these unit tests make things a bit more clear.

>
> What if we need to allocate two chunks of memory and return an integer? Do
> we need to hand-write some glue code?

Please provide a proper example, like the unit tests with C header and some API documentation.
Also don't forget to use 'const' whenever you can, to remove the 'write-back' codegen.

>
> Thanks again for GlueGen and I'm looking forward to using it in this
> project.

You are very welcome.

~Sven

>
> Cheers,
> a.