aboutsummaryrefslogtreecommitdiffstats
path: root/lib/stdlib
diff options
context:
space:
mode:
Diffstat (limited to 'lib/stdlib')
-rw-r--r--lib/stdlib/doc/src/supervisor.xml44
-rw-r--r--lib/stdlib/src/dets_v8.erl40
-rw-r--r--lib/stdlib/src/edlin.erl10
-rw-r--r--lib/stdlib/src/escript.erl71
-rw-r--r--lib/stdlib/src/file_sorter.erl34
-rw-r--r--lib/stdlib/src/qlc.erl159
-rw-r--r--lib/stdlib/src/qlc_pt.erl32
-rw-r--r--lib/stdlib/src/supervisor.erl59
-rw-r--r--lib/stdlib/test/supervisor_SUITE.erl175
9 files changed, 415 insertions, 209 deletions
diff --git a/lib/stdlib/doc/src/supervisor.xml b/lib/stdlib/doc/src/supervisor.xml
index adf9d24eae..c696434d49 100644
--- a/lib/stdlib/doc/src/supervisor.xml
+++ b/lib/stdlib/doc/src/supervisor.xml
@@ -4,7 +4,7 @@
<erlref>
<header>
<copyright>
- <year>1996</year><year>2009</year>
+ <year>1996</year><year>2010</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -13,12 +13,12 @@
compliance with the License. You should have received a copy of the
Erlang Public License along with this software. If not, it can be
retrieved online at http://www.erlang.org/.
-
+
Software distributed under the License is distributed on an "AS IS"
basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
the License for the specific language governing rights and limitations
under the License.
-
+
</legalnotice>
<title>supervisor</title>
@@ -402,9 +402,12 @@ child_spec() = {Id,StartFunc,Restart,Shutdown,Type,Modules}
<v>&nbsp;Module = atom()</v>
</type>
<desc>
- <p>Returns a list with information about all child
+ <p>Returns a newly created list with information about all child
specifications and child processes belonging to
the supervisor <c>SupRef</c>.</p>
+ <p>Note that calling this function when supervising a large
+ number of children under low memory conditions can cause an
+ out of memory exception.</p>
<p>See <c>start_child/2</c> for a description of <c>SupRef</c>.</p>
<p>The information given for each child specification/process
is:</p>
@@ -428,6 +431,39 @@ child_spec() = {Id,StartFunc,Restart,Shutdown,Type,Modules}
</desc>
</func>
<func>
+ <name>count_children(SupRef) -> PropListOfCounts</name>
+ <fsummary>Return counts for the number of childspecs, active children, supervisors and workers.</fsummary>
+ <type>
+ <v>SupRef = Name | {Name,Node} | {global,Name} | pid()</v>
+ <v>&nbsp;Name = Node = atom()</v>
+ <v>PropListOfCounts = [{specs, ChildSpecCount}, {active, ActiveProcessCount}, {supervisors, ChildSupervisorCount}, {workers, ChildWorkerCount}]</v>
+ </type>
+ <desc>
+ <p>Returns a property list (see <c>proplists</c>) containing the
+ counts for each of the following elements of the supervisor's
+ child specifications and managed processes:</p>
+ <list type="bulleted">
+ <item>
+ <p><c>specs</c> - the total count of children, dead or alive.</p>
+ </item>
+ <item>
+ <p><c>active</c> - the count of all actively running child processes
+ managed by this supervisor.</p>
+ </item>
+ <item>
+ <p><c>supervisors</c> - the count of all children marked as
+ child_type = supervisor in the spec list, whether or not the
+ child process is still alive.</p>
+ </item>
+ <item>
+ <p><c>workers</c> - the count of all children marked as
+ child_type = worker in the spec list, whether or not the child
+ process is still alive.</p>
+ </item>
+ </list>
+ </desc>
+ </func>
+ <func>
<name>check_childspecs([ChildSpec]) -> Result</name>
<fsummary>Check if children specifications are syntactically correct.</fsummary>
<type>
diff --git a/lib/stdlib/src/dets_v8.erl b/lib/stdlib/src/dets_v8.erl
index b24df02882..1f9f84cd27 100644
--- a/lib/stdlib/src/dets_v8.erl
+++ b/lib/stdlib/src/dets_v8.erl
@@ -1,19 +1,19 @@
%%
%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2001-2009. All Rights Reserved.
-%%
+%%
+%% Copyright Ericsson AB 2001-2010. All Rights Reserved.
+%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
%% compliance with the License. You should have received a copy of the
%% Erlang Public License along with this software. If not, it can be
%% retrieved online at http://www.erlang.org/.
-%%
+%%
%% Software distributed under the License is distributed on an "AS IS"
%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
%% the License for the specific language governing rights and limitations
%% under the License.
-%%
+%%
%% %CopyrightEnd%
%%
-module(dets_v8).
@@ -1053,14 +1053,14 @@ wl([{_Seq, {insert, Object}} | Cs], Type, _Del, Lookup, _I, _Objs)
wl(Cs, Type, delete, Lookup, 1, [{Object,-1}]);
wl([{_Seq, {insert, Object}} | Cs], Type, Del, Lookup, _I, Objs) ->
NObjs =
- case lists:keysearch(Object, 1, Objs) of
- {value, {_, 0}} ->
+ case lists:keyfind(Object, 1, Objs) of
+ {_, 0} ->
lists:keyreplace(Object, 1, Objs, {Object,-1});
- {value, {_, _C}} when Type =:= bag -> % C =:= 1; C =:= -1
+ {_, _C} when Type =:= bag -> % C =:= 1; C =:= -1
Objs;
- {value, {_, C}} when C < 0 -> % when Type =:= duplicate_bag
+ {_, C} when C < 0 -> % when Type =:= duplicate_bag
lists:keyreplace(Object, 1, Objs, {Object,C-1});
- {value, {_, C}} -> % when C > 0, Type =:= duplicate_bag
+ {_, C} -> % when C > 0, Type =:= duplicate_bag
lists:keyreplace(Object, 1, Objs, {Object,C+1});
false when Del =:= delete ->
[{Object, -1} | Objs];
@@ -1258,8 +1258,8 @@ eval_slot(Head, TrySize, Pos, WLs, L, LU) ->
find_key(Head, Pos, NextPos, Size, Term, Key, WLs, L, LU).
find_key(Head, Pos, NextPos, Size, Term, Key, WLs, L, LU) ->
- case lists:keysearch(Key, 1, WLs) of
- {value, {_, {Delete, LookUp, Objects}} = WL} ->
+ case lists:keyfind(Key, 1, WLs) of
+ {_, {Delete, LookUp, Objects}} = WL ->
NWLs = lists:delete(WL, WLs),
{NewObjects, NL, LUK} = eval_object(Size, Term, Delete, LookUp,
Objects, Head, Pos, L, []),
@@ -1297,30 +1297,30 @@ eval_key(Key, Delete, LookUp, Objects, Head, Pos, WLs, L, LU, LUK) ->
%% All objects in Objects have the key Key.
eval_object(Size, Term, Delete, LookUp, Objects, Head, Pos, L, LU) ->
Type = Head#head.type,
- case lists:keysearch(Term, 1, Objects) of
- {value, {_Object, N}} when N =:= 0 ->
+ case lists:keyfind(Term, 1, Objects) of
+ {_Object, N} when N =:= 0 ->
L1 = [{delete,Pos,Size} | L],
{Objects, L1, LU};
- {value, {_Object, N}} when N < 0, Type =:= set ->
+ {_Object, N} when N < 0, Type =:= set ->
L1 = [{old,Pos} | L],
wl_lookup(LookUp, Objects, Term, L1, LU);
- {value, {Object, _N}} when Type =:= bag -> % when N =:= 1; N =:= -1
+ {Object, _N} when Type =:= bag -> % when N =:= 1; N =:= -1
L1 = [{old,Pos} | L],
Objects1 = lists:keydelete(Object, 1, Objects),
wl_lookup(LookUp, Objects1, Term, L1, LU);
- {value, {Object, N}} when N < 0, Type =:= duplicate_bag ->
+ {Object, N} when N < 0, Type =:= duplicate_bag ->
L1 = [{old,Pos} | L],
Objects1 = lists:keyreplace(Object, 1, Objects, {Object,N+1}),
wl_lookup(LookUp, Objects1, Term, L1, LU);
- {value, {_Object, N}} when N > 0, Type =:= duplicate_bag ->
+ {_Object, N} when N > 0, Type =:= duplicate_bag ->
L1 = [{old,Pos} | L],
wl_lookup(LookUp, Objects, Term, L1, LU);
false when Type =:= set, Delete =:= delete ->
- case lists:keysearch(-1, 2, Objects) of
+ case lists:keyfind(-1, 2, Objects) of
false -> % no inserted object, perhaps deleted objects
L1 = [{delete,Pos,Size} | L],
{[], L1, LU};
- {value, {Term2,-1}} ->
+ {Term2, -1} ->
Bin2 = term_to_binary(Term2),
NSize = byte_size(Bin2),
Overwrite =
diff --git a/lib/stdlib/src/edlin.erl b/lib/stdlib/src/edlin.erl
index 0e98bbaa06..6cb441dbed 100644
--- a/lib/stdlib/src/edlin.erl
+++ b/lib/stdlib/src/edlin.erl
@@ -30,8 +30,6 @@
-import(lists, [reverse/1, reverse/2]).
-%-import([nthtail/2, keysearch/3, prefix/2]).
-
-export([over_word/3]).
@@ -476,8 +474,8 @@ prompt({line,Pbs,_,_}) ->
%% case erlang:module_loaded(Mod) of
%% true ->
%% L = apply(Mod, module_info, []),
-%% case keysearch(exports, 1, L) of
-%% {value, {_, Exports}} ->
+%% case lists:keyfind(exports, 1, L) of
+%% {_, Exports} ->
%% match(FuncPrefix, Exports, "(");
%% _ ->
%% no
@@ -493,7 +491,7 @@ prompt({line,Pbs,_,_}) ->
%% print_matches(Matches),
%% no;
%% {partial, Str} ->
-%% case nthtail(length(Prefix), Str) of
+%% case lists:nthtail(length(Prefix), Str) of
%% [] ->
%% print_matches(Matches),
%% {yes, []};
@@ -501,7 +499,7 @@ prompt({line,Pbs,_,_}) ->
%% {yes, Remain}
%% end;
%% {complete, Str} ->
-%% {yes, nthtail(length(Prefix), Str) ++ Extra};
+%% {yes, lists:nthtail(length(Prefix), Str) ++ Extra};
%% no ->
%% no
%% end.
diff --git a/lib/stdlib/src/escript.erl b/lib/stdlib/src/escript.erl
index c0f71fb3f5..b2562c6169 100644
--- a/lib/stdlib/src/escript.erl
+++ b/lib/stdlib/src/escript.erl
@@ -139,7 +139,8 @@ start(EscriptOptions) ->
parse_and_run(File, Args, Options) ->
CheckOnly = lists:member("s", Options),
- {Source, Module, FormsOrBin, Mode} = parse_file(File, CheckOnly),
+ {Source, Module, FormsOrBin, HasRecs, Mode} =
+ parse_file(File, CheckOnly),
Mode2 =
case lists:member("d", Options) of
true ->
@@ -159,7 +160,7 @@ parse_and_run(File, Args, Options) ->
is_list(FormsOrBin) ->
case Mode2 of
interpret ->
- interpret(FormsOrBin, File, Args);
+ interpret(FormsOrBin, HasRecs, File, Args);
compile ->
case compile:forms(FormsOrBin, [report]) of
{ok, Module, BeamBin} ->
@@ -246,7 +247,8 @@ parse_file(File, CheckOnly) ->
#state{mode = Mode,
source = Source,
module = Module,
- forms_or_bin = FormsOrBin} =
+ forms_or_bin = FormsOrBin,
+ has_records = HasRecs} =
case ScriptType of
archive ->
%% Archive file
@@ -260,7 +262,7 @@ parse_file(File, CheckOnly) ->
%% Source code
parse_source(S, File, Fd, StartLine, HeaderSz, CheckOnly)
end,
- {Source, Module, FormsOrBin, Mode}.
+ {Source, Module, FormsOrBin, HasRecs, Mode}.
%% Skip header and make a heuristic guess about the script type
skip_header(P, LineNo) ->
@@ -421,8 +423,7 @@ check_source(S, CheckOnly) ->
case S of
#state{n_errors = Nerrs} when Nerrs =/= 0 ->
fatal("There were compilation errors.");
- #state{exports_main = ExpMain,
- has_records = HasRecs,
+ #state{exports_main = ExpMain,
forms_or_bin = [FileForm2, ModForm2 | Forms]} ->
%% Optionally add export of main/1
Forms2 =
@@ -433,36 +434,15 @@ check_source(S, CheckOnly) ->
Forms3 = [FileForm2, ModForm2 | Forms2],
case CheckOnly of
true ->
- %% Optionally expand records
- Forms4 =
- case HasRecs of
- false -> Forms3;
- true -> erl_expand_records:module(Forms3, [])
- end,
%% Strong validation and halt
- case compile:forms(Forms4, [report,strong_validation]) of
+ case compile:forms(Forms3, [report,strong_validation]) of
{ok,_} ->
my_halt(0);
_Other ->
fatal("There were compilation errors.")
end;
false ->
- %% Basic validation before execution
- case erl_lint:module(Forms3) of
- {ok,Ws} ->
- report_warnings(Ws);
- {error,Es,Ws} ->
- report_errors(Es),
- report_warnings(Ws),
- fatal("There were compilation errors.")
- end,
- %% Optionally expand records
- Forms4 =
- case HasRecs of
- false -> Forms3;
- true -> erl_expand_records:module(Forms3, [])
- end,
- S#state{forms_or_bin = Forms4}
+ S#state{forms_or_bin = Forms3}
end
end.
@@ -495,17 +475,9 @@ epp_parse_file2(Epp, S, Forms, Parsed) ->
case Parsed of
{ok, Form} ->
case Form of
- {attribute,Ln,record,{Record,Fields}} ->
- S2 = S#state{has_records = true},
- case epp:normalize_typed_record_fields(Fields) of
- {typed, NewFields} ->
- epp_parse_file(Epp, S2,
- [{attribute, Ln, record, {Record, NewFields}},
- {attribute, Ln, type,
- {{record, Record}, Fields, []}} | Forms]);
- not_typed ->
- epp_parse_file(Epp, S2, [Form | Forms])
- end;
+ {attribute,_,record, _} ->
+ S2 = S#state{has_records = true},
+ epp_parse_file(Epp, S2, [Form | Forms]);
{attribute,Ln,mode,NewMode} ->
S2 = S#state{mode = NewMode},
if
@@ -564,8 +536,23 @@ run(Module, Args) ->
fatal(format_exception(Class, Reason))
end.
-interpret(Forms, File, Args) ->
- Dict = parse_to_dict(Forms),
+interpret(Forms, HasRecs, File, Args) ->
+ %% Basic validation before execution
+ case erl_lint:module(Forms) of
+ {ok,Ws} ->
+ report_warnings(Ws);
+ {error,Es,Ws} ->
+ report_errors(Es),
+ report_warnings(Ws),
+ fatal("There were compilation errors.")
+ end,
+ %% Optionally expand records
+ Forms2 =
+ case HasRecs of
+ false -> Forms;
+ true -> erl_expand_records:module(Forms, [])
+ end,
+ Dict = parse_to_dict(Forms2),
ArgsA = erl_parse:abstract(Args, 0),
Call = {call,0,{atom,0,main},[ArgsA]},
try
diff --git a/lib/stdlib/src/file_sorter.erl b/lib/stdlib/src/file_sorter.erl
index de9e628e22..e21a0c88f3 100644
--- a/lib/stdlib/src/file_sorter.erl
+++ b/lib/stdlib/src/file_sorter.erl
@@ -1,19 +1,19 @@
%%
%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2001-2009. All Rights Reserved.
-%%
+%%
+%% Copyright Ericsson AB 2001-2010. All Rights Reserved.
+%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
%% compliance with the License. You should have received a copy of the
%% Erlang Public License along with this software. If not, it can be
%% retrieved online at http://www.erlang.org/.
-%%
+%%
%% Software distributed under the License is distributed on an "AS IS"
%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
%% the License for the specific language governing rights and limitations
%% under the License.
-%%
+%%
%% %CopyrightEnd%
%%
-module(file_sorter).
@@ -186,7 +186,7 @@ options(Option) ->
options([{format, Format} | L], Opts) when Format =:= binary;
Format =:= term;
is_function(Format),
- is_function(Format, 1) ->
+ is_function(Format, 1) ->
options(L, Opts#opts{format = Format});
options([{format, binary_term} | L], Opts) ->
options(L, Opts#opts{format = binary_term_fun()});
@@ -419,9 +419,9 @@ culprit_found(IFun, F, FNs, W, L, I, [_Size | BT]) ->
IFun(close),
check_files(FNs, W, [{F,I,binary_to_term(BT)} | L]).
-files(_I, L, _LSz, #w{seq = 1}=W, []) ->
+files(_I, L, _LSz, #w{seq = 1, out = Out}=W, []) ->
%% No temporary files created, everything in L.
- case W#w.out of
+ case Out of
Fun when is_function(Fun) ->
SL = internal_sort(L, W),
W1 = outfun(binterm_objects(SL, []), W),
@@ -462,8 +462,8 @@ fun_run(I, L, LSz, W, []) ->
{cont, NW, Objs} ->
fun_run(I, L, LSz, NW, Objs)
end;
-fun_run(I, L, LSz, W, Objs) when LSz < W#w.runsize ->
- {NI, NObjs, NL, NLSz} = fun_objs(Objs, L, LSz, W#w.runsize, I, W),
+fun_run(I, L, LSz, #w{runsize = Runsize}=W, Objs) when LSz < Runsize ->
+ {NI, NObjs, NL, NLSz} = fun_objs(Objs, L, LSz, Runsize, I, W),
fun_run(NI, NL, NLSz, W, NObjs);
fun_run(I, L, _LSz, W, Objs) ->
NW = write_run(L, W),
@@ -1201,11 +1201,11 @@ infun(W) ->
erlang:raise(Class, Reason, erlang:get_stacktrace())
end.
-outfun(A, W) when W#w.inout_value =/= no_value ->
+outfun(A, #w{inout_value = Val} = W) when Val =/= no_value ->
W1 = W#w{inout_value = no_value},
W2 = if
W1#w.fun_out ->
- outfun(W#w.inout_value, W1);
+ outfun(Val, W1);
true -> W1
end,
outfun(A, W2);
@@ -1372,19 +1372,19 @@ cleanup(W) ->
end,
lists:foreach(F, W1#w.temp).
-close_input(W) when is_function(W#w.in) ->
- catch (W#w.in)(close),
+close_input(#w{in = In}=W) when is_function(In) ->
+ catch In(close),
W#w{in = undefined};
close_input(#w{in = undefined}=W) ->
W.
-close_out(W) when is_function(W#w.out) ->
- catch (W#w.out)(close);
+close_out(#w{out = Out}) when is_function(Out) ->
+ catch Out(close);
close_out(_) ->
ok.
close_file(Fd, W) ->
- {value, {Fd, FileName}} = lists:keysearch(Fd, 1, W#w.temp),
+ {Fd, FileName} = lists:keyfind(Fd, 1, W#w.temp),
?DEBUG("closing ~p~n", [FileName]),
file:close(Fd),
W#w{temp = [FileName | lists:keydelete(Fd, 1, W#w.temp)]}.
diff --git a/lib/stdlib/src/qlc.erl b/lib/stdlib/src/qlc.erl
index ef142e1c8a..6e48d95973 100644
--- a/lib/stdlib/src/qlc.erl
+++ b/lib/stdlib/src/qlc.erl
@@ -1,19 +1,19 @@
%%
%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2004-2009. All Rights Reserved.
-%%
+%%
+%% Copyright Ericsson AB 2004-2010. All Rights Reserved.
+%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
%% compliance with the License. You should have received a copy of the
%% Erlang Public License along with this software. If not, it can be
%% retrieved online at http://www.erlang.org/.
-%%
+%%
%% Software distributed under the License is distributed on an "AS IS"
%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
%% the License for the specific language governing rights and limitations
%% under the License.
-%%
+%%
%% %CopyrightEnd%
%%
-module(qlc).
@@ -528,122 +528,111 @@ options(Options0, [Key | Keys], L) when is_list(Options0) ->
false ->
Options0
end,
- V = case lists:keysearch(Key, 1, Options) of
- {value, {format_fun, U=undefined}} ->
+ V = case lists:keyfind(Key, 1, Options) of
+ {format_fun, U=undefined} ->
{ok, U};
- {value, {info_fun, U=undefined}} ->
+ {info_fun, U=undefined} ->
{ok, U};
- {value, {lookup_fun, U=undefined}} ->
+ {lookup_fun, U=undefined} ->
{ok, U};
- {value, {parent_fun, U=undefined}} ->
+ {parent_fun, U=undefined} ->
{ok, U};
- {value, {post_fun, U=undefined}} ->
+ {post_fun, U=undefined} ->
{ok, U};
- {value, {pre_fun, U=undefined}} ->
+ {pre_fun, U=undefined} ->
{ok, U};
- {value, {info_fun, Fun}} when is_function(Fun),
- is_function(Fun, 1) ->
+ {info_fun, Fun} when is_function(Fun), is_function(Fun, 1) ->
{ok, Fun};
- {value, {pre_fun, Fun}} when is_function(Fun),
- is_function(Fun, 1) ->
+ {pre_fun, Fun} when is_function(Fun), is_function(Fun, 1) ->
{ok, Fun};
- {value, {post_fun, Fun}} when is_function(Fun),
- is_function(Fun, 0) ->
+ {post_fun, Fun} when is_function(Fun), is_function(Fun, 0) ->
{ok, Fun};
- {value, {lookup_fun, Fun}} when is_function(Fun),
- is_function(Fun, 2) ->
+ {lookup_fun, Fun} when is_function(Fun), is_function(Fun, 2) ->
{ok, Fun};
- {value, {max_lookup, Max}} when is_integer(Max), Max >= 0 ->
+ {max_lookup, Max} when is_integer(Max), Max >= 0 ->
{ok, Max};
- {value, {max_lookup, infinity}} ->
+ {max_lookup, infinity} ->
{ok, -1};
- {value, {format_fun, Fun}} when is_function(Fun),
- is_function(Fun, 1) ->
+ {format_fun, Fun} when is_function(Fun), is_function(Fun, 1) ->
{ok, Fun};
- {value, {parent_fun, Fun}} when is_function(Fun),
- is_function(Fun, 0) ->
+ {parent_fun, Fun} when is_function(Fun), is_function(Fun, 0) ->
{ok, Fun};
- {value, {key_equality, KE='=='}}->
+ {key_equality, KE='=='} ->
{ok, KE};
- {value, {key_equality, KE='=:='}}->
+ {key_equality, KE='=:='} ->
{ok, KE};
- {value, {join, J=any}} ->
+ {join, J=any} ->
{ok, J};
- {value, {join, J=nested_loop}} ->
+ {join, J=nested_loop} ->
{ok, J};
- {value, {join, J=merge}} ->
+ {join, J=merge} ->
{ok, J};
- {value, {join, J=lookup}} ->
+ {join, J=lookup} ->
{ok, J};
- {value, {lookup, LookUp}} when LookUp;
- not LookUp;
- LookUp =:= any ->
+ {lookup, LookUp} when is_boolean(LookUp); LookUp =:= any ->
{ok, LookUp};
- {value, {max_list_size, Max}} when is_integer(Max), Max >= 0 ->
+ {max_list_size, Max} when is_integer(Max), Max >= 0 ->
{ok, Max};
- {value, {tmpdir_usage, TmpUsage}} when TmpUsage =:= allowed;
- TmpUsage =:= not_allowed;
- TmpUsage =:= info_msg;
- TmpUsage =:= warning_msg;
- TmpUsage =:= error_msg ->
+ {tmpdir_usage, TmpUsage} when TmpUsage =:= allowed;
+ TmpUsage =:= not_allowed;
+ TmpUsage =:= info_msg;
+ TmpUsage =:= warning_msg;
+ TmpUsage =:= error_msg ->
{ok, TmpUsage};
- {value, {unique, Unique}} when Unique; not Unique ->
+ {unique, Unique} when is_boolean(Unique) ->
{ok, Unique};
- {value, {cache, Cache}} when Cache; not Cache; Cache =:= list ->
+ {cache, Cache} when is_boolean(Cache); Cache =:= list ->
{ok, Cache};
- {value, {cache, ets}} ->
+ {cache, ets} ->
{ok, true};
- {value, {cache, no}} ->
+ {cache, no} ->
{ok, false};
- {value, {unique_all, UniqueAll}} when UniqueAll; not UniqueAll ->
+ {unique_all, UniqueAll} when is_boolean(UniqueAll) ->
{ok, UniqueAll};
- {value, {cache_all, CacheAll}} when CacheAll;
- not CacheAll;
- CacheAll =:= list ->
+ {cache_all, CacheAll} when is_boolean(CacheAll);
+ CacheAll =:= list ->
{ok, CacheAll};
- {value, {cache_all, ets}} ->
+ {cache_all, ets} ->
{ok, true};
- {value, {cache_all, no}} ->
+ {cache_all, no} ->
{ok, false};
- {value, {spawn_options, default}} ->
+ {spawn_options, default} ->
{ok, default};
- {value, {spawn_options, SpawnOptions}} ->
+ {spawn_options, SpawnOptions} ->
case is_proper_list(SpawnOptions) of
true ->
{ok, SpawnOptions};
false ->
badarg
end;
- {value, {flat, Flat}} when Flat; not Flat ->
+ {flat, Flat} when is_boolean(Flat) ->
{ok, Flat};
- {value, {format, Format}} when Format =:= string;
- Format =:= abstract_code;
- Format =:= debug ->
+ {format, Format} when Format =:= string;
+ Format =:= abstract_code;
+ Format =:= debug ->
{ok, Format};
- {value, {n_elements, NElements}} when NElements =:= infinity;
- is_integer(NElements),
- NElements > 0 ->
+ {n_elements, NElements} when NElements =:= infinity;
+ is_integer(NElements),
+ NElements > 0 ->
{ok, NElements};
- {value, {depth, Depth}} when Depth =:= infinity;
- is_integer(Depth), Depth >= 0 ->
+ {depth, Depth} when Depth =:= infinity;
+ is_integer(Depth), Depth >= 0 ->
{ok, Depth};
- {value, {order, Order}} when is_function(Order),
- is_function(Order, 2);
- (Order =:= ascending);
- (Order =:= descending) ->
+ {order, Order} when is_function(Order), is_function(Order, 2);
+ (Order =:= ascending);
+ (Order =:= descending) ->
{ok, Order};
- {value, {compressed, Comp}} when Comp ->
+ {compressed, Comp} when Comp ->
{ok, [compressed]};
- {value, {compressed, Comp}} when not Comp ->
+ {compressed, Comp} when not Comp ->
{ok, []};
- {value, {tmpdir, T}} ->
+ {tmpdir, T} ->
{ok, T};
- {value, {size, Size}} when is_integer(Size), Size > 0 ->
+ {size, Size} when is_integer(Size), Size > 0 ->
{ok, Size};
- {value, {no_files, NoFiles}} when is_integer(NoFiles),
- NoFiles > 1 ->
+ {no_files, NoFiles} when is_integer(NoFiles), NoFiles > 1 ->
{ok, NoFiles};
- {value, {Key, _}} ->
+ {Key, _} ->
badarg;
false ->
Default = default_option(Key),
@@ -1457,7 +1446,7 @@ prep_qlc_lc({qlc_v1, QFun, CodeF, Qdata0, QOpt}, Opt, GOpt, _H) ->
{?qual_data(QNum, GoI, SI, {gen, Prep}), ModGens}
end,
{Qdata, ModGens} = lists:mapfoldl(F, [], Qdata0),
- SomeLookUp = lists:keymember(true, 2, ModGens) =/= false,
+ SomeLookUp = lists:keymember(true, 2, ModGens),
check_lookup_option(Opt, SomeLookUp),
case ModGens of
[{_QNum, _LookUp, all, OnePrep}] ->
@@ -1503,7 +1492,7 @@ pos_fun('==', QOpt, QNum) ->
prep_gen(#qlc_table{lu_vals = LuV0, ms = MS0, trav_MS = TravMS,
info_fun = IF, lookup_fun = LU_fun,
- key_equality = KeyEquality}=LE0,
+ key_equality = KeyEquality}=LE0,
Prep0, PosFun0, {MS, Fs}, Opt) ->
PosFun = PosFun0(KeyEquality),
{LuV, {STag,SkipFils}} = find_const_positions(IF, LU_fun, PosFun, Opt),
@@ -1998,8 +1987,8 @@ no_cache_of_first_generator(Optz, 1) ->
Optz#optz{cache = false}.
maybe_sort(LE, QNum, DoSort, Opt) ->
- case lists:keysearch(QNum, 1, DoSort) of
- {value, {QNum, Col}} ->
+ case lists:keyfind(QNum, 1, DoSort) of
+ {QNum, Col} ->
#qlc_opt{tmpdir = TmpDir, tmpdir_usage = TmpUsage} = Opt,
SortOpts = [{tmpdir,Dir} || Dir <- [TmpDir], Dir =/= ""],
Sort = #qlc_sort{h = LE, keypos = {keysort, Col}, unique = false,
@@ -2025,7 +2014,7 @@ skip_lookup_filters(Qdata0, LU_SkipFs) ->
%% specification it must be applied _after_ the lookup join (the
%% filter must not be skipped!).
activate_join_lookup_filter(QNum, Qdata) ->
- {value, {_,GoI2,SI2,{gen,Prep2}}} = lists:keysearch(QNum, 1, Qdata),
+ {_,GoI2,SI2,{gen,Prep2}} = lists:keyfind(QNum, 1, Qdata),
Table2 = Prep2#prepared.qh,
NPrep2 = Prep2#prepared{qh = Table2#qlc_table{ms = no_match_spec}},
%% Table2#qlc_table.ms has been reset; the filter will be run.
@@ -2059,7 +2048,7 @@ opt_join(Join, JoinOption, Qdata, Opt, LU_SkipQuals) ->
opt_join_lu([{{_Q1,_C1,Q2,_C2}=J,[{lookup_join,_KEols,JKE,Skip0} | _]} | LJ],
Qdata, LU_SkipQuals) ->
- {value, {Q2,_,_,{gen,Prep2}}} = lists:keysearch(Q2, 1, Qdata),
+ {Q2,_,_,{gen,Prep2}} = lists:keyfind(Q2, 1, Qdata),
#qlc_table{ms = MS, key_equality = KE,
lookup_fun = LU_fun} = Prep2#prepared.qh,
%% If there is no filter to skip (the match spec was derived
@@ -2670,8 +2659,8 @@ sort_list_output(L) ->
%% Don't use the file_sorter unless it is known that objects will be
%% put on a temporary file (optimization).
sort_handle(H, ListFun, FileFun, SortOptions, Post, LocalPost, TmpUsageM) ->
- Size = case lists:keysearch(size, 1, SortOptions) of
- {value, {size, Size0}} -> Size0;
+ Size = case lists:keyfind(size, 1, SortOptions) of
+ {size, Size0} -> Size0;
false -> default_option(size)
end,
sort_cache(H, [], Size, {ListFun, FileFun, Post, LocalPost, TmpUsageM}).
@@ -2891,8 +2880,8 @@ ucache_recall(UTab, MTab, SeqNo) ->
Object = case ets:lookup(UTab, Hash) of
[{Hash, SeqNo, Object0}] -> Object0;
HashSeqObjects ->
- {value, {Hash, SeqNo, Object0}} =
- lists:keysearch(SeqNo, 2, HashSeqObjects),
+ {Hash, SeqNo, Object0} =
+ lists:keyfind(SeqNo, 2, HashSeqObjects),
Object0
end,
[Object | fun() -> ucache_recall(UTab, MTab, SeqNo + 1) end]
@@ -3403,8 +3392,8 @@ merge_join_id() ->
tmp_merge_file(MergeId) ->
TmpFiles = get(?MERGE_JOIN_FILE),
- case lists:keysearch(MergeId, 1, TmpFiles) of
- {value, {MergeId, Fd, FileName}} ->
+ case lists:keyfind(MergeId, 1, TmpFiles) of
+ {MergeId, Fd, FileName} ->
{Fd, FileName};
false ->
none
diff --git a/lib/stdlib/src/qlc_pt.erl b/lib/stdlib/src/qlc_pt.erl
index 2d7874d99f..24378a0698 100644
--- a/lib/stdlib/src/qlc_pt.erl
+++ b/lib/stdlib/src/qlc_pt.erl
@@ -1,19 +1,19 @@
%%
%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2004-2009. All Rights Reserved.
-%%
+%%
+%% Copyright Ericsson AB 2004-2010. All Rights Reserved.
+%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
%% compliance with the License. You should have received a copy of the
%% Erlang Public License along with this software. If not, it can be
%% retrieved online at http://www.erlang.org/.
-%%
+%%
%% Software distributed under the License is distributed on an "AS IS"
%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
%% the License for the specific language governing rights and limitations
%% under the License.
-%%
+%%
%% %CopyrightEnd%
%%
-module(qlc_pt).
@@ -845,8 +845,8 @@ join_handle(AP, L, [F, H, O, C], Constants) ->
join_handle_constants(QId, ExtraConstants) ->
IdNo = QId#qid.no,
- case lists:keysearch(IdNo, 1, ExtraConstants) of
- {value, {IdNo, ConstOps}} ->
+ case lists:keyfind(IdNo, 1, ExtraConstants) of
+ {IdNo, ConstOps} ->
ConstOps;
false ->
[]
@@ -1231,9 +1231,9 @@ lu_skip(ColConstants, FilterData, PatternFrame, PatternVars,
%% The filter can only be skipped if all constants
%% are looked up.
LookedUpConstants =
- case lists:keysearch(Column, 1, ColConstants) of
+ case lists:keyfind(Column, 1, ColConstants) of
false -> [];
- {value, {Column,LUCs}} -> LUCs
+ {Column, LUCs} -> LUCs
end,
%% Don't try to handle filters that compare several
%% values equal. See also frames_to_columns().
@@ -1279,8 +1279,8 @@ join_gens(Cs0, Qs, Skip) ->
join_gens2(lists:filter(fun(C) -> length(C) > 2 end, Cs), FD, Skip)}.
join_gens2(Cs0, FilterData, Skip) ->
- [{J, skip_tag(case lists:keysearch(J, 1, Skip) of
- {value, {J,FilL}} ->
+ [{J, skip_tag(case lists:keyfind(J, 1, Skip) of
+ {J, FilL} ->
FilL;
false ->
[]
@@ -1296,8 +1296,8 @@ skip_tag(FilList, FilterData) ->
end, FilList}.
skip_tag(Col, ColFils, FilterData) ->
- case lists:keysearch(Col, 1, ColFils) of
- {value, {Col, FilL}} ->
+ case lists:keyfind(Col, 1, ColFils) of
+ {Col, FilL} ->
Tag = if
length(FilterData) =:= length(FilL) ->
all;
@@ -1415,7 +1415,7 @@ sel_gf([], _N, _Deps, _RDs, _Gens, _Gens1) ->
sel_gf([{#qid{no = N}=Id,{fil,F}}=Fil | FData], N, Deps, RDs, Gens, Gens1) ->
case erl_lint:is_guard_test(F, RDs) of
true ->
- {value, {Id,GIds}} = lists:keysearch(Id, 1, Deps),
+ {Id,GIds} = lists:keyfind(Id, 1, Deps),
case length(GIds) =< 1 of
true ->
case generators_in_scope(GIds, Gens1) of
@@ -2572,8 +2572,8 @@ nos_pattern([P0 | Ps0], S0, PVs0) ->
{[P | Ps], S, PVs};
nos_pattern({var,L,V}, {LI,Vs0,UV,A,Sg}, PVs0) when V =/= '_' ->
{Name, Vs, PVs} =
- case lists:keysearch(V, 1, PVs0) of
- {value, {V,VN}} ->
+ case lists:keyfind(V, 1, PVs0) of
+ {V, VN} ->
_ = used_var(V, Vs0, UV),
{VN, Vs0, PVs0};
false ->
diff --git a/lib/stdlib/src/supervisor.erl b/lib/stdlib/src/supervisor.erl
index fb1303d1eb..22269a8d1b 100644
--- a/lib/stdlib/src/supervisor.erl
+++ b/lib/stdlib/src/supervisor.erl
@@ -1,19 +1,19 @@
%%
%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1996-2009. All Rights Reserved.
-%%
+%%
+%% Copyright Ericsson AB 1996-2010. All Rights Reserved.
+%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
%% compliance with the License. You should have received a copy of the
%% Erlang Public License along with this software. If not, it can be
%% retrieved online at http://www.erlang.org/.
-%%
+%%
%% Software distributed under the License is distributed on an "AS IS"
%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
%% the License for the specific language governing rights and limitations
%% under the License.
-%%
+%%
%% %CopyrightEnd%
%%
-module(supervisor).
@@ -24,7 +24,7 @@
-export([start_link/2,start_link/3,
start_child/2, restart_child/2,
delete_child/2, terminate_child/2,
- which_children/1,
+ which_children/1, count_children/1,
check_childspecs/1]).
-export([behaviour_info/1]).
@@ -95,6 +95,9 @@ terminate_child(Supervisor, Name) ->
which_children(Supervisor) ->
call(Supervisor, which_children).
+count_children(Supervisor) ->
+ call(Supervisor, count_children).
+
call(Supervisor, Req) ->
gen_server:call(Supervisor, Req, infinity).
@@ -297,7 +300,49 @@ handle_call(which_children, _From, State) ->
{Name, Pid, ChildType, Mods}
end,
State#state.children),
- {reply, Resp, State}.
+ {reply, Resp, State};
+
+handle_call(count_children, _From, State) when ?is_simple(State) ->
+ [#child{child_type = CT}] = State#state.children,
+ {Active, Count} =
+ ?DICT:fold(fun(Pid, _Val, {Alive, Tot}) ->
+ if is_pid(Pid) -> {Alive+1, Tot +1};
+ true -> {Alive, Tot + 1} end
+ end, {0, 0}, State#state.dynamics),
+ Reply = case CT of
+ supervisor -> [{specs, 1}, {active, Active},
+ {supervisors, Count}, {workers, 0}];
+ worker -> [{specs, 1}, {active, Active},
+ {supervisors, 0}, {workers, Count}]
+ end,
+ {reply, Reply, State};
+
+handle_call(count_children, _From, State) ->
+
+ %% Specs and children are together on the children list...
+ {Specs, Active, Supers, Workers} =
+ lists:foldl(fun(Child, Counts) ->
+ count_child(Child, Counts)
+ end, {0,0,0,0}, State#state.children),
+
+ %% Reformat counts to a property list.
+ Reply = [{specs, Specs}, {active, Active},
+ {supervisors, Supers}, {workers, Workers}],
+ {reply, Reply, State}.
+
+
+count_child(#child{pid = Pid, child_type = worker},
+ {Specs, Active, Supers, Workers}) ->
+ case is_pid(Pid) andalso is_process_alive(Pid) of
+ true -> {Specs+1, Active+1, Supers, Workers+1};
+ false -> {Specs+1, Active, Supers, Workers+1}
+ end;
+count_child(#child{pid = Pid, child_type = supervisor},
+ {Specs, Active, Supers, Workers}) ->
+ case is_pid(Pid) andalso is_process_alive(Pid) of
+ true -> {Specs+1, Active+1, Supers+1, Workers};
+ false -> {Specs+1, Active, Supers+1, Workers}
+ end.
%%% Hopefully cause a function-clause as there is no API function
diff --git a/lib/stdlib/test/supervisor_SUITE.erl b/lib/stdlib/test/supervisor_SUITE.erl
index f25e877289..039ea298c4 100644
--- a/lib/stdlib/test/supervisor_SUITE.erl
+++ b/lib/stdlib/test/supervisor_SUITE.erl
@@ -50,7 +50,7 @@
simple_one_for_one_extra/1]).
%% Misc tests
--export([child_unlink/1, tree/1]).
+-export([child_unlink/1, tree/1, count_children_memory/1]).
%-------------------------------------------------------------------------
@@ -60,7 +60,8 @@ all(suite) ->
child_adm_simple, extra_return, child_specs,
restart_one_for_one, restart_one_for_all,
restart_simple_one_for_one, restart_rest_for_one,
- normal_termination, abnormal_termination, child_unlink, tree]}.
+ normal_termination, abnormal_termination, child_unlink, tree,
+ count_children_memory]}.
start(InitResult) ->
@@ -72,6 +73,15 @@ init(fail) ->
init(InitResult) ->
InitResult.
+%% Respect proplist return of supervisor:count_children
+get_child_counts(Supervisor) ->
+ Counts = supervisor:count_children(Supervisor),
+ [proplists:get_value(specs, Counts),
+ proplists:get_value(active, Counts),
+ proplists:get_value(supervisors, Counts),
+ proplists:get_value(workers, Counts)].
+
+
%-------------------------------------------------------------------------
%
% Test cases starts here.
@@ -140,6 +150,8 @@ sup_start_ignore_child(Config) when is_list(Config) ->
?line [{child2, CPid2, worker, []},{child1, undefined, worker, []}]
= supervisor:which_children(sup_test),
+ ?line [2,1,0,2] = get_child_counts(sup_test),
+
ok.
%-------------------------------------------------------------------------
@@ -341,6 +353,8 @@ extra_return(Config) when is_list(Config) ->
?line {error, running} = supervisor:delete_child(sup_test, child1),
?line {error, running} = supervisor:restart_child(sup_test, child1),
?line [{child1, CPid, worker, []}] = supervisor:which_children(sup_test),
+ ?line [1,1,0,1] = get_child_counts(sup_test),
+
?line ok = supervisor:terminate_child(sup_test, child1),
receive
{'EXIT', CPid, shutdown} -> ok;
@@ -350,22 +364,31 @@ extra_return(Config) when is_list(Config) ->
?line test_server:fail(no_child_termination)
end,
?line [{child1,undefined,worker,[]}] = supervisor:which_children(sup_test),
+ ?line [1,0,0,1] = get_child_counts(sup_test),
+
?line {ok, CPid2,extra_return} =
supervisor:restart_child(sup_test, child1),
?line [{child1, CPid2, worker, []}] = supervisor:which_children(sup_test),
+ ?line [1,1,0,1] = get_child_counts(sup_test),
+
?line ok = supervisor:terminate_child(sup_test, child1),
?line ok = supervisor:terminate_child(sup_test, child1),
?line ok = supervisor:delete_child(sup_test, child1),
?line {error, not_found} = supervisor:restart_child(sup_test, child1),
?line [] = supervisor:which_children(sup_test),
+ ?line [0,0,0,0] = get_child_counts(sup_test),
+
?line {ok, CPid3, extra_return} = supervisor:start_child(sup_test, Child),
?line [{child1, CPid3, worker, []}] = supervisor:which_children(sup_test),
+ ?line [1,1,0,1] = get_child_counts(sup_test),
+
ok.
%-------------------------------------------------------------------------
child_adm(doc)->
["Test API functions start_child/2, terminate_child/2, delete_child/2 "
- "restart_child/2, which_children/1. Only correct childspecs are used, "
- "handling of incorrect childspecs is tested in child_specs/1"];
+ "restart_child/2, which_children/1, count_children/1. Only correct "
+ "childspecs are used, handling of incorrect childspecs is tested in "
+ "child_specs/1"];
child_adm(suite) -> [];
child_adm(Config) when is_list(Config) ->
process_flag(trap_exit, true),
@@ -373,6 +396,7 @@ child_adm(Config) when is_list(Config) ->
worker, []},
?line {ok, _Pid} = start({ok, {{one_for_one, 2, 3600}, [Child]}}),
?line [{child1, CPid, worker, []}] = supervisor:which_children(sup_test),
+ ?line [1,1,0,1] = get_child_counts(sup_test),
link(CPid),
%% Start of an already runnig process
@@ -392,6 +416,7 @@ child_adm(Config) when is_list(Config) ->
?line test_server:fail(no_child_termination)
end,
?line [{child1,undefined,worker,[]}] = supervisor:which_children(sup_test),
+ ?line [1,0,0,1] = get_child_counts(sup_test),
%% Like deleting something that does not exist, it will succeed!
?line ok = supervisor:terminate_child(sup_test, child1),
@@ -402,6 +427,7 @@ child_adm(Config) when is_list(Config) ->
%% Restart
?line {ok, CPid2} = supervisor:restart_child(sup_test, child1),
?line [{child1, CPid2, worker, []}] = supervisor:which_children(sup_test),
+ ?line [1,1,0,1] = get_child_counts(sup_test),
?line {error, running} = supervisor:restart_child(sup_test, child1),
?line {error, not_found} = supervisor:restart_child(sup_test, child2),
@@ -414,15 +440,19 @@ child_adm(Config) when is_list(Config) ->
?line ok = supervisor:delete_child(sup_test, child1),
?line {error, not_found} = supervisor:restart_child(sup_test, child1),
?line [] = supervisor:which_children(sup_test),
+ ?line [0,0,0,0] = get_child_counts(sup_test),
%% Start
?line {'EXIT',{noproc,{gen_server,call, _}}} =
(catch supervisor:start_child(foo, Child)),
?line {ok, CPid3} = supervisor:start_child(sup_test, Child),
?line [{child1, CPid3, worker, []}] = supervisor:which_children(sup_test),
+ ?line [1,1,0,1] = get_child_counts(sup_test),
?line {'EXIT',{noproc,{gen_server,call,[foo,which_children,infinity]}}}
= (catch supervisor:which_children(foo)),
+ ?line {'EXIT',{noproc,{gen_server,call,[foo,count_children,infinity]}}}
+ = (catch supervisor:count_children(foo)),
ok.
%-------------------------------------------------------------------------
child_adm_simple(doc) ->
@@ -436,6 +466,7 @@ child_adm_simple(Config) when is_list(Config) ->
?line {ok, _Pid} = start({ok, {{simple_one_for_one, 2, 3600}, [Child]}}),
%% In simple_one_for_one all children are added dynamically
?line [] = supervisor:which_children(sup_test),
+ ?line [1,0,0,0] = get_child_counts(sup_test),
%% Start
?line {'EXIT',{noproc,{gen_server,call, _}}} =
@@ -443,12 +474,14 @@ child_adm_simple(Config) when is_list(Config) ->
?line {ok, CPid1} = supervisor:start_child(sup_test, []),
?line [{undefined, CPid1, worker, []}] =
supervisor:which_children(sup_test),
+ ?line [1,1,0,1] = get_child_counts(sup_test),
?line {ok, CPid2} = supervisor:start_child(sup_test, []),
?line Children = supervisor:which_children(sup_test),
?line 2 = length(Children),
?line true = lists:member({undefined, CPid2, worker, []}, Children),
?line true = lists:member({undefined, CPid1, worker, []}, Children),
+ ?line [1,2,0,2] = get_child_counts(sup_test),
%% Termination
?line {error, simple_one_for_one} =
@@ -541,8 +574,10 @@ permanent_normal(Config) when is_list(Config) ->
ok;
false ->
?line test_server:fail({permanent_child_not_restarted, Child1})
- end.
+ end,
+ ?line [1,1,0,1] = get_child_counts(sup_test),
+ ok.
%-------------------------------------------------------------------------
transient_normal(doc) ->
["A transient child should not be restarted if it exits with "
@@ -558,8 +593,10 @@ transient_normal(Config) when is_list(Config) ->
CPid1 ! stop,
test_server:sleep(100),
- ?line [{child1,undefined,worker,[]}] = supervisor:which_children(sup_test).
+ ?line [{child1,undefined,worker,[]}] = supervisor:which_children(sup_test),
+ ?line [1,0,0,1] = get_child_counts(sup_test),
+ ok.
%-------------------------------------------------------------------------
temporary_normal(doc) ->
["A temporary process should never be restarted"];
@@ -574,8 +611,10 @@ temporary_normal(Config) when is_list(Config) ->
CPid1 ! stop,
test_server:sleep(100),
- ?line [{child1,undefined,worker,[]}] = supervisor:which_children(sup_test).
+ ?line [{child1,undefined,worker,[]}] = supervisor:which_children(sup_test),
+ ?line [1,0,0,1] = get_child_counts(sup_test),
+ ok.
%-------------------------------------------------------------------------
abnormal_termination(doc) ->
["Testes the supervisors behaviour if a child dies with reason abnormal"];
@@ -601,8 +640,10 @@ permanent_abnormal(Config) when is_list(Config) ->
ok;
false ->
?line test_server:fail({permanent_child_not_restarted, Child1})
- end.
+ end,
+ ?line [1,1,0,1] = get_child_counts(sup_test),
+ ok.
%-------------------------------------------------------------------------
transient_abnormal(doc) ->
["A transient child should be restarted if it exits with "
@@ -624,9 +665,10 @@ transient_abnormal(Config) when is_list(Config) ->
ok;
false ->
?line test_server:fail({transient_child_not_restarted, Child1})
- end.
-
+ end,
+ ?line [1,1,0,1] = get_child_counts(sup_test),
+ ok.
%-------------------------------------------------------------------------
temporary_abnormal(doc) ->
["A temporary process should never be restarted"];
@@ -641,8 +683,10 @@ temporary_abnormal(Config) when is_list(Config) ->
CPid1 ! die,
test_server:sleep(100),
- ?line [{child1,undefined,worker,[]}] = supervisor:which_children(sup_test).
+ ?line [{child1,undefined,worker,[]}] = supervisor:which_children(sup_test),
+ ?line [1,0,0,1] = get_child_counts(sup_test),
+ ok.
%-------------------------------------------------------------------------
restart_one_for_one(doc) ->
["Test that the one_for_one strategy works."];
@@ -679,6 +723,7 @@ one_for_one(Config) when is_list(Config) ->
end;
true -> ?line test_server:fail({bad_child_list, Children})
end,
+ ?line [2,2,0,2] = get_child_counts(sup_test),
%% Test restart frequency property
CPid2 ! die,
@@ -772,6 +817,8 @@ one_for_all(Config) when is_list(Config) ->
true -> ?line test_server:fail(bad_child);
false -> ok
end,
+ ?line [2,2,0,2] = get_child_counts(sup_test),
+
%%% Test restart frequency property
[{_, Pid3, _, _}|_] = supervisor:which_children(sup_test),
Pid3 ! die,
@@ -854,6 +901,8 @@ simple_one_for_one(Config) when is_list(Config) ->
end;
true -> ?line test_server:fail({bad_child_list, Children})
end,
+ ?line [1,2,0,2] = get_child_counts(sup_test),
+
%% Test restart frequency property
CPid2 ! die,
receive
@@ -896,6 +945,8 @@ simple_one_for_one_extra(Config) when is_list(Config) ->
end;
true -> ?line test_server:fail({bad_child_list, Children})
end,
+ ?line [1,2,0,2] = get_child_counts(sup_test),
+
CPid2 ! die,
receive
{'EXIT', CPid2, _} -> ok
@@ -962,6 +1013,8 @@ rest_for_one(Config) when is_list(Config) ->
link(CPid2),
?line {ok, CPid3} = supervisor:start_child(sup_test, Child3),
link(CPid3),
+ ?line [3,3,0,3] = get_child_counts(sup_test),
+
CPid2 ! die,
receive
{'EXIT', CPid2, died} -> ok;
@@ -987,6 +1040,8 @@ rest_for_one(Config) when is_list(Config) ->
if length(Children) == 3 -> ok;
true -> ?line test_server:fail({bad_child_list, Children})
end,
+ ?line [3,3,0,3] = get_child_counts(sup_test),
+
%% Test that no old children is still alive
SCh = lists:map(fun({_,P,_,_}) -> P end, Children),
case lists:member(CPid1, SCh) of
@@ -1114,15 +1169,19 @@ tree(Config) when is_list(Config) ->
%% Child supervisors
?line {ok, Sup1} = supervisor:start_child(Pid, ChildSup1),
?line {ok, Sup2} = supervisor:start_child(Pid, ChildSup2),
+ ?line [2,2,2,0] = get_child_counts(Pid),
%% Workers
-
?line [{_, CPid2, _, _},{_, CPid1, _, _}] =
supervisor:which_children(Sup1),
+ ?line [2,2,0,2] = get_child_counts(Sup1),
+ ?line [0,0,0,0] = get_child_counts(Sup2),
%% Dynamic children
?line {ok, CPid3} = supervisor:start_child(Sup2, Child3),
?line {ok, CPid4} = supervisor:start_child(Sup2, Child4),
+ ?line [2,2,0,2] = get_child_counts(Sup1),
+ ?line [2,2,0,2] = get_child_counts(Sup2),
link(Sup1),
link(Sup2),
@@ -1144,9 +1203,11 @@ tree(Config) when is_list(Config) ->
?line [{_, CPid2, _, _},{_, CPid1, _, _}] =
supervisor:which_children(Sup1),
+ ?line [2,2,0,2] = get_child_counts(Sup1),
?line [{_, NewCPid4, _, _},{_, CPid3, _, _}] =
supervisor:which_children(Sup2),
+ ?line [2,2,0,2] = get_child_counts(Sup2),
link(NewCPid4),
@@ -1195,9 +1256,99 @@ tree(Config) when is_list(Config) ->
?line [{supchild2, NewSup2, _, _},{supchild1, NewSup1, _, _}] =
supervisor:which_children(Pid),
+ ?line [2,2,2,0] = get_child_counts(Pid),
?line [{child2, _, _, _},{child1, _, _, _}] =
supervisor:which_children(NewSup1),
+ ?line [2,2,0,2] = get_child_counts(NewSup1),
+
?line [] = supervisor:which_children(NewSup2),
+ ?line [0,0,0,0] = get_child_counts(NewSup2),
ok.
+%-------------------------------------------------------------------------
+count_children_allocator_test(MemoryState) ->
+ Allocators = [temp_alloc, eheap_alloc, binary_alloc, ets_alloc,
+ driver_alloc, sl_alloc, ll_alloc, fix_alloc, std_alloc,
+ sys_alloc],
+ MemoryStateList = element(4, MemoryState),
+ AllocTypes = [lists:keyfind(Alloc, 1, MemoryStateList)
+ || Alloc <- Allocators],
+ AllocStates = [lists:keyfind(e, 1, AllocValue)
+ || {_Type, AllocValue} <- AllocTypes],
+ lists:all(fun(State) -> State == {e, true} end, AllocStates).
+
+count_children_memory(doc) ->
+ ["Test that which_children eats memory, but count_children does not."];
+count_children_memory(suite) ->
+ MemoryState = erlang:system_info(allocator),
+ case count_children_allocator_test(MemoryState) of
+ true -> [];
+ false ->
+ {skip, "+Meamin used during test; erlang:memory/1 not available"}
+ end;
+count_children_memory(Config) when is_list(Config) ->
+ process_flag(trap_exit, true),
+ Child = {child, {supervisor_1, start_child, []}, temporary, 1000,
+ worker, []},
+ ?line {ok, _Pid} = start({ok, {{simple_one_for_one, 2, 3600}, [Child]}}),
+ [supervisor:start_child(sup_test, []) || _Ignore <- lists:seq(1,1000)],
+
+ garbage_collect(),
+ _Size1 = erlang:memory(processes_used),
+ Children = supervisor:which_children(sup_test),
+ _Size2 = erlang:memory(processes_used),
+ ChildCount = get_child_counts(sup_test),
+ Size3 = erlang:memory(processes_used),
+
+ [supervisor:start_child(sup_test, []) || _Ignore2 <- lists:seq(1,1000)],
+
+ garbage_collect(),
+ Children2 = supervisor:which_children(sup_test),
+ Size4 = erlang:memory(processes_used),
+ ChildCount2 = get_child_counts(sup_test),
+ Size5 = erlang:memory(processes_used),
+
+ garbage_collect(),
+ Children3 = supervisor:which_children(sup_test),
+ Size6 = erlang:memory(processes_used),
+ ChildCount3 = get_child_counts(sup_test),
+ Size7 = erlang:memory(processes_used),
+
+ ?line 1000 = length(Children),
+ ?line [1,1000,0,1000] = ChildCount,
+ ?line 2000 = length(Children2),
+ ?line [1,2000,0,2000] = ChildCount2,
+ ?line Children3 = Children2,
+ ?line ChildCount3 = ChildCount2,
+
+ %% count_children consumes memory using an accumulator function,
+ %% but the space can be reclaimed incrementally, whereas
+ %% which_children generates a return list.
+ case (Size5 =< Size4) of
+ true -> ok;
+ false ->
+ ?line test_server:fail({count_children, used_more_memory})
+ end,
+ case Size7 =< Size6 of
+ true -> ok;
+ false ->
+ ?line test_server:fail({count_children, used_more_memory})
+ end,
+
+ case Size4 > Size3 of
+ true -> ok;
+ false ->
+ ?line test_server:fail({which_children, used_no_memory})
+ end,
+ case Size6 > Size5 of
+ true -> ok;
+ false ->
+ ?line test_server:fail({which_children, used_no_memory})
+ end,
+
+ [exit(Pid, kill) || {undefined, Pid, worker, _Modules} <- Children3],
+ test_server:sleep(100),
+ ?line [1,0,0,0] = get_child_counts(sup_test),
+
+ ok.