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

classic Classic list List threaded Threaded
4 messages Options
Reply | Threaded
Open this post in threaded view
|

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
|

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
|

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.
Reply | Threaded
Open this post in threaded view
|

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

ananyagupta
In reply to this post by a001
I think this will help you just check:



realloc() “realloc” or “re-allocation” method is used to dynamically change the memory allocation of a previously allocated memory. In other words, if the memory previously allocated with the help of malloc or calloc is insufficient, realloc can be used to dynamically re-allocate memory.

This procedure is referred to as Dynamic Memory Allocation in C.

Therefore, C Dynamic Memory Allocation can be defined as a procedure in which the size of a data structure (like Array) is changed during the runtime.

C provides some functions to achieve these tasks. There are 4 library functions provided by C defined under <stdlib.h> header file to facilitate dynamic memory allocation in C programming. They are:

malloc()
calloc()
free()
realloc()
Let’s look at each of them in greater detail.

C malloc() method
“malloc” or “memory allocation” method in C is used to dynamically allocate a single large block of memory with the specified size. It returns a pointer of type void which can be cast into a pointer of any form.

Syntax:

ptr = (cast-type*) malloc(byte-size)
For Example:

ptr = (int*) malloc(100 * sizeof(int));

Since the size of int is 4 bytes, this statement will allocate 400 bytes of memory. And, the pointer ptr holds the address of the first byte in the allocated memory.

Here I share whatever I know because now i working as C language developer and for more :
https://www.cetpainfotech.com/technology/C-Language-Training