Re: UDP recvmsg blocks after select(), 2.6 bug?

Martijn Sipkema
2004-10-17T18:59:00Z

From: "Buddy Lucas" <buddy.lucas@gmail.com>
> On Sun, 17 Oct 2004 18:35:34 +0100, Martijn Sipkema <martijn@entmoot.nl> wrote:
> > From: "Buddy Lucas" <buddy.lucas@gmail.com>
> > > On Sun, 17 Oct 2004 11:05:09 -0400, Mark Mielke <mark@mark.mielke.cc> wrote:
> > > > On Sun, Oct 17, 2004 at 04:17:06PM +0200, Buddy Lucas wrote:
> > > > > On Sun, 17 Oct 2004 15:35:37 +0200, Lars Marowsky-Bree <lmb@suse.de> wrote:
> > > > > > The SuV spec is actually quite detailed about the options here:
> > > > > > A descriptor shall be considered ready for reading when a call
> > > > > > to an input function with O_NONBLOCK clear would not block,
> > > > > > whether or not the function would transfer data successfully.
> > > > > > (The function might return data, an end-of-file indication, or
> > > > > > an error other than one indicating that it is blocked, and in
> > > > > > each of these cases the descriptor shall be considered ready for
> > > > > > reading.)
> > > > > But it says nowhere that the select()/recvmsg() operation is atomic, right?
> > > >
> > > > This is a distraction. If the call to select() had been substituted
> > > > with a call to recvmsg(), it would have blocked. Instead, select() is
> > > > returning 'yes, you can read', and then recvmsg() is blocking. The
> > > > select() lied. The information is all sitting in the kernel packet
> > >
> > > No. A million things might happen between select() and recvmsg(), both
> > > in kernel and application. For a consistent behaviour throughout all
> > > possibilities, you *have* to assume that any read on a blocking fd may
> > > block, and that a fd ready for reading at select() time might not be
> > > readable once the app gets to recvmsg() -- for whatever reason.
> >
> > It is perfectly possible to not have a million things happen between
> > select() and recvmsg() and POSIX defines what can happen and what
> > can't; it states that a process calling select() on a socket will not block
> > on a subsequent recvmsg() on that socket.
> >
> > > And indeed, that implies that select() on blocking fds is generally
> > > not useful if you expect to bypass the blocking through select().
> > > Personally, I think any application that implements this expectation
> > > is broken. (If only because you might have to do a second read() or
> > > recvmsg() which will either result in a crappy select() loop or a
> > > broken read()/recvmsg() loop).
> >
> > The way select() is defined in POSIX effectively means that once an
> > application has done a select() on a socket, the data that caused
> > select() to return is committed, i.e. it can no longer be dropped and
> > should be considered received by the application; this has nothing
>
> That is plainly wrong. Data is never received by an application before
> recvmsg() has succeeded.

I didn't say it was, but that from the view of the UDP protocol it is, i.e.
a UDP packet can not be dropped from that point onwards.

> > to do with UDP being unreliable and being unreliable for the sake
> > of it is not what UDP was meant for.
> >
> > Whether you think an application that is written to use select() as
> > defined in POSIX is broken is not really important. The fact remains
> > that Linux currently implements a select() that is _not_ POSIX
> > compliant and is so solely for performance reasons. I personally think
> > correct behaviour is much more important.
>
> All I'm saying is, that applications that are not correct now, will
> probably not be correct even if we change the way Linux handles this
> situation. The sanest thing really seems to accept the fact that any
> read() on a blocking fd might block, even if the programmer thinks it
> really shouldn't.
>
> But then I am one of those who thinks it's sane to check for
> EWOULDBLOCK on a nonblocking socket after blocking in select().

A POSIX comliant implementation would never do this.

> Let's just document this and move on to something more important.

It actually _is_ important. Just implement select() and recvmsg() as
described in the standard.

--ms