Path: csiph.com!usenet.pasdenom.info!weretis.net!feeder4.news.weretis.net!storethat.news.telefonica.de!telefonica.de!news-1.dfn.de!news.dfn.de!fu-berlin.de!uni-berlin.de!individual.net!not-for-mail From: Rainer Weikusat Newsgroups: comp.os.linux.development.apps Subject: Re: Linux O_NONBLOCK bug/ quirk Date: Thu, 03 Apr 2014 16:36:19 +0100 Lines: 84 Message-ID: <87d2gyzaq4.fsf@sable.mobileactivedefense.com> References: <878urvu0gx.fsf@sable.mobileactivedefense.com> <87siq23wwg.fsf@sable.mobileactivedefense.com> Mime-Version: 1.0 Content-Type: text/plain; charset=us-ascii X-Trace: individual.net QHkYUiZRyCs2CwGyekks6AluX21RBKaIEqpEkfAYFPOMewxwI= Cancel-Lock: sha1:ShhDffSHulHjNu//eiBkVhBhJUQ= sha1:EK8BjdRGXvDSzLof7fJ2LXppyP8= User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/23.2 (gnu/linux) Xref: csiph.com comp.os.linux.development.apps:680 unixb4coffee writes: > On 03/28/2014 01:12 PM, Rainer Weikusat wrote: >> Rainer Weikusat writes: >> >> [...] >> >>> a receive operation on a socket in >>> non-blocking mode can actually be blocked forever on Linux, example >>> code: [...] >> ------------ >> #include >> #include >> #include >> #include >> >> int main(void) >> { >> struct sockaddr_un sun; >> int fd; >> >> fd = socket(AF_UNIX, SOCK_DGRAM, 0); >> sun.sun_family = AF_UNIX; >> strncpy(sun.sun_path, "/tmp/bla", sizeof(sun.sun_path)); >> bind(fd, (struct sockaddr *)&sun, sizeof(sun)); >> >> if (fork() == 0) recv(fd, &fd, sizeof(fd), 0); >> >> sleep(1); >> >> recv(fd, &fd, sizeof(fd), MSG_DONTWAIT); >> >> return 0; >> } >> ------------- >> >> What happens here is that the 2nd recv stops on a mutex held by the >> first and thus, effectively blocks until a message is received on this >> socket, IOW, the implementation of MSG_DONTWAIT is completely broken for >> datagram sockets (certainly AF_UNIX, likely, AF_INET, too). Further, it >> is not going to be fixed because the so-called 'networking maintainer' >> 'completely disagrees' with the idea that 'non-blocking operation' >> actually means 'the call will not block' (that's the state of 2 days >> ago). >> > If the MSG_DONTWAIT triggers an EAGAIN or EWOULDBLOCK, it's easier to > maintain a connection in a stable state - as long as the forking > process knows the status of the forked process. Communicating the > status of a child process is not normally performed by the socket > connection (though somebody probably has and will say that it can be > done) - The wait () and waitpid () man pages are just one place to > begin reading about communicating between endpoints. I don't quite understand this in the given context. The reason I used fork in the example above was just because it's the easiest way to create an independent thread of execution which has access to the same socket. > If I'm reading this correctly, then the mutex would cause a hang. It will cause the supposedly non-blocking second recv to block until a message is received on the socket. This message will then be returned by the first recv and the second will return an EAGAIN error (unless another message becomes available 'quickly'). This should work like the pipe-handling code in fs/pipe.c does -- a thread acquires the mutex using mutex_lock instead of mutex_lock_interruptible, looks for available messages and in case there are none, it unlocks the mutex and either goes to sleep (reacquiring the mutex after it was woken up) if it was a blocking call or returns EAGAIN if it wasn't. That's a better solution then the 'trylock' I suggested 'elsewhere' but I didn't think of it until the next morning (and checked pipe.c afterwards because I couldn't imagine this to be broken everywhere). Not that this had made any difference (pointing at pipe.c might have 'worked' in the sense that 'appeals to authority' tend to be less futile than 'appeals to reason' ...). > But hangs aren't that unusual if a program doesn't take care to monitor > the forked processes' status. It also doesn't really say anything about the > connection's state, or whether it's still possible to monitor it. There is no connection here, just a datagram socket shared by multiple threads of execution.