caml-list - the Caml user's mailing list
 help / color / mirror / Atom feed
* [Caml-list] Val_int vs caml_copy_nativeint
@ 2011-08-08  3:15 Erik de Castro Lopo
  2011-08-08  3:48 ` Romain Beauxis
                   ` (2 more replies)
  0 siblings, 3 replies; 19+ messages in thread
From: Erik de Castro Lopo @ 2011-08-08  3:15 UTC (permalink / raw)
  To: caml-list

Hi all,

I'm writing a C stub function to allow the calling of a C library
function from ocaml. The return from the stub is a tuple and I'm
doing this:

    /* Package up the result as a tuple. */
    v_response = caml_alloc_tuple (3) ;

    Store_field (v_response, 0, Val_int (width)) ;
    Store_field (v_response, 1, Val_int (height)) ;
    Store_field (v_response, 2, caml_copy_string (code)) ;

    CAMLreturn (v_response) ;

The above works now, but didn't work when I was using
caml_copy_nativeint() instead of Val_int() and I'd like to know
why. I found it especially confusing because caml_copy_string()
worked and was obvioulsy the right thing to do.

Cheers,
Erik
-- 
----------------------------------------------------------------------
Erik de Castro Lopo
http://www.mega-nerd.com/

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [Caml-list] Val_int vs caml_copy_nativeint
  2011-08-08  3:15 [Caml-list] Val_int vs caml_copy_nativeint Erik de Castro Lopo
@ 2011-08-08  3:48 ` Romain Beauxis
  2011-08-08  3:59   ` Guillaume Yziquel
  2011-08-08  3:53 ` Guillaume Yziquel
  2011-08-08  5:20 ` malc
  2 siblings, 1 reply; 19+ messages in thread
From: Romain Beauxis @ 2011-08-08  3:48 UTC (permalink / raw)
  To: caml-list

2011/8/7 Erik de Castro Lopo <mle+ocaml@mega-nerd.com>:
> Hi all,

Hi,

> I'm writing a C stub function to allow the calling of a C library
> function from ocaml. The return from the stub is a tuple and I'm
> doing this:
>
>    /* Package up the result as a tuple. */
>    v_response = caml_alloc_tuple (3) ;
>
>    Store_field (v_response, 0, Val_int (width)) ;
>    Store_field (v_response, 1, Val_int (height)) ;
>    Store_field (v_response, 2, caml_copy_string (code)) ;
>
>    CAMLreturn (v_response) ;
>
> The above works now, but didn't work when I was using
> caml_copy_nativeint() instead of Val_int() and I'd like to know
> why. I found it especially confusing because caml_copy_string()
> worked and was obvioulsy the right thing to do.

Reading very briefly the headers. is seems to me that intnat = value =
long. Could it be that on the arch you're using sizeof(int) <
sizeof(long) ?

Romain


^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [Caml-list] Val_int vs caml_copy_nativeint
  2011-08-08  3:15 [Caml-list] Val_int vs caml_copy_nativeint Erik de Castro Lopo
  2011-08-08  3:48 ` Romain Beauxis
@ 2011-08-08  3:53 ` Guillaume Yziquel
  2011-08-08  7:46   ` Erik de Castro Lopo
  2011-08-08  5:20 ` malc
  2 siblings, 1 reply; 19+ messages in thread
From: Guillaume Yziquel @ 2011-08-08  3:53 UTC (permalink / raw)
  To: caml-list

Le Monday 08 Aug 2011 à 13:15:04 (+1000), Erik de Castro Lopo a écrit :
> Hi all,
> 
> I'm writing a C stub function to allow the calling of a C library
> function from ocaml. The return from the stub is a tuple and I'm
> doing this:
> 
>     /* Package up the result as a tuple. */
>     v_response = caml_alloc_tuple (3) ;
> 
>     Store_field (v_response, 0, Val_int (width)) ;
>     Store_field (v_response, 1, Val_int (height)) ;
>     Store_field (v_response, 2, caml_copy_string (code)) ;
> 
>     CAMLreturn (v_response) ;
> 
> The above works now, but didn't work when I was using
> caml_copy_nativeint() instead of Val_int() and I'd like to know
> why. I found it especially confusing because caml_copy_string()
> worked and was obvioulsy the right thing to do.

Did you use CAMLlocal on v_response? Why don't you use some intermediate
variable to store the result of caml_copy_nativeint beforehand and then use
Store_field (or even a Field () = assignment with caml_alloc_small this case)?

Judging by the code of caml_copy_nativeint in ints.c:

	CAMLexport value caml_copy_nativeint(intnat i)
	{
	  value res = caml_alloc_custom(&caml_nativeint_ops, sizeof(intnat), 0, 1);
	  Nativeint_val(res) = i;
	  return res;
	}

and of Store_field in memory.h

	#define Store_field(block, offset, val) do{ \
	  mlsize_t caml__temp_offset = (offset); \
	  value caml__temp_val = (val); \
	  caml_modify (&Field ((block), caml__temp_offset), caml__temp_val); \
	}while(0)

I do not see why that wouldn't work if CAMLlocal is properly used on
v_response. If it's not properly used, you may be invalidating the
v_response pointer when evaluating caml_copy_nativeint in the line

	value caml__temp_val = (val);

Other than that, I do not really see an issue with your code.

What do you mean by "doesn't work" precisely?

> Cheers,
> Erik

-- 
     Guillaume Yziquel


^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [Caml-list] Val_int vs caml_copy_nativeint
  2011-08-08  3:48 ` Romain Beauxis
@ 2011-08-08  3:59   ` Guillaume Yziquel
  2011-08-08  7:49     ` Erik de Castro Lopo
  0 siblings, 1 reply; 19+ messages in thread
From: Guillaume Yziquel @ 2011-08-08  3:59 UTC (permalink / raw)
  To: Romain Beauxis; +Cc: caml-list

Le Sunday 07 Aug 2011 à 22:48:08 (-0500), Romain Beauxis a écrit :
> 2011/8/7 Erik de Castro Lopo <mle+ocaml@mega-nerd.com>:
> > Hi all,
> 
> Hi,
> 
> > I'm writing a C stub function to allow the calling of a C library
> > function from ocaml. The return from the stub is a tuple and I'm
> > doing this:
> >
> >    /* Package up the result as a tuple. */
> >    v_response = caml_alloc_tuple (3) ;
> >
> >    Store_field (v_response, 0, Val_int (width)) ;
> >    Store_field (v_response, 1, Val_int (height)) ;
> >    Store_field (v_response, 2, caml_copy_string (code)) ;
> >
> >    CAMLreturn (v_response) ;
> >
> > The above works now, but didn't work when I was using
> > caml_copy_nativeint() instead of Val_int() and I'd like to know
> > why. I found it especially confusing because caml_copy_string()
> > worked and was obvioulsy the right thing to do.
> 
> Reading very briefly the headers. is seems to me that intnat = value =
> long. Could it be that on the arch you're using sizeof(int) <
> sizeof(long) ?
> 
> Romain

Given that Val_int is Val_long (in mlvalues.h):

	#define Val_int(x) Val_long(x)

it's not an issue with this piece of code.

But depending on what "doesn't work" means and on the declarations of
width and height, then sizeof(int) < sizeof(long) may explain the issue.

-- 
     Guillaume Yziquel


^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [Caml-list] Val_int vs caml_copy_nativeint
  2011-08-08  3:15 [Caml-list] Val_int vs caml_copy_nativeint Erik de Castro Lopo
  2011-08-08  3:48 ` Romain Beauxis
  2011-08-08  3:53 ` Guillaume Yziquel
@ 2011-08-08  5:20 ` malc
  2011-08-08  6:01   ` Guillaume Yziquel
  2 siblings, 1 reply; 19+ messages in thread
From: malc @ 2011-08-08  5:20 UTC (permalink / raw)
  To: caml-list

On Mon, 8 Aug 2011, Erik de Castro Lopo wrote:

> Hi all,
> 
> I'm writing a C stub function to allow the calling of a C library
> function from ocaml. The return from the stub is a tuple and I'm
> doing this:
> 
>     /* Package up the result as a tuple. */
>     v_response = caml_alloc_tuple (3) ;
> 
>     Store_field (v_response, 0, Val_int (width)) ;
>     Store_field (v_response, 1, Val_int (height)) ;
>     Store_field (v_response, 2, caml_copy_string (code)) ;
> 
>     CAMLreturn (v_response) ;
> 
> The above works now, but didn't work when I was using
> caml_copy_nativeint() instead of Val_int() and I'd like to know
> why. I found it especially confusing because caml_copy_string()
> worked and was obvioulsy the right thing to do.

18.5.2

Rule 5 

After a structured block (a block with tag less than No_scan_tag) 
is allocated with the low-level functions, all fields of this block must
be filled with well-formed values before the next allocation operation. If
the block has been allocated with  caml_alloc_small, filling is performed
by direct assignment to the fields of the block:
Field(v, n) = vn;
...

I'd say rule 5 has been violated here.

Why it "works" one way and doesn't work the other is the question to
Damien i suppose.

-- 
mailto:av1474@comtv.ru

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [Caml-list] Val_int vs caml_copy_nativeint
  2011-08-08  5:20 ` malc
@ 2011-08-08  6:01   ` Guillaume Yziquel
  2011-08-08  6:22     ` malc
  0 siblings, 1 reply; 19+ messages in thread
From: Guillaume Yziquel @ 2011-08-08  6:01 UTC (permalink / raw)
  To: malc; +Cc: caml-list

Le Monday 08 Aug 2011 à 09:20:17 (+0400), malc a écrit :
> On Mon, 8 Aug 2011, Erik de Castro Lopo wrote:
> 
> > Hi all,
> > 
> > I'm writing a C stub function to allow the calling of a C library
> > function from ocaml. The return from the stub is a tuple and I'm
> > doing this:
> > 
> >     /* Package up the result as a tuple. */
> >     v_response = caml_alloc_tuple (3) ;
> > 
> >     Store_field (v_response, 0, Val_int (width)) ;
> >     Store_field (v_response, 1, Val_int (height)) ;
> >     Store_field (v_response, 2, caml_copy_string (code)) ;
> > 
> >     CAMLreturn (v_response) ;
> > 
> > The above works now, but didn't work when I was using
> > caml_copy_nativeint() instead of Val_int() and I'd like to know
> > why. I found it especially confusing because caml_copy_string()
> > worked and was obvioulsy the right thing to do.
> 
> 18.5.2
> 
> Rule 5 
> 
> After a structured block (a block with tag less than No_scan_tag) 
> is allocated with the low-level functions, all fields of this block must
> be filled with well-formed values before the next allocation operation. If
> the block has been allocated with  caml_alloc_small, filling is performed
> by direct assignment to the fields of the block:
> Field(v, n) = vn;
> ...
> 
> I'd say rule 5 has been violated here.

No. caml_alloc_tuple is considered to be part of the simplified
interface, not part of the low-level interface. Rule 5 shouldn't apply
in this case.

One of the reasons for rule 5 is that the contents of the allocated
block may not satisfy GC constraints. So you should not allocate with
the blocks item pointing to inconsistent garbage as the GC may the run
over them.

	18.4.4

	caml_alloc(n, t) returns a fresh block of size n with tag t.
	If t is less than No_scan_tag, then the fields of the block
	are initialized with a valid value in order to satisfy the
	GC constraints.

In caml_alloc function in alloc.c:

	    if (tag < No_scan_tag){
	      for (i = 0; i < wosize; i++) Field (result, i) = 0;
	    }

and caml_alloc_tuple is roughly caml_alloc (in alloc.c) so definitely
part of the simplified interface:

	CAMLexport value caml_alloc_tuple(mlsize_t n)
	{
	  return caml_alloc(n, 0);
	}

-- 
     Guillaume Yziquel


^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [Caml-list] Val_int vs caml_copy_nativeint
  2011-08-08  6:01   ` Guillaume Yziquel
@ 2011-08-08  6:22     ` malc
  0 siblings, 0 replies; 19+ messages in thread
From: malc @ 2011-08-08  6:22 UTC (permalink / raw)
  To: Guillaume Yziquel; +Cc: caml-list

On Mon, 8 Aug 2011, Guillaume Yziquel wrote:

> Le Monday 08 Aug 2011 ? 09:20:17 (+0400), malc a ?crit :
> > On Mon, 8 Aug 2011, Erik de Castro Lopo wrote:
> > 
> > > Hi all,
> > > 
> > > I'm writing a C stub function to allow the calling of a C library
> > > function from ocaml. The return from the stub is a tuple and I'm
> > > doing this:
> > > 
> > >     /* Package up the result as a tuple. */
> > >     v_response = caml_alloc_tuple (3) ;
> > > 
> > >     Store_field (v_response, 0, Val_int (width)) ;
> > >     Store_field (v_response, 1, Val_int (height)) ;
> > >     Store_field (v_response, 2, caml_copy_string (code)) ;
> > > 
> > >     CAMLreturn (v_response) ;
> > > 
> > > The above works now, but didn't work when I was using
> > > caml_copy_nativeint() instead of Val_int() and I'd like to know
> > > why. I found it especially confusing because caml_copy_string()
> > > worked and was obvioulsy the right thing to do.
> > 
> > 18.5.2
> > 
> > Rule 5 
> > 
> > After a structured block (a block with tag less than No_scan_tag) 
> > is allocated with the low-level functions, all fields of this block must
> > be filled with well-formed values before the next allocation operation. If
> > the block has been allocated with  caml_alloc_small, filling is performed
> > by direct assignment to the fields of the block:
> > Field(v, n) = vn;
> > ...
> > 
> > I'd say rule 5 has been violated here.
> 
> No. caml_alloc_tuple is considered to be part of the simplified
> interface, not part of the low-level interface. Rule 5 shouldn't apply
> in this case.
> 
> One of the reasons for rule 5 is that the contents of the allocated
> block may not satisfy GC constraints. So you should not allocate with
> the blocks item pointing to inconsistent garbage as the GC may the run
> over them.
> 
> 	18.4.4
> 
> 	caml_alloc(n, t) returns a fresh block of size n with tag t.
> 	If t is less than No_scan_tag, then the fields of the block
> 	are initialized with a valid value in order to satisfy the
> 	GC constraints.
> 
> In caml_alloc function in alloc.c:
> 
> 	    if (tag < No_scan_tag){
> 	      for (i = 0; i < wosize; i++) Field (result, i) = 0;
> 	    }
> 
> and caml_alloc_tuple is roughly caml_alloc (in alloc.c) so definitely
> part of the simplified interface:
> 
> 	CAMLexport value caml_alloc_tuple(mlsize_t n)
> 	{
> 	  return caml_alloc(n, 0);
> 	}
> 
> 

I stand corrected.

-- 
mailto:av1474@comtv.ru

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [Caml-list] Val_int vs caml_copy_nativeint
  2011-08-08  3:53 ` Guillaume Yziquel
@ 2011-08-08  7:46   ` Erik de Castro Lopo
  2011-08-08  8:03     ` Guillaume Yziquel
  0 siblings, 1 reply; 19+ messages in thread
From: Erik de Castro Lopo @ 2011-08-08  7:46 UTC (permalink / raw)
  To: caml-list

Guillaume Yziquel wrote:

> What do you mean by "doesn't work" precisely?

The integer value I assign in the C file (and print out for a
sanity check) ends up as what looks like an address in the 
Ocaml code.

Erik
-- 
----------------------------------------------------------------------
Erik de Castro Lopo
http://www.mega-nerd.com/

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [Caml-list] Val_int vs caml_copy_nativeint
  2011-08-08  3:59   ` Guillaume Yziquel
@ 2011-08-08  7:49     ` Erik de Castro Lopo
  0 siblings, 0 replies; 19+ messages in thread
From: Erik de Castro Lopo @ 2011-08-08  7:49 UTC (permalink / raw)
  To: caml-list

Guillaume Yziquel wrote:

> Given that Val_int is Val_long (in mlvalues.h):
> 
> 	#define Val_int(x) Val_long(x)
> 
> it's not an issue with this piece of code.
> 
> But depending on what "doesn't work" means and on the declarations of
> width and height, then sizeof(int) < sizeof(long) may explain the issue.


The width and height variables are both defined as int and I'm working
on 32 bit Linux.

Doesn't work means I don't get the value I think I should (small integers
in the range [16, 144]) but rather gte values that look more like pointers.

Erik
-- 
----------------------------------------------------------------------
Erik de Castro Lopo
http://www.mega-nerd.com/

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [Caml-list] Val_int vs caml_copy_nativeint
  2011-08-08  7:46   ` Erik de Castro Lopo
@ 2011-08-08  8:03     ` Guillaume Yziquel
  2011-08-08  9:17       ` Mathias Kende
  2011-08-08 17:24       ` Xavier Leroy
  0 siblings, 2 replies; 19+ messages in thread
From: Guillaume Yziquel @ 2011-08-08  8:03 UTC (permalink / raw)
  To: caml-list

Le Monday 08 Aug 2011 à 17:46:19 (+1000), Erik de Castro Lopo a écrit :
> Guillaume Yziquel wrote:
> 
> > What do you mean by "doesn't work" precisely?
> 
> The integer value I assign in the C file (and print out for a
> sanity check) ends up as what looks like an address in the 
> Ocaml code.
> 
> Erik

Then I do not see anything wrong if the code snippet you sent. However,
when you change Val_int to caml_copy_nativeint, the layout of the tuple
is different.

With Val_int, you have an integral value in the tuple's field.

With caml_copy_nativeint, you have a pointer in the tuple's field.

So if you keep the same OCaml code when reading the result value, it's
no surprise that the pointer is shown in place of the integer you
expected.

But this is just guessing.

-- 
     Guillaume Yziquel


^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [Caml-list] Val_int vs caml_copy_nativeint
  2011-08-08  8:03     ` Guillaume Yziquel
@ 2011-08-08  9:17       ` Mathias Kende
  2011-08-08 17:24       ` Xavier Leroy
  1 sibling, 0 replies; 19+ messages in thread
From: Mathias Kende @ 2011-08-08  9:17 UTC (permalink / raw)
  To: caml-list

Le lundi 08 août 2011 à 10:03 +0200, Guillaume Yziquel a écrit :
> With Val_int, you have an integral value in the tuple's field.
> 
> With caml_copy_nativeint, you have a pointer in the tuple's field.

More explicitly, Val_int creates you a value of type int in the OCaml
world, while caml_copy_nativeint creates you a value of type natint in
the OCaml world. That's why you have two different "functions" in the
first place.

natints (and strings) are allocated blocks in OCaml so you need to copy
the data from the C world to some place in OCaml heap. Hence the
caml_copy_... function. You don not need such function for ints which
are directly stored in the value variable.

Mathias



^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [Caml-list] Val_int vs caml_copy_nativeint
  2011-08-08  8:03     ` Guillaume Yziquel
  2011-08-08  9:17       ` Mathias Kende
@ 2011-08-08 17:24       ` Xavier Leroy
  2011-08-09  1:33         ` Erik de Castro Lopo
  1 sibling, 1 reply; 19+ messages in thread
From: Xavier Leroy @ 2011-08-08 17:24 UTC (permalink / raw)
  To: caml-list

On 08/08/2011 10:03 AM, Guillaume Yziquel wrote:

> Then I do not see anything wrong if the code snippet you sent. However,
> when you change Val_int to caml_copy_nativeint, the layout of the tuple
> is different. [...] So if you keep the same OCaml code when reading
> the result value, it's no surprise that the pointer is shown in
> place of the integer you expected.

This is good advice indeed: make sure your Caml type declaration
matches the data representation that your Caml/C stub implements...

>    /* Package up the result as a tuple. */
>    v_response = caml_alloc_tuple (3) ;
>    Store_field (v_response, 0, Val_int (width)) ;
>    Store_field (v_response, 1, Val_int (height)) ;
>    Store_field (v_response, 2, caml_copy_string (code)) ;
>    CAMLreturn (v_response) ;

Additionally, do make sure that "v_response" is registered with the GC
(declared with one of the CAMLlocal macros).

If both conditions are met, your code should be all right.  If it
still misbehaves, feel free to post a repro case on the bug tracker
http://caml.inria.fr/mantis

- Xavier Leroy

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [Caml-list] Val_int vs caml_copy_nativeint
  2011-08-08 17:24       ` Xavier Leroy
@ 2011-08-09  1:33         ` Erik de Castro Lopo
  2011-08-09  1:40           ` Romain Beauxis
                             ` (2 more replies)
  0 siblings, 3 replies; 19+ messages in thread
From: Erik de Castro Lopo @ 2011-08-09  1:33 UTC (permalink / raw)
  To: caml-list

Xavier Leroy wrote:

> On 08/08/2011 10:03 AM, Guillaume Yziquel wrote:
> 
> > Then I do not see anything wrong if the code snippet you sent. However,
> > when you change Val_int to caml_copy_nativeint, the layout of the tuple
> > is different. [...] So if you keep the same OCaml code when reading
> > the result value, it's no surprise that the pointer is shown in
> > place of the integer you expected.
> 
> This is good advice indeed: make sure your Caml type declaration
> matches the data representation that your Caml/C stub implements...
> 
> >    /* Package up the result as a tuple. */
> >    v_response = caml_alloc_tuple (3) ;
> >    Store_field (v_response, 0, Val_int (width)) ;
> >    Store_field (v_response, 1, Val_int (height)) ;
> >    Store_field (v_response, 2, caml_copy_string (code)) ;
> >    CAMLreturn (v_response) ;
> 
> Additionally, do make sure that "v_response" is registered with the GC
> (declared with one of the CAMLlocal macros).

This is strange, it wasn't declared with a CAMLlocal macro and it
was working, but if I do declare it with one the program segfaults
during garbage collection (caml_oldify_local_roots).

The program is small, so I've included the working version of the
C stub code below. In the Ocaml code I have:

    external iec16022ecc200 :
	int -> (* size *)
	string -> (* code *)
	(int * int * string) = "caml_iec16022ecc200"

The C stub code below works. If I change "value v_response" to
"CAMLlocal1 (v_response)" it segfaults. If I use caml_copy_nativeint()
instead of Val_int when I'm preparing the v_response tuple I get what
looks like a pointer instead of the small integer (ie [16, 160] range)
I was expecting.

Cheers,
Erik

#include <caml/mlvalues.h>
#include <caml/alloc.h>
#include <caml/memory.h>
#include <caml/custom.h>
#include <caml/fail.h>
#include <caml/callback.h>
#include <caml/bigarray.h>

#include <stdio.h>
#include <string.h>
#include <assert.h>

#include <iec16022ecc200.h>


typedef union
{	unsigned char * u ;
    signed char * s ;
    char * c ;
} flexi_char_ptr_t ;


CAMLprim value
caml_iec16022ecc200 (value v_size, value v_code)
{	unsigned char buffer [2048] ;
	flexi_char_ptr_t code, barcode ;
	int width, height, k ;
	value v_response ;

	CAMLparam2 (v_size, v_code) ;

	width = height = Int_val (v_size) ;
	code.c = String_val (v_code) ;

	barcode.u = iec16022ecc200 (&width, &height, NULL, strlen (code.c), code.u, NULL, NULL, NULL) ;

	if (barcode.u == NULL)
	{	failwith ("iec16022ecc200 failed") ;
		fprintf (stderr, "%s %d: Should never get here.\n", __FILE__, __LINE__) ;
		exit (1) ;
		} ;

	/* Sanity check the buffer size. */
	assert (width * height < (int) sizeof (buffer) - 1) ;

	/* Need to convert the resulting 0x00 and 0x01 byte string to a text
	 * string that we can pass back to Ocaml. */
	for (k = 0 ; k < width * height ; k++)
		buffer [k] = barcode.c [k] ? '1' : '0' ;

	/* Make sure buffer is string terminated. */
	buffer [width * height] = 0 ;

	/* Free the memory allocated by iec16022ecc200(). */
	free (barcode.u) ;

	barcode.u = buffer ;

	/* Package up the result as a tuple. */
	v_response = caml_alloc_tuple (3) ;

	Store_field (v_response, 0, Val_int (width)) ;
	Store_field (v_response, 1, Val_int (height)) ;
	Store_field (v_response, 2, caml_copy_string (barcode.c)) ;

    CAMLreturn (v_response) ;
} /* caml_iec16022ecc200 */



-- 
----------------------------------------------------------------------
Erik de Castro Lopo
http://www.mega-nerd.com/

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [Caml-list] Val_int vs caml_copy_nativeint
  2011-08-09  1:33         ` Erik de Castro Lopo
@ 2011-08-09  1:40           ` Romain Beauxis
  2011-08-09  8:44           ` David Allsopp
  2011-08-09 22:53           ` Erik de Castro Lopo
  2 siblings, 0 replies; 19+ messages in thread
From: Romain Beauxis @ 2011-08-09  1:40 UTC (permalink / raw)
  To: caml-list

2011/8/8 Erik de Castro Lopo <mle+ocaml@mega-nerd.com>:
> Xavier Leroy wrote:
>
>> On 08/08/2011 10:03 AM, Guillaume Yziquel wrote:
>>
>> > Then I do not see anything wrong if the code snippet you sent. However,
>> > when you change Val_int to caml_copy_nativeint, the layout of the tuple
>> > is different. [...] So if you keep the same OCaml code when reading
>> > the result value, it's no surprise that the pointer is shown in
>> > place of the integer you expected.
>>
>> This is good advice indeed: make sure your Caml type declaration
>> matches the data representation that your Caml/C stub implements...
>>
>> >    /* Package up the result as a tuple. */
>> >    v_response = caml_alloc_tuple (3) ;
>> >    Store_field (v_response, 0, Val_int (width)) ;
>> >    Store_field (v_response, 1, Val_int (height)) ;
>> >    Store_field (v_response, 2, caml_copy_string (code)) ;
>> >    CAMLreturn (v_response) ;
>>
>> Additionally, do make sure that "v_response" is registered with the GC
>> (declared with one of the CAMLlocal macros).
>
> This is strange, it wasn't declared with a CAMLlocal macro and it
> was working, but if I do declare it with one the program segfaults
> during garbage collection (caml_oldify_local_roots).
>
> The program is small, so I've included the working version of the
> C stub code below. In the Ocaml code I have:
>
>    external iec16022ecc200 :
>        int -> (* size *)
>        string -> (* code *)
>        (int * int * string) = "caml_iec16022ecc200"
>
> The C stub code below works. If I change "value v_response" to
> "CAMLlocal1 (v_response)" it segfaults. If I use caml_copy_nativeint()
> instead of Val_int when I'm preparing the v_response tuple I get what
> looks like a pointer instead of the small integer (ie [16, 160] range)
> I was expecting.
>
> Cheers,
> Erik
>
> #include <caml/mlvalues.h>
> #include <caml/alloc.h>
> #include <caml/memory.h>
> #include <caml/custom.h>
> #include <caml/fail.h>
> #include <caml/callback.h>
> #include <caml/bigarray.h>
>
> #include <stdio.h>
> #include <string.h>
> #include <assert.h>
>
> #include <iec16022ecc200.h>
>
>
> typedef union
> {       unsigned char * u ;
>    signed char * s ;
>    char * c ;
> } flexi_char_ptr_t ;
>
>
> CAMLprim value
> caml_iec16022ecc200 (value v_size, value v_code)
> {       unsigned char buffer [2048] ;
>        flexi_char_ptr_t code, barcode ;
>        int width, height, k ;
>        value v_response ;

This look odd to me. I always place CAMLParam and CAMLlocal
declarations are the very beginning of the code.. Don't know if this
matters here but perhaps..

>        CAMLparam2 (v_size, v_code) ;
>
>        width = height = Int_val (v_size) ;
>        code.c = String_val (v_code) ;
>
>        barcode.u = iec16022ecc200 (&width, &height, NULL, strlen (code.c), code.u, NULL, NULL, NULL) ;
>
>        if (barcode.u == NULL)
>        {       failwith ("iec16022ecc200 failed") ;
>                fprintf (stderr, "%s %d: Should never get here.\n", __FILE__, __LINE__) ;
>                exit (1) ;
>                } ;
>
>        /* Sanity check the buffer size. */
>        assert (width * height < (int) sizeof (buffer) - 1) ;
>
>        /* Need to convert the resulting 0x00 and 0x01 byte string to a text
>         * string that we can pass back to Ocaml. */
>        for (k = 0 ; k < width * height ; k++)
>                buffer [k] = barcode.c [k] ? '1' : '0' ;
>
>        /* Make sure buffer is string terminated. */
>        buffer [width * height] = 0 ;
>
>        /* Free the memory allocated by iec16022ecc200(). */
>        free (barcode.u) ;
>
>        barcode.u = buffer ;
>
>        /* Package up the result as a tuple. */
>        v_response = caml_alloc_tuple (3) ;
>
>        Store_field (v_response, 0, Val_int (width)) ;
>        Store_field (v_response, 1, Val_int (height)) ;
>        Store_field (v_response, 2, caml_copy_string (barcode.c)) ;
>
>    CAMLreturn (v_response) ;
> } /* caml_iec16022ecc200 */

Romain


^ permalink raw reply	[flat|nested] 19+ messages in thread

* RE: [Caml-list] Val_int vs caml_copy_nativeint
  2011-08-09  1:33         ` Erik de Castro Lopo
  2011-08-09  1:40           ` Romain Beauxis
@ 2011-08-09  8:44           ` David Allsopp
  2011-08-09 10:07             ` malc
  2011-08-09 22:53           ` Erik de Castro Lopo
  2 siblings, 1 reply; 19+ messages in thread
From: David Allsopp @ 2011-08-09  8:44 UTC (permalink / raw)
  To: caml-list

Erik de Castro Lopo wrote:
> Xavier Leroy wrote:
> 
> > On 08/08/2011 10:03 AM, Guillaume Yziquel wrote:
> >
> > > Then I do not see anything wrong if the code snippet you sent.
> > > However, when you change Val_int to caml_copy_nativeint, the layout
> > > of the tuple is different. [...] So if you keep the same OCaml code
> > > when reading the result value, it's no surprise that the pointer is
> > > shown in place of the integer you expected.
> >
> > This is good advice indeed: make sure your Caml type declaration
> > matches the data representation that your Caml/C stub implements...
> >
> > >    /* Package up the result as a tuple. */
> > >    v_response = caml_alloc_tuple (3) ;
> > >    Store_field (v_response, 0, Val_int (width)) ;
> > >    Store_field (v_response, 1, Val_int (height)) ;
> > >    Store_field (v_response, 2, caml_copy_string (code)) ;
> > >    CAMLreturn (v_response) ;
> >
> > Additionally, do make sure that "v_response" is registered with the GC
> > (declared with one of the CAMLlocal macros).
> 
> This is strange, it wasn't declared with a CAMLlocal macro and it was
> working, but if I do declare it with one the program segfaults during
> garbage collection (caml_oldify_local_roots).

If you altered this but left the program exactly the same then you violated rule 1 in 18.5.1 of the manual: CAMLparamn must come first. The result is predictable - you attempt to allocate a local variable before the local root is properly initialised...

That said, in your specific example, my understanding is that it should be OK not using CAMLlocal because you return v_response with CAMLreturn before the GC could be triggered (no allocations or callbacks between caml_alloc_tuple and CAMLreturn). Whether that's a) correct and b) sensible (i.e. whether the performance "boost" justifies the commenting needed in the code to explain how brittle it is) is another matter!


David


^ permalink raw reply	[flat|nested] 19+ messages in thread

* RE: [Caml-list] Val_int vs caml_copy_nativeint
  2011-08-09  8:44           ` David Allsopp
@ 2011-08-09 10:07             ` malc
  2011-08-09 10:43               ` David Allsopp
  0 siblings, 1 reply; 19+ messages in thread
From: malc @ 2011-08-09 10:07 UTC (permalink / raw)
  To: David Allsopp; +Cc: caml-list

On Tue, 9 Aug 2011, David Allsopp wrote:

> Erik de Castro Lopo wrote:
> > Xavier Leroy wrote:
> > 
> > > On 08/08/2011 10:03 AM, Guillaume Yziquel wrote:
> > >
> > > > Then I do not see anything wrong if the code snippet you sent.
> > > > However, when you change Val_int to caml_copy_nativeint, the layout
> > > > of the tuple is different. [...] So if you keep the same OCaml code
> > > > when reading the result value, it's no surprise that the pointer is
> > > > shown in place of the integer you expected.
> > >
> > > This is good advice indeed: make sure your Caml type declaration
> > > matches the data representation that your Caml/C stub implements...
> > >
> > > >    /* Package up the result as a tuple. */
> > > >    v_response = caml_alloc_tuple (3) ;
> > > >    Store_field (v_response, 0, Val_int (width)) ;
> > > >    Store_field (v_response, 1, Val_int (height)) ;
> > > >    Store_field (v_response, 2, caml_copy_string (code)) ;
> > > >    CAMLreturn (v_response) ;
> > >
> > > Additionally, do make sure that "v_response" is registered with the GC
> > > (declared with one of the CAMLlocal macros).
> > 
> > This is strange, it wasn't declared with a CAMLlocal macro and it was
> > working, but if I do declare it with one the program segfaults during
> > garbage collection (caml_oldify_local_roots).
> 
> If you altered this but left the program exactly the same then you violated rule 1 in 18.5.1 of the manual: CAMLparamn must come first. The result is predictable - you attempt to allocate a local variable before the local root is properly initialised...
> 
> That said, in your specific example, my understanding is that it should 
> be OK not using CAMLlocal because you return v_response with CAMLreturn 
> before the GC could be triggered (no allocations or callbacks between 
> caml_alloc_tuple and CAMLreturn). 

I'm puzzled by this, caml_copy_string does allocation..

> Whether that's a) correct and b) 
> sensible (i.e. whether the performance "boost" justifies the commenting 
> needed in the code to explain how brittle it is) is another matter!
> 
> 
> David
> 
> 
> 

-- 
mailto:av1474@comtv.ru

^ permalink raw reply	[flat|nested] 19+ messages in thread

* RE: [Caml-list] Val_int vs caml_copy_nativeint
  2011-08-09 10:07             ` malc
@ 2011-08-09 10:43               ` David Allsopp
  0 siblings, 0 replies; 19+ messages in thread
From: David Allsopp @ 2011-08-09 10:43 UTC (permalink / raw)
  To: malc; +Cc: caml-list

malc wrote:
> On Tue, 9 Aug 2011, David Allsopp wrote:
> 
> > Erik de Castro Lopo wrote:
> > > Xavier Leroy wrote:
> > >
> > > > On 08/08/2011 10:03 AM, Guillaume Yziquel wrote:
> > > >
> > > > > Then I do not see anything wrong if the code snippet you sent.
> > > > > However, when you change Val_int to caml_copy_nativeint, the
> > > > > layout of the tuple is different. [...] So if you keep the same
> > > > > OCaml code when reading the result value, it's no surprise that
> > > > > the pointer is shown in place of the integer you expected.
> > > >
> > > > This is good advice indeed: make sure your Caml type declaration
> > > > matches the data representation that your Caml/C stub implements...
> > > >
> > > > >    /* Package up the result as a tuple. */
> > > > >    v_response = caml_alloc_tuple (3) ;
> > > > >    Store_field (v_response, 0, Val_int (width)) ;
> > > > >    Store_field (v_response, 1, Val_int (height)) ;
> > > > >    Store_field (v_response, 2, caml_copy_string (code)) ;
> > > > >    CAMLreturn (v_response) ;
> > > >
> > > > Additionally, do make sure that "v_response" is registered with
> > > > the GC (declared with one of the CAMLlocal macros).
> > >
> > > This is strange, it wasn't declared with a CAMLlocal macro and it
> > > was working, but if I do declare it with one the program segfaults
> > > during garbage collection (caml_oldify_local_roots).
> >
> > If you altered this but left the program exactly the same then you
> violated rule 1 in 18.5.1 of the manual: CAMLparamn must come first. The
> result is predictable - you attempt to allocate a local variable before
> the local root is properly initialised...
> 
> >
> > That said, in your specific example, my understanding is that it
> > should be OK not using CAMLlocal because you return v_response with
> > CAMLreturn before the GC could be triggered (no allocations or
> > callbacks between caml_alloc_tuple and CAMLreturn).
> 
> I'm puzzled by this, caml_copy_string does allocation..

Oops :$ So it does...


^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [Caml-list] Val_int vs caml_copy_nativeint
  2011-08-09  1:33         ` Erik de Castro Lopo
  2011-08-09  1:40           ` Romain Beauxis
  2011-08-09  8:44           ` David Allsopp
@ 2011-08-09 22:53           ` Erik de Castro Lopo
  2011-08-10  6:43             ` Gabriel Scherer
  2 siblings, 1 reply; 19+ messages in thread
From: Erik de Castro Lopo @ 2011-08-09 22:53 UTC (permalink / raw)
  To: caml-list

Erik de Castro Lopo wrote:

> This is strange, it wasn't declared with a CAMLlocal macro and it
> was working, but if I do declare it with one the program segfaults
> during garbage collection (caml_oldify_local_roots).

Ok, with the help of someone off list I've sorted this out to
my satisfaction. Things learned:

 a) In the C stub function, the call to CAMLParamN must be the
    first thing in the function, followed by any CAMLlocalN
    declarations. These should even occur before before any 
    declarations of local C variables.

 b) caml_copy_nativeint creates a boxed native int (either Int32.t
    or Int64.t) not an unboxed Ocaml int. To create an unboxed
    Ocaml int, Val_int() is the correct macro.

Thanks to all that responded.

Erik
-- 
----------------------------------------------------------------------
Erik de Castro Lopo
http://www.mega-nerd.com/

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [Caml-list] Val_int vs caml_copy_nativeint
  2011-08-09 22:53           ` Erik de Castro Lopo
@ 2011-08-10  6:43             ` Gabriel Scherer
  0 siblings, 0 replies; 19+ messages in thread
From: Gabriel Scherer @ 2011-08-10  6:43 UTC (permalink / raw)
  To: caml-list

[-- Attachment #1: Type: text/plain, Size: 448 bytes --]

Erik de Castro Lopo wrote:

>  b) caml_copy_nativeint creates a boxed native int (either Int32.t
>    or Int64.t) not an unboxed Ocaml int. To create an unboxed
>    Ocaml int, Val_int() is the correct macro.
>

caml_copy_nativeint returns a element of the OCaml type 'nativeint':
  http://caml.inria.fr/pub/docs/manual-ocaml/libref/Nativeint.html

The caml_copy_* documentation:
  http://caml.inria.fr/pub/docs/manual-ocaml/manual032.html#htoc238

[-- Attachment #2: Type: text/html, Size: 810 bytes --]

^ permalink raw reply	[flat|nested] 19+ messages in thread

end of thread, other threads:[~2011-08-10  6:43 UTC | newest]

Thread overview: 19+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2011-08-08  3:15 [Caml-list] Val_int vs caml_copy_nativeint Erik de Castro Lopo
2011-08-08  3:48 ` Romain Beauxis
2011-08-08  3:59   ` Guillaume Yziquel
2011-08-08  7:49     ` Erik de Castro Lopo
2011-08-08  3:53 ` Guillaume Yziquel
2011-08-08  7:46   ` Erik de Castro Lopo
2011-08-08  8:03     ` Guillaume Yziquel
2011-08-08  9:17       ` Mathias Kende
2011-08-08 17:24       ` Xavier Leroy
2011-08-09  1:33         ` Erik de Castro Lopo
2011-08-09  1:40           ` Romain Beauxis
2011-08-09  8:44           ` David Allsopp
2011-08-09 10:07             ` malc
2011-08-09 10:43               ` David Allsopp
2011-08-09 22:53           ` Erik de Castro Lopo
2011-08-10  6:43             ` Gabriel Scherer
2011-08-08  5:20 ` malc
2011-08-08  6:01   ` Guillaume Yziquel
2011-08-08  6:22     ` malc

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).