chicken-users
[Top][All Lists]
Advanced

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

Re: [Chicken-users] Passing zero-length (sub-)buffers to C functions


From: Florian Zumbiehl
Subject: Re: [Chicken-users] Passing zero-length (sub-)buffers to C functions
Date: Mon, 18 Feb 2013 08:44:16 +0100
User-agent: Mutt/1.5.20 (2009-06-14)

Hi,

> scheme-pointer is a better choice here.
> 
> (define (sys-write fd buf)
>    ((foreign-lambda int "write" int scheme-pointer int)
>      fd
>      buf
>      (string-length buf)))

So, c-pointer is for pointers to non-gc memory or for pointers to gc memory
except if you need to be able to pass zero-length things? And
scheme-pointers work for both gc and non-gc memory, but give you a useless
location with srfi-4 vectors? I somehow can't quite figure out what the
logic behind all that is--that is, how do you select which type specifier
to use?

Also, that implies that the bind egg cannot be used for that kind of
problem, at least not with unmodified type signatures?

> Instead of binding to EVP_CipherFinal_ex() directly, create a small
> wrapper in C which takes a pointer to beginning of buffer and an offset,
> add them together, and call EVP_CipherFinal_ex().  We do not have a way
> to create a shared subslice of a bytevector-like object right now, so
> you have to fudge it.
> 
> (define (evp-cipher-final buf offset)
>  ((foreign-lambda* int ((scheme-pointer ptr) (int offset))
>   "return EVP_CipherFinal_ex(ptr+offset);")
>   buf offset)
>   
> (untested, but typical pattern)
> 
> I assume you have no need to check that offset <= size buf, as you are somehow
> guaranteed this by the algorithm.

Well, I guess with EVP_CipherFinal_ex(), that would actually work, as it
seems to be declared with ints everywhere.

But usually, good APIs would declare buffer sizes as size_t, which there
doesn't seem to be any corresponding foreign type specifier for!? On the
other hand, if the documentation is to be believed, the bind egg maps
size_t to unsigned-integer anyway? Is there any recommended correct way to
portably map a size_t parameter (or return value, for that matter)?

> By the way, the best way to figure out how to do stuff like this (other than
> asking here of course) is to study existing eggs, many of which naturally
> have encountered the same problem countless times.  For example, the sendfile
> egg answers both your questions in one place:
> 
> (let ((write/offset
>  (foreign-lambda* int ((int dst) (nonnull-scheme-pointer buff)
>                        (unsigned-integer write_offset) (unsigned-integer 
> bytes))
>    "C_return(write(dst,buff + write_offset,bytes));")))
>  ...)

Well, not that reading code doesn't help to answer questions, but it's
mostly good for getting new ideas, IMO, not so much for finding the
appropriate/recommended/best solution to a problem, as existing code for
the most part doesn't tell you the selection criteria that led to the
specific solution, so it's difficult to judge whether the solution you are
looking at is for a problem that is similar to your own.

My best guess in this case would have been that maybe locatives are
expensive, so as a matter of optimization, the pointer arithmetic is done
in C--especially so, given that write/offset in that code isn't actually
ever called with a zero-length buffer:

| (when (positive? bytes-left)
|   (let ((written-bytes (write/offset dst buffer write_offset bytes-left)))

Regards, Florian



reply via email to

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