aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChristopher Faulet <[email protected]>2011-09-14 16:30:44 +0200
committerHenrik Nord <[email protected]>2011-09-16 14:54:44 +0200
commit42c581ddefd332fcadea696b5b2bedcdd575f14a (patch)
tree9f41afc778a70b70e5c50f354a5453864da3e1dd
parent47759479146ca11ad81eca0bb3236b265e20601d (diff)
downloadotp-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.
-rw-r--r--lib/stdlib/src/supervisor.erl123
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) ->