/* Guestfs.set_event_callback */ CAMLprim value ocaml_guestfs_set_event_callback (value gv, value closure, value events) { CAMLparam3 (gv, closure, events); char key[64]; int eh; uint64_t event_bitmask; guestfs_h *g = Guestfs_val (gv); event_bitmask = event_bitmask_of_event_list (events); value *root = guestfs_safe_malloc (g, sizeof *root); *root = closure; eh = guestfs_set_event_callback (g, event_callback_wrapper, event_bitmask, 0, root); if (eh == -1) { free (root); ocaml_guestfs_raise_error (g, "set_event_callback"); } /* XXX This global root is generational, but we cannot rely on every * user having the OCaml 3.11 version which supports this. */ caml_register_global_root (root); snprintf (key, sizeof key, "_ocaml_event_%d", eh); guestfs_set_private (g, key, root); CAMLreturn (Val_int (eh)); }
PyObject * py_guestfs_delete_event_callback (PyObject *self, PyObject *args) { PyObject *py_g; guestfs_h *g; int eh; PyObject *py_callback; char key[64]; if (!PyArg_ParseTuple (args, (char *) "Oi:guestfs_delete_event_callback", &py_g, &eh)) return NULL; g = get_handle (py_g); snprintf (key, sizeof key, "_python_event_%d", eh); py_callback = guestfs_get_private (g, key); if (py_callback) { Py_XDECREF (py_callback); guestfs_set_private (g, key, NULL); guestfs_delete_event_callback (g, eh); } Py_INCREF (Py_None); return Py_None; }
/* Guestfs.create */ CAMLprim value ocaml_guestfs_create (void) { CAMLparam0 (); CAMLlocal1 (gv); guestfs_h *g; value *v; g = guestfs_create (); if (g == NULL) caml_failwith ("failed to create guestfs handle"); guestfs_set_error_handler (g, NULL, NULL); gv = Val_guestfs (g); /* Store the OCaml handle into the C handle. This is only so we can * map the C handle to the OCaml handle in event_callback_wrapper. */ v = guestfs_safe_malloc (g, sizeof *v); *v = gv; /* XXX This global root is generational, but we cannot rely on every * user having the OCaml 3.11 version which supports this. */ caml_register_global_root (v); guestfs_set_private (g, "_ocaml_g", v); CAMLreturn (gv); }
/* Guestfs.set_event_callback */ value ocaml_guestfs_set_event_callback (value gv, value closure, value events) { CAMLparam3 (gv, closure, events); char key[64]; int eh; uint64_t event_bitmask; guestfs_h *g = Guestfs_val (gv); event_bitmask = event_bitmask_of_event_list (events); value *root = guestfs_int_safe_malloc (g, sizeof *root); *root = closure; eh = guestfs_set_event_callback (g, event_callback_wrapper, event_bitmask, 0, root); if (eh == -1) { free (root); ocaml_guestfs_raise_error (g, "set_event_callback"); } caml_register_generational_global_root (root); snprintf (key, sizeof key, "_ocaml_event_%d", eh); guestfs_set_private (g, key, root); CAMLreturn (Val_int (eh)); }
int main (int argc, char *argv[]) { guestfs_h *g; const char *key; void *data; size_t count; g = guestfs_create (); if (g == NULL) error (EXIT_FAILURE, errno, "guestfs_create"); if (guestfs_set_event_callback (g, close_callback, GUESTFS_EVENT_CLOSE, 0, NULL) == -1) exit (EXIT_FAILURE); guestfs_set_private (g, PREFIX "a", (void *) 1); guestfs_set_private (g, PREFIX "b", (void *) 2); guestfs_set_private (g, PREFIX "c", (void *) 3); guestfs_set_private (g, PREFIX "a", (void *) 4); /* overwrites previous */ /* Check we can fetch keys. */ assert (guestfs_get_private (g, PREFIX "a") == (void *) 4); assert (guestfs_get_private (g, PREFIX "b") == (void *) 2); assert (guestfs_get_private (g, PREFIX "c") == (void *) 3); assert (guestfs_get_private (g, PREFIX "d") == NULL); /* Check we can count keys by iterating. */ count = 0; data = guestfs_first_private (g, &key); while (data != NULL) { if (strncmp (key, PREFIX, strlen (PREFIX)) == 0) count++; data = guestfs_next_private (g, &key); } assert (count == 3); /* Delete some keys. */ guestfs_set_private (g, PREFIX "a", NULL); guestfs_set_private (g, PREFIX "b", NULL); /* Count them again. */ count = 0; data = guestfs_first_private (g, &key); while (data != NULL) { if (strncmp (key, PREFIX, strlen (PREFIX)) == 0) count++; data = guestfs_next_private (g, &key); } assert (count == 1); /* Closing should implicitly call the close_callback function. */ guestfs_close (g); assert (close_callback_called == 1); exit (EXIT_SUCCESS); }
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); } }
PyObject * py_guestfs_set_event_callback (PyObject *self, PyObject *args) { PyObject *py_g; guestfs_h *g; PyObject *py_callback; unsigned PY_LONG_LONG events; int eh; PyObject *py_eh; char key[64]; if (!PyArg_ParseTuple (args, (char *) "OOK:guestfs_set_event_callback", &py_g, &py_callback, &events)) return NULL; if (!PyCallable_Check (py_callback)) { PyErr_SetString (PyExc_TypeError, "callback parameter is not callable " "(eg. lambda or function)"); return NULL; } g = get_handle (py_g); eh = guestfs_set_event_callback (g, py_guestfs_event_callback_wrapper, events, 0, py_callback); if (eh == -1) { PyErr_SetString (PyExc_RuntimeError, guestfs_last_error (g)); return NULL; } /* Increase the refcount for this callback since we are storing it * in the opaque C libguestfs handle. We need to remember that we * did this, so we can decrease the refcount for all undeleted * callbacks left around at close time (see py_guestfs_close). */ Py_XINCREF (py_callback); snprintf (key, sizeof key, "_python_event_%d", eh); guestfs_set_private (g, key, py_callback); py_eh = PyLong_FromLong ((long) eh); return py_eh; }
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; }
/* Guestfs.delete_event_callback */ CAMLprim value ocaml_guestfs_delete_event_callback (value gv, value ehv) { CAMLparam2 (gv, ehv); char key[64]; int eh = Int_val (ehv); guestfs_h *g = Guestfs_val (gv); snprintf (key, sizeof key, "_ocaml_event_%d", eh); value *root = guestfs_get_private (g, key); if (root) { caml_remove_global_root (root); free (root); guestfs_set_private (g, key, NULL); guestfs_delete_event_callback (g, eh); } CAMLreturn (Val_unit); }
/* Guestfs.create */ value ocaml_guestfs_create (value environmentv, value close_on_exitv, value unitv) { CAMLparam3 (environmentv, close_on_exitv, unitv); CAMLlocal1 (gv); unsigned flags = 0; guestfs_h *g; value *v; if (environmentv != Val_int (0) && !Bool_val (Field (environmentv, 0))) flags |= GUESTFS_CREATE_NO_ENVIRONMENT; if (close_on_exitv != Val_int (0) && !Bool_val (Field (close_on_exitv, 0))) flags |= GUESTFS_CREATE_NO_CLOSE_ON_EXIT; g = guestfs_create_flags (flags); if (g == NULL) caml_failwith ("failed to create guestfs handle"); guestfs_set_error_handler (g, NULL, NULL); gv = Val_guestfs (g); /* Store the OCaml handle into the C handle. This is only so we can * map the C handle to the OCaml handle in event_callback_wrapper. */ v = guestfs_int_safe_malloc (g, sizeof *v); *v = gv; /* XXX This global root is generational, but we cannot rely on every * user having the OCaml 3.11 version which supports this. */ caml_register_global_root (v); guestfs_set_private (g, "_ocaml_g", v); CAMLreturn (gv); }
/* This callback deletes all test keys in the handle. */ static void close_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) { const char *key; void *data; close_callback_called++; again: data = guestfs_first_private (g, &key); while (data != NULL) { if (strncmp (key, PREFIX, strlen (PREFIX)) == 0) { guestfs_set_private (g, key, NULL); goto again; } data = guestfs_next_private (g, &key); } }