From: Rainer Weikusat on 4 May 2010 06:49 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 4 May 2010 06:57 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 4 May 2010 07:06 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 4 May 2010 07:26 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 4 May 2010 08:41
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 |