@@ -2541,6 +2541,7 @@ func (s *Server) closeDoneChanLocked() {
2541
2541
// Close returns any error returned from closing the Server's
2542
2542
// underlying Listener(s).
2543
2543
func (srv * Server ) Close () error {
2544
+ atomic .StoreInt32 (& srv .inShutdown , 1 )
2544
2545
srv .mu .Lock ()
2545
2546
defer srv .mu .Unlock ()
2546
2547
srv .closeDoneChanLocked ()
@@ -2578,9 +2579,11 @@ var shutdownPollInterval = 500 * time.Millisecond
2578
2579
// separately notify such long-lived connections of shutdown and wait
2579
2580
// for them to close, if desired. See RegisterOnShutdown for a way to
2580
2581
// register shutdown notification functions.
2582
+ //
2583
+ // Once Shutdown has been called on a server, it may not be reused;
2584
+ // future calls to methods such as Serve will return ErrServerClosed.
2581
2585
func (srv * Server ) Shutdown (ctx context.Context ) error {
2582
- atomic .AddInt32 (& srv .inShutdown , 1 )
2583
- defer atomic .AddInt32 (& srv .inShutdown , - 1 )
2586
+ atomic .StoreInt32 (& srv .inShutdown , 1 )
2584
2587
2585
2588
srv .mu .Lock ()
2586
2589
lnerr := srv .closeListenersLocked ()
@@ -2727,6 +2730,9 @@ func (sh serverHandler) ServeHTTP(rw ResponseWriter, req *Request) {
2727
2730
// If srv.Addr is blank, ":http" is used.
2728
2731
// ListenAndServe always returns a non-nil error.
2729
2732
func (srv * Server ) ListenAndServe () error {
2733
+ if srv .shuttingDown () {
2734
+ return ErrServerClosed
2735
+ }
2730
2736
addr := srv .Addr
2731
2737
if addr == "" {
2732
2738
addr = ":http"
@@ -2775,8 +2781,8 @@ var ErrServerClosed = errors.New("http: Server closed")
2775
2781
// srv.TLSConfig is non-nil and doesn't include the string "h2" in
2776
2782
// Config.NextProtos, HTTP/2 support is not enabled.
2777
2783
//
2778
- // Serve always returns a non-nil error. After Shutdown or Close, the
2779
- // returned error is ErrServerClosed.
2784
+ // Serve always returns a non-nil error and closes l.
2785
+ // After Shutdown or Close, the returned error is ErrServerClosed.
2780
2786
func (srv * Server ) Serve (l net.Listener ) error {
2781
2787
if fn := testHookServerServe ; fn != nil {
2782
2788
fn (srv , l ) // call hook with unwrapped listener
@@ -2785,15 +2791,19 @@ func (srv *Server) Serve(l net.Listener) error {
2785
2791
l = & onceCloseListener {Listener : l }
2786
2792
defer l .Close ()
2787
2793
2788
- var tempDelay time.Duration // how long to sleep on accept failure
2789
-
2790
2794
if err := srv .setupHTTP2_Serve (); err != nil {
2791
2795
return err
2792
2796
}
2793
2797
2794
- srv .trackListener (& l , true )
2798
+ serveDone := make (chan struct {})
2799
+ defer close (serveDone )
2800
+
2801
+ if ! srv .trackListener (& l , true ) {
2802
+ return ErrServerClosed
2803
+ }
2795
2804
defer srv .trackListener (& l , false )
2796
2805
2806
+ var tempDelay time.Duration // how long to sleep on accept failure
2797
2807
baseCtx := context .Background () // base is always background, per Issue 16220
2798
2808
ctx := context .WithValue (baseCtx , ServerContextKey , srv )
2799
2809
for {
@@ -2877,13 +2887,18 @@ func (srv *Server) ServeTLS(l net.Listener, certFile, keyFile string) error {
2877
2887
// trackListener via Serve and can track+defer untrack the same
2878
2888
// pointer to local variable there. We never need to compare a
2879
2889
// Listener from another caller.
2880
- func (s * Server ) trackListener (ln * net.Listener , add bool ) {
2890
+ //
2891
+ // It reports whether the server is still up (not Shutdown or Closed).
2892
+ func (s * Server ) trackListener (ln * net.Listener , add bool ) bool {
2881
2893
s .mu .Lock ()
2882
2894
defer s .mu .Unlock ()
2883
2895
if s .listeners == nil {
2884
2896
s .listeners = make (map [* net.Listener ]struct {})
2885
2897
}
2886
2898
if add {
2899
+ if s .shuttingDown () {
2900
+ return false
2901
+ }
2887
2902
// If the *Server is being reused after a previous
2888
2903
// Close or Shutdown, reset its doneChan:
2889
2904
if len (s .listeners ) == 0 && len (s .activeConn ) == 0 {
@@ -2893,6 +2908,7 @@ func (s *Server) trackListener(ln *net.Listener, add bool) {
2893
2908
} else {
2894
2909
delete (s .listeners , ln )
2895
2910
}
2911
+ return true
2896
2912
}
2897
2913
2898
2914
func (s * Server ) trackConn (c * conn , add bool ) {
@@ -2927,6 +2943,8 @@ func (s *Server) doKeepAlives() bool {
2927
2943
}
2928
2944
2929
2945
func (s * Server ) shuttingDown () bool {
2946
+ // TODO: replace inShutdown with the existing atomicBool type;
2947
+ // see https://github.com/golang/go/issues/20239#issuecomment-381434582
2930
2948
return atomic .LoadInt32 (& s .inShutdown ) != 0
2931
2949
}
2932
2950
@@ -3055,6 +3073,9 @@ func ListenAndServeTLS(addr, certFile, keyFile string, handler Handler) error {
3055
3073
//
3056
3074
// ListenAndServeTLS always returns a non-nil error.
3057
3075
func (srv * Server ) ListenAndServeTLS (certFile , keyFile string ) error {
3076
+ if srv .shuttingDown () {
3077
+ return ErrServerClosed
3078
+ }
3058
3079
addr := srv .Addr
3059
3080
if addr == "" {
3060
3081
addr = ":https"
0 commit comments