Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files. =================================================================== RCS file: /ftp/cvs/cvsroot/src/sys/kern/uipc_socket.c,v retrieving revision 1.29 retrieving revision 1.29.4.2 diff -u -p -r1.29 -r1.29.4.2 --- src/sys/kern/uipc_socket.c 1997/08/27 07:10:01 1.29 +++ src/sys/kern/uipc_socket.c 1999/01/25 05:49:42 1.29.4.2 @@ -1,4 +1,4 @@ -/* $NetBSD: uipc_socket.c,v 1.29 1997/08/27 07:10:01 mycroft Exp $ */ +/* $NetBSD: uipc_socket.c,v 1.29.4.2 1999/01/25 05:49:42 cgd Exp $ */ /* * Copyright (c) 1982, 1986, 1988, 1990, 1993 @@ -79,6 +79,8 @@ socreate(dom, aso, type, proto) return (EPROTOTYPE); MALLOC(so, struct socket *, sizeof(*so), M_SOCKET, M_WAIT); bzero((caddr_t)so, sizeof(*so)); + TAILQ_INIT(&so->so_q0); + TAILQ_INIT(&so->so_q); so->so_type = type; so->so_proto = prp; error = (*prp->pr_usrreq)(so, PRU_ATTACH, (struct mbuf *)0, @@ -127,7 +129,7 @@ solisten(so, backlog) splx(s); return (error); } - if (so->so_q == 0) + if (so->so_q.tqh_first == NULL) so->so_options |= SO_ACCEPTCONN; if (backlog < 0) backlog = 0; @@ -144,9 +146,13 @@ sofree(so) if (so->so_pcb || (so->so_state & SS_NOFDREF) == 0) return; if (so->so_head) { - if (!soqremque(so, 0) && !soqremque(so, 1)) - panic("sofree dq"); - so->so_head = 0; + /* + * We must not decommission a socket that's on the accept(2) + * queue. If we do, then accept(2) may hang after select(2) + * indicated that the listening socket was ready. + */ + if (!soqremque(so, 0)) + return; } sbrelease(&so->so_snd); sorflush(so); @@ -162,14 +168,19 @@ int soclose(so) register struct socket *so; { + struct socket *so2; int s = splsoftnet(); /* conservative */ int error = 0; if (so->so_options & SO_ACCEPTCONN) { - while (so->so_q0) - (void) soabort(so->so_q0); - while (so->so_q) - (void) soabort(so->so_q); + while ((so2 = so->so_q0.tqh_first) != 0) { + (void) soqremque(so2, 0); + (void) soabort(so2); + } + while ((so2 = so->so_q.tqh_first) != 0) { + (void) soqremque(so2, 1); + (void) soabort(so2); + } } if (so->so_pcb == 0) goto discard; @@ -186,7 +197,7 @@ soclose(so) while (so->so_state & SS_ISCONNECTED) { error = tsleep((caddr_t)&so->so_timeo, PSOCK | PCATCH, netcls, - so->so_linger); + so->so_linger * hz); if (error) break; } @@ -232,8 +243,11 @@ soaccept(so, nam) if ((so->so_state & SS_NOFDREF) == 0) panic("soaccept: !NOFDREF"); so->so_state &= ~SS_NOFDREF; - error = (*so->so_proto->pr_usrreq)(so, PRU_ACCEPT, (struct mbuf *)0, - nam, (struct mbuf *)0, (struct proc *)0); + if ((so->so_state & SS_ISDISCONNECTED) == 0) + error = (*so->so_proto->pr_usrreq)(so, PRU_ACCEPT, + (struct mbuf *)0, nam, (struct mbuf *)0, (struct proc *)0); + else + error = 0; splx(s); return (error); }