3

we have a C function in one of the libraries which are loaded in java, which accepts a function pointer

function defination as below

typedef char int8
typedef unsigned short uint16

uint32 poll_broadcasts(void *(pfn)(int8*,uint16));

In C it is used as below

void handle_broadcasts( int8 *broadcast, uint16 length )

uint32 a = poll_broadcasts( (void*(*)(int8*,uint16)) handle_broadcasts )

But when you use Swig to generate JNI wrapper it creates following definition for poll_broadcast

public static long poll_broadcasts(SWIGTYPE_p_f_p_char_unsigned_short__p_void pfn) {
    return TestJNI.poll_broadcasts(SWIGTYPE_p_f_p_char_unsigned_short__p_void.getCPtr(pfn));
  }

As per answer for
How should I write the .i file to wrap callbacks in Java or C#

Tried below

test.h

void * data;

typedef void* (*callback_handle_broadcast_t)(int8*, uint16);

static callback_handle_broadcast_t handle_broadcast;

static void set_handle_broadcast(callback_handle_broadcast_t cb, void *userdata) {
    handle_broadcast = cb;
    data = userdata;
}

Swig interface file Test.i

%module Test

%include "cpointer.i"
%include "carrays.i"
%include "various.i"
%include "arrays_java.i"

%pointer_functions(int, intp);
%pointer_functions(char, charp);

%include "arrays_java.i"
%include "typemaps.i"

%{

#include <assert.h>

#include "test.h"

struct callback_data {
  JNIEnv *env;
  jobject obj;
};



void java_callback(int8* arg1, uint16 arg2, void *ptr) {
  struct callback_data *data = ptr;
  const jclass callbackInterfaceClass = (*data->env)->FindClass(data->env, "BroadcastCallback");
  assert(callbackInterfaceClass);
  const jmethodID meth = (*data->env)->GetMethodID(data->env, callbackInterfaceClass, "handle", "([C)V");
  assert(meth);

  jcharArray charArr = (*data->env)->NewCharArray(data->env, arg2);
  (*data->env)->CallVoidMethod(data->env, data->obj, meth, (jcharArray)charArr);

}


%}

%typemap(jstype) callback_handle_broadcast_t cb "BroadcastCallback";
%typemap(jtype) callback_handle_broadcast_t cb "BroadcastCallback";
%typemap(jni) callback_handle_broadcast_t cb "jobject";
%typemap(javain) callback_handle_broadcast_t cb "$javainput";


%typemap(in,numinputs=1) (callback_handle_broadcast_t cb, void *userdata) {
  struct callback_data *data = malloc(sizeof *data);
  data->env = jenv;
  data->obj = JCALL1(NewGlobalRef, jenv, $input);
  JCALL1(DeleteLocalRef, jenv, $input);
  $1 = java_callback;
  $2 = data;
}


%include "test.h"

Java Interface BrodcastCallback.java

public interface BroadcastCallback {
    //public void handle(String broadcast);
    public void handle(char[] broadcast);
}

Implement the interface

class BtCallback implements BroadcastCallback {

    @Override
    public void handle(char[] broadcast) {
        LOG.debug("Broadcast callback handled: " + broadcast.length);
    }
}

Finally when used

BroadcastCallback cb = new BtCallback();
Test.set_handle_broadcast(cb, null);
Test.poll_broadcasts(Test.getHandle_broadcast());

There is no compilation error, but when program is run and and poll_broadcasts calls the handle broadcast function pointer (within C) passed from java, it crashes with EXCEPTION_ACCESS_VIOLATION.

Looks like it has to do something with int8* arg of the function, but can't figure out

somebody please help.

Community
  • 1
  • 1
Amol
  • 285
  • 1
  • 5
  • 15
  • When you put `uint32 poll_broadcasts(void *(pfn)(int8*,uint16));`, you mean a function pointer? if so, it should instead be `uint32 poll_broadcasts(void(*pfn)(int8*,uint16));` – Joe Aug 25 '15 at 17:14
  • Yes, it is a function accepting a function pointer as an argument. I want to pass a java method callback to poll_broacast using JNI. And we can not modify poll_broadcast. Got some success with the answer of the question mentioned in post but no luck, program crashes when run. – Amol Aug 25 '15 at 17:19
  • `typedef void* (*callback_handle_broadcast_t)(int8*, uint16);`: are you expecting the return type of the function to be `void` or `void*`? – Joe Aug 25 '15 at 17:21
  • Initially tried with void but the defination doesn't match with Swig created defination. And as per poll_broadcast defination, java callback has to be mapped to `typedef void* (*callback_handle_broadcast_t)(int8*, uint16)`. In C though it works as I've written, `poll_broadcasts( (void*(*)(int8*,uint16)) handle_broadcasts)` it calls handle_broadcast function and it has return type `void`. – Amol Aug 25 '15 at 17:31
  • do you have the definition for `data`? You are accessing it in `set_handle_broadcast`, but I can't seem to find its definition anywhere? – Joe Aug 25 '15 at 17:36
  • It's in swig interface file Test.i and I actually forgot to copy that line, its `void * data;` in test.h – Amol Aug 25 '15 at 17:45
  • In Test.i, you do a lot of `(*data->env)`, which does not work, as data is a `struct callback_data*`, and to access `env`, you only need to put `(data->env)` – Joe Aug 25 '15 at 17:47
  • It does work. It's actually pointer to data->env. Take a look at the question mentioned inside post, I just tried to follow that. – Amol Aug 25 '15 at 17:50
  • Oh ok, sorry... one more thing: `struct callback_data *data = malloc(sizeof *data);`, do you mean to put `struct callback_data *data = malloc(sizeof(struct callback_data));`? – Joe Aug 25 '15 at 17:53
  • That I used from the example only, and it worked. I guess your way will work too. – Amol Aug 25 '15 at 18:01
  • Have you tried not putting `int8*` as the parameter and just trying `int8` or `int` instead? – Joe Aug 25 '15 at 18:20
  • Simple int and int8 works as a single argument to callback. I was mainly struggling with multiple arguments in java callback and accessing pointer data properly. – Amol Aug 25 '15 at 18:34
  • In `void java_callback(int8* arg1, uint16 arg2, void *ptr)`, you specify `int8* arg1`, but never seem to use it - is there a reason for this? – Joe Aug 25 '15 at 18:35
  • I was meant to copy int8* data to jchararray, given the arg2 is the length of the data of type int8 which is char by typedef. – Amol Aug 25 '15 at 18:40
  • I don't know if this helps, but you define the function as `uint32 poll_broadcasts(void *(pfn)(int8*,uint16));`, but call it with `uint32 a = poll_broadcasts( (void*(*)(int8*,uint16)) handle_broadcasts )` (the parameter types are different) – Joe Aug 25 '15 at 18:45
  • thats how it is called in current c program, I gave it for reference. I don't care about that as I need to get callback in java now. – Amol Aug 25 '15 at 19:04
  • I'm not too sure what would cause the error in your code. Have you tried setting breakpoints to find exactly where the error occurs? – Joe Aug 25 '15 at 19:56

0 Answers0