Version française
Home     About     Download     Resources     Contact us    
Browse thread
Callbacks from C to OCaml
[ Home ] [ Index: by date | by threads ]
[ Search: ]

[ Message by date: previous | next ] [ Message in thread: previous | next ] [ Thread: previous | next ]
Date: -- (:)
From: David Allsopp <dra-news@m...>
Subject: Callbacks from C to OCaml
I'm having some trouble with a library wrapping Windows Services - I'm
wondering if anyone can shed some light on possible pitfalls with the
mechanism for C callbacks while I continue to scratch my head! Although my
problem is with a Windows-based solution my overall question is about
C-callbacks interacting with OCaml so please don't be put off by the Win32
aspect of it :o)

The overall layout is this: the main program is OCaml (i.e. it's an OCaml
program using C-stubs rather than a C-program calling OCaml). The flow of
execution is as follows:

The OCaml program invokes a C-stub which calls the Win32 API function
StartServiceCtrlDespatcher which, amongst other things, takes a pointer to a
C function called ServiceMain. This pointer will be invoked during
StartServiceCtrlDespatcher (synchronously - StartServiceCtrlDespatcher does
not return until the service is stopped) and carries out the following
tasks:

1. It registers a C function with the Windows Service Control Manager (SCM)
called ServiceCtrlHandler which the SCM may callback to *at any time*
2. It does some housekeeping to initialise the service which includes a
call-back to an OCaml function registered by the initial C-stub
3. Assuming success, a call-back is made to another OCaml function. This may
block or it may return immediately.
4. ServiceMain then waits on an event which will only be signalled when the
SCM instructs the service to stop (because ServiceMain is not supposed to
terminate until instructed to). The call to this code is wrapped with
caml_enter_blocking_section and caml_leave_blocking_section (but note that a
particular service may choose to block in the OCaml-land function called in
step 3 instead - the event is just in place to ensure that this is the case)

Now, at any time, the SCM may invoke the ServiceCtrlHandler function
registered with it. This also needs to callback to an OCaml function to work
out what to do (the closure was registered in the initial call).

What happens at this point with regard to OCaml's global lock and being in
the correct threading context? I must confess that I don't fully understand
how the callback works at all in the single-threaded context - presumably
when SCM calls the function, it simply executes code in its own thread
context (so it can presumably introduce a form of multi-threading to a
program which isn't expecting it?).

Should ServiceCtrlHandler (which is only ever invoked from Windows - i.e.
from C-land) be wrapped in the reverse of a blocking construct... i.e.

void WINAPI ServiceCtrlHandler(DWORD Opcode) {
  CAMLparam0(); // The function does allocate...

  caml_leave_blocking_section();

  /* code including caml_callback and caml_alloc_tuple calls */

  caml_enter_blocking_section();

  CAMLreturn0();
}

Can the *_blocking_section functions be used in this way or is there
something else which should be done? My current implementation is flaky - it
works for some services and not for others (and it's very unreliable when
compiled with threading enabled - my current implementation actually cheats
and provides a single-threaded stub application which communicates with a
threaded application via standard input and output to avoid this problem)
which leads to me think that the services which work are probably lucky on
the allocation front and so get away with it and the others essentially
corrupt the runtime and segfault.

Any pointers much appreciated - the manual on C stubs doesn't even mention
the caml_enter_blocking_section/caml_leave_blocking_section functions so
it's sort of a difficult area on which to get information. I'm at this stage
definitely more convinced that it's an error somewhere in my code rather
than the OCaml runtime :o)

Are there any other libraries which contains C stubs handling callbacks in a
similar fashion which I could look at?

Many thanks,


David