So this proves it: "happens-after Listener.Close()" is not a sufficient condition for being able to rebind the address. If another goroutine is in a Listener.Accept() call, the new bind must happen-after the return of both the Listener.Close() and the Listener.Accept() calls.
So the question is: are there any other conditions that can prevent Listener.Close() from resulting in close(2)? Is code that waits for the completion of both Close() and Accept() correct code? I don't understand the polling layer of the runtime to say whether it would be feasible for `Accept()` not to hold a reference during `WaitRead()` --- but it seems like that would be preferable. On Tuesday, September 12, 2017 at 12:39:11 AM UTC-4, Dave Cheney wrote: > > Yup, and when l.Close is called, Accept returns, releasing the readLock. > > > https://github.com/golang/go/blob/2d69e9e259ec0f5d5fbeb3498fbd9fed135fe869/src/internal/poll/fd_unix.go#L321 > > On Tuesday, 12 September 2017 14:30:54 UTC+10, Shivaram Lingamneni wrote: >> >> >> >> On Tuesday, September 12, 2017 at 12:13:15 AM UTC-4, Dave Cheney wrote: >>> >>> >>> >>> On Tuesday, 12 September 2017 13:40:04 UTC+10, Shivaram Lingamneni wrote: >>>> >>>> On Monday, September 11, 2017 at 11:17:01 PM UTC-4, Dave Cheney wrote: >>>>> >>>>> The already in use is probably coming from the TCP stack which waits a >>>>> certain time before allowing the address to be reused. However I thought >>>>> that the net package already used SO_REUSEADDR to avoid the delay in >>>>> close >>>>> to reopen. >>>>> >>>>> >>>>>> The question I'm really asking is not so much how to write code that >>>>>> works in practice (or, rather, appears to do so), but how to be certain >>>>>> (on >>>>>> the basis of the specification and API documentation) that the code is >>>>>> correct. >>>>>> >>>>> >>>>> As written the code is correct. Once the listener is closed, you can >>>>> reopen it, modulo TCP stack vagaries. >>>>> >>>> >>>> The net package is indeed setting SO_REUSEADDR, which allows re-bind on >>>> the address immediately after close(2). The problem is that close(2) is >>>> not >>>> guaranteed to occur as a result of Listener.Close(), because of reference >>>> counting of file descriptors. This is not an issue with the TCP stack; the >>>> runtime is simply failing to issue the required system call. >>>> >>> >>> I've had a look through the code for the TCPListener and I cannot see >>> where the reference count is being bumped by accept. As far as I understand >>> the *netFD returned from Accept is unassociated with the *netFD that is >>> bound to a listening socket. >>> >> >> On the one hand, I am more confident in the claim that "close(2) is not >> guaranteed to occur as a result of Listener.Close()" than I am in the >> specific explanation of `Accept()` holding a reference. On the other hand, >> I think I found the relevant line of code: >> >> >> https://github.com/golang/go/blob/2d69e9e259ec0f5d5fbeb3498fbd9fed135fe869/src/internal/poll/fd_unix.go#L318 >> >> >> If I'm reading this correctly, this layer of Accept() acquires a >> readLock() on the file, which includes a reference acquire: >> >> >> https://github.com/golang/go/blob/2d69e9e259ec0f5d5fbeb3498fbd9fed135fe869/src/internal/poll/fd_mutex.go#L216 >> >> and then continues holding this reference when it "blocks" on >> `fd.pd.WaitRead`. >> > -- You received this message because you are subscribed to the Google Groups "golang-nuts" group. To unsubscribe from this group and stop receiving emails from it, send an email to [email protected]. For more options, visit https://groups.google.com/d/optout.
