Issue #9356 has been updated by Shugo Maeda.


Eric Wong wrote:
>  > Ah, I see.  However, if getsockopt() returns no error, we can know
>  > that at least connect() succeeded, right?  I'm not sure whether it's a
>  > so-called race condition.
>  
>  I'm not sure if we can know for sure due to implementation differences.

Hmm..., do you know any implementation where getsockopt(SO_ERROR) causes a problem?
If there's such an implementation, it would be better to remove the call, but I don't come up with such a situation.

By contraries, getsockopt(SO_ERROR) might be necessary for winsock, if usa's comment is right.

>  And even if connect() succeeded, the server could decide to disconnect
>  right away after accept() due to overload, so probably less important.

It applies equally to connect() without signal interruption.
TCPSocket.new should handle EINTR as transparently as possible, I think.

>  > >  anyways, getsockopt(SO_ERROR) is worthless.
>  
>  > I don't think getsockopt(SO_ERROR) is worthless because users can know
>  > error information sooner and more exactly than subsequent read() or
>  > write().
>  
>  The error may be seen sooner, but I think the errors are uncommon
>  and most users will not care.  They will see any error and handle it
>  their own way.

Most applications might handle errors roughly, but logging the exact error information would help trouble shooting.

> Ah, I forget the outer for(;;) loop. Maybe it's better to not loop,
> the WAIT_IN_PROGRESS stuff is confusing...

I agree that the code is complicated, and it's better to simplify it, if possible.

> I have no idea how portable this is:
> http://bogomips.org/ruby.git/patch?id=f5e2eb00e5
> 
> Btw, I suspect the WAIT_IN_PROGRESS stuff is carried over from the
> 1.8 days where all sockets were non-blocking by default, and overly
> complicated as a result. I don't even think EINPROGRESS/EAGAIN is
> possible, only EINTR/ERESTART.

The patch worked both on Linux 3.2.0 and FreeBSD 10.0 for blocking sockets with signal interruption.

It might be better to re-call connect() on ERESTART as the error suggests, but I'm not sure.
It seems to be a Linux way to re-call connect(), but there's no description about ERESTART in Linux's manual of connect(2) and instead there's a reference to POSIX.1-2001 (SUSv3), to which Linux seem not to conform.  Funny.

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

* 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/