[comp.unix.questions] How to do a non-blocking write of more than one char?

brnstnd@stealth.acf.nyu.edu (01/07/90)

I'd like to write to a file descriptor without blocking. select() tells
me that I can write at least one character, but I don't want to have to
write the characters individually. The FNDELAY fcntl() is inappropriate
because it affects other processes.

If select() says the fd is writable, is the write() guaranteed not to
block? In that case, as long as it isn't interrupted, will the write()
always return the correct count of characters written? If not, is there
a solution?

---Dan

guy@auspex.auspex.com (Guy Harris) (01/09/90)

>If select() says the fd is writable, is the write() guaranteed not to
>block?

Which "write()"?  Not all "write()"s are guaranteed not to block.  It's
guaranteed that you can write *some* amount of data without blocking,
but no guarantee as to how much is made, in general.  Sorry, but you
really *are* expected to use non-blocking I/O in that case.... 

brnstnd@stealth.acf.nyu.edu (01/11/90)

In article <2799@auspex.auspex.com> guy@auspex.auspex.com (Guy Harris) writes:
> It's
> guaranteed that you can write *some* amount of data without blocking,
> but no guarantee as to how much is made, in general.

Can you show me a program that blocks on a write() after select() has
indicated that the descriptor is writable? (select() on this machine
is slightly buggy, so I'm not sure my tests are accurate.)

> Sorry, but you
> really *are* expected to use non-blocking I/O in that case.... 

Okay, Guy, tell me how I accomplish this: Process A writes data to a
pipe connected to Process B. Process A must not block on its writes,
because it has to handle other descriptors as well. Process B is an
already-written program that assumes that its reads are non-blocking;
it'll take EWOULDBLOCK as a read error and die horribly.

Process A can avoid blocking by using select() and writing just one
character at a time. Is there any other way?

C'mon, guys, this is a simple question!

---Dan

guy@auspex.auspex.com (Guy Harris) (01/12/90)

>Can you show me a program that blocks on a write() after select() has
>indicated that the descriptor is writable?

Sure - a program that writes 50,000 characters on a "write", if the
"select()" returns true because there are 2 bytes of buffer space
available in the socket.  (Or, more generally, a program that writes N
characters on a "write", when the "select()" returns true because there
are M < N bytes of buffer space left in the socket.)  Whether this will
actually occur in the real world depends on the value of "N" for any
particular write, and the value of "M" for any particular select wakeup;
the latter would depend on all sorts of things, like the type of socket,
whether you've set SO_SNDBUF, etc..

>Okay, Guy, tell me how I accomplish this: Process A writes data to a
>pipe connected to Process B. Process A must not block on its writes,
>because it has to handle other descriptors as well. Process B is an
>already-written program that assumes that its reads are non-blocking;
>it'll take EWOULDBLOCK as a read error and die horribly.

I have no idea how you'd accomplish that and, since it's not a problem
I've personally run into, it's not exactly high on my list of problems
to solve.  You have my sympathy, but that's about it....

>C'mon, guys, this is a simple question!

And it may have a simple answer like "sorry, you can't do it".

brnstnd@stealth.acf.nyu.edu (01/17/90)

I'm trying to write a ``multitee'' program so that, e.g.,

  multitee 0:6,7 6:1

would send all input from fd 0 to fd 6 and fd 7, while sending all input
from fd 6 to fd 1. It's a trivial problem, except that multitee should
do its best to never block on writes. (Otherwise it could enter a deadlock
with another process.) Buffering is easy, but how to avoid blocking?

One correct answer is to always write just one character per write()
call. Unfortunately, this usually forces a hellish overhead.

Another answer is to use fcntl() and set FNDELAY on the descriptor.
Unfortunately, this doesn't just affect the descriptor; it affects the
entire open file, including possibly other processes. (This is the real
problem.)

Another answer is that multitee should fork into separate processes,
one for each input descriptor. This works and solves the flow control
problems, but it's not very polite to other processes unless the system
supports threads.

In article <2816@auspex.auspex.com> guy@auspex.auspex.com (Guy Harris) writes:
> >C'mon, guys, this is a simple question!
> And it may have a simple answer like "sorry, you can't do it".

I guess it's a good question, then...

---Dan