|
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] Re: [Xen-devel] [PATCH v6 08/12] libxl: ocaml: drop the ocaml heap lock before calling into libxl
If you resent a single patch can you use "git send-email --in-reply-to"
to chain it into the original thread so I don't loose it when I come to
apply. Thanks.
On Tue, 2013-11-26 at 23:15 +0000, Rob Hoes wrote:
> Ocaml has a heap lock which must be held whenever ocaml code is running. Ocaml
> usually drops this lock when it enters a potentially blocking low-level
> function, such as writing to a file. Libxl has its own lock, which it may
> acquire when being called.
>
> Things get interesting when libxl calls back into ocaml code. There is a risk
> of ending up in a deadlock when a thread holds both locks at the same time,
> then temporarily drop the ocaml lock, while another thread calls another libxl
> function.
>
> To avoid deadlocks, we drop the ocaml heap lock before entering libxl, and
> reacquire it in callbacks to ocaml. This way, the ocaml heap lock is never
> held
> together with the libxl lock, except in osevent registration callbacks, and
> xentoollog callbacks. If we guarantee to not call any libxl functions inside
> those callbacks, we can avoid deadlocks.
>
> This patch handle the dropping and reacquiring of the ocaml heap lock by the
> caml_enter_blocking_section and caml_leave_blocking_section functions, and
> related macros. We are also careful to not call any functions that access the
> ocaml heap while the ocaml heap lock is dropped. This often involves copying
> ocaml values to C before dropping the ocaml lock.
>
> Signed-off-by: Rob Hoes <rob.hoes@xxxxxxxxxx>
> CC: Ian Campbell <ian.campbell@xxxxxxxxxx>
> CC: Ian Jackson <ian.jackson@xxxxxxxxxxxxx>
> CC: Dave Scott <dave.scott@xxxxxxxxxxxxx>
> ---
> tools/ocaml/libs/xentoollog/Makefile | 3 +
> tools/ocaml/libs/xentoollog/xentoollog_stubs.c | 13 +-
> tools/ocaml/libs/xl/Makefile | 5 +-
> tools/ocaml/libs/xl/xenlight_stubs.c | 265
> +++++++++++++++++++-----
> 4 files changed, 229 insertions(+), 57 deletions(-)
>
> diff --git a/tools/ocaml/libs/xentoollog/Makefile
> b/tools/ocaml/libs/xentoollog/Makefile
> index e535ba5..471b428 100644
> --- a/tools/ocaml/libs/xentoollog/Makefile
> +++ b/tools/ocaml/libs/xentoollog/Makefile
> @@ -2,6 +2,9 @@ TOPLEVEL=$(CURDIR)/../..
> XEN_ROOT=$(TOPLEVEL)/../..
> include $(TOPLEVEL)/common.make
>
> +# allow mixed declarations and code
> +CFLAGS += -Wno-declaration-after-statement
> +
> CFLAGS += $(CFLAGS_libxenctrl) $(CFLAGS_libxenguest)
> OCAMLINCLUDE +=
>
> diff --git a/tools/ocaml/libs/xentoollog/xentoollog_stubs.c
> b/tools/ocaml/libs/xentoollog/xentoollog_stubs.c
> index 3b2f91b..daf48fe 100644
> --- a/tools/ocaml/libs/xentoollog/xentoollog_stubs.c
> +++ b/tools/ocaml/libs/xentoollog/xentoollog_stubs.c
> @@ -31,6 +31,11 @@
>
> #include "caml_xentoollog.h"
>
> +/* The following is equal to the CAMLreturn macro, but without the return */
> +#define CAMLdone do{ \
> +caml_local_roots = caml__frame; \
> +}while (0)
> +
> #define XTL ((xentoollog_logger *) Xtl_val(handle))
>
> static char * dup_String_val(value s)
> @@ -81,6 +86,7 @@ static void stub_xtl_ocaml_vmessage(struct
> xentoollog_logger *logger,
> const char *format,
> va_list al)
> {
> + caml_leave_blocking_section();
> CAMLparam0();
> CAMLlocalN(args, 4);
> struct caml_xtl *xtl = (struct caml_xtl*)logger;
> @@ -103,7 +109,8 @@ static void stub_xtl_ocaml_vmessage(struct
> xentoollog_logger *logger,
> free(msg);
>
> caml_callbackN(*func, 4, args);
> - CAMLreturn0;
> + CAMLdone;
> + caml_enter_blocking_section();
> }
So the concern here is that CAMLreturn0/CAMLparam0 might call into ocaml
heap code, and trigger the gc and therefore need the lock? is that
right?
I might have been tempted to wrap each callback in a macro/function
which ensured the locking was appropriate rather than enabling
-Wno-declaration-after-statement but this works too.
We use no-declaration-after-statement in libxl itself so I have no
objection to it.
The dropping/taking of the lock is a bit repetitive as well. As a future
cleanup you might consider
#define LIBXL(call) ({ \
int libxl_retval;\
caml_leave...();\
libxl_retval = call;\
caml_enter...();\
libxl_retval;
})
foo = LIBXL( libxl_do_something(CTX) );
I dunno, maybe that's not cleaner. Or s/LIBXL/CAML_UNLOCKED/ perhaps is
more expressive. Some of those ";" might need to be ",".
> -static libxl_asyncop_how *aohow_val(value async, libxl_asyncop_how *ao_how)
> +static libxl_asyncop_how *aohow_val(value async)
> {
> CAMLparam1(async);
> + libxl_asyncop_how *ao_how = NULL;
>
> if (async != Val_none) {
> + libxl_asyncop_how *ao_how = malloc(sizeof(*ao_how));
> ao_how->callback = async_callback;
> ao_how->u.for_callback = (void *) Some_val(async);
> - CAMLreturnT(libxl_asyncop_how *, ao_how);
> }
> - else
> - CAMLreturnT(libxl_asyncop_how *, NULL);
> +
> + CAMLreturnT(libxl_asyncop_how *, ao_how);
> }
>
> value stub_libxl_domain_create_new(value ctx, value domain_config, value
> async, value unit)
> @@ -411,7 +420,7 @@ value stub_libxl_domain_create_new(value ctx, value
> domain_config, value async,
> int ret;
> libxl_domain_config c_dconfig;
> uint32_t c_domid;
> - libxl_asyncop_how ao_how;
> + libxl_asyncop_how *ao_how;
These changes seem to have something (subtle) to do with the lifecycle
of the ao_how rather than any of the locking stuff which is the meat of
this change? Does the ao_how need to be dynamically allocated rather
than stack based for some reason?
If this relates the locking stuff can we get a description in the commit
message please.
_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxx
http://lists.xen.org/xen-devel
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |