SIGINFO interrupts connect() with libpthread
deischen at freebsd.org
Sat Oct 8 08:40:26 PDT 2005
On Sat, 8 Oct 2005, Robert Watson wrote:
> On Fri, 7 Oct 2005, Daniel Eischen wrote:
> > On Thu, 6 Oct 2005, Robert Watson wrote:
> >> I was writing test tools yesterday, and was a bit surprised to find
> >> that hitting ctrl-T interrupts connect() for applications linked
> >> against libpthread(). I wrote a simple test tool and found that this
> >> is not the case for any of the other thread libraries (which seems
> >> correct to me). Test tool attached:
> > This isn't a problem with libpthread. If you install a signal handler
> > for SIGINFO in your application with sa_flags = SA_RESTART, it gets
> > interrupted even when just linked with libc.
> Unlike, say, an I/O operation, the notion of restarting a connect() system
> call is fairly fraught with peril. Normally, attempts to call connect()
> on a socket that is already in the process of connecting will return
> EALREADY, since you don't want to further frob the protocol state machine.
> A bit of googling suggests that Stephens talks about this in some detail,
> pointing out that in the EINTR case, the application will really need to
> select() for the socket becoming writable in order to wait for the
> connection attempt to finish (or fail). While a bit awkward for the
> application, it appears these are not uncommon semantics for the system
> call, and suggest the perils of using blocking I/O with signals are
> significant. Unfortunately, the problem with this libpthread feature is
> that, unlike our other thread libraries, it exposes the application to
> this peril even if the application itself doesn't actively use signals.
> Is your suggestion that connect() should detect an attempt to connect to
> the same host and "continue where it left off"? POSIX tells us that
> EALREADY should be returned if that is attempted:
No, SA_RESTART should do what it says it should do. System calls
should be restartable. The man page for sigaction() says that it
is only open(), read(), write(), sendto(), recvfrom(), sendmsg(),
and recvmsg() that are restartable. I don't know why connect()
should be any different.
In this case there is only one thread that is attempting to
[re]connect(), so I don't see why you'd think EALREADY should
be returned. A thread gets interrupted to run a signal handler,
it leaves the kernel so there is no thread attempting to connect().
If the handler returns (it doesn't have to), then why can't it
go back to connecting again? There is no timeout on connect()
(you'd have to select() or poll()), and the application can
choose SA_RESTART or not, so allowing connect() to be restartable
shouldn't break anything.
It only works with libc_r because libc_r wraps all these calls
(including connect()) with poll(). Obviously we're not going
to do that with libpthread. You're only seeing it with SIGINFO
because we use SIGINFO as a debugging signal for libpthread
(to dump thread state). libpthread doesn't install any other
signal handlers unless the application does. We could use a
different signal or not use SIGINFO at all.
More information about the freebsd-threads