Permalink
Browse files

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.
  • Loading branch information...
1 parent c35108d commit bddb6278c3f7d54cef888e4cfc964228124be3b4 @capflam committed Sep 14, 2011
Showing with 63 additions and 60 deletions.
  1. +63 −60 lib/stdlib/src/supervisor.erl
View
123 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) ->

0 comments on commit bddb627

Please sign in to comment.