Joel Reymont <joe...@gmail.com> writes: > So I ended up with something like this > > --- Callbacks.ml > > type t > > type 'a callback = > | Alert of ('a -> Alert.t -> unit) > | AskQuote of ('a -> Ask.t -> unit) > | BestAskQuote of ('a -> Ask.t -> unit) > | BidQuote of ('a -> Bid.t -> unit) > | BestBidQuote of ('a -> Bid.t -> unit) > | ClosePrice of ('a -> ClosePrice.t -> unit) > | ClosingIndicator of ('a -> ClosingIndicator.t -> unit) > | EndQuote of of ('a -> EndQuote.t -> unit) > | EquityOptionList of of ('a -> EquityOptionList.t -> unit) > | EquityOptionStrategyList of of ('a -> EquityOptionStrategyList.t -> unit) > | HighPrice of ('a -> HighPrice.t -> unit) > | Indicator of ('a -> Indicator.t -> unit) > | IndicatorReplay of ('a -> IndicatorReplay.t -> unit) > | LimitOrderBook of ('a -> LimitOrderBook.t -> unit) > | LowPrice of ('a -> LowPrice.t -> unit) > | MarketMode of ('a -> MarketMode.t -> unit) > | OpenPrice of ('a -> OpenPrice.t -> unit) > ... > > external make : unit -> t = "Callbacks_new" > external set : t -> 'a callback -> unit = "Callbacks_set" > > I now want to grab the closure from the constructor on the C side and > stick it into a callback array. Is this sufficient? > > extern "C" CAMLprim value > Callbacks_set(value v) > { > CAMLparam1(v); > int i = Tag_val(v); > CAMLlocal1(f); > f = Field(0, v); > caml_register_global_root(f); > callbacks[i] = f; > CAMLreturn(Val_unit); > } > > Thanks, Joel
This won't work. The value f is a pointer to a closure block butr that block is under the control of the GC. It will be moved around during compaction and then your callbacks[i] is invalid. As discussed on irc you need to create your callbacks[] array as ocaml block and register that itself as root. That also has the benefit that you only have to register a single root instead of 50. For an example you can look at my libfuse bindings: http://git.ocamlcore.org/cgi-bin/gitweb.cgi?p=libfuse-ocaml/libfuse-ocaml.git;a=tree;f=lib;h=72f44b5090e0d1341d679f52249bbf3974709c1c;hb=HEAD The idea there is to have a ocaml block with callbacks and a custom block with finalizer that contains a pointer to the ocaml block mixed with plain C data. The GC will not inspect the contents of the custom block so the block of callbacks is registered as global root to keep it alive and unregistered in the finalizer. Since you are going to use a static block of calbacks you only need to register the root, it never dies. In my case I use a record containing all callbacks to initialize the C side. With fuse most use cases will set most of the callbacks so having to set each in turn would be more work. I also use Obj.magic 0 to initialize callbacks that are unused. An alternative is to use 'a option types but I decided against that to avoid the extra indirection. Those callbacks get called a lot and speed is relevant. Callbacks can be set as needed and the intended use for this is let my_ops = { default_ops with init = my_init; destroy = my_destroy; } Using the "with" syntx of records one only overrides the callbckas one wishes to use. Changing the code to set callbacks individualy is left as an exercise to the reader. :) MfG Goswin -- Caml-list mailing list. Subscription management and archives: https://sympa-roc.inria.fr/wws/info/caml-list Beginner's list: http://groups.yahoo.com/group/ocaml_beginners Bug reports: http://caml.inria.fr/bin/caml-bugs