diff options
author | Christopher Faulet <[email protected]> | 2011-09-14 16:30:44 +0200 |
---|---|---|
committer | Henrik Nord <[email protected]> | 2011-09-16 14:54:44 +0200 |
commit | 42c581ddefd332fcadea696b5b2bedcdd575f14a (patch) | |
tree | 9f41afc778a70b70e5c50f354a5453864da3e1dd /lib | |
parent | 47759479146ca11ad81eca0bb3236b265e20601d (diff) | |
download | otp-42c581ddefd332fcadea696b5b2bedcdd575f14a.tar.gz otp-42c581ddefd332fcadea696b5b2bedcdd575f14a.tar.bz2 otp-42c581ddefd332fcadea696b5b2bedcdd575f14a.zip |
Stack errors when dynamic children are stopped
Because a simple_one_for_one supervisor can have many workers, we stack
errors during its shutdown to report only one message for each encountered
error type. Instead of reporting the child's pid, we use the number of
concerned children.
Diffstat (limited to 'lib')
-rw-r--r-- | lib/stdlib/src/supervisor.erl | 123 |
1 files changed, 63 insertions, 60 deletions
diff --git a/lib/stdlib/src/supervisor.erl b/lib/stdlib/src/supervisor.erl index 8e1ac1bb5c..d103487218 100644 --- a/lib/stdlib/src/supervisor.erl +++ b/lib/stdlib/src/supervisor.erl @@ -849,96 +849,92 @@ monitor_child(Pid) -> %% can have an significative overhead here. %%----------------------------------------------------------------- terminate_dynamic_children(Child, Dynamics, SupName) -> - Pids = monitor_dynamic_children(Child, Dynamics, SupName), - Sz = ?SETS:size(Pids), - case Child#child.shutdown of - brutal_kill -> - ?SETS:fold(fun(P, _) -> exit(P, kill) end, ok, Pids), - wait_dynamic_children(Child, Pids, SupName, Sz, undefined); - infinity -> - ?SETS:fold(fun(P, _) -> exit(P, shutdown) end, ok, Pids), - wait_dynamic_children(Child, Pids, SupName, Sz, undefined); - Time -> - ?SETS:fold(fun(P, _) -> exit(P, shutdown) end, ok, Pids), - TRef = erlang:start_timer(Time, self(), kill), - wait_dynamic_children(Child, Pids, SupName, Sz, TRef) - end. - - -monitor_dynamic_children(#child{restart_type=temporary} = Child, - Dynamics, SupName) -> - ?SETS:fold(fun(P, Acc) -> + {Pids, EStack0} = monitor_dynamic_children(Child, Dynamics), + Sz = ?SETS:size(Pids), + EStack = case Child#child.shutdown of + brutal_kill -> + ?SETS:fold(fun(P, _) -> exit(P, kill) end, ok, Pids), + wait_dynamic_children(Child, Pids, Sz, undefined, EStack0); + infinity -> + ?SETS:fold(fun(P, _) -> exit(P, shutdown) end, ok, Pids), + wait_dynamic_children(Child, Pids, Sz, undefined, EStack0); + Time -> + ?SETS:fold(fun(P, _) -> exit(P, shutdown) end, ok, Pids), + TRef = erlang:start_timer(Time, self(), kill), + wait_dynamic_children(Child, Pids, Sz, TRef, EStack0) + end, + %% Unrool stacked errors and report them + ?DICT:fold(fun(Reason, Ls, _) -> + report_error(shutdown_error, Reason, + Child#child{pid=Ls}, SupName) + end, ok, EStack). + + +monitor_dynamic_children(#child{restart_type=temporary}, Dynamics) -> + ?SETS:fold(fun(P, {Pids, EStack}) -> case monitor_child(P) of ok -> - ?SETS:add_element(P, Acc); + {?SETS:add_element(P, Pids), EStack}; {error, normal} -> - Acc; - {error, OtherReason} -> - report_error(shutdown_error, OtherReason, - Child#child{pid=P}, SupName), - Acc + {Pids, EStack}; + {error, Reason} -> + {Pids, ?DICT:append(Reason, P, EStack)} end - end, ?SETS:new(), Dynamics); -monitor_dynamic_children(#child{restart_type=RType} = Child, - Dynamics, SupName) -> - ?DICT:fold(fun(P, _, Acc) -> + end, {?SETS:new(), ?DICT:new()}, Dynamics); +monitor_dynamic_children(#child{restart_type=RType}, Dynamics) -> + ?DICT:fold(fun(P, _, {Pids, EStack}) -> case monitor_child(P) of ok -> - ?SETS:add_element(P, Acc); + {?SETS:add_element(P, Pids), EStack}; {error, normal} when RType =/= permanent -> - Acc; - {error, OtherReason} -> - report_error(shutdown_error, OtherReason, - Child#child{pid=P}, SupName), - Acc + {Pids, EStack}; + {error, Reason} -> + {Pids, ?DICT:append(Reason, P, EStack)} end - end, ?SETS:new(), Dynamics). - + end, {?SETS:new(), ?DICT:new()}, Dynamics). -wait_dynamic_children(_Child, _Pids, _SupName, 0, undefined) -> - ok; -wait_dynamic_children(_Child, _Pids, _SupName, 0, TRef) -> +wait_dynamic_children(_Child, _Pids, 0, undefined, EStack) -> + EStack; +wait_dynamic_children(_Child, _Pids, 0, TRef, EStack) -> %% If the timer has expired before its cancellation, we must empty the %% mail-box of the 'timeout'-message. erlang:cancel_timer(TRef), receive {timeout, TRef, kill} -> - ok + EStack after 0 -> - ok + EStack end; -wait_dynamic_children(#child{shutdown=brutal_kill} = Child, - Pids, SupName, Sz, TRef) -> +wait_dynamic_children(#child{shutdown=brutal_kill} = Child, Pids, Sz, + TRef, EStack) -> receive {'DOWN', _MRef, process, Pid, killed} -> - wait_dynamic_children(Child, ?SETS:del_element(Pid, Pids), SupName, - Sz-1, TRef); + wait_dynamic_children(Child, ?SETS:del_element(Pid, Pids), Sz-1, + TRef, EStack); {'DOWN', _MRef, process, Pid, Reason} -> - report_error(shutdown_error, Reason, Child#child{pid=Pid}, SupName), - wait_dynamic_children(Child, ?SETS:del_element(Pid, Pids), SupName, - Sz-1, TRef) + wait_dynamic_children(Child, ?SETS:del_element(Pid, Pids), Sz-1, + TRef, ?DICT:append(Reason, Pid, EStack)) end; -wait_dynamic_children(#child{restart_type=RType} = Child, Pids, - SupName, Sz, TRef) -> +wait_dynamic_children(#child{restart_type=RType} = Child, Pids, Sz, + TRef, EStack) -> receive {'DOWN', _MRef, process, Pid, shutdown} -> - wait_dynamic_children(Child, ?SETS:del_element(Pid, Pids), SupName, - Sz-1, TRef); + wait_dynamic_children(Child, ?SETS:del_element(Pid, Pids), Sz-1, + TRef, EStack); {'DOWN', _MRef, process, Pid, normal} when RType =/= permanent -> - wait_dynamic_children(Child, ?SETS:del_element(Pid, Pids), SupName, - Sz-1, TRef); + wait_dynamic_children(Child, ?SETS:del_element(Pid, Pids), Sz-1, + TRef, EStack); {'DOWN', _MRef, process, Pid, Reason} -> - report_error(shutdown_error, Reason, Child#child{pid=Pid}, SupName), - wait_dynamic_children(Child, ?SETS:del_element(Pid, Pids), SupName, - Sz-1, TRef); + wait_dynamic_children(Child, ?SETS:del_element(Pid, Pids), Sz-1, + TRef, ?DICT:append(Reason, Pid, EStack)); {timeout, TRef, kill} -> ?SETS:fold(fun(P, _) -> exit(P, kill) end, ok, Pids), - wait_dynamic_children(Child, Pids, SupName, Sz, undefined) + wait_dynamic_children(Child, Pids, Sz-1, undefined, EStack) end. %%----------------------------------------------------------------- @@ -1243,12 +1239,19 @@ report_error(Error, Reason, Child, SupName) -> error_logger:error_report(supervisor_report, ErrorMsg). -extract_child(Child) -> +extract_child(Child) when is_pid(Child#child.pid) -> [{pid, Child#child.pid}, {name, Child#child.name}, {mfargs, Child#child.mfargs}, {restart_type, Child#child.restart_type}, {shutdown, Child#child.shutdown}, + {child_type, Child#child.child_type}]; +extract_child(Child) -> + [{nb_children, length(Child#child.pid)}, + {name, Child#child.name}, + {mfargs, Child#child.mfargs}, + {restart_type, Child#child.restart_type}, + {shutdown, Child#child.shutdown}, {child_type, Child#child.child_type}]. report_progress(Child, SupName) -> |