I am trying to write a program that will process both Midi and OSC (open sound control) messages. The idea is to generate midi algorithmically and controlling the parameters of the program through OSC messages.
For Midi I/O, I have a wrapper around “jackd” C API and for OSC I use liblo package. Both of these work without issue when they are used separately.
However, I run into problems if I try to combine the two in parallel (using Thread.create & Thread.join).
I think I need threads because both functions are blocking (the OSC receive function (S.recv) blocks until it receives a message, so I cannot call it directly in the Midi generating callback).
let receive_osc_thread () =
let port = 7777 in
let s = S.create port myHandler in
while true do
S.recv s (* this blocks until a message is received, therefore I need the Thread. *)
done
let () =
let t1 = Thread.create midi_thread () in
let t2 = Thread.create receive_osc_thread () in
List.iter Thread.join [t2;t1]
It tends to crash after some time with a “segmentation fault: 11”. I have tried acquiring and releasing the caml runtime (as in: Chapter 20 Interfacing C with OCaml) in various locations of the C code of my Jack Midi client, but cannot get rid of the segfaults.
My question: why do segfaults occur when I combine two threads? Would there be a better way to combine two blocking C calls like this? I have been reading Threads, but feel that maybe my general approach is just not right :-).
As a general remark, one likely reason for a segfault is a bug in your C bindings. When releasing the runtime lock, you must make sure that the runtime is not accessed in any way by any other thread.
Thank you for this advice, I sieved through the C part once again, and after some adjustments, the segfaults have gone away! I’ll keep testing for a few hours to make sure.
Inspired by what I saw in this portaudio package I inserted a call to caml_c_thread_register() at the start of my process callback. “Process” is the function that fills the midi buffer, called by jackd itself at regular intervals. I further added a runtime lock/unlock around a critical section in this process function and this appears to do the trick. I will certainly not claim that I know why or how these additions exactly make it work, but if I remove or change any part of it and the segfaults are back. So for now, I assume this is how it should be done, and burn my time on more enjoyable things, like programming in ocaml itself .
caml_register_global_root(&midi_msg_array_out); // protect this pointer from the Ocaml garbage collector
I am still worried about this making a global root out of a variable on the stack, without any deregistration call. You already have it as a local root, and it should be enough. I am surprised it does not crash.
I’m not quite sure of your exact requirements, but I thought I should mention OCaml portmidi library bindings now exist and will be released to opam in the next few weeks.