From: Rainer Weikusat on
boltar2003(a)boltar.world writes:
> On Fri, 30 Apr 2010 12:19:49 -0400
> "Bill Cunningham" <nospam(a)nspam.invalid> wrote:
>>boltar2003(a)boltar.world wrote:
>>> On Fri, 30 Apr 2010 14:29:44 +0200
>>> Rainer Weikusat <rweikusat(a)mssgmbh.com> wrote:
>>
>>> Also poll doesn't return the amount of time left if in timeout mode
>>> and something happens unlike select.
>>
>> So you would say go with select() then? I'm certainly not knowledgable
>>enough to do anything manually here. I'm going to log into my server with
>>telnet. I know there's that timeval struct with poll().
>
> poll() is probably more efficient, but select() is easier to use for someone
> not used to writing server network code.

How many people have already asked here what could be wrong with their
select loops who didn't understand that the information they passed
into the kernel is no longer contained in the memory area they wrote
it to after the call? And how about the other classic, that the
nfds-member isn't used to pass the number of descriptors but the
numerically largest descriptor passed to the kernel + 1?

"Look ma, I dug a tunnel through the floor! After all, anyone could
use the door!
From: boltar2003 on
On Tue, 04 May 2010 12:49:18 +0200
Rainer Weikusat <rweikusat(a)mssgmbh.com> wrote:
>How many people have already asked here what could be wrong with their
>select loops who didn't understand that the information they passed
>into the kernel is no longer contained in the memory area they wrote
>it to after the call? And how about the other classic, that the

I never had a problem understanding that it changes the bits - otherwise how
the hell is it going to work?

>nfds-member isn't used to pass the number of descriptors but the
>numerically largest descriptor passed to the kernel + 1?

You pass in a constant - FD_SETSIZE - and forget about it. Easy.

>"Look ma, I dug a tunnel through the floor! After all, anyone could
>use the door!

Whatever. Try explaining to someone new that to use poll they'll have to do
their own memory management or artificially limit the number of descriptors
they'll use.

B2003

From: Rainer Weikusat on
boltar2003(a)boltar.world writes:
> On Tue, 04 May 2010 12:49:18 +0200
> Rainer Weikusat <rweikusat(a)mssgmbh.com> wrote:
>>How many people have already asked here what could be wrong with their
>>select loops who didn't understand that the information they passed
>>into the kernel is no longer contained in the memory area they wrote
>>it to after the call? And how about the other classic, that the
>
> I never had a problem understanding that it changes the bits - otherwise how
> the hell is it going to work?

You claimed that it would be 'easier to use'. I quoted two frequent
problems so-called 'newbies' typically have with select. Knowledge
about the intricacies of bitmaps isn't something people are born with.
From: boltar2003 on
On Tue, 04 May 2010 13:06:05 +0200
Rainer Weikusat <rweikusat(a)mssgmbh.com> wrote:
>> I never had a problem understanding that it changes the bits - otherwise how
>> the hell is it going to work?
>
>You claimed that it would be 'easier to use'. I quoted two frequent
>problems so-called 'newbies' typically have with select. Knowledge
>about the intricacies of bitmaps isn't something people are born with.

If they don't understand bitmaps then they haven't learnt C properly and
so they're unlikely to understand memory management properly either.

B2003

From: Ersek, Laszlo on
On Tue, 4 May 2010, boltar2003(a)boltar.world wrote:

> Try explaining to someone new that to use poll they'll have to do their
> own memory management or artificially limit the number of descriptors
> they'll use.

My problem with poll() is this:

POLLIN - Data other than high-priority data may be read without blocking.
POLLRDNORM - Normal data may be read without blocking.
POLLRDBAND - Priority data may be read without blocking.
POLLPRI - High-priority data may be read without blocking.
POLLOUT - Normal data may be written without blocking.
POLLWRNORM - Equivalent to POLLOUT.
POLLWRBAND - Priority data may be written.

What's the difference between POLLIN and POLLRDNORM? (Especially wrt.
POLLOUT being equivalent to POLLWRNORM.) And how does POLLRDBAND differ
from POLLPRI? How do they all map to normal TCP payload as opposed to
urgent bytes? What is the effect of POLLWRBAND on TCP, since select()
doesn't offer an fd_set for writing "exceptional data"?

IMO, select() is a more intuitive and simpler API, while poll() is very
STREAMS specific. pselect() is an interface that allows a thread to wait
safely and portably on input, output, signals, and timeout. I'm inclined
to find it telling that pselect() was added while "ppoll()" was not.

Hm, hm, hm, POLLHUP seems to open a can of worms too.

http://www.opengroup.org/onlinepubs/9699919799/functions/poll.html

----v----
POLLHUP

A device has been disconnected, or a pipe or FIFO has been closed by the
last process that had it open for writing. Once set, the hangup state of a
FIFO shall persist until some process opens the FIFO for writing or until
all read-only file descriptors for the FIFO are closed. This event and
POLLOUT are mutually-exclusive; a stream can never be writable if a hangup
has occurred. However, this event and POLLIN, POLLRDNORM, POLLRDBAND, or
POLLPRI are not mutually-exclusive. This flag is only valid in the revents
bitmask; it shall be ignored in the events member.
----^----

Notice "[t]his event and POLLOUT are mutually-exclusive". If select()
reports readability on a TCP socket file descriptor and read() (or its
equivalents) returns (ssize_t)0, I'm still allowed to write() to the
socket. If the peer only issued shutdown(fd, SHUT_WR) and the underlying
implementation sent a FIN packet to me accordingly, I can still send more
data in state CLOSE_WAIT, and the peer that started with active close can
read the data in state FIN_WAIT_2.

Indeed, when I wrote my TCP port forwarder to teach myself select() and
co., I took care to support half-open sockets. IIRC, an HTTP RFC or some
such even mentions this method as delineating the end of the request from
the client. The server receives the FIN, but it can still send back the
response through the half-open (half-closed) socket.

This makes it possible for poll() to signal POLLIN without POLLHUP, then
for read() to return 0 ever after. Not very intuitive.

Also notice "this event and POLLIN, POLLRDNORM, POLLRDBAND, or POLLPRI are
not mutually-exclusive". Specifying POLLHUP in /events/ without POLLIN
seems to make no sense. I'm not even sure a TCP implementation *could*
detect a POLLHUP condition without reading and acknowledging all
previously written data by way of POLLIN. (If the data is not
acknowledged, the sender will block after a while and the protocol simply
won't reach the point where the sender could issue a shutdown.) So waiting
solely for POLLHUP probably deadlocks a pair of peers communicating over
TCP.

Furthermore, provided I specify POLLIN | POLLHUP in /events/, I can't just
close (or shut down) on receiving a POLLHUP in /revents/; I have to check
for POLLIN anyway. If POLLIN is set, I have to call read() or a similar
function. I think that even when read() will return (ssize_t)0, an
implementation is allowed to set POLLIN beside POLLHUP, because the read()
will not block (or was that POLLRDNORM again?). So the availability of
POLLHUP in the standard won't necessarily save me a read() call on EOF.

poll() is needlessly complex for non-STREAMS-based files. Where
portability matters more than performance, I'd stick to select() under
SUSv[12] and pselect() under SUSv[34]. Otherwise, I'd probably use
whatever implementation-dependent fast API is present.

Cheers,
lacos