[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Xen-changelog] [xen master] libxl: ocaml: use 'for_app_registration' in osevent callbacks



commit 8aba7e1ce9e26cdf9d2b002ed87b4bd75fce4af3
Author:     Rob Hoes <rob.hoes@xxxxxxxxxx>
AuthorDate: Fri Jan 10 13:52:04 2014 +0000
Commit:     Ian Campbell <ian.campbell@xxxxxxxxxx>
CommitDate: Fri Jan 10 16:54:45 2014 +0000

    libxl: ocaml: use 'for_app_registration' in osevent callbacks
    
    This allows the application to pass a token to libxl in the fd/timeout
    registration callbacks, which it receives back in modification or
    deregistration callbacks.
    
    It turns out that this is essential for timeout handling, in order to
    identify which timeout to change on a modify event.
    
    Signed-off-by: Rob Hoes <rob.hoes@xxxxxxxxxx>
    Acked-by: David Scott <dave.scott@xxxxxxxxxxxxx>
    Acked-by: Ian Jackson <ian.jackson@xxxxxxxxxxxxx>
---
 tools/ocaml/libs/xl/xenlight.ml.in   |    4 +-
 tools/ocaml/libs/xl/xenlight.mli.in  |   10 +-
 tools/ocaml/libs/xl/xenlight_stubs.c |  149 +++++++++++++++++++++++++++++-----
 3 files changed, 136 insertions(+), 27 deletions(-)

diff --git a/tools/ocaml/libs/xl/xenlight.ml.in 
b/tools/ocaml/libs/xl/xenlight.ml.in
index 47f3487..80e620a 100644
--- a/tools/ocaml/libs/xl/xenlight.ml.in
+++ b/tools/ocaml/libs/xl/xenlight.ml.in
@@ -68,12 +68,12 @@ module Async = struct
        external osevent_occurred_fd : ctx -> for_libxl -> Unix.file_descr -> 
event list -> event list -> unit = "stub_libxl_osevent_occurred_fd"
        external osevent_occurred_timeout : ctx -> for_libxl -> unit = 
"stub_libxl_osevent_occurred_timeout"
 
-       let osevent_register_hooks ctx ~user ~fd_register ~fd_modify 
~fd_deregister ~timeout_register ~timeout_modify =
+       let osevent_register_hooks ctx ~user ~fd_register ~fd_modify 
~fd_deregister ~timeout_register ~timeout_fire_now =
                Callback.register "libxl_fd_register" fd_register;
                Callback.register "libxl_fd_modify" fd_modify;
                Callback.register "libxl_fd_deregister" fd_deregister;
                Callback.register "libxl_timeout_register" timeout_register;
-               Callback.register "libxl_timeout_modify" timeout_modify;
+               Callback.register "libxl_timeout_fire_now" timeout_fire_now;
                osevent_register_hooks' ctx user
 
        let async_register_callback ~async_callback =
diff --git a/tools/ocaml/libs/xl/xenlight.mli.in 
b/tools/ocaml/libs/xl/xenlight.mli.in
index b9819e1..b2c06b5 100644
--- a/tools/ocaml/libs/xl/xenlight.mli.in
+++ b/tools/ocaml/libs/xl/xenlight.mli.in
@@ -68,11 +68,11 @@ module Async : sig
 
        val osevent_register_hooks : ctx ->
                user:'a ->
-               fd_register:('a -> Unix.file_descr -> event list -> for_libxl 
-> unit) ->
-               fd_modify:('a -> Unix.file_descr -> event list -> unit) ->
-               fd_deregister:('a -> Unix.file_descr -> unit) ->
-               timeout_register:('a -> int64 -> int64 -> for_libxl -> unit) ->
-               timeout_modify:('a -> unit) ->
+               fd_register:('a -> Unix.file_descr -> event list -> for_libxl 
-> 'b) ->
+               fd_modify:('a -> Unix.file_descr -> 'b -> event list -> 'b) ->
+               fd_deregister:('a -> Unix.file_descr -> 'b -> unit) ->
+               timeout_register:('a -> int64 -> int64 -> for_libxl -> 'c) ->
+               timeout_fire_now:('a -> 'c -> 'c) ->
                osevent_hooks
 
        external osevent_occurred_fd : ctx -> for_libxl -> Unix.file_descr -> 
event list -> event list -> unit = "stub_libxl_osevent_occurred_fd"
diff --git a/tools/ocaml/libs/xl/xenlight_stubs.c 
b/tools/ocaml/libs/xl/xenlight_stubs.c
index 2e2606a..23f253a 100644
--- a/tools/ocaml/libs/xl/xenlight_stubs.c
+++ b/tools/ocaml/libs/xl/xenlight_stubs.c
@@ -31,6 +31,7 @@
 #include <libxl_utils.h>
 
 #include <unistd.h>
+#include <assert.h>
 
 #include "caml_xentoollog.h"
 
@@ -1211,14 +1212,20 @@ value Val_poll_events(short events)
        CAMLreturn(event_list);
 }
 
+/* The process for dealing with the for_app_registration_  values in the
+ * callbacks below (GC registrations etc) is similar to the way for_callback is
+ * handled in the asynchronous operations above. */
+
 int fd_register(void *user, int fd, void **for_app_registration_out,
                      short events, void *for_libxl)
 {
        caml_leave_blocking_section();
        CAMLparam0();
        CAMLlocalN(args, 4);
+       int ret = 0;
        static value *func = NULL;
        value *p = (value *) user;
+       value *for_app;
 
        if (func == NULL) {
                /* First time around, lookup by name */
@@ -1230,10 +1237,26 @@ int fd_register(void *user, int fd, void 
**for_app_registration_out,
        args[2] = Val_poll_events(events);
        args[3] = (value) for_libxl;
 
-       caml_callbackN(*func, 4, args);
+       for_app = malloc(sizeof(value));
+       if (!for_app) {
+               ret = ERROR_OSEVENT_REG_FAIL;
+               goto err;
+       }
+
+       *for_app = caml_callbackN_exn(*func, 4, args);
+       if (Is_exception_result(*for_app)) {
+               ret = ERROR_OSEVENT_REG_FAIL;
+               free(for_app);
+               goto err;
+       }
+
+       caml_register_global_root(for_app);
+       *for_app_registration_out = for_app;
+
+err:
        CAMLdone;
        caml_enter_blocking_section();
-       return 0;
+       return ret;
 }
 
 int fd_modify(void *user, int fd, void **for_app_registration_update,
@@ -1241,9 +1264,14 @@ int fd_modify(void *user, int fd, void 
**for_app_registration_update,
 {
        caml_leave_blocking_section();
        CAMLparam0();
-       CAMLlocalN(args, 3);
+       CAMLlocalN(args, 4);
+       int ret = 0;
        static value *func = NULL;
        value *p = (value *) user;
+       value *for_app = *for_app_registration_update;
+
+       /* If for_app == NULL, then something is very wrong */
+       assert(for_app);
 
        if (func == NULL) {
                /* First time around, lookup by name */
@@ -1252,21 +1280,37 @@ int fd_modify(void *user, int fd, void 
**for_app_registration_update,
 
        args[0] = *p;
        args[1] = Val_int(fd);
-       args[2] = Val_poll_events(events);
+       args[2] = *for_app;
+       args[3] = Val_poll_events(events);
+
+       *for_app = caml_callbackN_exn(*func, 4, args);
+       if (Is_exception_result(*for_app)) {
+               /* If an exception is caught, *for_app_registration_update is 
not
+                * changed. It remains a valid pointer to a value that is 
registered
+                * with the GC. */
+               ret = ERROR_OSEVENT_REG_FAIL;
+               goto err;
+       }
+
+       *for_app_registration_update = for_app;
 
-       caml_callbackN(*func, 3, args);
+err:
        CAMLdone;
        caml_enter_blocking_section();
-       return 0;
+       return ret;
 }
 
 void fd_deregister(void *user, int fd, void *for_app_registration)
 {
        caml_leave_blocking_section();
        CAMLparam0();
-       CAMLlocalN(args, 2);
+       CAMLlocalN(args, 3);
        static value *func = NULL;
        value *p = (value *) user;
+       value *for_app = for_app_registration;
+
+       /* If for_app == NULL, then something is very wrong */
+       assert(for_app);
 
        if (func == NULL) {
                /* First time around, lookup by name */
@@ -1275,12 +1319,26 @@ void fd_deregister(void *user, int fd, void 
*for_app_registration)
 
        args[0] = *p;
        args[1] = Val_int(fd);
+       args[2] = *for_app;
+
+       caml_callbackN_exn(*func, 3, args);
+       /* This hook does not return error codes, so the best thing we can do
+        * to avoid trouble, if we catch an exception from the app, is abort. */
+       if (Is_exception_result(*for_app))
+               abort();
+
+       caml_remove_global_root(for_app);
+       free(for_app);
 
-       caml_callbackN(*func, 2, args);
        CAMLdone;
        caml_enter_blocking_section();
 }
 
+struct timeout_handles {
+       void *for_libxl;
+       value for_app;
+};
+
 int timeout_register(void *user, void **for_app_registration_out,
                           struct timeval abs, void *for_libxl)
 {
@@ -1288,8 +1346,10 @@ int timeout_register(void *user, void 
**for_app_registration_out,
        CAMLparam0();
        CAMLlocal2(sec, usec);
        CAMLlocalN(args, 4);
+       int ret = 0;
        static value *func = NULL;
        value *p = (value *) user;
+       struct timeout_handles *handles;
 
        if (func == NULL) {
                /* First time around, lookup by name */
@@ -1299,15 +1359,36 @@ int timeout_register(void *user, void 
**for_app_registration_out,
        sec = caml_copy_int64(abs.tv_sec);
        usec = caml_copy_int64(abs.tv_usec);
 
+       /* This struct of "handles" will contain "for_libxl" as well as 
"for_app".
+        * We'll give a pointer to the struct to the app, and get it back in
+        * occurred_timeout, where we can clean it all up. */
+       handles = malloc(sizeof(*handles));
+       if (!handles) {
+               ret = ERROR_OSEVENT_REG_FAIL;
+               goto err;
+       }
+
+       handles->for_libxl = for_libxl;
+
        args[0] = *p;
        args[1] = sec;
        args[2] = usec;
-       args[3] = (value) for_libxl;
+       args[3] = (value) handles;
 
-       caml_callbackN(*func, 4, args);
+       handles->for_app = caml_callbackN_exn(*func, 4, args);
+       if (Is_exception_result(handles->for_app)) {
+               ret = ERROR_OSEVENT_REG_FAIL;
+               free(handles);
+               goto err;
+       }
+
+       caml_register_global_root(&handles->for_app);
+       *for_app_registration_out = handles;
+
+err:
        CAMLdone;
        caml_enter_blocking_section();
-       return 0;
+       return ret;
 }
 
 int timeout_modify(void *user, void **for_app_registration_update,
@@ -1315,25 +1396,49 @@ int timeout_modify(void *user, void 
**for_app_registration_update,
 {
        caml_leave_blocking_section();
        CAMLparam0();
+       CAMLlocal1(for_app_update);
+       CAMLlocalN(args, 2);
+       int ret = 0;
        static value *func = NULL;
        value *p = (value *) user;
+       struct timeout_handles *handles = *for_app_registration_update;
+
+       /* If for_app == NULL, then something is very wrong */
+       assert(handles->for_app);
+
+       /* Libxl currently promises that timeout_modify is only ever called with
+        * abs={0,0}, meaning "right away". We cannot deal with other values. */
+       assert(abs.tv_sec == 0 && abs.tv_usec == 0);
 
        if (func == NULL) {
                /* First time around, lookup by name */
-               func = caml_named_value("libxl_timeout_modify");
+               func = caml_named_value("libxl_timeout_fire_now");
+       }
+
+       args[0] = *p;
+       args[1] = handles->for_app;
+
+       for_app_update = caml_callbackN_exn(*func, 2, args);
+       if (Is_exception_result(for_app_update)) {
+               /* If an exception is caught, *for_app_registration_update is 
not
+                * changed. It remains a valid pointer to a value that is 
registered
+                * with the GC. */
+               ret = ERROR_OSEVENT_REG_FAIL;
+               goto err;
        }
 
-       caml_callback(*func, *p);
+       handles->for_app = for_app_update;
+
+err:
        CAMLdone;
        caml_enter_blocking_section();
-       return 0;
+       return ret;
 }
 
 void timeout_deregister(void *user, void *for_app_registration)
 {
-       caml_leave_blocking_section();
-       failwith_xl(ERROR_FAIL, "timeout_deregister not yet implemented");
-       caml_enter_blocking_section();
+       /* This hook will never be called by libxl. */
+       abort();
 }
 
 value stub_libxl_osevent_register_hooks(value ctx, value user)
@@ -1384,14 +1489,18 @@ value stub_libxl_osevent_occurred_fd(value ctx, value 
for_libxl, value fd,
        CAMLreturn(Val_unit);
 }
 
-value stub_libxl_osevent_occurred_timeout(value ctx, value for_libxl)
+value stub_libxl_osevent_occurred_timeout(value ctx, value handles)
 {
-       CAMLparam2(ctx, for_libxl);
+       CAMLparam1(ctx);
+       struct timeout_handles *c_handles = (struct timeout_handles *) handles;
 
        caml_enter_blocking_section();
-       libxl_osevent_occurred_timeout(CTX, (void *) for_libxl);
+       libxl_osevent_occurred_timeout(CTX, (void *) c_handles->for_libxl);
        caml_leave_blocking_section();
 
+       caml_remove_global_root(&c_handles->for_app);
+       free(c_handles);
+
        CAMLreturn(Val_unit);
 }
 
--
generated by git-patchbot for /home/xen/git/xen.git#master

_______________________________________________
Xen-changelog mailing list
Xen-changelog@xxxxxxxxxxxxx
http://lists.xensource.com/xen-changelog


 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.