[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


 


Rackspace

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