mirror of
https://github.com/libguestfs/libguestfs.git
synced 2026-03-21 22:53:37 +00:00
java: Split up large Java extension into smaller C files.
This commit is contained in:
@@ -566,7 +566,7 @@ public class %s {
|
||||
|
||||
pr "}\n"
|
||||
|
||||
and generate_java_c () =
|
||||
and generate_java_c actions () =
|
||||
generate_header CStyle LGPLv2plus;
|
||||
|
||||
pr "\
|
||||
@@ -581,20 +581,6 @@ and generate_java_c () =
|
||||
#include \"guestfs.h\"
|
||||
#include \"guestfs-internal-frontend.h\"
|
||||
|
||||
/* This is the opaque data passed between _set_event_callback and
|
||||
* the C wrapper which calls the Java event callback.
|
||||
*
|
||||
* NB: The 'callback' in the following struct is registered as a global
|
||||
* reference. It must be freed along with the struct.
|
||||
*/
|
||||
struct callback_data {
|
||||
JavaVM *jvm; // JVM
|
||||
jobject callback; // object supporting EventCallback interface
|
||||
jmethodID method; // callback.event method
|
||||
};
|
||||
|
||||
static struct callback_data **get_all_event_callbacks (JNIEnv *env, guestfs_h *g, size_t *len_rtn);
|
||||
|
||||
/* Note that this function returns. The exception is not thrown
|
||||
* until after the wrapper function returns.
|
||||
*/
|
||||
@@ -618,241 +604,12 @@ throw_out_of_memory (JNIEnv *env, const char *msg)
|
||||
\"com/redhat/et/libguestfs/LibGuestFSOutOfMemory\");
|
||||
(*env)->ThrowNew (env, cl, msg);
|
||||
}
|
||||
|
||||
JNIEXPORT jlong JNICALL
|
||||
Java_com_redhat_et_libguestfs_GuestFS__1create (JNIEnv *env,
|
||||
jobject obj_unused, jint flags)
|
||||
{
|
||||
guestfs_h *g;
|
||||
|
||||
g = guestfs_create_flags ((int) flags);
|
||||
if (g == NULL) {
|
||||
throw_exception (env, \"GuestFS.create: failed to allocate handle\");
|
||||
return 0;
|
||||
}
|
||||
guestfs_set_error_handler (g, NULL, NULL);
|
||||
return (jlong) (long) g;
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
Java_com_redhat_et_libguestfs_GuestFS__1close
|
||||
(JNIEnv *env, jobject obj, jlong jg)
|
||||
{
|
||||
guestfs_h *g = (guestfs_h *) (long) jg;
|
||||
size_t len, i;
|
||||
struct callback_data **data;
|
||||
|
||||
/* There is a nasty, difficult to solve case here where the
|
||||
* user deletes events in one of the callbacks that we are
|
||||
* about to invoke, resulting in a double-free. XXX
|
||||
*/
|
||||
data = get_all_event_callbacks (env, g, &len);
|
||||
|
||||
guestfs_close (g);
|
||||
|
||||
for (i = 0; i < len; ++i) {
|
||||
(*env)->DeleteGlobalRef (env, data[i]->callback);
|
||||
free (data[i]);
|
||||
}
|
||||
free (data);
|
||||
}
|
||||
|
||||
/* See EventCallback interface. */
|
||||
#define METHOD_NAME \"event\"
|
||||
#define METHOD_SIGNATURE \"(JILjava/lang/String;[J)V\"
|
||||
|
||||
static void
|
||||
java_callback (guestfs_h *g,
|
||||
void *opaque,
|
||||
uint64_t event,
|
||||
int event_handle,
|
||||
int flags,
|
||||
const char *buf, size_t buf_len,
|
||||
const uint64_t *array, size_t array_len)
|
||||
{
|
||||
struct callback_data *data = opaque;
|
||||
JavaVM *jvm = data->jvm;
|
||||
JNIEnv *env;
|
||||
int r;
|
||||
jstring jbuf;
|
||||
jlongArray jarray;
|
||||
size_t i;
|
||||
jlong jl;
|
||||
|
||||
/* Get the Java environment. See:
|
||||
* http://stackoverflow.com/questions/12900695/how-to-obtain-jni-interface-pointer-jnienv-for-asynchronous-calls
|
||||
*/
|
||||
r = (*jvm)->GetEnv (jvm, (void **) &env, JNI_VERSION_1_6);
|
||||
if (r != JNI_OK) {
|
||||
switch (r) {
|
||||
case JNI_EDETACHED:
|
||||
/* This can happen when the close event is generated during an atexit
|
||||
* cleanup. The JVM has probably been destroyed so I doubt it is
|
||||
* safe to run Java code at this point.
|
||||
*/
|
||||
fprintf (stderr, \"%%s: event %%\" PRIu64 \" (eh %%d) ignored because the thread is not attached to the JVM. This can happen when libguestfs handles are cleaned up at program exit after the JVM has been destroyed.\\n\",
|
||||
__func__, event, event_handle);
|
||||
return;
|
||||
|
||||
case JNI_EVERSION:
|
||||
fprintf (stderr, \"%%s: event %%\" PRIu64 \" (eh %%d) failed because the JVM version is too old. JVM >= 1.6 is required.\\n\",
|
||||
__func__, event, event_handle);
|
||||
return;
|
||||
|
||||
default:
|
||||
fprintf (stderr, \"%%s: jvm->GetEnv failed! (JNI_* error code = %%d)\\n\",
|
||||
__func__, r);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* Convert the buffer and array to Java objects. */
|
||||
jbuf = (*env)->NewStringUTF (env, buf); // XXX size
|
||||
|
||||
jarray = (*env)->NewLongArray (env, array_len);
|
||||
for (i = 0; i < array_len; ++i) {
|
||||
jl = array[i];
|
||||
(*env)->SetLongArrayRegion (env, jarray, i, 1, &jl);
|
||||
}
|
||||
|
||||
/* Call the event method. If it throws an exception, all we can do is
|
||||
* print it on stderr.
|
||||
*/
|
||||
(*env)->ExceptionClear (env);
|
||||
(*env)->CallVoidMethod (env, data->callback, data->method,
|
||||
(jlong) event, (jint) event_handle,
|
||||
jbuf, jarray);
|
||||
if ((*env)->ExceptionOccurred (env)) {
|
||||
(*env)->ExceptionDescribe (env);
|
||||
(*env)->ExceptionClear (env);
|
||||
}
|
||||
}
|
||||
|
||||
JNIEXPORT jint JNICALL
|
||||
Java_com_redhat_et_libguestfs_GuestFS__1set_1event_1callback
|
||||
(JNIEnv *env, jobject obj, jlong jg, jobject jcallback, jlong jevents)
|
||||
{
|
||||
guestfs_h *g = (guestfs_h *) (long) jg;
|
||||
int r;
|
||||
struct callback_data *data;
|
||||
jclass callback_class;
|
||||
jmethodID method;
|
||||
char key[64];
|
||||
|
||||
callback_class = (*env)->GetObjectClass (env, jcallback);
|
||||
method = (*env)->GetMethodID (env, callback_class, METHOD_NAME, METHOD_SIGNATURE);
|
||||
if (method == 0) {
|
||||
throw_exception (env, \"GuestFS.set_event_callback: callback class does not implement the EventCallback interface\");
|
||||
return -1;
|
||||
}
|
||||
|
||||
data = malloc (sizeof *data);
|
||||
if (data == NULL) {
|
||||
throw_out_of_memory (env, \"malloc\");
|
||||
return -1;
|
||||
}
|
||||
(*env)->GetJavaVM (env, &data->jvm);
|
||||
data->method = method;
|
||||
|
||||
r = guestfs_set_event_callback (g, java_callback,
|
||||
(uint64_t) jevents, 0, data);
|
||||
if (r == -1) {
|
||||
free (data);
|
||||
throw_exception (env, guestfs_last_error (g));
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Register jcallback as a global reference so the GC won't free it. */
|
||||
data->callback = (*env)->NewGlobalRef (env, jcallback);
|
||||
|
||||
/* Store 'data' in the handle, so we can free it at some point. */
|
||||
snprintf (key, sizeof key, \"_java_event_%%d\", r);
|
||||
guestfs_set_private (g, key, data);
|
||||
|
||||
return (jint) r;
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
Java_com_redhat_et_libguestfs_GuestFS__1delete_1event_1callback
|
||||
(JNIEnv *env, jobject obj, jlong jg, jint eh)
|
||||
{
|
||||
guestfs_h *g = (guestfs_h *) (long) jg;
|
||||
char key[64];
|
||||
struct callback_data *data;
|
||||
|
||||
snprintf (key, sizeof key, \"_java_event_%%d\", eh);
|
||||
|
||||
data = guestfs_get_private (g, key);
|
||||
if (data) {
|
||||
(*env)->DeleteGlobalRef (env, data->callback);
|
||||
free (data);
|
||||
guestfs_set_private (g, key, NULL);
|
||||
guestfs_delete_event_callback (g, eh);
|
||||
}
|
||||
}
|
||||
|
||||
JNIEXPORT jstring JNICALL
|
||||
Java_com_redhat_et_libguestfs_GuestFS__1event_1to_1string
|
||||
(JNIEnv *env, jclass cl, jlong jevents)
|
||||
{
|
||||
uint64_t events = (uint64_t) jevents;
|
||||
char *str;
|
||||
jstring jr;
|
||||
|
||||
str = guestfs_event_to_string (events);
|
||||
if (str == NULL) {
|
||||
perror (\"guestfs_event_to_string\");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
jr = (*env)->NewStringUTF (env, str);
|
||||
free (str);
|
||||
|
||||
return jr;
|
||||
}
|
||||
|
||||
static struct callback_data **
|
||||
get_all_event_callbacks (JNIEnv *env, guestfs_h *g, size_t *len_rtn)
|
||||
{
|
||||
struct callback_data **r;
|
||||
size_t i;
|
||||
const char *key;
|
||||
struct callback_data *data;
|
||||
|
||||
/* Count the length of the array that will be needed. */
|
||||
*len_rtn = 0;
|
||||
data = guestfs_first_private (g, &key);
|
||||
while (data != NULL) {
|
||||
if (strncmp (key, \"_java_event_\", strlen (\"_java_event_\")) == 0)
|
||||
(*len_rtn)++;
|
||||
data = guestfs_next_private (g, &key);
|
||||
}
|
||||
|
||||
/* Copy them into the return array. */
|
||||
r = malloc (sizeof (struct callback_data *) * (*len_rtn));
|
||||
if (r == NULL) {
|
||||
throw_out_of_memory (env, \"malloc\");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
i = 0;
|
||||
data = guestfs_first_private (g, &key);
|
||||
while (data != NULL) {
|
||||
if (strncmp (key, \"_java_event_\", strlen (\"_java_event_\")) == 0) {
|
||||
r[i] = data;
|
||||
i++;
|
||||
}
|
||||
data = guestfs_next_private (g, &key);
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
";
|
||||
|
||||
List.iter (
|
||||
fun { name = name; style = (ret, args, optargs as style);
|
||||
c_function = c_function } ->
|
||||
pr "\n";
|
||||
pr "JNIEXPORT ";
|
||||
(match ret with
|
||||
| RErr -> pr "void ";
|
||||
|
||||
Reference in New Issue
Block a user