diff options
author | Matt Holt <mholt@users.noreply.github.com> | 2023-03-02 21:00:18 -0700 |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-03-03 04:00:18 +0000 |
commit | 99d47050e97a8ccac2aad3bda46be46d4fec85ed (patch) | |
tree | 0cba5f2c4cf9191e5dfa72b1f063b93d2a92c784 /listen_unix.go | |
parent | 85375861f6a903da9af8aa665552a6546d075c9f (diff) |
core: Eliminate unnecessary shutdown delay on Unix (#5413)
* core: Eliminate unnecessary shutdown delay on Unix
Fix #5393, alternate to #5405
* Comments, cleanup, adjust logs
* Fix build constraint
Diffstat (limited to 'listen_unix.go')
-rw-r--r-- | listen_unix.go | 36 |
1 files changed, 31 insertions, 5 deletions
diff --git a/listen_unix.go b/listen_unix.go index 7ea6745..50d9a66 100644 --- a/listen_unix.go +++ b/listen_unix.go @@ -12,10 +12,10 @@ // See the License for the specific language governing permissions and // limitations under the License. -// TODO: Go 1.19 introduced the "unix" build tag. We have to support Go 1.18 until Go 1.20 is released. -// When Go 1.19 is our minimum, remove this build tag, since "_unix" in the filename will do this. -// (see also change needed in listen.go) -//go:build aix || android || darwin || dragonfly || freebsd || hurd || illumos || ios || linux || netbsd || openbsd || solaris +// Even though the filename ends in _unix.go, we still have to specify the +// build constraint here, because the filename convention only works for +// literal GOOS values, and "unix" is a shortcut unique to build tags. +//go:build unix package caddy @@ -98,7 +98,19 @@ func listenTCPOrUnix(ctx context.Context, lnKey string, network, address string, } return reusePort(network, address, c) } - return config.Listen(ctx, network, address) + + // even though SO_REUSEPORT lets us bind the socket multiple times, + // we still put it in the listenerPool so we can count how many + // configs are using this socket; necessary to ensure we can know + // whether to enforce shutdown delays, for example (see #5393). + ln, err := config.Listen(ctx, network, address) + if err == nil { + listenerPool.LoadOrStore(lnKey, nil) + } + + // lightly wrap the listener so that when it is closed, + // we can decrement the usage pool counter + return deleteListener{ln, lnKey}, err } // reusePort sets SO_REUSEPORT. Ineffective for unix sockets. @@ -116,3 +128,17 @@ func reusePort(network, address string, conn syscall.RawConn) error { } }) } + +// deleteListener is a type that simply deletes itself +// from the listenerPool when it closes. It is used +// solely for the purpose of reference counting (i.e. +// counting how many configs are using a given socket). +type deleteListener struct { + net.Listener + lnKey string +} + +func (dl deleteListener) Close() error { + _, _ = listenerPool.Delete(dl.lnKey) + return dl.Listener.Close() +} |