shhyou / ypsilon-fork

Automatically exported from code.google.com/p/ypsilon
Other
0 stars 0 forks source link

ffi peekers and pokers #60

Closed GoogleCodeExporter closed 9 years ago

GoogleCodeExporter commented 9 years ago
Special functions are needed to set/get fields in foreign data structures.
Unfortunately, not all C language libraries provide setters and getters
(for example Zlib does not).

Scheme has the bytevector functions, but they require the offset of the
first by to be a multiple of the data type to be poked/peeked (and it is
good for these functions). So they are not reliable when using C data
structures that may have fields packed in a platform (or program)
specific way.

Pokers and peekers have to work with malloc'ed memory, too. Dangerous,
but we can live dangerously every now and then.

Ikarus has peekers:

pointer-ref-c-signed-char   pointer-ref-c-unsigned-char
pointer-ref-c-signed-short  pointer-ref-c-unsigned-short
pointer-ref-c-signed-int    pointer-ref-c-unsigned-int
pointer-ref-c-signed-long   pointer-ref-c-unsigned-long
pointer-ref-c-float     pointer-ref-c-double
pointer-ref-c-pointer

the pokers:

pointer-set-c-char! pointer-set-c-short!
pointer-set-c-int!  pointer-set-c-long!
pointer-set-c-float!    pointer-set-c-double!
pointer-set-c-pointer!

which are documented in "the other" Ikarus guide[1] or the documentation
of the latest checkouts. I like these ones because the procedure names
embed the C type name and the arguments have a base pointer and an
(unscaled) offset:

(pointer-set-c-int! pointer offset 123)
(pointer-ref-c-signed-int pointer offset)

source code for them is in "src/ikarus-pointers.c" in the Ikarus
distribution.

Larceny has peekers:

(%peek-int addr) => integer
(%peek-long addr) => integer
(%peek-unsigned addr) => integer
(%peek-ulong addr) => integer
(%peek-short addr) => integer
(%peek-ushort addr) => integer
(%peek-pointer addr) => integer

and pokers:

(%poke-int addr val) => unspecified
(%poke-long addr val) => unspecified
(%poke-unsigned addr val) => unspecified
(%poke-ulong addr val) => unspecified
(%poke-short addr val) => unspecified
(%poke-ushort addr val) => unspecified
(%poke-pointer addr val) => unspecified

documented in the manual[2]. :-/

PLT Scheme has stuff[3] which (as usual with PLT ;-) takes one full
(unproductive) day to learn (and many to deploy).

Bigloo also has stuff[4], PLT style.

[1] http://github.com/marcomaggi/nausicaa/tree/master/doc/ikarus.info.gz
[2] http://www.ccs.neu.edu/home/lth/larceny/manual/ffi.html#access
[3] http://docs.plt-scheme.org/foreign/foreign_pointer-funcs.html
[4] http://www-sop.inria.fr/mimosa/fp/Bigloo/doc/bigloo.pdf page 185

Original issue reported on code.google.com by mrc....@gmail.com on 1 Dec 2008 at 10:27

GoogleCodeExporter commented 9 years ago
I implemented them as in the attached file. One only needs to define
the variables "on-32-bits-system" and "sizeof-pointer".  I see that
the following fails:

(import (rnrs))
(define bv (make-bytevector 1064))
;(bytevector-s32-set! bv 16 (expt 2 31) (native-endianness))
(bytevector-s32-set! bv 16 (- (expt 2 32) 1) (native-endianness))

and IMHO this breaks R6RS because the value to poke should
be acceptable. Are you poking only fixnums? The other
accessors seem to have the same problem.

Original comment by mrc....@gmail.com on 3 Dec 2008 at 1:37

Attachments:

GoogleCodeExporter commented 9 years ago
Thank you for your kind message and code :)

> IMHO this breaks R6RS because the value to poke should
> be acceptable. Are you poking only fixnums? The other
> accessors seem to have the same problem.
Yes, It is a problem and I think about it. According to R6RS, 
bytevector-s32-set!
accept x only if (<= INT32_MIN x INT32_MAX) and bytevector-u32-set! accept x 
only if
(<= 0 x UINT32_MAX). So, pointer-set-c-int! should be defined as follows:

  (define (pointer-set-c-int! pointer position value)
    (let ((bv (make-bytevector-mapping
                  (pointer-value pointer)
                  (+ 4 position))))
      (cond ((<= -2147483648 x 2147483647)
             (bytevector-s32-set! bv value (native-endiannes)))
            ((<= 0 x 4294967295)
             (bytevector-u32-set! bv value (native-endiannes)))
            (else
             (assertion-violation 
                 'pointer-set-c-int!
                 "value out of range")))))

Because it looks too much for just poking one 32bit value, I conclude I should
implement it in C.
I'm going to take ikarus's API. I like that one too. :)
-- fujita

Original comment by y.fujita...@gmail.com on 3 Dec 2008 at 4:32

GoogleCodeExporter commented 9 years ago
[deleted comment]
GoogleCodeExporter commented 9 years ago
I have added new API to ffi and trunk directory is updated to revision 322.

new procedures:

  (bytevector-c-void*-ref <bv> <index>)
  (bytevector-c-short-ref <bv> <index>)
  (bytevector-c-int-ref <bv> <index>)
  (bytevector-c-long-ref <bv> <index>)
  (bytevector-c-unsigned-int-ref <bv> <index>)
  (bytevector-c-unsigned-short-ref <bv> <index>)
  (bytevector-c-unsigned-long-ref <bv> <index>)
  (bytevector-c-void*-set! <bv> <index> <value>)
  (bytevector-c-short-set! <bv> <index> <value>)
  (bytevector-c-int-set! <bv> <index> <value>)
  (bytevector-c-long-set! <bv> <index> <value>)

new constants:

  sizeof:short sizeof:int 
  sizeof:long  sizeof:void*                                   

  alignof:short   alignof:int 
  alignof:long    alignof:void*
  alignof:float   alignof:double
  alignof:int8_t  alignof:int16_t 
  alignof:int32_t alignof:int64_t

With new procedure bytevector-c-long-set!, you can write pointer-set-c-long! as 
follows:

  (define (pointer-set-c-long! pointer position value)
    (bytevector-c-long-set! (make-bytevector-mapping 
                              (+ pointer position) sizeof:long)
                            value 0)

It does the same stuff as follows:

  (define (pointer-set-c-long! pointer position value)
    (if on-32-bits-system
        (cond ((<= -2147483648 x 2147483647)
               (bytevector-s32-set! (make-bytevector-mapping pointer (+ 4 position))
                                    position value (native-endianness)))
              ((<= 0 x 4294967295)
               (bytevector-u32-set! (make-bytevector-mapping pointer (+ 4 position))
                                    position value (native-endianness)))
              (else
               (assertion-violation 'pointer-set-c-long! "value out of range")))
        (cond ((<= -9223372036854775808 x 9223372036854775807)
               (bytevector-s64-set! (make-bytevector-mapping pointer (+ 8 position))
                                    position value (native-endianness)))
              ((<= 0 x 18446744073709551615)
               (bytevector-u64-set! (make-bytevector-mapping pointer (+ 8 position))
                                    position value (native-endianness)))
              (else
               (assertion-violation 'pointer-set-c-long! "value out of range")))))

Please try. Thank you!
-- fujita

Original comment by y.fujita...@gmail.com on 16 Dec 2008 at 12:00

GoogleCodeExporter commented 9 years ago
New version 0.9.6-update3 has released and I close this issue. Thank you again!
-- fujita

Original comment by y.fujita...@gmail.com on 23 Dec 2008 at 10:24

GoogleCodeExporter commented 9 years ago
Thanks. I have tested the peekers and pokers with my libs[1] and they seem to 
work (I
have not yet pushed the code that uses them on the public repository, 
refactoring is
taking more time than I had expected).

[1] http://sites.google.com/site/mrcmgg/nausicaa

Original comment by mrc....@gmail.com on 24 Dec 2008 at 10:27