summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEmile Joubert <emile@rabbitmq.com>2011-11-07 13:07:30 +0000
committerEmile Joubert <emile@rabbitmq.com>2011-11-07 13:07:30 +0000
commit9c8a388c061477c00e07fdc60b5abf4563ea7011 (patch)
treec380f2ef705d3444da2ef3856953940642c0c9f3
parentb43248811c2b1e380218bfff5e6713ce6ec6d083 (diff)
parenta4460624b982c294bd3bf35d13474b6191c01998 (diff)
downloadrabbitmq-server-9c8a388c061477c00e07fdc60b5abf4563ea7011.tar.gz
Merged bug24534 into default
-rw-r--r--src/supervisor2.erl72
1 files changed, 65 insertions, 7 deletions
diff --git a/src/supervisor2.erl b/src/supervisor2.erl
index 405949ef..f75da872 100644
--- a/src/supervisor2.erl
+++ b/src/supervisor2.erl
@@ -649,15 +649,69 @@ terminate_children([], _SupName, Res) ->
Res.
terminate_simple_children(Child, Dynamics, SupName) ->
- dict:fold(fun (Pid, _Args, _Any) ->
- do_terminate(Child#child{pid = Pid}, SupName)
- end, ok, Dynamics),
+ Pids = dict:fold(fun (Pid, _Args, Pids) ->
+ erlang:monitor(process, Pid),
+ unlink(Pid),
+ exit(Pid, child_exit_reason(Child)),
+ [Pid | Pids]
+ end, [], Dynamics),
+ TimeoutMsg = {timeout, make_ref()},
+ TRef = timeout_start(Child, TimeoutMsg),
+ {Replies, Timedout} =
+ lists:foldl(
+ fun (_Pid, {Replies, Timedout}) ->
+ {Reply, Timedout1} =
+ receive
+ TimeoutMsg ->
+ Remaining = Pids -- [P || {P, _} <- Replies],
+ [exit(P, kill) || P <- Remaining],
+ receive {'DOWN', _MRef, process, Pid, Reason} ->
+ {{error, Reason}, true}
+ end;
+ {'DOWN', _MRef, process, Pid, Reason} ->
+ {child_res(Child, Reason, Timedout), Timedout};
+ {'EXIT', Pid, Reason} ->
+ receive {'DOWN', _MRef, process, Pid, _} ->
+ {{error, Reason}, Timedout}
+ end
+ end,
+ {[{Pid, Reply} | Replies], Timedout1}
+ end, {[], false}, Pids),
+ timeout_stop(Child, TRef, TimeoutMsg, Timedout),
+ ReportError = shutdown_error_reporter(SupName),
+ [case Reply of
+ {_Pid, ok} -> ok;
+ {Pid, {error, R}} -> ReportError(R, Child#child{pid = Pid})
+ end || Reply <- Replies],
+ ok.
+
+child_exit_reason(#child{shutdown = brutal_kill}) -> kill;
+child_exit_reason(#child{}) -> shutdown.
+
+child_res(#child{shutdown=brutal_kill}, killed, false) -> ok;
+child_res(#child{}, shutdown, false) -> ok;
+child_res(#child{restart_type=permanent}, normal, false) -> {error, normal};
+child_res(#child{restart_type={permanent,_}},normal, false) -> {error, normal};
+child_res(#child{}, normal, false) -> ok;
+child_res(#child{}, R, _) -> {error, R}.
+
+timeout_start(#child{shutdown = Time}, Msg) when is_integer(Time) ->
+ erlang:send_after(Time, self(), Msg);
+timeout_start(#child{}, _Msg) ->
+ ok.
+
+timeout_stop(#child{shutdown = Time}, TRef, Msg, false) when is_integer(Time) ->
+ erlang:cancel_timer(TRef),
+ receive
+ Msg -> ok
+ after
+ 0 -> ok
+ end;
+timeout_stop(#child{}, ok, _Msg, _Timedout) ->
ok.
do_terminate(Child, SupName) when Child#child.pid =/= undefined ->
- ReportError = fun (Reason) ->
- report_error(shutdown_error, Reason, Child, SupName)
- end,
+ ReportError = shutdown_error_reporter(SupName),
case shutdown(Child#child.pid, Child#child.shutdown) of
ok ->
ok;
@@ -668,7 +722,7 @@ do_terminate(Child, SupName) when Child#child.pid =/= undefined ->
_ -> ok
end;
{error, OtherReason} ->
- ReportError(OtherReason)
+ ReportError(OtherReason, Child)
end,
Child#child{pid = undefined};
do_terminate(Child, _SupName) ->
@@ -998,6 +1052,10 @@ report_error(Error, Reason, Child, SupName) ->
{offender, extract_child(Child)}],
error_logger:error_report(supervisor_report, ErrorMsg).
+shutdown_error_reporter(SupName) ->
+ fun(Reason, Child) ->
+ report_error(shutdown_error, Reason, Child, SupName)
+ end.
extract_child(Child) ->
[{pid, Child#child.pid},