Quantcast

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

classic Classic list List threaded Threaded
3 messages Options
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

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

a001
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?

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.

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

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

Cheers,
a.
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

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

Sven Gothel
Administrator
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.
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

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

a001
Sven, thank you very much. Your detailed answer was very useful.

There is still one more question, if you may.

I've mapped the foo_t to long, with Opaque long foo_t.

Now,  GlueGen provides:
  public int foo(PointerBuffer arg1, PointerBuffer arg2)
as the interface to:
  int foo(foo_t **a, foo_t **b);


What if I need to pass a (foo_t *) written by foo() to another API, say bar()?
  int bar(foo_t *a, int c);

Here, keeping foo_t opaque with long, a LongBuffer would be generated to the pointer to foo_t:
  public int bar(LongBuffer arg1, int arg1)


Looking at the PointerBuffer documentation, I've noticed the getBuffer() method, that could be used to return a ByteBuffer. In turn, a view of the ByteBuffer as LongBuffer can be created using the asLongBuffer() method.

Is there a better method to pass the PointerBuffer written by foo() as a LongBuffer to bar()?

Thank you very much.

Cheers,
a.
Loading...