Browse Source

Properly clean up timers when terminating

Loïc Hoguin 7 years ago
parent
commit
daef32d907
1 changed files with 20 additions and 5 deletions
  1. 20 5
      src/cowboy_children.erl

+ 20 - 5
src/cowboy_children.erl

@@ -99,9 +99,16 @@ shutdown_timeout(Children, Ref, Pid) ->
 
 -spec terminate(children()) -> ok.
 terminate(Children) ->
-	%% Ask all children to shutdown first.
-	_ = [exit(Pid, shutdown) || #child{pid=Pid} <- Children],
-	%% Loop until that time or until all children are dead.
+	%% For each child, either ask for it to shut down,
+	%% or cancel its shutdown timer if it already is.
+	%%
+	%% We do not need to flush stray timeout messages out because
+	%% we are either terminating or switching protocols,
+	%% and in the latter case we flush all messages.
+	_ = [case TRef of
+		undefined -> exit(Pid, shutdown);
+		_ -> erlang:cancel_timer(TRef, [{async, true}, {info, false}])
+	end || #child{pid=Pid, timer=TRef} <- Children],
 	before_terminate_loop(Children).
 
 before_terminate_loop([]) ->
@@ -115,10 +122,18 @@ before_terminate_loop(Children) ->
 		infinity -> undefined;
 		_ -> erlang:start_timer(Time, self(), terminate)
 	end,
+	%% Loop until that time or until all children are dead.
 	terminate_loop(Children, TRef).
 
-terminate_loop([], _) ->
-	ok;
+terminate_loop([], TRef) ->
+	%% Don't forget to cancel the timer, if any!
+	case TRef of
+		undefined ->
+			ok;
+		_ ->
+			_ = erlang:cancel_timer(TRef, [{async, true}, {info, false}]),
+			ok
+	end;
 terminate_loop(Children, TRef) ->
 	receive
 		{'EXIT', Pid, _} when TRef =:= undefined ->