caml-list - the Caml user's mailing list
 help / color / mirror / Atom feed
* 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;
as well as URLs for NNTP newsgroup(s).