Issue #9356 has been updated by Shugo Maeda.


Eric Wong wrote:
>  OK.  I wonder if we should even use getsockopt(SO_ERROR) at all.
>  
>  I know there's much literature which recommends it, but any error check
>  in this way is racy.  Better to let any subsequent
>  write/read/send/recv/etc error out.

Could you describe such a race condition in detail?

I don't see a race condition on FreeBSD 10.

The problem I've seen is that rb_wait_for_single_fd() returns RB_WAITFD_OUT, and getsockopt() with SO_ERROR doesn't return any error (this is an expected behavior when the socket is connected), and Ruby goes in an infinite loop.

This problem was introduced by r31424, and usa is not guilty at least for the problem I've seen.

How about to fix the code as follows?

            if (sockerr == 0) {
                if (revents & RB_WAITFD_OUT) {
                    break;
                }
                else {
                    continue;       /* control is reached here on winsock? */
                }
            }

And the following code seems to be unnecessary.

            if ((revents & (RB_WAITFD_IN|RB_WAITFD_OUT)) == RB_WAITFD_OUT) {
                ret = 0;
                break;
            }

As the following comment says, the intentions of `if (revents & (RB_WAITFD_IN|RB_WAITFD_OUT)) {` might be `if (revents & RB_WIATFD_IN && revents & RB_WAITFD_OUT)`, but I guess revents & RB_WAITFD_IN is true not only when a failure occurs, but when data is ready to read.

        /*
         * Stevens book says, successful finish turn on RB_WAITFD_OUT and
         * failure finish turn on both RB_WAITFD_IN and RB_WAITFD_OUT.
         */

Note that the original problem reported by Charlie must be a different issue.
Charlie, could you show the output of dtruss when the problem happens?


----------------------------------------
Bug #9356: TCPSocket.new does not seem to handle INTR
https://bugs.ruby-lang.org/issues/9356#change-45269

* Author: Charlie Somerville
* Status: Open
* Priority: Normal
* Assignee: 
* Category: 
* Target version: 
* ruby -v: -
* Backport: 1.9.3: UNKNOWN, 2.0.0: UNKNOWN, 2.1: UNKNOWN
----------------------------------------
TCPSocket.new does not seem to handle EINTR properly.

In the attached test script, I try to open a TCP connection to my server and make an HTTP request while a background thread continually sends a signal to the process.

This causes the #write call to fail with:

x.rb:13:in `write': Socket is not connected (Errno::ENOTCONN)
	from x.rb:13:in `<main>'

This also appears to affect 2.0.0. 1.9.3 is unaffected.

---Files--------------------------------
socket-eintr.rb (207 Bytes)


-- 
http://bugs.ruby-lang.org/