# CAMLlocal for caml\_callbackN arg array required?

**URL:** <https://discuss.ocaml.org/t/camllocal-for-caml-callbackn-arg-array-required/11012>\
**Category:** Learning\
**Tags:** runtime\
**Created:** [December 20, 2022, 4:38pm UTC](https://discuss.ocaml.org/t/camllocal-for-caml-callbackn-arg-array-required/11012 "2022-12-20T16:38:35Z")\
**Posts on this page:** 7\
**Page:** 1

<div class="post-metadata">

**Author:** ![lindig](https://sea2.discourse-cdn.com/flex020/user_avatar/discuss.ocaml.org/lindig/32/532_2.png) [@lindig](https://discuss.ocaml.org/u/lindig)\
**Post date:** [December 20, 2022, 4:38pm UTC](https://discuss.ocaml.org/t/camllocal-for-caml-callbackn-arg-array-required/11012/1 "2022-12-20T16:38:35Z")

</div>

I’m using `caml_callbackN` and need to create a `value` array to pass arguments. Looking trough OCaml compiler code I see that this array is not declared as GC roots but I am not sure about this would and would like to ask for advice. At least one value from that array is later returned, which is not the case for the test cases below and which might have been written with this knowledge in the background.

- [ocaml/test1\_.c at trunk · ocaml/ocaml · GitHub](https://github.com/ocaml/ocaml/blob/trunk/testsuite/tests/callback/test1_.c#L41-L51)
- [ocaml/test\_signalhandler\_.c at trunk · ocaml/ocaml · GitHub](https://github.com/ocaml/ocaml/blob/trunk/testsuite/tests/callback/test_signalhandler_.c#L46)

```auto
CAMLprim value
caml_polly_wait_fold(value val_epfd, value val_max, value val_timeout,
		     value val_init, value val_f)
{
	CAMLparam5(val_epfd, val_max, val_timeout, val_init, val_f);
	value args[4];

	struct epoll_event *events;
	int ready, i;

	if (Int_val(val_max) <= 0)
		uerror( __FUNCTION__ , Nothing);
	events =
	    (struct epoll_event *)alloca(Int_val(val_max) *
					 sizeof(struct epoll_event));

	caml_enter_blocking_section();
	ready = epoll_wait(Int_val(val_epfd), events, Int_val(val_max),
			   Int_val(val_timeout));
	caml_leave_blocking_section();

	if (ready == -1)
		uerror( __FUNCTION__ , Nothing);

	args[0] = val_epfd;
	args[3] = val_init;
	for (i = 0; i < ready; i++) {
		args[1] = Val_int(events[i].data.fd);
		args[2] = Val_int(events[i].events);
		args[3] = caml_callbackN(val_f, 4, args);
	}

	CAMLreturn(args[3]);
}

```

---

<div class="post-metadata">

**Author:** ![nojb](https://sea2.discourse-cdn.com/flex020/user_avatar/discuss.ocaml.org/nojb/32/519_2.png) [@nojb](https://discuss.ocaml.org/u/nojb)\
**Post date:** [December 21, 2022, 4:51pm UTC](https://discuss.ocaml.org/t/camllocal-for-caml-callbackn-arg-array-required/11012/2 "2022-12-21T16:51:06Z")

</div>

My understanding is that this is correct. Arguments to `caml_callback*` do not need to be declared as roots (either for the small argument count variants or the N variant). If a poll point occurs in the body of the callback, the argument will be recorded as root as needed, in the same manner as every other local variable.

Cheers,  
Nicolas

---

<div class="post-metadata">

**Author:** ![lindig](https://sea2.discourse-cdn.com/flex020/user_avatar/discuss.ocaml.org/lindig/32/532_2.png) [@lindig](https://discuss.ocaml.org/u/lindig)\
**Post date:** [December 21, 2022, 5:46pm UTC](https://discuss.ocaml.org/t/camllocal-for-caml-callbackn-arg-array-required/11012/3 "2022-12-21T17:46:32Z")

</div>

So I do not have to worry about `args[3]` being moved by the GC between it being returned by `caml_callbackN` and it being returned in `CAMLreturn(args[3])` or used in another iteration of the loop? Because this is where I suspected things could go wrong. Is this still true in OCaml 5?

---

<div class="post-metadata">

**Author:** ![nojb](https://sea2.discourse-cdn.com/flex020/user_avatar/discuss.ocaml.org/nojb/32/519_2.png) [@nojb](https://discuss.ocaml.org/u/nojb)\
**Post date:** [December 21, 2022, 5:55pm UTC](https://discuss.ocaml.org/t/camllocal-for-caml-callbackn-arg-array-required/11012/4 "2022-12-21T17:55:43Z")

</div>

That’s right. In C code, a value can only be moved when allocating, when releasing the runtime lock or by calling into the GC in some other way. Since this cannot happen in those parts of the code, the value cannot be moved.

The same reasoning holds in OCaml 5.

Cheers,  
Nicolas

---

<div class="post-metadata">

**Author:** ![vlaviron](https://avatars.discourse-cdn.com/v4/letter/v/ec9cab/32.png) [@vlaviron](https://discuss.ocaml.org/u/vlaviron)\
**Post date:** [December 21, 2022, 10:59pm UTC](https://discuss.ocaml.org/t/camllocal-for-caml-callbackn-arg-array-required/11012/5 "2022-12-21T22:59:21Z")

</div>

Please correct me if I’m wrong, but the code pasted above has a for loop that calls `caml_callbackN`. Each of these calls can trigger a GC, so all values held in C memory around these calls (like the `args` array) need to be registered with the GC. I don’t know what is the correct way to register an array of values tough; using an OCaml array should work but then you have to use the proper macros instead of just array indexing.  
Alternaltively, you can register four local variables and re-initialize the array from these variables before each call, but it’s less elegant.

---

<div class="post-metadata">

**Author:** ![nojb](https://sea2.discourse-cdn.com/flex020/user_avatar/discuss.ocaml.org/nojb/32/519_2.png) [@nojb](https://discuss.ocaml.org/u/nojb)\
**Post date:** [December 22, 2022, 3:16am UTC](https://discuss.ocaml.org/t/camllocal-for-caml-callbackn-arg-array-required/11012/6 "2022-12-22T03:16:01Z")

</div>

`args[1]` and `args[2]` are reloaded on each iteration of the loop (and are also immediates) so they do not need to be registered, and `args[3]` is redefined to be the result of the callback, so it is still OK. I assumed that `val_epfd` was also an immediate, but if it isn’t then indeed `args[0]` needs to be registered as root or reloaded in each iteration of the loop.

Cheers,  
Nicolas

---

<div class="post-metadata">

**Author:** ![lindig](https://sea2.discourse-cdn.com/flex020/user_avatar/discuss.ocaml.org/lindig/32/532_2.png) [@lindig](https://discuss.ocaml.org/u/lindig)\
**Post date:** [January 4, 2023, 2:03pm UTC](https://discuss.ocaml.org/t/camllocal-for-caml-callbackn-arg-array-required/11012/7 "2023-01-04T14:03:10Z")

</div>

@edwin pointed out to me that the documentation has been updated to explicitly not declaring the `args` as GC roots:

> <https://github.com/ocaml/ocaml/commit/9acf32acf8843db4083c92a0200309fa51d0e4d1>
>
> The \`args\` argument array must not be declared with \`CAMLlocalN\`, otherwise
> the… array can be registered a second time by \`caml\_callbackN\`, confusing
> the compactor.
> 
> Also: suggests using a C99 compound literal, it looks good and avoids the issue.
> 
> Fixes: #11045

> The array \var{args} must \emph{not} be declared with “CAMLlocalN”.  
> It should be declared as “value “\var{args}”[”\var{n}“];”.  
> Alternatively, a C99 compound literal can be used:  
> “caml\_callbackN(”\var{f, n, }“(value){”\nth{arg}{1}, \ldots, \nth{arg}{n}“})”.
