Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 4 Jun 2001 22:18:10 +0200 (CEST)
From:      Jaromír Dolecek <jdolecek@NetBSD.org>
To:        hackers@freebsd.org
Cc:        alfred@freebsd.org
Subject:   pipe implementation questions
Message-ID:  <200106042018.f54KIAV00619@saruman.ics.muni.cz>

next in thread | raw e-mail | index | archive | help
Hi folks,
I'm working on a port of FreeBSD pipe implementation to NetBSD. So far,
the results are pretty owesame, the new pipes are significantly faster
than the old socketpair-based ones. Good work!

However, I found couple of things I don't quite understand and would
like to clarify if this is how things are supposed to work or if
I'm consfused :)

1) SIGIO for O_ASYNC reader, sync writer
   I made a test program which makes a pipe, sets owner of the read end,
   setup signal handler for SIGIO and switches the read end to
   O_NONBLOCK|O_ASYNC mode. Program forks,
   child makes sync write to the write (synchronous) end of pipe.
   When parents loops calling read() on the read end until it succeeds.
   However, I found out the parent gets SIGIO for each read(2) attempt.

This behaviour seems to be due to last couple of lines of pipe_read():

	if ((rpipe->pipe_buffer.size - rpipe->pipe_buffer.cnt) >= PIPE_BUF)
		pipeselwakeup(rpipe);

This condition is commonly true if the reader is polling for input. The code
should signal the writer, not the reader - it doesn't make sense to
signal possibility of writing more data to the reader itself.
IMHO the code should be like:

	if ((rpipe->pipe_buffer.size - rpipe->pipe_buffer.cnt) >= PIPE_BUF) {
		struct pipe *wpipe = rpipe->pipe_peer;
		if (wpipe)
			pipeselwakeup(wpipe);
	}

Also, the code could possibly only call the pipeselwakeup() if anything
was actually read from the pipe previously (or, even better, only once
since last write(2)), to avoid sending SIGIO's to the writer if the
the reader found the pipe empty.

2) direct write - first uio only
  FreeBSD direct write code seems to handle only first uio buffer,
  so e.g. writev(2) with multiple buffers doesn't write all data
  at once.  This is valid behaviour (return short write and expect
  writer to update itself and try again with rest), I'd like just
  to ensure I read the code correctly.

3) direct write - loses for huge buffers?
  It seems pipe_build_write_buffer() tries to fault all the address space
  specified by uio. However, pipe_map.ms[] has only (BIG_PIPE_SIZE/PAGE_SIZE+1)
  members, so this seems to lose if the covered address space (size of
  buffer passed to write(2)) is > 64+4=68KB. Also, the code
  which calls pmap_qenter() thinks the buffer size is
  wpipe->pipe_buffer.size + PAGE_SIZE maximum. Do I read the code correctly,
  or is there anything I miss? The current port to NetBSD doesn't use
  this particular piece of code (the difference between FreeBSD VM and UVM
  is too big), but it's something I encountered and would like to understand :)
  
Thanks for you cooperation :)

Jaromir

P.S. Please CC: me, I'm not on the list
-- 
Jaromir Dolecek <jdolecek@NetBSD.org>      http://www.ics.muni.cz/~dolecek/
NetBSD - just plain best OS! -=*=- Got spare MCA cards or docs? Hand me them!

To Unsubscribe: send mail to majordomo@FreeBSD.org
with "unsubscribe freebsd-hackers" in the body of the message




Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200106042018.f54KIAV00619>