Loading ...
Sorry, an error occurred while loading the content.
 

Interfacing Ocaml with global C variables ?

Expand Messages
  • Fabrice Marchant
    Hi List ! I m new to try mixing OCaml and C. Please how to read/write a C global variable from OCaml ? The normal external interfacing way we can use to call C
    Message 1 of 8 , Aug 29, 2008
      Hi List !

      I'm new to try mixing OCaml and C.

      Please how to read/write a C global variable from OCaml ?

      The normal external interfacing way we can use to call C functions doesn't work - getting the error :
      "External identifiers must be functions".

      The way to bypass this could it be to declare two functions :
      - one to read from the C variable and
      - the other to write into it ?

      But maybe is it far more simple or, the opposite way, does this raises some problem with the GC ?

      Thanks for your help,

      Fabrice
    • Richard Jones
      ... The big question is what is the C global? An int? A string? An array? Structure? etc. OCaml cannot just directly access C globals. At best you d need
      Message 2 of 8 , Aug 30, 2008
        On Sat, Aug 30, 2008 at 08:43:19AM +0200, Fabrice Marchant wrote:
        > Please how to read/write a C global variable from OCaml ?

        The big question is what is the C global? An int? A string? An
        array? Structure? etc.

        OCaml cannot just directly access C globals. At best you'd need to
        have a function that returns the address of the C global, _and_ the C
        global would need to be in a form that OCaml code could understand
        although that is pretty easy to arrange.

        The other not so big question is when can the C global change. If it
        changes asynchronously to the OCaml code then I know of no way to
        force OCaml to re-read it (like 'volatile') in C.

        So basically accessor functions are probably your best bet since they
        avoid all of the above issues, they're documented, and reasonably
        simple to write. If the C variable is simple (eg. an int or float)
        then you could even get away with a "noalloc" or "float" external[1]
        which is just a direct call to a C function.

        Rich.

        [1] http://camltastic.blogspot.com/2008/08/tip-calling-c-functions-directly-with.html

        --
        Richard Jones
        Red Hat
      • Florent Monnier
        ... maybe another way than what richard pointed, if you really wish to share a variable between OCaml and C whithout calling a function at each access to the
        Message 3 of 8 , Aug 30, 2008
          > > Please how to read/write a C global variable from OCaml ?

          maybe another way than what richard pointed, if you really wish to share a
          variable between OCaml and C whithout calling a function at each access to
          the variable, could be to make the C global variable a pointer of type value,
          then init this pointer feeding it with the address of your caml identifier,
          then you can use it from C at any time with the convertion macros from
          <caml/mlvalues.h>

          static value * glob_var;

          CAMLprim value init_glob_var(value ml_glob_var) {
          glob_var = & ml_glob_var;
          return Val_unit;
          }

          external init_glob_var : 'a -> unit = "init_glob_var"
          let _ = init_glob_var something ;;

          static void some_c_func(args ...) {
          c_func( Double_val(*glob_var) );
          }

          but then be very carefull from the caml code that the value is not garbage
          collected while still used from C, so maybe better define the identifier at a
          root level and use it in an ignore statment at the end of the code to keep it
          alived, also care if the identifier is used in a functional piece of code
          that ocaml in fact creates new identifiers and the pointer will not follow the
          evolution of it but only the original place.

          in this case maybe a good style could be to use a type reference, and make:
          let _ = init_glob_var something.contents ;;

          Florent
        • Fabrice Marchant
          Thanks a lot for your answer that covers interesting and unexpected points ! On Sat, 30 Aug 2008 10:33:50 +0100 ... Returning only the address of the C global
          Message 4 of 8 , Aug 30, 2008
            Thanks a lot for your answer that covers interesting and unexpected points !

            On Sat, 30 Aug 2008 10:33:50 +0100
            Richard Jones <rich@...> wrote:

            > OCaml cannot just directly access C globals. At best you'd need to
            > have a function that returns the address of the C global, _and_ the C
            > global would need to be in a form that OCaml code could understand
            > although that is pretty easy to arrange.

            Returning only the address of the C global instead of using a read and a write accessor : I do not see the kind of handling OCaml side. Please how to use this technique ?

            > So basically accessor functions are probably your best bet since they
            > avoid all of the above issues, they're documented, and reasonably
            > simple to write.
            > If the C variable is simple (eg. an int or float)
            > then you could even get away with a "noalloc" or "float" external[1]
            > which is just a direct call to a C function.

            > http://camltastic.blogspot.com/2008/08/tip-calling-c-functions-directly-with.html

            Thanks for this optimizing noalloc so easy to use !

            > The big question is what is the C global? An int? A string? An
            > array? Structure? etc.
            In fact I wanted to shift to OCaml the 'nasm' examples about interfacing with C :
            http://www.fifi.org/doc/nasm/examples/
            , files elftest.c and elftest.asm.

            Here is the beginning of the job :
            http://fabrice.marchant.free.fr/exemples/asmCml.tar

            Regards,

            Fabrice
          • Fabrice Marchant
            Thanks a lot Florent for your interesting alternative answers ! However, there are some points I m not sure to understand : On Sat, 30 Aug 2008 16:04:42 +0200
            Message 5 of 8 , Aug 30, 2008
              Thanks a lot Florent for your interesting alternative answers !

              However, there are some points I'm not sure to understand :

              On Sat, 30 Aug 2008 16:04:42 +0200
              Florent Monnier <fmonnier@...> wrote:

              >
              > > > Please how to read/write a C global variable from OCaml ?
              >
              > maybe another way than what richard pointed, if you really wish to share a
              > variable between OCaml and C whithout calling a function at each access to
              > the variable, could be to make the C global variable a pointer of type value,
              > then init this pointer feeding it with the address of your caml identifier,
              > then you can use it from C at any time with the convertion macros from
              > <caml/mlvalues.h>
              Please is it possible to use this pointer for writing too ?

              > static value * glob_var;
              >
              > CAMLprim value init_glob_var(value ml_glob_var) {
              > glob_var = & ml_glob_var;
              > return Val_unit;
              > }
              >
              > external init_glob_var : 'a -> unit = "init_glob_var"
              > let _ = init_glob_var something ;;
              >
              > static void some_c_func(args ...) {
              > c_func( Double_val(*glob_var) );
              > }

              If I've understood a bit, the "Double_val" could be changed to "Int_val" - for instance - for the case 'a is instancied with an int type ?

              > but then be very carefull from the caml code that the value is not garbage
              > collected while still used from C, so maybe better define the identifier at a
              > root level and use it in an ignore statment at the end of the code to keep it
              > alived, also care if the identifier is used in a functional piece of code
              > that ocaml in fact creates new identifiers and the pointer will not follow the
              > evolution of it but only the original place.
              >
              > in this case maybe a good style could be to use a type reference, and make:
              > let _ = init_glob_var something.contents ;;

              A C global variable makes naturally think to an OCaml reference, indeed.

              Do you think there is some efficiency gain with your technique vs r/w variable accessors ?

              Friendly,

              Fabrice
            • Richard Jones
              ... /* Variable shared between C and OCaml. */ #include /* On the OCaml side, this will be made to look like a structure * containing a
              Message 6 of 8 , Aug 30, 2008
                On Sat, Aug 30, 2008 at 04:07:01PM +0200, Fabrice Marchant wrote:
                > On Sat, 30 Aug 2008 10:33:50 +0100
                > Richard Jones <rich@...> wrote:
                > > OCaml cannot just directly access C globals. At best you'd need to
                > > have a function that returns the address of the C global, _and_ the C
                > > global would need to be in a form that OCaml code could understand
                > > although that is pretty easy to arrange.
                >
                > Returning only the address of the C global instead of using a read
                > and a write accessor : I do not see the kind of handling OCaml
                > side. Please how to use this technique ?

                Something like this:

                ------------------------------------------------------------ test_c.c
                /* Variable shared between C and OCaml. */

                #include <caml/mlvalues.h>

                /* On the OCaml side, this will be made to look like a structure
                * containing a single int (well, provided you don't look *too*
                * closely at it).
                */
                value shared_var = Val_int (0);

                value
                get_struct_addr (value unitv)
                {
                /* Return the address of the 'structure'. */
                return ((value) &shared_var);
                }

                /* Increment the shared variable. */
                value
                increment_it (value unitv)
                {
                int i = Int_val (shared_var);
                i++;
                shared_var = Val_int (i);
                return (Val_unit);
                }
                ----------------------------------------------------------------------

                ------------------------------------------------------------ test.ml
                (* Variable shared between C and OCaml. *)

                type var = {
                shared_var : int;
                }

                external get_struct_addr : unit -> var = "get_struct_addr" "noalloc"
                external increment_it : unit -> unit = "increment_it" "noalloc"

                let var = get_struct_addr () ;;

                while true do
                Printf.printf "value of the variable now is %d\n%!" var.shared_var;
                increment_it ();
                (* OCaml isn't expecting that increment_it modifies a variable, so
                * there is no guarantee that we will see the changed value next
                * time around.
                *)
                Unix.sleep 1;
                done
                ----------------------------------------------------------------------

                $ gcc -I /usr/lib/ocaml -c test_c.c
                $ ocamlopt -c test.ml
                $ ocamlopt unix.cmxa test_c.o test.cmx -o test
                $ ./test
                value of the variable now is 0
                value of the variable now is 1
                value of the variable now is 2
                value of the variable now is 3
                value of the variable now is 4
                [etc.]

                Rich.

                --
                Richard Jones
                Red Hat
              • Fabrice Marchant
                Many thanks Rich for this example I needed to understand ! On Sat, 30 Aug 2008 20:56:43 +0100 ... It sounds theoretical because all runs fine. But maybe does
                Message 7 of 8 , Aug 30, 2008
                  Many thanks Rich for this example I needed to understand !

                  On Sat, 30 Aug 2008 20:56:43 +0100
                  Richard Jones <rich@...> wrote:

                  > > I do not see the kind of handling OCaml
                  > > side. Please how to use this technique ?
                  >
                  > Something like this:
                  >
                  > ------------------------------------------------------------ test_c.c
                  > /* Variable shared between C and OCaml. */
                  >
                  > #include <caml/mlvalues.h>
                  >
                  > /* On the OCaml side, this will be made to look like a structure
                  > * containing a single int (well, provided you don't look *too*
                  > * closely at it).
                  > */
                  > value shared_var = Val_int (0);
                  >
                  > value
                  > get_struct_addr (value unitv)
                  > {
                  > /* Return the address of the 'structure'. */
                  > return ((value) &shared_var);
                  > }
                  >
                  > /* Increment the shared variable. */
                  > value
                  > increment_it (value unitv)
                  > {
                  > int i = Int_val (shared_var);
                  > i++;
                  > shared_var = Val_int (i);
                  > return (Val_unit);
                  > }
                  > ----------------------------------------------------------------------
                  >
                  > ------------------------------------------------------------ test.ml
                  > (* Variable shared between C and OCaml. *)
                  >
                  > type var = {
                  > shared_var : int;
                  > }
                  >
                  > external get_struct_addr : unit -> var = "get_struct_addr" "noalloc"
                  > external increment_it : unit -> unit = "increment_it" "noalloc"
                  >
                  > let var = get_struct_addr () ;;
                  >
                  > while true do
                  > Printf.printf "value of the variable now is %d\n%!" var.shared_var;
                  > increment_it ();
                  > (* OCaml isn't expecting that increment_it modifies a variable, so
                  > * there is no guarantee that we will see the changed value next
                  > * time around.
                  > *)
                  > Unix.sleep 1;
                  > done

                  About your warning :
                  > (*OCaml isn't expecting that increment_it modifies a variable, so
                  > * there is no guarantee that we will see the changed value next
                  > * time around.
                  > *)
                  It sounds theoretical because all runs fine.
                  But maybe does it means that in further OCaml versions, for example, we could run into problems ?

                  I'm glad to discover new C mix examples, generally speaking, in this topic because there are not numerous things about the subject : the main pieces apart from INRIA doc I know are Oreilly book and Florent's tutorial :
                  http://www.linux-nantes.org/~fmonnier/OCaml/ocaml-wrapping-c.php

                  Thanks for your time.

                  Regards,

                  Fabrice
                • Richard Jones
                  ... It s possible, although in this case it seems unlikely. ocamlopt compiles very literally, so if you ask it to access a structure member, then it
                  Message 8 of 8 , Aug 31, 2008
                    On Sat, Aug 30, 2008 at 10:16:37PM +0200, Fabrice Marchant wrote:
                    > It sounds theoretical because all runs fine.
                    > But maybe does it means that in further OCaml versions, for example,
                    > we could run into problems ?

                    It's possible, although in this case it seems unlikely. 'ocamlopt'
                    compiles very literally, so if you ask it to access a structure
                    member, then it accesses a structure member each time.

                    Rich.

                    --
                    Richard Jones
                    Red Hat
                  Your message has been successfully submitted and would be delivered to recipients shortly.