[Libguestfs] [PATCH libnbd 3/7] ocaml: Remove NBD.Buffer.free function, use a free callback instead.
Eric Blake
eblake at redhat.com
Mon Aug 12 16:58:42 UTC 2019
On 8/12/19 11:08 AM, Richard W.M. Jones wrote:
> By using the free callback mechanism we don't need to manually free
> the buffer.
>
> This reverts part of commit fef1c281a65d061127bf178e5f8cfca0a2475c56.
> ---
> generator/generator | 43 +++++++++++++++++++++-----------
> ocaml/buffer.c | 22 ----------------
> ocaml/examples/asynch_copy.ml | 4 +--
> ocaml/libnbd-ocaml.pod | 22 ----------------
> ocaml/nbd-c.h | 8 ++++++
> ocaml/tests/test_590_aio_copy.ml | 4 +--
> 6 files changed, 39 insertions(+), 64 deletions(-)
>
> diff --git a/generator/generator b/generator/generator
> index d6b9352..92ce170 100755
> --- a/generator/generator
> +++ b/generator/generator
> @@ -4961,10 +4961,6 @@ module Buffer : sig
> (** Allocate an uninitialized buffer. The parameter is the size
> in bytes. *)
>
> - val free : t -> unit
> - (** The buffer must be manually freed when it is no longer used.
> - An AIO completion callback is usually a good place. *)
> -
Getting rid of this public function is nice. Hopefully, how we get rid
of it is internal enough that we can switch between either a list of
free functions at the C level, or else a smarter forwarding of aio_pread
to the C nbd_aio_pread_completion, without affecting what else leaks
through to the OCaml view.
> @@ -5244,10 +5239,8 @@ let print_ocaml_binding (name, { args; optargs; ret }) =
> pr " caml_enter_blocking_section ();\n";
> pr " }\n";
> pr "\n";
> - pr " if (valid_flag & LIBNBD_CALLBACK_FREE) {\n";
> - pr " caml_remove_generational_global_root ((value *)user_data);\n";
> - pr " free (user_data);\n";
> - pr " }\n";
> + pr " if (valid_flag & LIBNBD_CALLBACK_FREE)\n";
> + pr " free_root (NULL, user_data);\n";
> pr "\n";
Here, I'm unfamiliar enough with the OCaml GC rules to know if you're
doing it right, but trust that you have been testing with valgrind or
similar with a forced GC run to catch obvious mistakes.
> @@ -5313,17 +5306,39 @@ let print_ocaml_binding (name, { args; optargs; ret }) =
> | BytesIn (n, count) ->
> pr " const void *%s = Bytes_val (%sv);\n" n n;
> pr " size_t %s = caml_string_length (%sv);\n" count n
> + | BytesOut (n, count) ->
> + pr " void *%s = Bytes_val (%sv);\n" n n;
> + pr " size_t %s = caml_string_length (%sv);\n" count n
> | BytesPersistIn (n, count) ->
> + pr " /* The function may save a reference to the Buffer, so we\n";
> + pr " * must treat it as a possible GC root.\n";
> + pr " */\n";
> + pr " value *%s_user_data;\n" n;
> + pr " %s_user_data = malloc (sizeof (value));\n" n;
> + pr " if (%s_user_data == NULL) caml_raise_out_of_memory ();\n" n;
> + pr " *%s_user_data = %sv;\n" n n;
> + pr " caml_register_generational_global_root (%s_user_data);\n" n;
> pr " struct nbd_buffer *%s_buf = NBD_buffer_val (%sv);\n" n n;
> pr " const void *%s = %s_buf->data;\n" n n;
> - pr " size_t %s = %s_buf->len;\n" count n
> - | BytesOut (n, count) ->
> - pr " void *%s = Bytes_val (%sv);\n" n n;
> - pr " size_t %s = caml_string_length (%sv);\n" count n
> + pr " size_t %s = %s_buf->len;\n" count n;
> + pr " if (nbd_add_free_callback (h, (void *)%s,\n" n;
Is the cast to void* necessary? I guess so - it looks like you are
casting away const.
> + pr " free_root, %s_user_data) == -1)\n" n;
Hmm. In patch 1, I questioned if we need a separate user_data argument
when registering a free callback. But here, you are keying off of the
last use of one pointer (the buffer), but with a different pointer (the
user_data wrapper) to be passed to the free function...
> +++ b/ocaml/nbd-c.h
> @@ -107,4 +107,12 @@ struct callback_data {
> extern char **nbd_internal_ocaml_string_list (value);
> extern value nbd_internal_ocaml_alloc_int32_array (uint32_t *, size_t);
>
> +/* Free a generational global root and its container. */
> +static inline void
> +free_root (void *ptr /* unused */, void *rootp)
> +{
> + caml_remove_generational_global_root ((value *)rootp);
> + free (rootp);
> +}
...and indeed, the free function is ignoring the first pointer and
instead acting on the second. If we change the C signature to take only
a single pointer, then you have to be a bit more creative on h ow to
pass the rootp as the pointer to be adjusted when the buffer lifetime
ends. So maybe this is the answer to my question in patch 1 as to why
you needed two arguments. Or maybe it is all the more reason to try
harder to get the generator to call nbd_aio_pread_callback even when the
OCaml language did not pass a callback.
--
Eric Blake, Principal Software Engineer
Red Hat, Inc. +1-919-301-3226
Virtualization: qemu.org | libvirt.org
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 488 bytes
Desc: OpenPGP digital signature
URL: <http://listman.redhat.com/archives/libguestfs/attachments/20190812/762cf4e9/attachment.sig>
More information about the Libguestfs
mailing list