Re: sizeof PIPE_BUF
Laurent Bercot <[email protected]>
| Newsgroups | gmane.linux.lib.dietlibc |
|---|---|
| Message-ID | <[email protected]> |
> I don't quite understand what you are trying to do that needs to know
> the exact value of PIPE_BUF. My hunch is that if you need to know the
> exact value, you are doing something you are not supposed to :-)
Nikola doesn't want to know the numerical value of PIPE_BUF.
He wants to have a macro for PIPE_SIZE, i.e. the total size of the
kernel pipe buffer. PIPE_BUF can be used, but it's not optimal: when
PIPE_SIZE > PIPE_BUF (which is the case on Linux), if you only allow
yourself to fill PIPE_BUF bytes at a time, you're doing unnecessary
system calls.
Consider the following functions (they'll be available in the next
skalibs release) :
int iobuffer_fill (iobuffer *b)
{
register int r = splice(b->fd[0], 0, b->p[1], 0, IOBUFFER_SIZE - b->n, 0) ;
if (r > 0) b->n += r ;
return r ;
}
int iobuffer_flush (iobuffer_ref b)
{
unsigned int w = 0 ;
while (b->n)
{
register int r = splice(b->p[0], 0, b->fd[1], 0, b->n, 0) ;
if (r < 0) return r ;
else if (!r) return (errno = EAGAIN, -1) ;
b->n -= r ; w += r ;
}
return (int)w ;
}
The point is to transfer data from b->fd[0] to b->fd[1] without
copying it into userspace. For this, an internal pipe b->p is used
and data is spliced first from b->fd[0] to b->p[1] (iobuffer_fill)
then from b->p[0] to b->fd[1] (iobuffer_flush). An application
will loop around iobuffer_fill and iobuffer_flush; if works in
either blocking or nonblocking mode (b->p[0] and b->p[1] are
nonblocking, and b->fd[0] and b->fd[1] are controlled by the
application).
b->n is the number of bytes contained in the kernel buffer at
all times.
You can see that the efficiency of the implementation depends on the
value of the IOBUFFER_SIZE macro. If IOBUFFER_SIZE is PIPE_BUF,
a user application will loop 16 times more than is necessary, because
data could actually be transferred by chunks of 64k (PIPE_SIZE) instead
of 4k (PIPE_BUF).
Can you suggest an optimal implementation of iobuffer_fill that
does not rely on knowing the kernel pipe buffer size ? I know it doesn't
hurt to manually set a huge value for IOBUFFER_SIZE, because the splice()
system call in iobuffer_fill will only transfer data up to PIPE_SIZE
bytes anyway and the function will work; but it's not elegant, and I'd
rather have IOBUFFER_SIZE equal to PIPE_SIZE.
--
Laurent