* Using the C FFI to wrap an OCaml library @ 2008-02-06 23:54 Joel Stanley 2008-02-07 22:26 ` [Caml-list] " Damien Doligez 0 siblings, 1 reply; 5+ messages in thread From: Joel Stanley @ 2008-02-06 23:54 UTC (permalink / raw) To: caml-list Hi everyone, I have a couple of questions about the OCaml FFI. I'm attempting to wrap up an existing OCaml library and provide a C API for it, as opposed to the other way around, which seems to be much more common. 1. Can the CAMLparam*/CAMLlocal*/CAMLreturn macros be used to safely carry values of type 'value' between C functions (even C functions that have the appropriate CAMLparam/CAMLreturn invocations present)? I thought this worked, but more extensive testing has yielded some hangs with the stack trace looking like: #0 0x00002b98 in caml_oldify_local_roots () #1 0x00004dd7 in caml_empty_minor_heap () #2 0x00004f28 in caml_minor_collection () #3 0x00003501 in caml_garbage_collection () #4 0x00011888 in caml_call_gc () #5 0x00013577 in run_solver () #6 0x00013cb4 in main () where run_solver here is the C function that is passed an opaque object reference (elided by a value of type 'value') from another C function, and is calling methods repeatedly on the provided object via caml_callback. Looking at the macro expansions, I'm suspicious about the safety between C functions, and wonder if the only way to carry data is use caml_register_global_root (and manage my own memory if I need dynamic allocation). 2. As a follow-up question to #1, the OCaml values may need to be carried across yet another FFI, in this case, C <-> Poly/ML . Even if using the macros was a safe way to carry values between C functions, I"m not sure I can easily replicate the macros on the other side of the FFI, so am wondering if an explicit memory management approach using caml_register_global_root will work. E.g., value* alloc_value() { value* p = malloc(sizeof(value)); caml_register_global_root(p); return p; } Any help is greatly appreciated. -- Joel Stanley ^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [Caml-list] Using the C FFI to wrap an OCaml library 2008-02-06 23:54 Using the C FFI to wrap an OCaml library Joel Stanley @ 2008-02-07 22:26 ` Damien Doligez 2008-02-08 21:53 ` Joel Stanley 0 siblings, 1 reply; 5+ messages in thread From: Damien Doligez @ 2008-02-07 22:26 UTC (permalink / raw) To: caml-list; +Cc: Joel Stanley On 2008-02-07, at 00:54, Joel Stanley wrote: > 1. Can the CAMLparam*/CAMLlocal*/CAMLreturn macros be used to safely > carry values of type 'value' between C functions (even C functions > that > have the appropriate CAMLparam/CAMLreturn invocations present)? Yes, they are designed for that. > I > thought this worked, but more extensive testing has yielded some hangs > with the stack trace looking like: > > #0 0x00002b98 in caml_oldify_local_roots () > #1 0x00004dd7 in caml_empty_minor_heap () > #2 0x00004f28 in caml_minor_collection () > #3 0x00003501 in caml_garbage_collection () > #4 0x00011888 in caml_call_gc () > #5 0x00013577 in run_solver () > #6 0x00013cb4 in main () > > where run_solver here is the C function that is passed an opaque > object > reference (elided by a value of type 'value') from another C function, > and is calling methods repeatedly on the provided object via > caml_callback. This could be anything, the most likely is that you used "return" somewhere instead of "CAMLreturn". > Looking at the macro expansions, I'm suspicious about the safety > between > C functions, Could you elaborate on what makes you say that? The macros carefully implement a stack discipline designed for nested calls. > and wonder if the only way to carry data is use > caml_register_global_root (and manage my own memory if I need dynamic > allocation). You don't want to do that, it would be too inefficient. > 2. As a follow-up question to #1, the OCaml values may need to be > carried across yet another FFI, in this case, C <-> Poly/ML . Even if > using the macros was a safe way to carry values between C functions, > I"m > not sure I can easily replicate the macros on the other side of the > FFI, > so am wondering if an explicit memory management approach using > caml_register_global_root will work. E.g., > > value* alloc_value() { > value* p = malloc(sizeof(value)); > caml_register_global_root(p); > return p; > } In order to make this work, you have to explain to Poly/ML that every access to the value must be done through the value*. Or you need to make sure that Poly/ML code never allocates in the OCaml heap, and never calls back to a C function that does. I think it's more reasonable to just copy the data between worlds instead of trying to share pointers between OCaml and Poly/ML. -- Damien ^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [Caml-list] Using the C FFI to wrap an OCaml library 2008-02-07 22:26 ` [Caml-list] " Damien Doligez @ 2008-02-08 21:53 ` Joel Stanley 2008-02-09 4:07 ` Jonathan Bryant 0 siblings, 1 reply; 5+ messages in thread From: Joel Stanley @ 2008-02-08 21:53 UTC (permalink / raw) To: damien.doligez; +Cc: caml-list >>>>> Damien Doligez writes: >> Looking at the macro expansions, I'm suspicious about the safety between >> C functions, > Could you elaborate on what makes you say that? The macros carefully > implement a stack discipline designed for nested calls. Well, much of my curiosity stems from the fact that I know little about the OCaml runtime or how the OCaml GC is invoked. If the GC can ever be invoked in its own thread, it seems like while the values (of type 'value') are being passed back on the stack (but *after* the caml__local_roots pointer has been reverted) there could be problems? If this can't ever happen, great! Why not? >> 2. As a follow-up question to #1, the OCaml values may need to be >> carried across yet another FFI, in this case, C <-> Poly/ML . Even if >> using the macros was a safe way to carry values between C functions, I"m >> not sure I can easily replicate the macros on the other side of the FFI, >> so am wondering if an explicit memory management approach using >> caml_register_global_root will work. E.g., >> >> value* alloc_value() { >> value* p = malloc(sizeof(value)); >> caml_register_global_root(p); >> return p; >> } > In order to make this work, you have to explain to Poly/ML that every > access to the value must be done through the value*...I think it's > more reasonable to just copy the data between worlds instead of trying > to share pointers between OCaml and Poly/ML. So let's talk about a concrete example here. Let's say that I have some dynamically-allocated object on the OCaml heap (for discussion purposes, say it's an instance of some simple 'stack' class) and that I've returned a reference to that object to a C function. Are you saying that the stack contents (e.g., a deep copy of my object) themselves are marshaled across this boundary every time? What about, perhaps, having an object registration mechanism on the OCaml so that a newly-allocated object's reference goes into a (global) hash table, and an opaque handle (e.g., some fresh, unique integer value) is yielded back to C land? This would require an explicit deallocation (just passing the handle back) to come from the C side, but should keep the heap object around until such a deallocation call is made. Right? Basically, the problem is that I have a large OCaml library that constructs a variety of different types of objects and I would like a 1-1 correspondence between those objects and Poly/ML values that wrap corresponding C volatiles. I'd like to do this in the most straightforward and safe way possible. Thanks for your help, Joel ^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [Caml-list] Using the C FFI to wrap an OCaml library 2008-02-08 21:53 ` Joel Stanley @ 2008-02-09 4:07 ` Jonathan Bryant 2008-02-12 21:58 ` Damien Doligez 0 siblings, 1 reply; 5+ messages in thread From: Jonathan Bryant @ 2008-02-09 4:07 UTC (permalink / raw) To: Joel Stanley; +Cc: Caml Mailing List [-- Attachment #1: Type: text/plain, Size: 904 bytes --] On Fri, Feb 8, 2008 at 4:53 PM, Joel Stanley <jstanley@galois.com> wrote: > > Well, much of my curiosity stems from the fact that I know little about > the OCaml runtime or how the OCaml GC is invoked. If the GC can ever be > invoked in its own thread, it seems like while the values (of type > 'value') are being passed back on the stack (but *after* the > caml__local_roots pointer has been reverted) there could be problems? > > If this can't ever happen, great! Why not? > > I believe GC cycles can only be kicked off by an allocation since this is the only time that any memory would need to be recovered, so this could never happen. As I understand it, any GC cycles would start and complete within the call to the allocation function. Multi threaded code might be an exception, because there could be a context switch and a GC triggered by another thread at just the wrong moment. --Jonathan [-- Attachment #2: Type: text/html, Size: 1262 bytes --] ^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [Caml-list] Using the C FFI to wrap an OCaml library 2008-02-09 4:07 ` Jonathan Bryant @ 2008-02-12 21:58 ` Damien Doligez 0 siblings, 0 replies; 5+ messages in thread From: Damien Doligez @ 2008-02-12 21:58 UTC (permalink / raw) To: Caml Mailing List On 2008-02-09, at 05:07, Jonathan Bryant wrote: > On Fri, Feb 8, 2008 at 4:53 PM, Joel Stanley <jstanley@galois.com> > wrote: > >> Well, much of my curiosity stems from the fact that I know little >> about >> the OCaml runtime or how the OCaml GC is invoked. If the GC can >> ever be >> invoked in its own thread, it seems like while the values (of type >> 'value') are being passed back on the stack (but *after* the >> caml__local_roots pointer has been reverted) there could be problems? >> >> If this can't ever happen, great! Why not? > > > I believe GC cycles can only be kicked off by an allocation since > this is the only time that any memory would need to be recovered, so > this could never happen. As I understand it, any GC cycles would > start and complete within the call to the allocation function. That is true, but there is a more fundamental reason. > Multi threaded code might be an exception, because there could be a > context switch and a GC triggered by another thread at just the > wrong moment. Even if the GC was concurrent, it would have to get the roots from the worker thread's stack in an synchronous fashion, so it would be safe. On 2008-02-08, at 22:53, Joel Stanley wrote: > So let's talk about a concrete example here. Let's say that I have > some > dynamically-allocated object on the OCaml heap (for discussion > purposes, > say it's an instance of some simple 'stack' class) and that I've > returned a reference to that object to a C function. Are you saying > that the stack contents (e.g., a deep copy of my object) themselves > are > marshaled across this boundary every time? No, it's just a pointer, and if your C function allocates in the OCaml heap, you'd better declare that pointer as a root and make sure you reread it after each time it could have moved. > What about, perhaps, having an object registration mechanism on the > OCaml so that a newly-allocated object's reference goes into a > (global) > hash table, and an opaque handle (e.g., some fresh, unique integer > value) is yielded back to C land? This would require an explicit > deallocation (just passing the handle back) to come from the C side, > but > should keep the heap object around until such a deallocation call is > made. Right? This is pretty much what caml_register_global_root and caml_remove_global_root do, except that the handle isn't opaque. -- Damien ^ permalink raw reply [flat|nested] 5+ messages in thread
end of thread, other threads:[~2008-02-12 21:58 UTC | newest] Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed) -- links below jump to the message on this page -- 2008-02-06 23:54 Using the C FFI to wrap an OCaml library Joel Stanley 2008-02-07 22:26 ` [Caml-list] " Damien Doligez 2008-02-08 21:53 ` Joel Stanley 2008-02-09 4:07 ` Jonathan Bryant 2008-02-12 21:58 ` Damien Doligez
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox