From owner-freebsd-threads@FreeBSD.ORG Sat Oct 8 10:16:20 2005 Return-Path: X-Original-To: threads@freebsd.org Delivered-To: freebsd-threads@FreeBSD.ORG Received: from mx1.FreeBSD.org (mx1.freebsd.org [216.136.204.125]) by hub.freebsd.org (Postfix) with ESMTP id 9E54816A41F; Sat, 8 Oct 2005 10:16:20 +0000 (GMT) (envelope-from rwatson@FreeBSD.org) Received: from cyrus.watson.org (cyrus.watson.org [204.156.12.53]) by mx1.FreeBSD.org (Postfix) with ESMTP id 2479A43D45; Sat, 8 Oct 2005 10:16:20 +0000 (GMT) (envelope-from rwatson@FreeBSD.org) Received: from fledge.watson.org (fledge.watson.org [204.156.12.50]) by cyrus.watson.org (Postfix) with ESMTP id 572A646BA5; Sat, 8 Oct 2005 06:16:17 -0400 (EDT) Date: Sat, 8 Oct 2005 11:16:17 +0100 (BST) From: Robert Watson X-X-Sender: robert@fledge.watson.org To: Daniel Eischen In-Reply-To: Message-ID: <20051008105232.B84936@fledge.watson.org> References: MIME-Version: 1.0 Content-Type: TEXT/PLAIN; charset=US-ASCII; format=flowed Cc: threads@freebsd.org Subject: Re: SIGINFO interrupts connect() with libpthread X-BeenThere: freebsd-threads@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: Threading on FreeBSD List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sat, 08 Oct 2005 10:16:20 -0000 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: [EALREADY] A connection request is already in progress for the specified socket. I guess in principle we could add a thread flag to indicate that a system call has been restarted, and therefore that the system call should adopt different blocking/waiting smeantics? There are a lot of potential complications though, since you might want to know when it was restarted. In the connect() case it might be straight forward though, converting the current logic to something that short circuits passage into the socket and protocol code: if ((so->so_state & SS_ISCONNECTING) && (td->td_flags & TDF_SARESTARTED)) goto skip_proto: ... error = soconnect(so, sa td); ... skip_proto: if ((so->so_state & SS_NBIO) && (so->so_state & SS_ISCONNECTING)) { error = EINPROGRESS; goto done1; } ... This is only good if we can assume the only interruptible sleep of interest is the msleep() waiting for a transition to SS_ISCONNECTED. If the protocol code itself (called via soconnect()) has interruptible sleeps, then we might need more handling here. I have to admit the whole idea of this is worrying, but then so is the socket life cycle state machine :-). Robert N M Watson > > -- > DE > > /*- > * Copyright (c) 2005 Robert N. M. Watson > * All rights reserved. > * > * Redistribution and use in source and binary forms, with or without > * modification, are permitted provided that the following conditions > * are met: > * 1. Redistributions of source code must retain the above copyright > * notice, this list of conditions and the following disclaimer. > * 2. Redistributions in binary form must reproduce the above copyright > * notice, this list of conditions and the following disclaimer in the > * documentation and/or other materials provided with the distribution. > * > * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND > * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE > * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE > * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE > * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL > * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS > * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) > * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT > * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY > * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF > * SUCH DAMAGE. > * > * $FreeBSD$ > */ > > #include > #include > > #include > > #include > > #include > #include > #include > #include > #include > #include > > void > sighandler(int sig) > { > } > > int > main(int argc, char *argv[]) > { > struct sockaddr_in sin; > struct sigaction act; > int sock; > > if (argc != 3) > errx(-1, "usage: connect [ip] [port]"); > > sigfillset(&act.sa_mask); > act.sa_flags = SA_RESTART; > act.sa_handler = sighandler; > sigaction(SIGINFO, &act, NULL); > > bzero(&sin, sizeof(sin)); > sin.sin_len = sizeof(sin); > sin.sin_family = AF_INET; > sin.sin_addr.s_addr = inet_addr(argv[1]); > sin.sin_port = htons(atoi(argv[2])); > > sock = socket(PF_INET, SOCK_STREAM, 0); > if (sock < 0) > err(-1, "socket(PF_INET, SOCK_STREAM, 0)"); > > printf("Connecting to %s:%d\n", inet_ntoa(sin.sin_addr), > htons(sin.sin_port)); > if (connect(sock, (struct sockaddr *)&sin, sizeof(sin)) < 0) > err(-1, "connect(%s %d)", inet_ntoa(sin.sin_addr), > htons(sin.sin_port)); > printf("Connected\n"); > > return (0); > } > > >