Version française
Home     About     Download     Resources     Contact us    
Browse thread
problem creating .cma library
[ Home ] [ Index: by date | by threads ]
[ Search: ]

[ Message by date: previous | next ] [ Message in thread: previous | next ] [ Thread: previous | next ]
Date: -- (:)
From: Guillaume Yziquel <guillaume.yziquel@c...>
Subject: Re: [Caml-list] problem creating .cma library
Richard Jones a écrit :
>
> Why is this a problem?  Because you might in your C code have some
> value on the stack.  'value' is (or can be) a pointer.  The OCaml
> garbage collector can move pointed-to-objects around, firstly from the
> minor heap to the major heap, secondly when compacting the major heap.
> So your C value (pointer) *could* become an invalid pointer if what it
> was pointing to got moved.

Yes, I understood the nature of the problem.

> The way to avoid this small chance is to register the value with the
> garbage collector, which is essentially what the CAMLparam* and
> CAMLlocal* macros do.  So if the GC needs to move that object, it will
> update the pointer for you.
> 
> If your function never allocates (and never calls anything which
> allocates), then you don't need to register values, because no
> allocation => they can't be moved.  [In fact there are some other
> exceptions as well where you can prove that an allocation won't move
> your pointer, eg. if you only allocate one thing and immediately
> return the value.]

I've been looking at the pcre bindings, and these bindings make minimal 
usage of CAMLparam, CAMLlocal and CAMLreturn.

For instance, here is the piece of code that executes R code ad catches 
errors. I've tried to follow guidelines available on the net, and 
inspired myself from pcre.

> CAMLprim value r_eval_sxp (value sexp_list) {
>   CAMLparam0();
>   CAMLlocal2(ml_error_call, ml_error_message);
>   SEXP e;
>   int error = 0;
>   PROTECT(e = R_tryEval(Sexp_val(sexp_list), R_GlobalEnv, &error));
>   UNPROTECT(1);
>   if (error) {
>     ml_error_call = Val_sexp(error_call);
>     error_call = NULL;
>     ml_error_message = caml_copy_string(error_message);
>     error_message = NULL;
>     value error_result = caml_alloc_small(2, 0);
>     Store_field(error_result, 0, ml_error_call);
>     Store_field(error_result, 1, ml_error_message);
>     raise_with_arg(*caml_named_value("OCaml-R generic error"), error_result);
>   }
>   CAMLreturn(Val_sexp(e));
> }

Do you see GC / allocation / threading problems with it?

Would it be legitimate to include CAMLlocal2 inside the error-handling 
braces?

> You might find my series on the garbage collector interesting if you
> want to look into this further:
> 
> http://rwmj.wordpress.com/?s=ocaml+internals

These are very interesting. Could not find part 6, though...

> Also if you are calling C functions which don't allocate from OCaml
> code, you might want to read about noalloc:
> 
> http://camltastic.blogspot.com/2008/08/tip-calling-c-functions-directly-with.html

Two comments on this:

-1- I remember a post by Jon Harrop concerning external mathematical 
functions such as the exponential in Pervasives. He was arguing that it 
could be done directly from the .ml file by using such "tags". Where can 
I find a list of all these tags for external functions? There's "float", 
but are there others?

-2- If I understand this post well, the following function

> CAMLprim value init_r (value argv, value sigs) {
> 
>   /* -1- argv is an OCaml array of strings, which gives the command line
>      arguments used to invoke the R interpreter. Code segfaults if
>      the array does not contain a first element, which is the name of
>      the program, typically "R", or "OCaml-R". Other arguments typically
>      are "--vanilla", "--slave"...
> 
>      -2- sigs is an OCaml int. When set to 0, R signal handlers are not
>      removed. When set to, say, 1, R signal handlers are removed. It is
>      very useful to remove signal handlers when embedding R. */
> 
>   int length = Wosize_val(argv);
>   char* argv2[length];
>   int i;
> 
>   // We duplicate the OCaml array into a C array.
>   for (i=0; i<length; i++) argv2[i]=String_val(Field(argv, i));
> 
>   /* Don't let R set up its own signal handlers when sigs = 1.
>      This requires R >= 2.3.1. */
>   if (Int_val(sigs)) R_SignalHandlers = 0;
> 
>   // This is the libR.so function.
>   i = Rf_initEmbeddedR(length, argv2);
> 
>   // Returns 1 if R is correctly initialised.
>   return Val_int(i);
> }

could be called with "noalloc"?

>> By the way, here's a question I've been wondering about this section. 
>> Rule 3: When I have a Abstract_tag block used to wrap a pointer in the C 
>> heap, it seems to me that you can just do it with a Field(v,0)= 
>> assignment. Do you need Store_field for that?
> 
> This is to do with the Remembered Set.  See part 5 of the above
> series.

The remembere set, in this context, explains why I would need 
Store_field when dealing with pure OCaml world. When wrapping pointers 
to the C heap in abstract blocks, I do not see the point of Store_field, 
and it seems to me that Field= assignment is fine. Am I mistaken?

All the best,

-- 
      Guillaume Yziquel
http://yziquel.homelinux.org/