chicken-users
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Chicken-users] Re: FFI to libgmp questions


From: felix
Subject: Re: [Chicken-users] Re: FFI to libgmp questions
Date: Sat, 29 Jun 2002 12:35:05 +0200

Hello, Peter!

>Ok, here is another attempt that finally *appears* to work:
>
>;; convert a pointer known to be a char* into a c-string so I can free the
>;; c pointer later and still have a garbage collected scheme string laying
>;; around.
>(define c-pointer->c-string
>    (foreign-callback-lambda* c-string ((c-pointer ptr))
>        "   char *arena = C_alloc(C_SIZEOF_STRING(strlen(ptr) + 1));
>            strcpy(arena, ptr);
>            return (arena); /* copied into gc-memory??? */ "))


`C_alloc()' allocates memory on the C-stack. After returning from
this procedure, the memory is invalid! `C_alloc()' should only be called
in CPS-converted code, i.e. that was Chicken produces.
Another thing is that a value of return-type `c-string' is always copied,
so the `arena' buffer above will be copied again, leaking memory again
(if we would have used `mallloc()' instead of `C_alloc()').

>
>;; if there is a return char *, then manually copy it into a c-string, and
>;; free the real c-pointer returned by the function. This should make garbage
>;; collection happy.
>(define mpz_get_str
>    (let (  (alloc (foreign-lambda c-pointer "mpz_get_str" c-string int mpz_t))
>            (dealloc (foreign-lambda void "free" c-pointer)))
>    (lambda (ptr base mpz)
>        (let ((c-ptr (alloc ptr base mpz)))
>            (if (equal? ptr #f)
>                (let ((str (c-pointer->c-string c-ptr))) ;; copy the string...
>                    (dealloc c-ptr) ;; remove the mem alloced by mpz_get_str
>                    str)
>                ptr)))))
>
>
>Does that look correct? in c-pointer->c-string, is the arena memory 
>going to get copied into the garbage collector correctly without leaking
>any memory or using any dangling pointers?

Hm, not quite (see above). I would write it like this:

(define c-pointer->c-string
  (foreign-lambda* c-string ((c-pointer ptr)) "return(ptr);") )

(define mpz_get_str
  (let ([alloc (foreign-lambda c-pointer "mpz_get_str" pointer int mpz_t)]
[free (foreign-lambda void "free" c-pointer)] )
    (lambda (ptr base mpz)
      (let ([c-ptr (alloc ptr base mpz)])
(if (not ptr)
     (let ([c-str (c-pointer->c-string c-ptr)])
       (free c-ptr)
       c-str)
     c-ptr) ) ) ) )

Here, we use the foreign argument type `pointer', which accepts any
non-immediate (besides #f) Scheme value and passes a (void) pointer to 
it's contents, without copying.

Another possibilty would be to never pass a default buffer, just copy 
always:

(define mpz_get_str
  (let ([buffer (make-string 1024)] ; `1024' might not be sufficient.
[alloc (foreign-lambda c-string "mpz_get_str" pointer int mpz_t)] )
    (lambda (int mpz)
      (alloc buffer int mpz) ) )


Generally there are three pointer types in the Chicken FFI:

1) c-pointer
    argument-value: a machine-pointer object, passed as void*
    return-value a freshly allocated machine-pointer object, returned as void*

2) pointer
    argument-value: any non-immediate Scheme value or #f, passed as void*
    return-value: not allowed as a return-value

    byte-vector is similar, but only for byte-vector objects.

3) c-string
    argument-value: a string or #f, passed as char*
    return-value: a fresh string, copied from the address returned by the call 
(char*)

This is a little bit confusing. Sorry.


cheers,
felix
--
P.S. External enums can be quite simply accessed, using
`define-foreign-variable':

(define-macro (define-foreign-enum . items)
  `(begin
      ,@(map
                (match-lambda
                    [(name realname) `(define-foreign-variable ,name int 
,realname)]
                    [name `(define-foreign-variable ,name int)] )
                items) ) )

; so for "enum {abc=3, def};" we would have:

(define-foreign-enum abc def)





reply via email to

[Prev in Thread] Current Thread [Next in Thread]