Project

General

Profile

Actions

Bug #3307

closed

select() not working as expect when a pipe is closed

Added by tmunro over 2 years ago. Updated over 2 years ago.

Status:
Resolved
Priority:
High
Assignee:
-
Category:
-
Target version:
Start date:
11/19/2021
Due date:
% Done:

0%

Estimated time:

Description

When a the write end of a pipe is in the writefds set of a call to select(), and the read end is closed, I think select() should report the descriptor as writable (because writing would produce EPIPE or SIGPIPE), but it does not. We suspect this changed, and we noticed the change in the PostgreSQL build farm after upgrading an ancient Dragonfly build machine to the current release. In our real usage, this causes Perl IPC::Run in our test harness to hang, but here's a minimal repro in C:

https://www.postgresql.org/message-id/flat/CA%2BhUKG%2BUZi3tp%3De0ffO1R7eZ%3Dx8azSJDNzO0E2zOy9PhuyOpAQ%40mail.gmail.com#f90edeec19759a8b62ce98ea5a11cb6e

(Please disregard the discussion of kqueue problems on ancient macOS, which turned out to be a separate problem, completely unrelated).

Actions #1

Updated by deef over 2 years ago

Just a guess... Shouldn't a descriptor in such state (ie. remote end has closed connection) be reported in exceptfds instead of writefds? I'd expect this to be a more reasonable behaviour, as such descriptor is simply not writable, so reporting it writable is kind-of non-sense.

Actions #2

Updated by deef over 2 years ago

And, AFAIR, in case the remote closes connection "properly", the descriptor should appear in readfds, and read()ing from it then returns zero. That's "the correct" way to detect connection closed by remote.

Actions #3

Updated by dillon over 2 years ago

  • Status changed from New to Resolved
  • Priority changed from Normal to High

Pushed 3e6cd71a300e70d8644d to master fixing the problem.

The pipe driver was refusing to register a knote for writing if the other end was closed prior to the registration. So it would work properly if the parent got its first select() in before the child exited, but would not work properly if the child exited first. Only the pipe driver had this behavior. Should now be fixed and will be MFCd momentarily.

-Matt

Actions #4

Updated by tmunro over 2 years ago

Thanks!

Actions #5

Updated by tmunro over 2 years ago

Hi again, will the fix be MFC'd to the 6.0 branch? Thanks,

Actions #6

Updated by dillon over 2 years ago

It will set a HUP condition on the descriptor. It still has to be flagged writable regardless because most programs detect the closed pipe by trying to write() to it. For poll*() there is a specific POLL_HUP flag.

For select() its really up in the air. EOF on read is not considered an error of any sort, and that throws confusion on whether EOF on write should be considered an error or not. Pipes can be half-closed via shutdown() as well as fully closed, for example, and it is unclear whether the two situations should be handled differently or not. I don't think we currently set exceptfds bits for the condition, and it is unclear whether we should. Mostly this comes down to ports compatibility and what linux does. So if someone wants to test what a closed pipe does to select() on linux, I'm happy to do the same thing on DFly.

-Matt

Actions #7

Updated by tuxillo over 2 years ago

It's MFC'ed now.

Actions

Also available in: Atom PDF