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
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.