caml-list - the Caml user's mailing list
 help / color / mirror / Atom feed
From: Goswin von Brederlow <goswin-v-b@web.de>
To: Joel Reymont <joelr1@gmail.com>
Cc: Gabriel Scherer <gabriel.scherer@gmail.com>,
	Goswin von Brederlow <goswin-v-b@web.de>,
	caml-list@inria.fr
Subject: Re: [Caml-list] using modules to wrap c++ classes
Date: Fri, 04 May 2012 10:43:55 +0200	[thread overview]
Message-ID: <8762ccqqt0.fsf@frosties.localnet> (raw)
In-Reply-To: <CAOQwdX0Hap02NZMW53Mx-bUiP3tOUZPH6tUYQv7fWY3EdSjdcQ@mail.gmail.com> (Joel Reymont's message of "Thu, 3 May 2012 19:41:27 +0100")

Joel Reymont <joelr1@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

  parent reply	other threads:[~2012-05-04  8:44 UTC|newest]

Thread overview: 11+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2012-05-03 12:22 Joel Reymont
2012-05-03 13:35 ` Goswin von Brederlow
2012-05-03 13:56   ` Joel Reymont
2012-05-03 14:27     ` Gabriel Scherer
2012-05-03 15:02       ` Joel Reymont
2012-05-03 18:41         ` Joel Reymont
2012-05-03 19:20           ` Joel Reymont
2012-05-04  8:43           ` Goswin von Brederlow [this message]
2012-05-04 17:23             ` Joel Reymont
2012-05-05 12:39               ` Goswin von Brederlow
2012-05-05 14:11                 ` Joel Reymont

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=8762ccqqt0.fsf@frosties.localnet \
    --to=goswin-v-b@web.de \
    --cc=caml-list@inria.fr \
    --cc=gabriel.scherer@gmail.com \
    --cc=joelr1@gmail.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
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).