diff options
author | Emile Joubert <emile@rabbitmq.com> | 2011-11-07 13:07:30 +0000 |
---|---|---|
committer | Emile Joubert <emile@rabbitmq.com> | 2011-11-07 13:07:30 +0000 |
commit | 9c8a388c061477c00e07fdc60b5abf4563ea7011 (patch) | |
tree | c380f2ef705d3444da2ef3856953940642c0c9f3 /src | |
parent | b43248811c2b1e380218bfff5e6713ce6ec6d083 (diff) | |
parent | a4460624b982c294bd3bf35d13474b6191c01998 (diff) | |
download | rabbitmq-server-9c8a388c061477c00e07fdc60b5abf4563ea7011.tar.gz |
Merged bug24534 into default
Diffstat (limited to 'src')
-rw-r--r-- | src/supervisor2.erl | 72 |
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}, |