Mantis Bug Tracker

View Issue Details Jump to Notes ] Issue History ] Print ]
IDProjectCategoryView StatusDate SubmittedLast Update
0004891OCaml~DO NOT USE (was: OCaml general)public2009-10-13 16:132016-12-07 17:52
Assigned Todoligez 
PlatformOSOS Version
Product Version3.11.1 
Target Version4.05.0 +dev/beta1/beta2/beta3/rc1Fixed in Version 
Summary0004891: provide CAMLreturn macros suitable for callbacks
DescriptionConsider callbacks from C to OCaml. Call to caml_callback in the C wrapper code is surrounded with caml_leave_blocking_section and caml_enter_blocking_section. In case when this C callback manipulates ocaml values, it registers them with CAMLlocal. Consequently one should use CAMLreturn to unregister those values. But both CAMLlocal and CAMLreturn should be called with ocaml runtime lock acquired (to prevent race condition on caml_local_roots). But caml_enter_blocking_section cannot be called after CAMLreturn because the latter actually returns from the function. So one has to wrap the C function into another one which solely manages the runtime lock and passes arguments, like this :

static int progressFunction(void *data,
                            double dlTotal,
                            double dlNow,
                            double ulTotal,
                            double ulNow)
  int r;
  r = progressFunction_nolock(data,dlTotal,dlNow,ulTotal,ulNow);
  return r;

It would be much nicer to have macros like CAML_callback_return and CAML_callback_returnT (and possibly CAML_callback_enter (alias to CAMLparam0?)) to unregister local values, release runtime lock and return.
TagsNo tags attached.
Attached Files

- Relationships

-  Notes
yziquel (reporter)
2010-10-11 04:17

Yes. I have the same issue. I do:

caml_local_roots = caml__frame;

to return from OCaml code into standalone C(++) code.

Moreover, I haven't checked yet, but I'm worried about the caml_local_roots. If caml_local_roots is managed each time there's an OCaml thread context switch, then it's fine. We can just pop up the frames this way.

If not, then how can we be sure that there isn't a race condition? I mean:

-1- thread1: caml_leave_blocking_section
-2- thread1: CAMLparam3();
-3- thread1: caml_callbackN(...);
-4- thread2: CAMLparam2()
-5- thread1: returns from OCaml callback
-6- thread1: caml_local_roots = caml__frame;
-15- thread2: CAMLreturn(...)

The order of -2-, -4-, -6-, -15- seems problematic to me.
doligez (administrator)
2011-05-20 15:52

I think it's better to just add a macro to pop the frame without returning.
ygrek (reporter)
2012-07-08 11:22

Yes, sounds reasonable.
ygrek (reporter)
2013-12-23 07:08
edited on: 2013-12-23 08:09

#define CAMLleave() do{ \
  caml_local_roots = caml__frame; \
}while (0)

Name comes from the observation that CAMLparam0 enters the scope where OCaml values will be introduced with CAMLlocal macros and CAMLleave explicitly leaves that scope

ygrek (reporter)
2015-06-24 23:54

apparently this is fixed by [^]
goswin (reporter)
2016-09-05 12:06


It must be handled by the GC on every thread switch or it wouldn't work. I believe, without checking the source, it must be handled as part of leave/enter blocking section. Makes sense to backup the threads root when entering a blocking section and restoring it when leaving it.
goswin (reporter)
2016-09-05 12:20


I see the patch adds CAMLdrop() to replace the CAMLreturn0(). But that leaves CAMLparam0(). I don't think it is documented anywhere either way so let me make sure:

Does CAMLparam0() have to be the first think in a function? I assume not.

Is this how CAMLdrop() should be used?

    int do_callback(const char *name) {
        int res;
        CAMLlocal2(_name, _res);
        _name = caml_copy_string(name);
        _res = caml_callback1(_func, _name);
        if (Is_exception_result(_res)) {
            // Extract_exception(_res)
        res = Int_val(res);
        return res;

I still think the caml_leave_blocking_section() could be combined with CAMLparam0() and maybe even CAMLlocalX() as mentioned in [^] Same for CAMLdrop() and caml_enter_blocking_section(). This is a pattern every single callback to ocaml needs to repeat.
ygrek (reporter)
2016-09-27 01:46

I think the intention was to keep things explicit and I am happy with current solution. See e.g. [^]
shinwell (developer)
2016-12-07 17:51

Any further discussion can go to 0007340 since the original poster's wishes have been satisfied here, as far as I can tell.

- Issue History
Date Modified Username Field Change
2009-10-13 16:13 ygrek New Issue
2010-10-11 04:17 yziquel Note Added: 0005678
2011-05-20 15:52 doligez Note Added: 0005919
2011-05-20 15:52 doligez Assigned To => doligez
2011-05-20 15:52 doligez Status new => assigned
2012-07-08 11:22 ygrek Note Added: 0007658
2013-12-23 07:08 ygrek Note Added: 0010761
2013-12-23 08:09 ygrek Note Edited: 0010761 View Revisions
2015-06-24 23:54 ygrek Note Added: 0014145
2016-09-05 12:06 goswin Note Added: 0016269
2016-09-05 12:20 goswin Note Added: 0016270
2016-09-07 16:44 shinwell Target Version => 4.05.0 +dev/beta1/beta2/beta3/rc1
2016-09-27 01:46 ygrek Note Added: 0016323
2016-12-07 17:51 shinwell Note Added: 0016749
2016-12-07 17:52 shinwell Status assigned => resolved
2016-12-07 17:52 shinwell Resolution open => fixed
2017-02-23 16:36 doligez Category OCaml general => -OCaml general
2017-03-03 17:55 doligez Category -OCaml general => -(deprecated) general
2017-03-03 18:01 doligez Category -(deprecated) general => ~deprecated (was: OCaml general)
2017-03-06 17:04 doligez Category ~deprecated (was: OCaml general) => ~DO NOT USE (was: OCaml general)

Copyright © 2000 - 2011 MantisBT Group
Powered by Mantis Bugtracker