From 5e9d05198cd00f74b99f697eb022ae0b2f31f136 Mon Sep 17 00:00:00 2001
From: Sam Bobroff
Date: Tue, 18 May 2010 11:49:08 +1000
Subject: Change make:files to behave more like erlc
Currently make:files will fail with the atom 'error' and
no message when the input (.erl) file is unreadable or the
output (.beam) file is unwritable. This differs from erlc
which will print a useful error message, or when possible,
remove the unwritable output file and continue successfully.
This change removes the unnecessary checks on the files when
make:files is called and allows the error checking to be
done in compile:file, where the error messages are produced.
It does not affect the return value.
In particular this resolves the mysterious problem of make:files
failing but erlc succeeding, caused by an unwritable (usually
root owned) beam file in an otherwise writable build directory.
---
lib/tools/src/make.erl | 15 +--------------
1 file changed, 1 insertion(+), 14 deletions(-)
(limited to 'lib')
diff --git a/lib/tools/src/make.erl b/lib/tools/src/make.erl
index 77c354651b..e78e2a43a4 100644
--- a/lib/tools/src/make.erl
+++ b/lib/tools/src/make.erl
@@ -222,12 +222,7 @@ recompilep(File, NoExec, Load, Opts) ->
recompilep1(File, NoExec, Load, Opts, ObjFile) ->
{ok, Erl} = file:read_file_info(lists:append(File, ".erl")),
{ok, Obj} = file:read_file_info(ObjFile),
- case {readable(Erl), writable(Obj)} of
- {true, true} ->
- recompilep1(Erl, Obj, File, NoExec, Load, Opts);
- _ ->
- error
- end.
+ recompilep1(Erl, Obj, File, NoExec, Load, Opts).
recompilep1(#file_info{mtime=Te},
#file_info{mtime=To}, File, NoExec, Load, Opts) when Te>To ->
@@ -277,14 +272,6 @@ exists(File) ->
false
end.
-readable(#file_info{access=read_write}) -> true;
-readable(#file_info{access=read}) -> true;
-readable(_) -> false.
-
-writable(#file_info{access=read_write}) -> true;
-writable(#file_info{access=write}) -> true;
-writable(_) -> false.
-
coerce_2_list(X) when is_atom(X) ->
atom_to_list(X);
coerce_2_list(X) ->
--
cgit v1.2.3
From eb02beb1c33fafb32e0596d947310d8c17e8bbf2 Mon Sep 17 00:00:00 2001
From: Tobias Schlager
Date: Thu, 23 Sep 2010 11:40:19 +0200
Subject: add user specified compiler options on form reloading
In order to be able to test non-exported functions from another (test) module
it is necessary to compile the specific module (at least during the test phase)
with the export_all compiler option. This allows complete separation of testing
and productive code. At the moment it is not possible to combine this with a
test code coverage using the cover module. The problem is that when cover
compiling a module using cover:compile_* the code is reloaded into the emulator
omitting/filtering the passed user options. In my example above the export_all
option would be removed and the non-exported functions cannot be called any
more.
---
lib/tools/src/cover.erl | 9 +++++----
1 file changed, 5 insertions(+), 4 deletions(-)
(limited to 'lib')
diff --git a/lib/tools/src/cover.erl b/lib/tools/src/cover.erl
index c4d1bd1d2f..b8884fed2c 100644
--- a/lib/tools/src/cover.erl
+++ b/lib/tools/src/cover.erl
@@ -229,6 +229,7 @@ compile_modules(Files,Options) ->
{i, Dir} when is_list(Dir) -> true;
{d, _Macro} -> true;
{d, _Macro, _Value} -> true;
+ export_all -> true;
_ -> false
end
end,
@@ -569,7 +570,7 @@ main_process_loop(State) ->
case get_beam_file(Module,BeamFile0,Compiled0) of
{ok,BeamFile} ->
{Reply,Compiled} =
- case do_compile_beam(Module,BeamFile) of
+ case do_compile_beam(Module,BeamFile,[]) of
{ok, Module} ->
remote_load_compiled(State#main_state.nodes,
[{Module,BeamFile}]),
@@ -1227,13 +1228,13 @@ do_compile(File, UserOptions) ->
Options = [debug_info,binary,report_errors,report_warnings] ++ UserOptions,
case compile:file(File, Options) of
{ok, Module, Binary} ->
- do_compile_beam(Module,Binary);
+ do_compile_beam(Module,Binary,UserOptions);
error ->
error
end.
%% Beam is a binary or a .beam file name
-do_compile_beam(Module,Beam) ->
+do_compile_beam(Module,Beam,UserOptions) ->
%% Clear database
do_clear(Module),
@@ -1253,7 +1254,7 @@ do_compile_beam(Module,Beam) ->
%% Compile and load the result
%% It's necessary to check the result of loading since it may
%% fail, for example if Module resides in a sticky directory
- {ok, Module, Binary} = compile:forms(Forms, []),
+ {ok, Module, Binary} = compile:forms(Forms, UserOptions),
case code:load_binary(Module, ?TAG, Binary) of
{module, Module} ->
--
cgit v1.2.3
From 60826a52cbed78fa3b30bacd6d37e1c7766f5d99 Mon Sep 17 00:00:00 2001
From: Kostis Sagonas
Date: Thu, 10 Feb 2011 02:08:14 +0200
Subject: Added loader for ppc64
---
lib/kernel/src/hipe_unified_loader.erl | 11 ++++++-----
1 file changed, 6 insertions(+), 5 deletions(-)
(limited to 'lib')
diff --git a/lib/kernel/src/hipe_unified_loader.erl b/lib/kernel/src/hipe_unified_loader.erl
index f289b8110d..1d3eb926ca 100644
--- a/lib/kernel/src/hipe_unified_loader.erl
+++ b/lib/kernel/src/hipe_unified_loader.erl
@@ -258,7 +258,7 @@ find_callee_mfas(Patches) when is_list(Patches) ->
amd64 -> [];
arm -> find_callee_mfas(Patches, gb_sets:empty(), false);
powerpc -> find_callee_mfas(Patches, gb_sets:empty(), true);
- %% ppc64 -> find_callee_mfas(Patches, gb_sets:empty(), true);
+ ppc64 -> find_callee_mfas(Patches, gb_sets:empty(), true);
ultrasparc -> [];
x86 -> []
end.
@@ -301,6 +301,7 @@ mk_trampoline_map(CalleeMFAs, Trampolines) ->
SizeofLong =
case erlang:system_info(hipe_architecture) of
amd64 -> 8;
+ ppc64 -> 8;
_ -> 4
end,
mk_trampoline_map(tuple_size(CalleeMFAs), CalleeMFAs,
@@ -625,15 +626,15 @@ patch_instr(Address, Value, Type) ->
%%
%% XXX: It appears this is used for inserting both code addresses
%% and other data. In HiPE, code addresses are still 32-bit on
-%% 64-bit machines.
+%% some 64-bit machines.
write_word(DataAddress, DataWord) ->
case erlang:system_info(hipe_architecture) of
amd64 ->
hipe_bifs:write_u64(DataAddress, DataWord),
DataAddress+8;
- %% ppc64 ->
- %% hipe_bifs:write_u64(DataAddress, DataWord),
- %% DataAddress+8;
+ ppc64 ->
+ hipe_bifs:write_u64(DataAddress, DataWord),
+ DataAddress+8;
_ ->
hipe_bifs:write_u32(DataAddress, DataWord),
DataAddress+4
--
cgit v1.2.3
From 861cfc9763ecc684b11bf2d88aee0478fe186c97 Mon Sep 17 00:00:00 2001
From: Kostis Sagonas
Date: Thu, 10 Feb 2011 02:42:43 +0200
Subject: Additions for the PPC64 backend
---
lib/hipe/rtl/hipe_rtl_arch.erl | 57 +++++++++++++++++++++++++++++++++++++-----
1 file changed, 51 insertions(+), 6 deletions(-)
(limited to 'lib')
diff --git a/lib/hipe/rtl/hipe_rtl_arch.erl b/lib/hipe/rtl/hipe_rtl_arch.erl
index 2afdf4eb6b..22cda57a3a 100644
--- a/lib/hipe/rtl/hipe_rtl_arch.erl
+++ b/lib/hipe/rtl/hipe_rtl_arch.erl
@@ -1,20 +1,20 @@
%% -*- erlang-indent-level: 2 -*-
%%
%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2001-2009. All Rights Reserved.
-%%
+%%
+%% Copyright Ericsson AB 2001-2011. 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%
%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@@ -86,6 +86,8 @@ first_virtual_reg() ->
hipe_sparc_registers:first_virtual();
powerpc ->
hipe_ppc_registers:first_virtual();
+ ppc64 ->
+ hipe_ppc_registers:first_virtual();
arm ->
hipe_arm_registers:first_virtual();
x86 ->
@@ -100,6 +102,8 @@ heap_pointer() -> % {GetHPInsn, HPReg, PutHPInsn}
heap_pointer_from_reg(hipe_sparc_registers:heap_pointer());
powerpc ->
heap_pointer_from_reg(hipe_ppc_registers:heap_pointer());
+ ppc64 ->
+ heap_pointer_from_reg(hipe_ppc_registers:heap_pointer());
arm ->
heap_pointer_from_reg(hipe_arm_registers:heap_pointer());
x86 ->
@@ -143,6 +147,8 @@ heap_limit() -> % {GetHLIMITInsn, HLIMITReg}
heap_limit_from_pcb();
powerpc ->
heap_limit_from_pcb();
+ ppc64 ->
+ heap_limit_from_pcb();
arm ->
heap_limit_from_pcb();
x86 ->
@@ -165,6 +171,8 @@ fcalls() -> % {GetFCallsInsn, FCallsReg, PutFCallsInsn}
fcalls_from_pcb();
powerpc ->
fcalls_from_pcb();
+ ppc64 ->
+ fcalls_from_pcb();
arm ->
fcalls_from_pcb();
x86 ->
@@ -188,6 +196,8 @@ reg_name(Reg) ->
hipe_sparc_registers:reg_name_gpr(Reg);
powerpc ->
hipe_ppc_registers:reg_name_gpr(Reg);
+ ppc64 ->
+ hipe_ppc_registers:reg_name_gpr(Reg);
arm ->
hipe_arm_registers:reg_name_gpr(Reg);
x86 ->
@@ -215,6 +225,8 @@ is_precolored_regnum(RegNum) ->
hipe_sparc_registers:is_precoloured_gpr(RegNum);
powerpc ->
hipe_ppc_registers:is_precoloured_gpr(RegNum);
+ ppc64 ->
+ hipe_ppc_registers:is_precoloured_gpr(RegNum);
arm ->
hipe_arm_registers:is_precoloured_gpr(RegNum);
x86 ->
@@ -243,6 +255,9 @@ live_at_return() ->
powerpc ->
ordsets:from_list([hipe_rtl:mk_reg(R)
|| {R,_} <- hipe_ppc_registers:live_at_return()]);
+ ppc64 ->
+ ordsets:from_list([hipe_rtl:mk_reg(R)
+ || {R,_} <- hipe_ppc_registers:live_at_return()]);
arm ->
ordsets:from_list([hipe_rtl:mk_reg(R)
|| {R,_} <- hipe_arm_registers:live_at_return()]);
@@ -262,6 +277,7 @@ word_size() ->
case get(hipe_target_arch) of
ultrasparc -> 4;
powerpc -> 4;
+ ppc64 -> 8;
arm -> 4;
x86 -> 4;
amd64 -> 8
@@ -284,6 +300,7 @@ log2_word_size() ->
case get(hipe_target_arch) of
ultrasparc -> 2;
powerpc -> 2;
+ ppc64 -> 3;
arm -> 2;
x86 -> 2;
amd64 -> 3
@@ -297,6 +314,7 @@ endianess() ->
case get(hipe_target_arch) of
ultrasparc -> big;
powerpc -> big;
+ ppc64 -> big;
x86 -> little;
amd64 -> little;
arm -> ?ARM_ENDIANESS
@@ -313,6 +331,8 @@ load_big_2(Dst, Base, Offset, Signedness) ->
case get(hipe_target_arch) of
powerpc ->
load_2_directly(Dst, Base, Offset, Signedness);
+ ppc64 ->
+ load_2_directly(Dst, Base, Offset, Signedness);
%% Note: x86 could use a "load;xchgb" or "load;rol $8,<16-bit reg>"
%% sequence here. This has been implemented, but unfortunately didn't
%% make consistent improvements to our benchmarks.
@@ -333,6 +353,13 @@ load_little_2(Dst, Base, Offset, Signedness) ->
unsigned -> [];
signed -> [hipe_rtl:mk_call([Dst], 'extsh', [Dst], [], [], not_remote)]
end];
+ ppc64 ->
+ [hipe_rtl:mk_call([Dst], 'lhbrx', [Base,Offset], [], [], not_remote),
+ hipe_rtl:mk_alu(Offset, Offset, add, hipe_rtl:mk_imm(2)) |
+ case Signedness of
+ unsigned -> [];
+ signed -> [hipe_rtl:mk_call([Dst], 'extsh', [Dst], [], [], not_remote)]
+ end];
_ ->
load_little_2_in_pieces(Dst, Base, Offset, Signedness)
end.
@@ -365,6 +392,8 @@ load_big_4(Dst, Base, Offset, Signedness) ->
case get(hipe_target_arch) of
powerpc ->
load_4_directly(Dst, Base, Offset, Signedness);
+ ppc64 ->
+ load_4_directly(Dst, Base, Offset, Signedness);
%% Note: x86 could use a "load;bswap" sequence here.
%% This has been implemented, but unfortunately didn't
%% make any noticeable improvements in our benchmarks.
@@ -386,6 +415,13 @@ load_little_4(Dst, Base, Offset, Signedness) ->
powerpc ->
[hipe_rtl:mk_call([Dst], 'lwbrx', [Base,Offset], [], [], not_remote),
hipe_rtl:mk_alu(Offset, Offset, add, hipe_rtl:mk_imm(4))];
+ ppc64 ->
+ [hipe_rtl:mk_call([Dst], 'lwbrx', [Base,Offset], [], [], not_remote),
+ hipe_rtl:mk_alu(Offset, Offset, add, hipe_rtl:mk_imm(4)) |
+ case Signedness of
+ unsigned -> [];
+ signed -> [hipe_rtl:mk_call([Dst], 'extsw', [Dst], [], [], not_remote)]
+ end];
arm ->
%% When loading 4 bytes into a 32-bit register, the
%% signedness of the high-order byte doesn't matter.
@@ -396,7 +432,7 @@ load_little_4(Dst, Base, Offset, Signedness) ->
end.
load_4_directly(Dst, Base, Offset, Signedness) ->
- [hipe_rtl:mk_load(Dst, Base, Offset, word, Signedness),
+ [hipe_rtl:mk_load(Dst, Base, Offset, int32, Signedness),
hipe_rtl:mk_alu(Offset, Offset, add, hipe_rtl:mk_imm(4))].
load_big_4_in_pieces(Dst, Base, Offset, Signedness) ->
@@ -440,6 +476,8 @@ store_4(Base, Offset, Src) ->
store_4_directly(Base, Offset, Src);
powerpc ->
store_4_directly(Base, Offset, Src);
+ ppc64 ->
+ store_4_directly(Base, Offset, Src);
arm ->
store_big_4_in_pieces(Base, Offset, Src);
ultrasparc ->
@@ -525,6 +563,7 @@ fwait() ->
amd64 -> [hipe_rtl:mk_call([], 'fwait', [], [], [], not_remote)];
arm -> [];
powerpc -> [];
+ ppc64 -> [];
ultrasparc -> []
end.
@@ -549,6 +588,8 @@ handle_fp_exception() ->
[];
powerpc ->
[];
+ ppc64 ->
+ [];
ultrasparc ->
[]
end.
@@ -577,6 +618,8 @@ proc_pointer() -> % must not be exported
hipe_rtl:mk_reg_gcsafe(hipe_sparc_registers:proc_pointer());
powerpc ->
hipe_rtl:mk_reg_gcsafe(hipe_ppc_registers:proc_pointer());
+ ppc64 ->
+ hipe_rtl:mk_reg_gcsafe(hipe_ppc_registers:proc_pointer());
arm ->
hipe_rtl:mk_reg_gcsafe(hipe_arm_registers:proc_pointer());
x86 ->
@@ -601,6 +644,8 @@ nr_of_return_regs() ->
%% hipe_sparc_registers:nr_rets();
powerpc ->
1;
+ ppc64 ->
+ 1;
%% hipe_ppc_registers:nr_rets();
arm ->
1;
--
cgit v1.2.3
From ea5edef4efd13d3027db9fa7999e74b587459869 Mon Sep 17 00:00:00 2001
From: Kostis Sagonas
Date: Thu, 10 Feb 2011 02:58:40 +0200
Subject: Changes in ppc files for PPC64
---
lib/hipe/ppc/hipe_ppc.erl | 172 ++++++++++++++++++------
lib/hipe/ppc/hipe_ppc_assemble.erl | 76 +++++++++--
lib/hipe/ppc/hipe_ppc_frame.erl | 30 +++--
lib/hipe/ppc/hipe_rtl_to_ppc.erl | 260 +++++++++++++++++++++++--------------
4 files changed, 375 insertions(+), 163 deletions(-)
(limited to 'lib')
diff --git a/lib/hipe/ppc/hipe_ppc.erl b/lib/hipe/ppc/hipe_ppc.erl
index 047e86c45b..4014fc1561 100644
--- a/lib/hipe/ppc/hipe_ppc.erl
+++ b/lib/hipe/ppc/hipe_ppc.erl
@@ -1,20 +1,20 @@
%% -*- erlang-indent-level: 2 -*-
%%
%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2004-2009. All Rights Reserved.
-%%
+%%
+%% Copyright Ericsson AB 2004-2011. 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%
%%
@@ -58,6 +58,10 @@
mk_blr/0,
mk_cmp/3,
+ cmpop_word/0,
+ cmpiop_word/0,
+ cmplop_word/0,
+ cmpliop_word/0,
mk_comment/1,
@@ -73,6 +77,8 @@
mk_loadx/4,
mk_load/6,
ldop_to_ldxop/1,
+ ldop_word/0,
+ ldop_wordx/0,
mk_mfspr/2,
@@ -110,6 +116,8 @@
mk_storex/4,
mk_store/6,
stop_to_stxop/1,
+ stop_word/0,
+ stop_wordx/0,
mk_unary/3,
@@ -189,6 +197,31 @@ mk_blr() -> #blr{}.
mk_cmp(CmpOp, Src1, Src2) -> #cmp{cmpop=CmpOp, src1=Src1, src2=Src2}.
+cmpop_word() ->
+ case get(hipe_target_arch) of
+ powerpc -> 'cmp';
+ ppc64 -> 'cmpd'
+ end.
+
+cmpiop_word() ->
+ case get(hipe_target_arch) of
+ powerpc -> 'cmpi';
+ ppc64 -> 'cmpdi'
+ end.
+
+cmplop_word() ->
+ case get(hipe_target_arch) of
+ powerpc -> 'cmpl';
+ ppc64 -> 'cmpld'
+ end.
+
+cmpliop_word() ->
+ case get(hipe_target_arch) of
+ powerpc -> 'cmpli';
+ ppc64 -> 'cmpldi'
+ end.
+
+
mk_comment(Term) -> #comment{term=Term}.
mk_label(Label) -> #label{label=Label}.
@@ -198,9 +231,50 @@ label_label(#label{label=Label}) -> Label.
%%% Load an integer constant into a register.
mk_li(Dst, Value) -> mk_li(Dst, Value, []).
-mk_li(Dst, Value, Tail) ->
+mk_li(Dst, Value, Tail) -> % Dst can be R0
R0 = mk_temp(0, 'untagged'),
- mk_addi(Dst, R0, Value, Tail).
+ %% Check if immediate can fit in the 32 bits, this is obviously a
+ %% sufficient check for PPC32
+ if Value >= -16#80000000,
+ Value =< 16#7FFFFFFF ->
+ mk_li32(Dst, R0, Value, Tail);
+ true ->
+ Highest = (Value bsr 48), % Value@highest
+ Higher = (Value bsr 32) band 16#FFFF, % Value@higher
+ High = (Value bsr 16) band 16#FFFF, % Value@h
+ Low = Value band 16#FFFF, % Value@l
+ LdLo =
+ case Low of
+ 0 -> Tail;
+ _ -> [mk_alu('ori', Dst, Dst, mk_uimm16(Low)) | Tail]
+ end,
+ Ld32bits =
+ case High of
+ 0 -> LdLo;
+ _ -> [mk_alu('oris', Dst, Dst, mk_uimm16(High)) | LdLo]
+ end,
+ [mk_alu('addis', Dst, R0, mk_simm16(Highest)),
+ mk_alu('ori', Dst, Dst, mk_uimm16(Higher)),
+ mk_alu('sldi', Dst, Dst, mk_uimm16(32)) |
+ Ld32bits]
+ end.
+
+mk_li32(Dst, R0, Value, Tail) ->
+ case at_ha(Value) of
+ 0 ->
+ %% Value[31:16] are the sign-extension of Value[15].
+ %% Use a single addi to load and sign-extend 16 bits.
+ [mk_alu('addi', Dst, R0, mk_simm16(at_l(Value))) | Tail];
+ _ ->
+ %% Use addis to load the high 16 bits, followed by an
+ %% optional ori to load non sign-extended low 16 bits.
+ High = simm16sext((Value bsr 16) band 16#FFFF),
+ [mk_alu('addis', Dst, R0, mk_simm16(High)) |
+ case (Value band 16#FFFF) of
+ 0 -> Tail;
+ Low -> [mk_alu('ori', Dst, Dst, mk_uimm16(Low)) | Tail]
+ end]
+ end.
mk_addi(Dst, R0, Value, Tail) ->
Low = at_l(Value),
@@ -232,27 +306,6 @@ simm16sext(Value) ->
true -> Value
end.
-mk_li_new(Dst, Value, Tail) -> % Dst may be R0
- R0 = mk_temp(0, 'untagged'),
- case at_ha(Value) of
- 0 ->
- %% Value[31:16] are the sign-extension of Value[15].
- %% Use a single addi to load and sign-extend 16 bits.
- [mk_alu('addi', Dst, R0, mk_simm16(at_l(Value))) |
- Tail];
- _ ->
- %% Use addis to load the high 16 bits, followed by an
- %% optional ori to load non sign-extended low 16 bits.
- High = simm16sext((Value bsr 16) band 16#FFFF),
- [mk_alu('addis', Dst, R0, mk_simm16(High)) |
- case (Value band 16#FFFF) of
- 0 -> Tail;
- Low ->
- [mk_alu('ori', Dst, Dst, mk_uimm16(Low)) |
- Tail]
- end]
- end.
-
mk_load(LDop, Dst, Disp, Base) ->
#load{ldop=LDop, dst=Dst, disp=Disp, base=Base}.
@@ -260,8 +313,15 @@ mk_loadx(LdxOp, Dst, Base1, Base2) ->
#loadx{ldxop=LdxOp, dst=Dst, base1=Base1, base2=Base2}.
mk_load(LdOp, Dst, Offset, Base, Scratch, Rest) when is_integer(Offset) ->
- if Offset >= -32768, Offset =< 32767 ->
- [mk_load(LdOp, Dst, Offset, Base) | Rest];
+ RequireAlignment =
+ case LdOp of
+ 'ld' -> true;
+ 'ldx' -> true;
+ _ -> false
+ end,
+ if Offset >= -32768, Offset =< 32767,
+ not RequireAlignment orelse Offset band 3 =:= 0 ->
+ [mk_load(LdOp, Dst, Offset, Base) | Rest];
true ->
LdxOp = ldop_to_ldxop(LdOp),
Index =
@@ -272,8 +332,8 @@ mk_load(LdOp, Dst, Offset, Base, Scratch, Rest) when is_integer(Offset) ->
true -> mk_scratch(Scratch)
end
end,
- mk_li_new(Index, Offset,
- [mk_loadx(LdxOp, Dst, Base, Index) | Rest])
+ mk_li(Index, Offset,
+ [mk_loadx(LdxOp, Dst, Base, Index) | Rest])
end.
ldop_to_ldxop(LdOp) ->
@@ -281,7 +341,21 @@ ldop_to_ldxop(LdOp) ->
'lbz' -> 'lbzx';
'lha' -> 'lhax';
'lhz' -> 'lhzx';
- 'lwz' -> 'lwzx'
+ 'lwa' -> 'lwax';
+ 'lwz' -> 'lwzx';
+ 'ld' -> 'ldx'
+ end.
+
+ldop_word() ->
+ case get(hipe_target_arch) of
+ powerpc -> 'lwz';
+ ppc64 -> 'ld'
+ end.
+
+ldop_wordx() ->
+ case get(hipe_target_arch) of
+ powerpc -> 'lwzx';
+ ppc64 -> 'ldx'
end.
mk_scratch(Scratch) ->
@@ -354,20 +428,40 @@ mk_storex(StxOp, Src, Base1, Base2) ->
#storex{stxop=StxOp, src=Src, base1=Base1, base2=Base2}.
mk_store(StOp, Src, Offset, Base, Scratch, Rest)when is_integer(Offset) ->
- if Offset >= -32768, Offset =< 32767 ->
+ RequireAlignment =
+ case StOp of
+ 'std' -> true;
+ 'stdx' -> true;
+ _ -> false
+ end,
+ if Offset >= -32768, Offset =< 32767,
+ not RequireAlignment orelse Offset band 3 =:= 0 ->
[mk_store(StOp, Src, Offset, Base) | Rest];
true ->
StxOp = stop_to_stxop(StOp),
Index = mk_scratch(Scratch),
- mk_li_new(Index, Offset,
- [mk_storex(StxOp, Src, Base, Index) | Rest])
+ mk_li(Index, Offset,
+ [mk_storex(StxOp, Src, Base, Index) | Rest])
end.
stop_to_stxop(StOp) ->
case StOp of
'stb' -> 'stbx';
'sth' -> 'sthx';
- 'stw' -> 'stwx'
+ 'stw' -> 'stwx';
+ 'std' -> 'stdx'
+ end.
+
+stop_word() ->
+ case get(hipe_target_arch) of
+ powerpc -> 'stw';
+ ppc64 -> 'std'
+ end.
+
+stop_wordx() ->
+ case get(hipe_target_arch) of
+ powerpc -> 'stwx';
+ ppc64 -> 'stdx'
end.
mk_unary(UnOp, Dst, Src) -> #unary{unop=UnOp, dst=Dst, src=Src}.
@@ -379,7 +473,7 @@ mk_fload(Dst, Offset, Base, Scratch) when is_integer(Offset) ->
[mk_lfd(Dst, Offset, Base)];
true ->
Index = mk_scratch(Scratch),
- mk_li_new(Index, Offset, [mk_lfdx(Dst, Base, Index)])
+ mk_li(Index, Offset, [mk_lfdx(Dst, Base, Index)])
end.
mk_stfd(Src, Disp, Base) -> #stfd{src=Src, disp=Disp, base=Base}.
@@ -389,7 +483,7 @@ mk_fstore(Src, Offset, Base, Scratch) when is_integer(Offset) ->
[mk_stfd(Src, Offset, Base)];
true ->
Index = mk_scratch(Scratch),
- mk_li_new(Index, Offset, [mk_stfdx(Src, Base, Index)])
+ mk_li(Index, Offset, [mk_stfdx(Src, Base, Index)])
end.
mk_fp_binary(FpBinOp, Dst, Src1, Src2) ->
diff --git a/lib/hipe/ppc/hipe_ppc_assemble.erl b/lib/hipe/ppc/hipe_ppc_assemble.erl
index 6f06f8b841..b2fd50517b 100644
--- a/lib/hipe/ppc/hipe_ppc_assemble.erl
+++ b/lib/hipe/ppc/hipe_ppc_assemble.erl
@@ -1,20 +1,20 @@
%% -*- erlang-indent-level: 2 -*-
%%
%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2004-2009. All Rights Reserved.
-%%
+%%
+%% Copyright Ericsson AB 2004-2011. 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%
%%
@@ -39,7 +39,7 @@ assemble(CompiledCode, Closures, Exports, Options) ->
|| {MFA, Defun} <- CompiledCode],
%%
{ConstAlign,ConstSize,ConstMap,RefsFromConsts} =
- hipe_pack_constants:pack_constants(Code, 4),
+ hipe_pack_constants:pack_constants(Code, hipe_rtl_arch:word_size()),
%%
{CodeSize,CodeBinary,AccRefs,LabelMap,ExportMap} =
encode(translate(Code, ConstMap), Options),
@@ -159,6 +159,13 @@ do_alu(I) ->
'srwi.' -> {'rlwinm.', do_srwi_opnds(NewDst, NewSrc1, NewSrc2)};
'srawi' -> {'srawi', {NewDst,NewSrc1,do_srawi_src2(NewSrc2)}};
'srawi.' -> {'srawi.', {NewDst,NewSrc1,do_srawi_src2(NewSrc2)}};
+ %ppc64 extension
+ 'sldi' -> {'rldicr', do_sldi_opnds(NewDst, NewSrc1, NewSrc2)};
+ 'sldi.' -> {'rldicr.', do_sldi_opnds(NewDst, NewSrc1, NewSrc2)};
+ 'srdi' -> {'rldicl', do_srdi_opnds(NewDst, NewSrc1, NewSrc2)};
+ 'srdi.' -> {'rldicl.', do_srdi_opnds(NewDst, NewSrc1, NewSrc2)};
+ 'sradi' -> {'sradi', {NewDst,NewSrc1,do_sradi_src2(NewSrc2)}};
+ 'sradi.' -> {'sradi.', {NewDst,NewSrc1,do_sradi_src2(NewSrc2)}};
_ -> {AluOp, {NewDst,NewSrc1,NewSrc2}}
end,
[{NewI, NewOpnds, I}].
@@ -171,6 +178,15 @@ do_srwi_opnds(Dst, Src1, {uimm,N}) when is_integer(N), 0 =< N, N < 32 ->
do_srawi_src2({uimm,N}) when is_integer(N), 0 =< N, N < 32 -> {sh,N}.
+%% ppc64 extension
+do_sldi_opnds(Dst, Src1, {uimm,N}) when is_integer(N), 0 =< N, N < 64 ->
+ {Dst, Src1, {sh6,N}, {me6,63-N}}.
+
+do_srdi_opnds(Dst, Src1, {uimm,N}) when is_integer(N), 0 =< N, N < 64 ->
+ {Dst, Src1, {sh6,64-N}, {mb6,N}}.
+
+do_sradi_src2({uimm,N}) when is_integer(N), 0 =< N, N < 64 -> {sh6,N}.
+
do_b_fun(I) ->
#b_fun{'fun'=Fun,linkage=Linkage} = I,
[{'.reloc', {b_fun,Fun,Linkage}, #comment{term='fun'}},
@@ -205,7 +221,18 @@ do_cmp(I) ->
#cmp{cmpop=CmpOp,src1=Src1,src2=Src2} = I,
NewSrc1 = do_reg(Src1),
NewSrc2 = do_reg_or_imm(Src2),
- [{CmpOp, {{crf,0},0,NewSrc1,NewSrc2}, I}].
+ {RealOp,L} =
+ case CmpOp of
+ 'cmpd' -> {'cmp',1};
+ 'cmpdi' -> {'cmpi',1};
+ 'cmpld' -> {'cmpl',1};
+ 'cmpldi' -> {'cmpli',1};
+ 'cmp' -> {CmpOp,0};
+ 'cmpi' -> {CmpOp,0};
+ 'cmpl' -> {CmpOp,0};
+ 'cmpli' -> {CmpOp,0}
+ end,
+ [{RealOp, {{crf,0},L,NewSrc1,NewSrc2}, I}].
do_label(I) ->
#label{label=Label} = I,
@@ -214,7 +241,12 @@ do_label(I) ->
do_load(I) ->
#load{ldop=LdOp,dst=Dst,disp=Disp,base=Base} = I,
NewDst = do_reg(Dst),
- NewDisp = do_disp(Disp),
+ NewDisp =
+ case LdOp of
+ 'ld' -> do_disp_ds(Disp);
+ 'ldu' -> do_disp_ds(Disp);
+ _ -> do_disp(Disp)
+ end,
NewBase = do_reg(Base),
[{LdOp, {NewDst,NewDisp,NewBase}, I}].
@@ -265,14 +297,30 @@ do_pseudo_li(I, MFA, ConstMap) ->
end,
NewDst = do_reg(Dst),
Simm0 = {simm,0},
- [{'.reloc', RelocData, #comment{term=reloc}},
- {addi, {NewDst,{r,0},Simm0}, I},
- {addis, {NewDst,NewDst,Simm0}, I}].
+ Uimm0 = {uimm,0},
+ case get(hipe_target_arch) of
+ powerpc ->
+ [{'.reloc', RelocData, #comment{term=reloc}},
+ {addi, {NewDst,{r,0},Simm0}, I},
+ {addis, {NewDst,NewDst,Simm0}, I}];
+ ppc64 ->
+ [{'.reloc', RelocData, #comment{term=reloc}},
+ {addis, {NewDst,{r,0},Simm0}, I}, % @highest
+ {ori, {NewDst,NewDst,Uimm0}, I}, % @higher
+ {rldicr, {NewDst,NewDst,{sh6,32},{me6,31}}, I},
+ {oris, {NewDst,NewDst,Uimm0}, I}, % @h
+ {ori, {NewDst,NewDst,Uimm0}, I}] % @l
+ end.
do_store(I) ->
#store{stop=StOp,src=Src,disp=Disp,base=Base} = I,
NewSrc = do_reg(Src),
- NewDisp = do_disp(Disp),
+ NewDisp =
+ case StOp of
+ 'std' -> do_disp_ds(Disp);
+ 'stdu' -> do_disp_ds(Disp);
+ _ -> do_disp(Disp)
+ end,
NewBase = do_reg(Base),
[{StOp, {NewSrc,NewDisp,NewBase}, I}].
@@ -344,6 +392,10 @@ do_reg_or_imm(Src) ->
do_disp(Disp) when is_integer(Disp), -32768 =< Disp, Disp =< 32767 ->
{d, Disp band 16#ffff}.
+do_disp_ds(Disp) when is_integer(Disp),
+ -32768 =< Disp, Disp =< 32767, Disp band 3 =:= 0 ->
+ {ds, (Disp band 16#ffff) bsr 2}.
+
do_spr(SPR) ->
SPR_NR =
case SPR of
diff --git a/lib/hipe/ppc/hipe_ppc_frame.erl b/lib/hipe/ppc/hipe_ppc_frame.erl
index 158009872f..8a4d1906c0 100644
--- a/lib/hipe/ppc/hipe_ppc_frame.erl
+++ b/lib/hipe/ppc/hipe_ppc_frame.erl
@@ -1,20 +1,20 @@
%% -*- erlang-indent-level: 2 -*-
%%
%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2004-2009. All Rights Reserved.
-%%
+%%
+%% Copyright Ericsson AB 2004-2011. 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%
%%
@@ -103,12 +103,12 @@ do_pseudo_move(I, Context, FPoff) ->
case temp_is_pseudo(Dst) of
true ->
Offset = pseudo_offset(Dst, FPoff, Context),
- mk_store('stw', Src, Offset, mk_sp(), []);
+ mk_store(hipe_ppc:stop_word(), Src, Offset, mk_sp(), []);
_ ->
case temp_is_pseudo(Src) of
true ->
Offset = pseudo_offset(Src, FPoff, Context),
- mk_load('lwz', Dst, Offset, mk_sp(), []);
+ mk_load(hipe_ppc:ldop_word(), Dst, Offset, mk_sp(), []);
_ ->
[hipe_ppc:mk_alu('or', Dst, Src, Src)]
end
@@ -152,7 +152,7 @@ restore_lr(FPoff, Context, Rest) ->
false -> Rest;
true ->
Temp = mk_temp1(),
- mk_load('lwz', Temp, FPoff - word_size(), mk_sp(),
+ mk_load(hipe_ppc:ldop_word(), Temp, FPoff - word_size(), mk_sp(),
[hipe_ppc:mk_mtspr('lr', Temp) |
Rest])
end.
@@ -324,8 +324,8 @@ simple_moves([{SrcOff,DstOff,Type}|Moves], FPoff, TempReg, Rest) ->
LoadOff = FPoff+SrcOff,
StoreOff = FPoff+DstOff,
simple_moves(Moves, FPoff, TempReg,
- mk_load('lwz', Temp, LoadOff, SP,
- mk_store('stw', Temp, StoreOff, SP,
+ mk_load(hipe_ppc:ldop_word(), Temp, LoadOff, SP,
+ mk_store(hipe_ppc:stop_word(), Temp, StoreOff, SP,
Rest)));
simple_moves([], _, _, Rest) ->
Rest.
@@ -343,7 +343,8 @@ store_moves([{Src,DstOff}|Moves], FPoff, TempReg, Rest) ->
{Temp, hipe_ppc:mk_li(Temp, Src)}
end,
store_moves(Moves, FPoff, TempReg,
- FixSrc ++ mk_store('stw', NewSrc, StoreOff, SP, Rest));
+ FixSrc ++ mk_store(hipe_ppc:stop_word(), NewSrc,
+ StoreOff, SP, Rest));
store_moves([], _, _, Rest) ->
Rest.
@@ -400,7 +401,7 @@ mk_temp_map(Formals, ClobbersLR, Temps) ->
enter_vars([V|Vs], PrevOff, Map) ->
Off =
case hipe_ppc:temp_type(V) of
- 'double' -> PrevOff - 2*word_size();
+ 'double' -> PrevOff - 8;
_ -> PrevOff - word_size()
end,
enter_vars(Vs, Off, tmap_bind(Map, V, Off));
@@ -454,7 +455,8 @@ do_prologue(CFG, Context) ->
AllocFrameCodeTail =
case ClobbersLR of
false -> GotoOldStartCode;
- true -> mk_store('stw', Temp1, FrameSize-word_size(), SP, GotoOldStartCode)
+ true -> mk_store(hipe_ppc:stop_word(), Temp1,
+ FrameSize-word_size(), SP, GotoOldStartCode)
end,
%%
Arity = context_arity(Context),
@@ -484,7 +486,7 @@ do_prologue(CFG, Context) ->
true -> [hipe_ppc:mk_mfspr(Temp1, 'lr') | NewStartCodeTail2]
end,
NewStartCode0 =
- [hipe_ppc:mk_load('lwz', Temp1, ?P_NSP_LIMIT, P) |
+ [hipe_ppc:mk_load(hipe_ppc:ldop_word(), Temp1, ?P_NSP_LIMIT, P) |
hipe_ppc:mk_addi(Temp2, SP, -MaxStack,
[hipe_ppc:mk_cmp('cmpl', Temp2, Temp1) |
NewStartCodeTail1])],
diff --git a/lib/hipe/ppc/hipe_rtl_to_ppc.erl b/lib/hipe/ppc/hipe_rtl_to_ppc.erl
index 458af250de..7dfa56df29 100644
--- a/lib/hipe/ppc/hipe_rtl_to_ppc.erl
+++ b/lib/hipe/ppc/hipe_rtl_to_ppc.erl
@@ -1,20 +1,20 @@
%%% -*- erlang-indent-level: 2 -*-
%%%
%%% %CopyrightBegin%
-%%%
-%%% Copyright Ericsson AB 2004-2009. All Rights Reserved.
-%%%
+%%%
+%%% Copyright Ericsson AB 2004-2011. 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%
%%%
%%% The PowerPC instruction set is quite irregular.
@@ -110,20 +110,27 @@ conv_fconv(I, Map, Data) ->
mk_fconv(Dst, Src) ->
CSP = hipe_ppc:mk_temp(1, 'untagged'),
- R0 = hipe_ppc:mk_temp(0, 'untagged'),
- RTmp1 = hipe_ppc:mk_new_temp('untagged'),
- RTmp2 = hipe_ppc:mk_new_temp('untagged'),
- RTmp3 = hipe_ppc:mk_new_temp('untagged'),
- FTmp1 = hipe_ppc:mk_new_temp('double'),
- FTmp2 = hipe_ppc:mk_new_temp('double'),
- [hipe_ppc:mk_pseudo_li(RTmp1, {fconv_constant,c_const}),
- hipe_ppc:mk_lfd(FTmp1, 0, RTmp1),
- hipe_ppc:mk_alu('xoris', RTmp2, Src, hipe_ppc:mk_uimm16(16#8000)),
- hipe_ppc:mk_store('stw', RTmp2, 28, CSP),
- hipe_ppc:mk_alu('addis', RTmp3, R0, hipe_ppc:mk_simm16(16#4330)),
- hipe_ppc:mk_store('stw', RTmp3, 24, CSP),
- hipe_ppc:mk_lfd(FTmp2, 24, CSP),
- hipe_ppc:mk_fp_binary('fsub', Dst, FTmp2, FTmp1)].
+ case get(hipe_target_arch) of
+ powerpc ->
+ R0 = hipe_ppc:mk_temp(0, 'untagged'),
+ RTmp1 = hipe_ppc:mk_new_temp('untagged'),
+ RTmp2 = hipe_ppc:mk_new_temp('untagged'),
+ RTmp3 = hipe_ppc:mk_new_temp('untagged'),
+ FTmp1 = hipe_ppc:mk_new_temp('double'),
+ FTmp2 = hipe_ppc:mk_new_temp('double'),
+ [hipe_ppc:mk_pseudo_li(RTmp1, {fconv_constant,c_const}),
+ hipe_ppc:mk_lfd(FTmp1, 0, RTmp1),
+ hipe_ppc:mk_alu('xoris', RTmp2, Src, hipe_ppc:mk_uimm16(16#8000)),
+ hipe_ppc:mk_store('stw', RTmp2, 28, CSP),
+ hipe_ppc:mk_alu('addis', RTmp3, R0, hipe_ppc:mk_simm16(16#4330)),
+ hipe_ppc:mk_store('stw', RTmp3, 24, CSP),
+ hipe_ppc:mk_lfd(FTmp2, 24, CSP),
+ hipe_ppc:mk_fp_binary('fsub', Dst, FTmp2, FTmp1)];
+ ppc64 ->
+ [hipe_ppc:mk_store('std', Src, 24, CSP),
+ hipe_ppc:mk_lfd(Dst, 24, CSP),
+ hipe_ppc:mk_fp_unary('fcfid', Dst, Dst)]
+ end.
conv_fmove(I, Map, Data) ->
%% Dst := Src, where both Dst and Src are FP regs
@@ -280,10 +287,14 @@ mk_alu_ri(Dst, Src1, RtlAluOp, Src2) ->
'mul' -> % 'mulli' has a 16-bit simm operand
mk_alu_ri_simm16(Dst, Src1, RtlAluOp, 'mulli', Src2);
'and' -> % 'andi.' has a 16-bit uimm operand
- case rlwinm_mask(Src2) of
- {MB,ME} ->
- [hipe_ppc:mk_unary({'rlwinm',0,MB,ME}, Dst, Src1)];
- _ ->
+ if Src2 band (bnot 16#ffffffff) =:= 0 ->
+ case rlwinm_mask(Src2) of
+ {MB,ME} ->
+ [hipe_ppc:mk_unary({'rlwinm',0,MB,ME}, Dst, Src1)];
+ _ ->
+ mk_alu_ri_bitop(Dst, Src1, RtlAluOp, 'andi.', Src2)
+ end;
+ true ->
mk_alu_ri_bitop(Dst, Src1, RtlAluOp, 'andi.', Src2)
end;
'or' -> % 'ori' has a 16-bit uimm operand
@@ -360,17 +371,33 @@ mk_alu_ri_bitop(Dst, Src1, RtlAluOp, AluOp, Src2) ->
end.
mk_alu_ri_shift(Dst, Src1, RtlAluOp, Src2) ->
- if Src2 < 32, Src2 >= 0 ->
- AluOp =
- case RtlAluOp of
- 'sll' -> 'slwi'; % alias for rlwinm
- 'srl' -> 'srwi'; % alias for rlwinm
- 'sra' -> 'srawi'
- end,
- [hipe_ppc:mk_alu(AluOp, Dst, Src1,
- hipe_ppc:mk_uimm16(Src2))];
- true ->
- mk_alu_ri_rr(Dst, Src1, RtlAluOp, Src2)
+ case get(hipe_target_arch) of
+ ppc64 ->
+ if Src2 < 64, Src2 >= 0 ->
+ AluOp =
+ case RtlAluOp of
+ 'sll' -> 'sldi'; % alias for rldimi %%% buggy
+ 'srl' -> 'srdi'; % alias for rldimi %%% buggy
+ 'sra' -> 'sradi' %%% buggy
+ end,
+ [hipe_ppc:mk_alu(AluOp, Dst, Src1,
+ hipe_ppc:mk_uimm16(Src2))];
+ true ->
+ mk_alu_ri_rr(Dst, Src1, RtlAluOp, Src2)
+ end;
+ powerpc ->
+ if Src2 < 32, Src2 >= 0 ->
+ AluOp =
+ case RtlAluOp of
+ 'sll' -> 'slwi'; % alias for rlwinm
+ 'srl' -> 'srwi'; % alias for rlwinm
+ 'sra' -> 'srawi'
+ end,
+ [hipe_ppc:mk_alu(AluOp, Dst, Src1,
+ hipe_ppc:mk_uimm16(Src2))];
+ true ->
+ mk_alu_ri_rr(Dst, Src1, RtlAluOp, Src2)
+ end
end.
mk_alu_ri_rr(Dst, Src1, RtlAluOp, Src2) ->
@@ -384,15 +411,21 @@ mk_alu_rr(Dst, Src1, RtlAluOp, Src2) ->
[hipe_ppc:mk_alu('subf', Dst, Src2, Src1)];
_ ->
AluOp =
- case RtlAluOp of
- 'add' -> 'add';
- 'mul' -> 'mullw';
- 'or' -> 'or';
- 'and' -> 'and';
- 'xor' -> 'xor';
- 'sll' -> 'slw';
- 'srl' -> 'srw';
- 'sra' -> 'sraw'
+ case {get(hipe_target_arch), RtlAluOp} of
+ {_, 'add'} -> 'add';
+ {_, 'or'} -> 'or';
+ {_, 'and'} -> 'and';
+ {_, 'xor'} -> 'xor';
+
+ {powerpc, 'mul'} -> 'mullw';
+ {powerpc, 'sll'} -> 'slw';
+ {powerpc, 'srl'} -> 'srw';
+ {powerpc, 'sra'} -> 'sraw';
+
+ {ppc64, 'mul'} -> 'mulld';
+ {ppc64, 'sll'} -> 'sld';
+ {ppc64, 'srl'} -> 'srd';
+ {ppc64, 'sra'} -> 'srad'
end,
[hipe_ppc:mk_alu(AluOp, Dst, Src1, Src2)]
end.
@@ -431,16 +464,22 @@ conv_alub(I, Map, Data) ->
{I1 ++ I2, Map2, Data}.
conv_alub_op(RtlAluOp) ->
- case RtlAluOp of
- 'add' -> 'add';
- 'sub' -> 'subf'; % XXX: must swap operands
- 'mul' -> 'mullw';
- 'or' -> 'or';
- 'and' -> 'and';
- 'xor' -> 'xor';
- 'sll' -> 'slw';
- 'srl' -> 'srw';
- 'sra' -> 'sraw'
+ case {get(hipe_target_arch), RtlAluOp} of
+ {_, 'add'} -> 'add';
+ {_, 'sub'} -> 'subf'; % XXX: must swap operands
+ {_, 'or'} -> 'or';
+ {_, 'and'} -> 'and';
+ {_, 'xor'} -> 'xor';
+
+ {powerpc, 'mul'} -> 'mullw';
+ {powerpc, 'sll'} -> 'slw';
+ {powerpc, 'srl'} -> 'srw';
+ {powerpc, 'sra'} -> 'sraw';
+
+ {ppc64, 'mul'} -> 'mulld';
+ {ppc64, 'sll'} -> 'sld';
+ {ppc64, 'srl'} -> 'srd';
+ {ppc64, 'sra'} -> 'srad'
end.
aluop_commutes(AluOp) ->
@@ -454,7 +493,11 @@ aluop_commutes(AluOp) ->
'xor' -> true;
'slw' -> false;
'srw' -> false;
- 'sraw' -> false
+ 'sraw' -> false;
+ 'mulld' -> true; % ppc64
+ 'sld' -> false; % ppc64
+ 'srd' -> false; % ppc64
+ 'srad' -> false % ppc64
end.
conv_alub_cond(Cond) -> % only signed
@@ -528,17 +571,24 @@ mk_alub_ri_Rc(Dst, Src1, AluOp, Src2) ->
mk_alub_ri_Rc_addi(Dst, Src1, Src2, 'addic.', 'add.');
'addc' -> % 'addic' has a 16-bit simm operand
mk_alub_ri_Rc_addi(Dst, Src1, Src2, 'addic', 'addc');
- 'mullw' -> % there is no 'mulli.'
+ 'mullw' -> % there is no 'mulli.'
mk_alub_ri_Rc_rr(Dst, Src1, 'mullw.', Src2);
+ 'mulld' -> % there is no 'mulli.'
+ mk_alub_ri_Rc_rr(Dst, Src1, 'mulld.', Src2);
'or' -> % there is no 'ori.'
mk_alub_ri_Rc_rr(Dst, Src1, 'or.', Src2);
'xor' -> % there is no 'xori.'
mk_alub_ri_Rc_rr(Dst, Src1, 'xor.', Src2);
'and' -> % 'andi.' has a 16-bit uimm operand
- case rlwinm_mask(Src2) of
- {MB,ME} ->
- [hipe_ppc:mk_unary({'rlwinm.',0,MB,ME}, Dst, Src1)];
- _ ->
+ if
+ Src2 band (bnot 16#ffffffff) =:= 0 ->
+ case rlwinm_mask(Src2) of
+ {MB,ME} ->
+ [hipe_ppc:mk_unary({'rlwinm.',0,MB,ME}, Dst, Src1)];
+ _ ->
+ mk_alub_ri_Rc_andi(Dst, Src1, Src2)
+ end;
+ true ->
mk_alub_ri_Rc_andi(Dst, Src1, Src2)
end;
_ -> % shift ops have 5-bit uimm operands
@@ -562,13 +612,16 @@ mk_alub_ri_Rc_andi(Dst, Src1, Src2) ->
end.
mk_alub_ri_Rc_shift(Dst, Src1, AluOp, Src2) ->
- if Src2 < 32, Src2 >= 0 ->
- AluOpIDot =
- case AluOp of
- 'slw' -> 'slwi.'; % alias for rlwinm.
- 'srw' -> 'srwi.'; % alias for rlwinm.
- 'sraw' -> 'srawi.'
- end,
+ {AluOpIDot, MaxIShift} =
+ case AluOp of
+ 'slw' -> {'slwi.', 32}; % alias for rlwinm.
+ 'srw' -> {'srwi.', 32}; % alias for rlwinm.
+ 'sraw' -> {'srawi.', 32};
+ 'sld' -> {'sldi.', 64};
+ 'srd' -> {'srdi.', 64};
+ 'srad' -> {'sradi.', 64}
+ end,
+ if Src2 < MaxIShift, Src2 >= 0 ->
[hipe_ppc:mk_alu(AluOpIDot, Dst, Src1,
hipe_ppc:mk_uimm16(Src2))];
true ->
@@ -576,7 +629,10 @@ mk_alub_ri_Rc_shift(Dst, Src1, AluOp, Src2) ->
case AluOp of
'slw' -> 'slw.';
'srw' -> 'srw.';
- 'sraw' -> 'sraw.'
+ 'sraw' -> 'sraw.';
+ 'sld' -> 'sld.';
+ 'srd' -> 'srd.';
+ 'srad' -> 'srad.'
end,
mk_alub_ri_Rc_rr(Dst, Src1, AluOpDot, Src2)
end.
@@ -598,8 +654,9 @@ mk_alub_rr_OE(Dst, Src1, AluOp, Src2) ->
case AluOp of
'subf' -> 'subfo.';
'add' -> 'addo.';
- 'mullw' -> 'mullwo.'
- %% fail for addc, or, and, xor, slw, srw, sraw
+ 'mullw' -> 'mullwo.';
+ 'mulld' -> 'mulldo.'
+ %% fail for addc, or, and, xor, slw, srw, sraw
end,
[hipe_ppc:mk_alu(AluOpODot, Dst, Src1, Src2)].
@@ -610,12 +667,16 @@ mk_alub_rr_Rc(Dst, Src1, AluOp, Src2) ->
'add' -> 'add.';
'addc' -> 'addc'; % only interested in CA, no Rc needed
'mullw' -> 'mullw.';
+ 'mulld' -> 'mulld.';
'or' -> 'or.';
'and' -> 'and.';
'xor' -> 'xor.';
'slw' -> 'slw.';
+ 'sld' -> 'sld.';
'srw' -> 'srw.';
- 'sraw' -> 'sraw.'
+ 'srd' -> 'srd.';
+ 'sraw' -> 'sraw.';
+ 'srad' -> 'srad.'
end,
[hipe_ppc:mk_alu(AluOpDot, Dst, Src1, Src2)].
@@ -682,17 +743,17 @@ mk_branch_ri(Src1, BCond, Sign, Src2, TrueLab, FalseLab, Pred) ->
case Sign of
'signed' ->
if is_integer(Src2), -32768 =< Src2, Src2 < 32768 ->
- {[], hipe_ppc:mk_simm16(Src2), 'cmpi'};
+ {[], hipe_ppc:mk_simm16(Src2), hipe_ppc:cmpiop_word()};
true ->
Tmp = new_untagged_temp(),
- {mk_li(Tmp, Src2), Tmp, 'cmp'}
+ {mk_li(Tmp, Src2), Tmp, hipe_ppc:cmpop_word()}
end;
'unsigned' ->
if is_integer(Src2), 0 =< Src2, Src2 < 65536 ->
- {[], hipe_ppc:mk_uimm16(Src2), 'cmpli'};
+ {[], hipe_ppc:mk_uimm16(Src2), hipe_ppc:cmpliop_word()};
true ->
Tmp = new_untagged_temp(),
- {mk_li(Tmp, Src2), Tmp, 'cmpl'}
+ {mk_li(Tmp, Src2), Tmp, hipe_ppc:cmplop_word()}
end
end,
FixSrc2 ++
@@ -701,8 +762,8 @@ mk_branch_ri(Src1, BCond, Sign, Src2, TrueLab, FalseLab, Pred) ->
mk_branch_rr(Src1, BCond, Sign, Src2, TrueLab, FalseLab, Pred) ->
CmpOp =
case Sign of
- 'signed' -> 'cmp';
- 'unsigned' -> 'cmpl'
+ 'signed' -> hipe_ppc:cmpop_word();
+ 'unsigned' -> hipe_ppc:cmplop_word()
end,
mk_cmp_bc(CmpOp, Src1, Src2, BCond, TrueLab, FalseLab, Pred).
@@ -841,7 +902,7 @@ mk_store_args([Arg|Args], PrevOffset, Tail) ->
Tmp = new_tagged_temp(),
{Tmp, mk_li(Tmp, Arg)}
end,
- Store = hipe_ppc:mk_store('stw', Src, Offset, mk_sp()),
+ Store = hipe_ppc:mk_store(hipe_ppc:stop_word(), Src, Offset, mk_sp()),
mk_store_args(Args, Offset, FixSrc ++ [Store | Tail]);
mk_store_args([], _, Tail) ->
Tail.
@@ -883,25 +944,19 @@ conv_load(I, Map, Data) ->
{I2, Map2, Data}.
mk_load(Dst, Base1, Base2, LoadSize, LoadSign) ->
- Rest =
- case LoadSize of
- byte ->
- case LoadSign of
- signed -> [hipe_ppc:mk_unary('extsb', Dst, Dst)];
- _ -> []
+ {LdOp, Rest} =
+ case {LoadSize, LoadSign} of
+ {byte, signed} -> {'lbz', [hipe_ppc:mk_unary('extsb', Dst, Dst)]};
+ {byte, unsigned} -> {'lbz', []};
+ {int16, signed} -> {'lha', []};
+ {int16, unsigned} -> {'lhz', []};
+ {int32, signed} ->
+ case get(hipe_target_arch) of
+ powerpc -> {'lwz', []};
+ ppc64 -> {'lwa', []}
end;
- _ -> []
- end,
- LdOp =
- case LoadSize of
- byte -> 'lbz';
- int32 -> 'lwz';
- word -> 'lwz';
- int16 ->
- case LoadSign of
- signed -> 'lha';
- unsigned -> 'lhz'
- end
+ {int32, unsigned} -> {'lwz', []};
+ {word, _} -> {hipe_ppc:ldop_word(), []}
end,
case hipe_ppc:is_temp(Base1) of
true ->
@@ -980,7 +1035,7 @@ mk_store(Src, Base1, Base2, StoreSize) ->
byte -> 'stb';
int16 -> 'sth';
int32 -> 'stw';
- word -> 'stw'
+ word -> hipe_ppc:stop_word()
end,
case hipe_ppc:is_temp(Src) of
true ->
@@ -1022,10 +1077,16 @@ conv_switch(I, Map, Data) ->
JTabR = new_untagged_temp(),
OffsetR = new_untagged_temp(),
DestR = new_untagged_temp(),
+ ShiftInstruction =
+ case get(hipe_target_arch) of
+ powerpc -> 'slwi';
+ ppc64 -> 'sldi'
+ end,
I2 =
[hipe_ppc:mk_pseudo_li(JTabR, {JTabLab,constant}),
- hipe_ppc:mk_alu('slwi', OffsetR, IndexR, hipe_ppc:mk_uimm16(2)),
- hipe_ppc:mk_loadx('lwzx', DestR, JTabR, OffsetR),
+ hipe_ppc:mk_alu(ShiftInstruction, OffsetR, IndexR,
+ hipe_ppc:mk_uimm16(log2_word_size())),
+ hipe_ppc:mk_loadx(hipe_ppc:ldop_wordx(), DestR, JTabR, OffsetR),
hipe_ppc:mk_mtspr('ctr', DestR),
hipe_ppc:mk_bctr(Labels)],
{I2, Map1, NewData}.
@@ -1247,3 +1308,6 @@ vmap_bind(Map, Key, Val) ->
word_size() ->
hipe_rtl_arch:word_size().
+
+log2_word_size() ->
+ hipe_rtl_arch:log2_word_size().
--
cgit v1.2.3
From 6f40a8665675377a4413b97745711e9ab09a83c5 Mon Sep 17 00:00:00 2001
From: Kostis Sagonas
Date: Thu, 10 Feb 2011 03:09:44 +0200
Subject: Translate RTL to PPC code on PPC64 too
---
lib/hipe/main/hipe_main.erl | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
(limited to 'lib')
diff --git a/lib/hipe/main/hipe_main.erl b/lib/hipe/main/hipe_main.erl
index e81642fb33..99028cc3c1 100644
--- a/lib/hipe/main/hipe_main.erl
+++ b/lib/hipe/main/hipe_main.erl
@@ -2,7 +2,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2001-2010. All Rights Reserved.
+%% Copyright Ericsson AB 2001-2011. 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
@@ -313,7 +313,7 @@ icode_ssa_struct_reuse(IcodeSSA, Options) ->
icode_ssa_type_info(IcodeSSA, MFA, Options, Servers) ->
?option_time(hipe_icode_type:cfg(IcodeSSA, MFA, Options, Servers),
- "Icode SSA type info", Options).
+ io_lib:format("Icode SSA type info for ~p", [MFA]), Options).
icode_range_analysis(IcodeSSA, MFA, Options, Servers) ->
case proplists:get_bool(icode_range, Options) of
@@ -527,6 +527,8 @@ rtl_to_native(MFA, LinearRTL, Options, DebugState) ->
hipe_sparc_main:rtl_to_sparc(MFA, LinearRTL, Options);
powerpc ->
hipe_ppc_main:rtl_to_ppc(MFA, LinearRTL, Options);
+ ppc64 ->
+ hipe_ppc_main:rtl_to_ppc(MFA, LinearRTL, Options);
arm ->
hipe_arm_main:rtl_to_arm(MFA, LinearRTL, Options);
x86 ->
--
cgit v1.2.3
From b715c077a88d5ba68e4e79b32c1c0de087234bbf Mon Sep 17 00:00:00 2001
From: Sverker Eriksson
Date: Tue, 22 Mar 2011 12:25:49 +0100
Subject: Fix hipe bug in convert_matchstate, bignum-padding one word too long
---
lib/hipe/rtl/hipe_tagscheme.erl | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
(limited to 'lib')
diff --git a/lib/hipe/rtl/hipe_tagscheme.erl b/lib/hipe/rtl/hipe_tagscheme.erl
index 5859c345d0..0cc6c2deec 100644
--- a/lib/hipe/rtl/hipe_tagscheme.erl
+++ b/lib/hipe/rtl/hipe_tagscheme.erl
@@ -1045,7 +1045,7 @@ convert_matchstate(Ms) ->
build_sub_binary(Ms, ByteSize, ByteOffset, BitSize, BitOffset,
hipe_rtl:mk_imm(0), Orig),
size_from_header(SizeInWords, Header),
- hipe_rtl:mk_alu(Hole, SizeInWords, sub, hipe_rtl:mk_imm(?SUB_BIN_WORDSIZE-1)),
+ hipe_rtl:mk_alu(Hole, SizeInWords, sub, hipe_rtl:mk_imm(?SUB_BIN_WORDSIZE)),
mk_var_header(BigIntHeader, Hole, ?TAG_HEADER_POS_BIG),
hipe_rtl:mk_store(Ms, hipe_rtl:mk_imm(?SUB_BIN_WORDSIZE*WordSize-?TAG_PRIMARY_BOXED),
BigIntHeader)].
--
cgit v1.2.3
From deaaaa252863fbda315f7eeee37fcb903c36494e Mon Sep 17 00:00:00 2001
From: Maria Christakis
Date: Tue, 29 Mar 2011 20:07:16 +0300
Subject: Fix the name of an error function
---
lib/dialyzer/src/dialyzer_plt.erl | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
(limited to 'lib')
diff --git a/lib/dialyzer/src/dialyzer_plt.erl b/lib/dialyzer/src/dialyzer_plt.erl
index 8d62f2c529..6033d7f17c 100644
--- a/lib/dialyzer/src/dialyzer_plt.erl
+++ b/lib/dialyzer/src/dialyzer_plt.erl
@@ -317,7 +317,7 @@ merge_plts_or_report_conflicts(PltFiles, Plts) ->
Msg = io_lib:format("Could not merge PLTs since they are not disjoint\n"
"The following files are included in more than one "
"PLTs:\n~p\n", [ConfFiles]),
- error(Msg)
+ plt_error(Msg)
end.
find_duplicates(List) ->
--
cgit v1.2.3
From ed2b38d6fb29f4df7eda0fe1ec3d8fd9aee49fb6 Mon Sep 17 00:00:00 2001
From: Siri Hansen
Date: Fri, 25 Mar 2011 12:32:02 +0100
Subject: Change default behaviour to not check src code when creating release
Add new option src_tests to systools:make_script and
systools:make_tar. The old option no_module_tests is now
ignored as this is the default behaviour.
---
lib/sasl/doc/src/systools.xml | 16 ++++----
lib/sasl/src/systools_make.erl | 83 +++++++++++++++++++++++------------------
lib/sasl/src/systools_relup.erl | 9 ++---
3 files changed, 56 insertions(+), 52 deletions(-)
(limited to 'lib')
diff --git a/lib/sasl/doc/src/systools.xml b/lib/sasl/doc/src/systools.xml
index e28cd25f27..883c9c372b 100644
--- a/lib/sasl/doc/src/systools.xml
+++ b/lib/sasl/doc/src/systools.xml
@@ -130,7 +130,7 @@
Generate a boot script .script/.boot.
Name = string()
- Opt = no_module_tests | {path,[Dir]} | local | {variables,[Var]} | exref | {exref,[App]}] | silent | {outdir,Dir}
+ Opt = src_tests | {path,[Dir]} | local | {variables,[Var]} | exref | {exref,[App]}] | silent | {outdir,Dir}
Dir = string()
Var = {VarName,Prefix}
VarName = Prefix = string()
@@ -174,15 +174,13 @@
the applications.
-
-
There should no duplicated modules, that is, modules with
+
There should be no duplicated modules, that is, modules with
the same name but belonging to different applications.
-
-
A warning is issued if the source code for a module is
- missing or newer than the object code.
-
- If the no_module_tests option is specified, this
- check is omitted.
+ If the src_tests option is specified, a
+ warning is issued if the source code for a module is
+ missing or newer than the object code.
The applications are sorted according to the dependencies
@@ -242,7 +240,7 @@
Create a release package.
Name = string()
- Opt = {dirs,[IncDir]} | {path,[Dir]} | {variables,[Var]} | {var_tar,VarTar} | {erts,Dir} | no_module_tests | exref | {exref,[App]} | silent | {outdir,Dir}
+ Opt = {dirs,[IncDir]} | {path,[Dir]} | {variables,[Var]} | {var_tar,VarTar} | {erts,Dir} | src_tests | exref | {exref,[App]} | silent | {outdir,Dir}
Dir = string()
IncDir = src | include | atom()
Var = {VarName,PreFix}
@@ -330,7 +328,7 @@ myapp-1/ebin/myapp.app
system {erts,Dir} is copied to erts-ErtsVsn/bin.
All checks performed with the make_script function
are performed before the release package is created. The
- no_module_tests and exref options are also
+ src_tests and exref options are also
valid here.
The return value and the handling of errors and warnings
are the same as described for make_script above.
diff --git a/lib/sasl/src/systools_make.erl b/lib/sasl/src/systools_make.erl
index 20a142c763..7489ee58d2 100644
--- a/lib/sasl/src/systools_make.erl
+++ b/lib/sasl/src/systools_make.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2009. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2011. 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
@@ -50,7 +50,7 @@
%% the applications are found.
%%
%% New options: {path,Path} can contain wildcards
-%% no_module_tests
+%% src_tests
%% {variables,[{Name,AbsString}]}
%% {machine, jam | beam | vee}
%% exref | {exref, [AppName]}
@@ -82,8 +82,7 @@ make_script(RelName, Output, Flags) when is_list(RelName),
Path0 = get_path(Flags),
Path1 = mk_path(Path0), % expand wildcards etc.
Path = make_set(Path1 ++ code:get_path()),
- ModTestP = {not member(no_module_tests, Flags),
- xref_p(Flags)},
+ ModTestP = {member(src_tests, Flags),xref_p(Flags)},
case get_release(RelName, Path, ModTestP, machine(Flags)) of
{ok, Release, Appls, Warnings} ->
case generate_script(Output,Release,Appls,Flags) of
@@ -155,7 +154,7 @@ return({error,Mod,Error},_,Flags) ->
%% should be included in the release package and there it can be found.
%%
%% New options: {path,Path} can contain wildcards
-%% no_module_tests
+%% src_tests
%% exref | {exref, [AppName]}
%% {variables,[{Name,AbsString}]}
%% {machine, jam | beam | vee}
@@ -190,8 +189,7 @@ make_tar(RelName, Flags) when is_list(RelName), is_list(Flags) ->
Path0 = get_path(Flags),
Path1 = mk_path(Path0),
Path = make_set(Path1 ++ code:get_path()),
- ModTestP = {not member(no_module_tests, Flags),
- xref_p(Flags)},
+ ModTestP = {member(src_tests, Flags),xref_p(Flags)},
case get_release(RelName, Path, ModTestP, machine(Flags)) of
{ok, Release, Appls, Warnings} ->
case catch mk_tar(RelName, Release, Appls, Flags, Path1) of
@@ -218,7 +216,7 @@ make_tar(RelName, Flags) ->
%% {ok, #release, [{{Name,Vsn},#application}], Warnings} | {error, What}
get_release(File, Path) ->
- get_release(File, Path, true, false).
+ get_release(File, Path, {false,false}, false).
get_release(File, Path, ModTestP) ->
get_release(File, Path, ModTestP, false).
@@ -771,36 +769,40 @@ get_mod_vsn([]) ->
%% Use the module extension of the running machine as extension for
%% the checked modules.
-check_mods(Modules, Appls, Path, {true, XrefP}, Machine) ->
- Ext = objfile_extension(Machine),
- IncPath = create_include_path(Appls, Path),
- Res = append(map(fun(ModT) ->
- {Mod,_Vsn,App,_,Dir} = ModT,
- case check_mod(Mod,App,Dir,Ext,IncPath) of
- ok ->
- [];
- {error, Error} ->
- [{error,{Error, ModT}}];
- {warning, Warn} ->
- [{warning,{Warn,ModT}}]
- end
- end,
- Modules)),
- Res2 = Res ++ check_xref(Appls, Path, XrefP),
+check_mods(Modules, Appls, Path, {SrcTestP, XrefP}, Machine) ->
+ SrcTestRes = check_src(Modules, Appls, Path, SrcTestP, Machine),
+ XrefRes = check_xref(Appls, Path, XrefP),
+ Res = SrcTestRes ++ XrefRes,
case filter(fun({error, _}) -> true;
(_) -> false
end,
- Res2) of
+ Res) of
[] ->
{ok, filter(fun({warning, _}) -> true;
(_) -> false
end,
- Res2)};
+ Res)};
Errors ->
{error, Errors}
- end;
-check_mods(_, _, _, _, _) ->
- {ok, []}.
+ end.
+
+check_src(Modules, Appls, Path, true, Machine) ->
+ Ext = objfile_extension(Machine),
+ IncPath = create_include_path(Appls, Path),
+ append(map(fun(ModT) ->
+ {Mod,_Vsn,App,_,Dir} = ModT,
+ case check_mod(Mod,App,Dir,Ext,IncPath) of
+ ok ->
+ [];
+ {error, Error} ->
+ [{error,{Error, ModT}}];
+ {warning, Warn} ->
+ [{warning,{Warn,ModT}}]
+ end
+ end,
+ Modules));
+check_src(_, _, _, _, _) ->
+ [].
check_xref(_Appls, _Path, false) ->
[];
@@ -1853,11 +1855,11 @@ cas([silent | Args], {Path, _Sil, Loc, Test, Var, Mach,
cas([local | Args], {Path, Sil, _Loc, Test, Var, Mach,
Xref, XrefApps, X}) ->
cas(Args, {Path, Sil, local, Test, Var, Mach, Xref, XrefApps, X});
-%%% no_module_tests ----------------------------------------------------
-cas([no_module_tests | Args], {Path, Sil, Loc, _Test, Var, Mach,
- Xref, XrefApps, X}) ->
+%%% src_tests -------------------------------------------------------
+cas([src_tests | Args], {Path, Sil, Loc, _Test, Var, Mach,
+ Xref, XrefApps, X}) ->
cas(Args,
- {Path, Sil, Loc, no_module_tests, Var, Mach, Xref, XrefApps,X});
+ {Path, Sil, Loc, src_tests, Var, Mach, Xref, XrefApps,X});
%%% variables ----------------------------------------------------------
cas([{variables, V} | Args], {Path, Sil, Loc, Test, Var, Mach,
Xref, XrefApps, X}) when is_list(V) ->
@@ -1896,6 +1898,10 @@ cas([{outdir, Dir} | Args], {Path, Sil, Loc, Test, Var, Mach,
cas([otp_build | Args], {Path, Sil, Loc, Test, Var, Mach,
Xref, XrefApps, X}) ->
cas(Args, {Path, Sil, Loc, Test, Var, Mach, Xref, XrefApps, X});
+%%% no_module_tests (kept for backwards compatibility, but ignored) ----
+cas([no_module_tests | Args], {Path, Sil, Loc, Test, Var, Mach,
+ Xref, XrefApps, X}) ->
+ cas(Args, {Path, Sil, Loc, Test, Var, Mach, Xref, XrefApps,X});
%%% ERROR --------------------------------------------------------------
cas([Y | Args], {Path, Sil, Loc, Test, Var, Mach, Xref, XrefApps, X}) ->
cas(Args, {Path, Sil, Loc, Test, Var, Mach, Xref, XrefApps,X++[Y]}).
@@ -1935,10 +1941,10 @@ cat([{dirs, D} | Args], {Path, Sil, Dirs, Erts, Test,
cat([{erts, E} | Args], {Path, Sil, Dirs, _Erts, Test,
Var, VarTar, Mach, Xref, XrefApps, X}) when is_list(E)->
cat(Args, {Path, Sil, Dirs, E, Test, Var, VarTar, Mach, Xref, XrefApps, X});
-%%% no_module_tests ----------------------------------------------------
-cat([no_module_tests | Args], {Path, Sil, Dirs, Erts, _Test, Var, VarTar, Mach, Xref, XrefApps, X}) ->
- cat(Args, {Path, Sil, Dirs, Erts, no_module_tests, Var, VarTar, Mach,
- Xref, XrefApps, X});
+%%% src_tests ----------------------------------------------------
+cat([src_tests | Args], {Path, Sil, Dirs, Erts, _Test, Var, VarTar, Mach, Xref, XrefApps, X}) ->
+ cat(Args, {Path, Sil, Dirs, Erts, src_tests, Var, VarTar, Mach,
+ Xref, XrefApps, X});
%%% variables ----------------------------------------------------------
cat([{variables, V} | Args], {Path, Sil, Dirs, Erts, Test, Var, VarTar, Mach, Xref, XrefApps, X}) when is_list(V) ->
case check_vars(V) of
@@ -1982,6 +1988,9 @@ cat([{outdir, Dir} | Args], {Path, Sil, Dirs, Erts, Test, Var, VarTar, Mach, Xre
%%% otp_build (secret, not documented) ---------------------------------
cat([otp_build | Args], {Path, Sil, Dirs, Erts, Test, Var, VarTar, Mach, Xref, XrefApps, X}) ->
cat(Args, {Path, Sil, Dirs, Erts, Test, Var, VarTar, Mach, Xref, XrefApps, X});
+%%% no_module_tests (kept for backwards compatibility, but ignored) ----
+cat([no_module_tests | Args], {Path, Sil, Dirs, Erts, Test, Var, VarTar, Mach, Xref, XrefApps, X}) ->
+ cat(Args, {Path, Sil, Dirs, Erts, Test, Var, VarTar, Mach, Xref, XrefApps, X});
%%% ERROR --------------------------------------------------------------
cat([Y | Args], {Path, Sil, Dirs, Erts, Test, Var, VarTar, Mach, Xref, XrefApps, X}) ->
cat(Args, {Path, Sil, Dirs, Erts, Test, Var, VarTar, Mach, Xref, XrefApps, X++[Y]}).
diff --git a/lib/sasl/src/systools_relup.erl b/lib/sasl/src/systools_relup.erl
index 6b0f77703e..ec5486226c 100644
--- a/lib/sasl/src/systools_relup.erl
+++ b/lib/sasl/src/systools_relup.erl
@@ -179,8 +179,7 @@ check_opts([]) ->
[].
do_mk_relup(TopRelFile, BaseUpRelDcs, BaseDnRelDcs, Path, Opts) ->
- ModTest = false,
- case systools_make:get_release(to_list(TopRelFile), Path, ModTest) of
+ case systools_make:get_release(to_list(TopRelFile), Path) of
%%
%% TopRel = #release
%% NameVsnApps = [{{Name, Vsn}, #application}]
@@ -246,9 +245,8 @@ foreach_baserel_up(TopRel, TopApps, [BaseRelDc|BaseRelDcs], Path, Opts,
{RUs4, Ws4} =
check_for_emulator_restart(TopRel, BaseRel, RUs3, Ws3, Opts),
- ModTest = false,
BaseApps =
- case systools_make:get_release(BaseRelFile, Path, ModTest) of
+ case systools_make:get_release(BaseRelFile, Path) of
{ok, _, NameVsnApps, _Warns} ->
lists:map(fun({_,App}) -> App end, NameVsnApps);
Other1 ->
@@ -283,9 +281,8 @@ foreach_baserel_dn(TopRel, TopApps, [BaseRelDc|BaseRelDcs], Path, Opts,
%%
{RUs1, Ws1} = collect_appup_scripts(dn, TopApps, BaseRel, Ws, []),
- ModTest = false,
{BaseApps, Ws2} =
- case systools_make:get_release(BaseRelFile, Path, ModTest) of
+ case systools_make:get_release(BaseRelFile, Path) of
%%
%% NameVsnApps = [{{Name, Vsn}, #application}]
{ok, _, NameVsnApps, Warns} ->
--
cgit v1.2.3
From f135c4e688dba07b42024295c1f111a106a0820c Mon Sep 17 00:00:00 2001
From: Hans Bolinder
Date: Fri, 1 Apr 2011 08:53:48 +0200
Subject: Fix a bug in erl_recomment
In a file containing declarations and comments without any empty lines
between them, the recomment_forms() function would associate a
multi-line comment with the declaration above it rather than the one
following it. (Thanks to Richard Carlsson.)
This bug has been reported several times. It was corrected by Kostis
Sagonas, but the fix didn't make into the R14B02 release.
---
lib/syntax_tools/src/erl_recomment.erl | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
(limited to 'lib')
diff --git a/lib/syntax_tools/src/erl_recomment.erl b/lib/syntax_tools/src/erl_recomment.erl
index 919e9cfc5d..fc7c515700 100644
--- a/lib/syntax_tools/src/erl_recomment.erl
+++ b/lib/syntax_tools/src/erl_recomment.erl
@@ -163,7 +163,7 @@ recomment_forms_2(C, [N | Ns] = Nodes, Insert) ->
Trailing =
case Ns of
[] -> true;
- [Next | _] -> L < node_min(Next) - 2
+ [Next | _] -> L + Delta < node_min(Next) - 2
end,
if L > Max + 1 ; L =:= Max + 1, not Trailing ->
[N | recomment_forms_2(C, Ns, Insert)];
--
cgit v1.2.3
From aa69482e98b02e99ff8c9dea6434daedf637aee9 Mon Sep 17 00:00:00 2001
From: Bernard Duggan
Date: Wed, 23 Feb 2011 16:00:20 +1100
Subject: Various small documentation fixes
This change fixes a bunch of small (and a few less small) typos and
other errors in various modules that I've spotted throughout my travels.
---
lib/crypto/doc/src/crypto.xml | 12 ++++++++----
lib/inets/doc/src/http_server.xml | 8 ++++----
lib/inets/doc/src/httpd.xml | 5 +++--
lib/inets/doc/src/mod_esi.xml | 19 ++++++++++---------
lib/stdlib/doc/src/binary.xml | 2 +-
lib/stdlib/doc/src/dict.xml | 6 ++----
lib/webtool/doc/src/webtool_chapter.xml | 4 ++--
7 files changed, 30 insertions(+), 26 deletions(-)
(limited to 'lib')
diff --git a/lib/crypto/doc/src/crypto.xml b/lib/crypto/doc/src/crypto.xml
index c407350c47..91b89c8796 100644
--- a/lib/crypto/doc/src/crypto.xml
+++ b/lib/crypto/doc/src/crypto.xml
@@ -415,7 +415,7 @@ Mpint() = >]]>
- blowfish_ecb_encrypt(Key, Text) -> Cipher
+ blowfish_ecb_encrypt(Key, IVec, Text) -> Cipher
Encrypt the first 64 bits of Text using Blowfish in ECB mode
Key = Text = iolist() | binary()
@@ -424,7 +424,9 @@ Mpint() = >]]>
Encrypts the first 64 bits of Text using Blowfish in ECB mode. Key is the Blowfish key. The length of Text must be at least 64 bits (8 bytes).
- blowfish_ecb_decrypt(Key, Text) -> Cipher
+
+
+ blowfish_ecb_decrypt(Key, IVec, Text) -> Cipher
Decrypt the first 64 bits of Text using Blowfish in ECB mode
Key = Text = iolist() | binary()
@@ -436,7 +438,7 @@ Mpint() = >]]>
- blowfish_cbc_encrypt(Key, Text) -> Cipher
+ blowfish_cbc_encrypt(Key, IVec, Text) -> Cipher
Encrypt Text using Blowfish in CBC mode
Key = Text = iolist() | binary()
@@ -447,7 +449,9 @@ Mpint() = >]]>
arbitrary initializing vector. The length of IVec
must be 64 bits (8 bytes). The length of Text must be a multiple of 64 bits (8 bytes).
- blowfish_cbc_decrypt(Key, Text) -> Cipher
+
+
+ blowfish_cbc_decrypt(Key, IVec, Text) -> Cipher
Decrypt Text using Blowfish in CBC mode
Key = Text = iolist() | binary()
diff --git a/lib/inets/doc/src/http_server.xml b/lib/inets/doc/src/http_server.xml
index 47ed9cd229..959386e471 100644
--- a/lib/inets/doc/src/http_server.xml
+++ b/lib/inets/doc/src/http_server.xml
@@ -63,9 +63,9 @@
technologies such as SOAP.
Allmost all server functionality has been implemented using an
- especially crafted server API, it is described in the Erlang Web
- Server API. This API can be used to advantage by all who wants
- to enhance the server core functionality, for example custom
+ especially crafted server API which is described in the Erlang Web
+ Server API. This API can be used to advantage by all who wish
+ to enhance the core server functionality, for example with custom
logging and authentication.
@@ -472,7 +472,7 @@ http://your.server.org/eval?httpd_example:print(atom_to_list(apply(erlang,halt,[
bytes
- The content-length of the document transferred.
- Internal server errors are recorde in the error log file. The
+
Internal server errors are recorded in the error log file. The
format of this file is a more ad hoc format than the logs using
Common Logfile Format, but conforms to the following syntax:
diff --git a/lib/inets/doc/src/httpd.xml b/lib/inets/doc/src/httpd.xml
index 62f4e18f82..6470b6fac7 100644
--- a/lib/inets/doc/src/httpd.xml
+++ b/lib/inets/doc/src/httpd.xml
@@ -525,12 +525,13 @@ bytes
scheme scripts. A matching URL is mapped into a specific module
and function. For example:
- {erl_script_alias, {"/cgi-bin/example" [httpd_example]}
+ {erl_script_alias, {"/cgi-bin/example", [httpd_example]}
and a request to
http://your.server.org/cgi-bin/example/httpd_example:yahoo
- would refer to httpd_example:yahoo/2 and
+ would refer to httpd_example:yahoo/3 or, if that did not exist,
+ httpd_example:yahoo/2 and
http://your.server.org/cgi-bin/example/other:yahoo would
not be allowed to execute.
diff --git a/lib/inets/doc/src/mod_esi.xml b/lib/inets/doc/src/mod_esi.xml
index 3c473d3f94..aa98a8e85c 100644
--- a/lib/inets/doc/src/mod_esi.xml
+++ b/lib/inets/doc/src/mod_esi.xml
@@ -78,24 +78,24 @@
The Module must be found in the code path and export
- Function with an arity of two. An erlScriptAlias must
+ Function with an arity of three. An erlScriptAlias must
also be set up in the configuration file for the Web server.
- If the HTTP request is a post request and a body is sent
+
If the HTTP request is a 'post' request and a body is sent
then content_length will be the length of the posted
- data. If get is used query_string will be the data after
+ data. If 'get' is used query_string will be the data after
? in the url.
ParsedHeader is the HTTP request as a key value tuple
list. The keys in parsed header will be the in lower case.
SessionID is a identifier
- the server use when deliver/2 is called, do not
- assume any-thing about the datatype.
+ the server uses when deliver/2 is called; do not
+ assume anything about the datatype.
Use this callback function to dynamically generate dynamic web
content. when a part of the page is generated send the
data back to the client through deliver/2. Note
that the first chunk of data sent to the client must at
least contain all HTTP header fields that the response
- will generate. If the first chunk not contains
- End of HTTP header that is "\r\n\r\n"
+ will generate. If the first chunk does not contain the
+ End of HTTP the header, that is "\r\n\r\n",
the server will
assume that no HTTP header fields will be generated.
@@ -106,11 +106,12 @@
Env = [EnvironmentDirectives] ++ ParsedHeader
EnvironmentDirectives = {Key,Value}
- Key = query_string | content_length | server_software | gateway_interface | server_protocol | server_port | request_method | remote_addr | script_name. <v>Input = string()
+ Key = query_string | content_length | server_software | gateway_interface | server_protocol | server_port | request_method | remote_addr | script_name.
+ Input = string()
Response = string()
- This callback format consumes quite much memory since the
+
This callback format consumes a lot of memory since the
whole response must be generated before it is sent to the
user. This functions is deprecated and only keept for backwards
compatibility.
diff --git a/lib/stdlib/doc/src/binary.xml b/lib/stdlib/doc/src/binary.xml
index c5eb81a86a..da038bf30c 100644
--- a/lib/stdlib/doc/src/binary.xml
+++ b/lib/stdlib/doc/src/binary.xml
@@ -485,7 +485,7 @@
1> Bin = <<1,2,3,4,5,6,7,8,9,10>>.
-2> binary:part(Bin,{byte_size(Bin), -5)).
+2> binary:part(Bin,{byte_size(Bin), -5)}).
<<6,7,8,9,10>>
diff --git a/lib/stdlib/doc/src/dict.xml b/lib/stdlib/doc/src/dict.xml
index 40e61d7d33..1540a930ba 100644
--- a/lib/stdlib/doc/src/dict.xml
+++ b/lib/stdlib/doc/src/dict.xml
@@ -55,10 +55,8 @@ dictionary()
This function appends a new Value to the current list
- of values associated with Key. An exception is
- generated if the initial value associated with Key is
- not a list of values.
-
+ of values associated with Key.
+
append_list(Key, ValList, Dict1) -> Dict2
diff --git a/lib/webtool/doc/src/webtool_chapter.xml b/lib/webtool/doc/src/webtool_chapter.xml
index f72a255b0a..305fbcb8ee 100644
--- a/lib/webtool/doc/src/webtool_chapter.xml
+++ b/lib/webtool/doc/src/webtool_chapter.xml
@@ -151,7 +151,7 @@
http://Servername:Port/ErlScriptAlias/Mod/Func ]]>
An alias parameter in the configuration function can be
an ErlScriptAlias as used in the above URL. The definition of
- an ErlScripAlias shall be like this:
+ an ErlScriptAlias shall be like this:
{alias,{erl_alias,Path,[Modules]}}, e.g.
{alias,{erl_alias,"/testtool",[helloworld]}}
The following URL will then cause a call to the function
@@ -184,7 +184,7 @@ http://Servername:Port/ErlScriptAlias/Mod/Func ]]>
directory /usr/local/otp/lib/myapp-1.0/priv:
{alias,{"/mytool_home","/usr/local/otp/lib/myapp-1.0/priv"}}
See the INETS documentation, especially the module
- mod_esi, for a more in depht coverage of Erl Scheme.
+ mod_esi, for a more in depth coverage of the Erl Scheme.
--
cgit v1.2.3
From 30f3f25d7c358ee65444621335692162de24a94f Mon Sep 17 00:00:00 2001
From: Bernard Duggan
Date: Wed, 23 Mar 2011 10:55:10 +1100
Subject: Compile fixes for earlier documentation fixes
Fixed a couple of compilation errors. Also backed out a tiny change
that had already been added by Tuncer Ayaz in his binary-part-typo
branch.
---
lib/inets/doc/src/mod_esi.xml | 2 +-
lib/stdlib/doc/src/binary.xml | 2 +-
lib/stdlib/doc/src/dict.xml | 2 +-
3 files changed, 3 insertions(+), 3 deletions(-)
(limited to 'lib')
diff --git a/lib/inets/doc/src/mod_esi.xml b/lib/inets/doc/src/mod_esi.xml
index aa98a8e85c..e81308a502 100644
--- a/lib/inets/doc/src/mod_esi.xml
+++ b/lib/inets/doc/src/mod_esi.xml
@@ -106,7 +106,7 @@
Env = [EnvironmentDirectives] ++ ParsedHeader
EnvironmentDirectives = {Key,Value}
- Key = query_string | content_length | server_software | gateway_interface | server_protocol | server_port | request_method | remote_addr | script_name.
+ Key = query_string | content_length | server_software | gateway_interface | server_protocol | server_port | request_method | remote_addr | script_name.
Input = string()
Response = string()
diff --git a/lib/stdlib/doc/src/binary.xml b/lib/stdlib/doc/src/binary.xml
index da038bf30c..c5eb81a86a 100644
--- a/lib/stdlib/doc/src/binary.xml
+++ b/lib/stdlib/doc/src/binary.xml
@@ -485,7 +485,7 @@
1> Bin = <<1,2,3,4,5,6,7,8,9,10>>.
-2> binary:part(Bin,{byte_size(Bin), -5)}).
+2> binary:part(Bin,{byte_size(Bin), -5)).
<<6,7,8,9,10>>
diff --git a/lib/stdlib/doc/src/dict.xml b/lib/stdlib/doc/src/dict.xml
index 1540a930ba..0cc76e0c78 100644
--- a/lib/stdlib/doc/src/dict.xml
+++ b/lib/stdlib/doc/src/dict.xml
@@ -55,7 +55,7 @@ dictionary()
This function appends a new Value to the current list
- of values associated with Key.
+ of values associated with Key.
--
cgit v1.2.3
From 6597f81ec28909d1b3670e1c701f1175394c3fc2 Mon Sep 17 00:00:00 2001
From: Bernard Duggan
Date: Fri, 1 Apr 2011 08:45:25 +1100
Subject: Fix mistake in blowfish_ebc_en/decrypt docs
---
lib/crypto/doc/src/crypto.xml | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
(limited to 'lib')
diff --git a/lib/crypto/doc/src/crypto.xml b/lib/crypto/doc/src/crypto.xml
index 91b89c8796..dfafe67348 100644
--- a/lib/crypto/doc/src/crypto.xml
+++ b/lib/crypto/doc/src/crypto.xml
@@ -415,22 +415,22 @@ Mpint() = >]]>
- blowfish_ecb_encrypt(Key, IVec, Text) -> Cipher
+ blowfish_ecb_encrypt(Key, Text) -> Cipher
Encrypt the first 64 bits of Text using Blowfish in ECB mode
Key = Text = iolist() | binary()
- IVec = Cipher = binary()
+ Cipher = binary()
Encrypts the first 64 bits of Text using Blowfish in ECB mode. Key is the Blowfish key. The length of Text must be at least 64 bits (8 bytes).
- blowfish_ecb_decrypt(Key, IVec, Text) -> Cipher
+ blowfish_ecb_decrypt(Key, Text) -> Cipher
Decrypt the first 64 bits of Text using Blowfish in ECB mode
Key = Text = iolist() | binary()
- IVec = Cipher = binary()
+ Cipher = binary()
Decrypts the first 64 bits of Text using Blowfish in ECB mode. Key is the Blowfish key. The length of Text must be at least 64 bits (8 bytes).
--
cgit v1.2.3
From 8a8e05929bb12ee96a0bb92505c3c410be9a5052 Mon Sep 17 00:00:00 2001
From: Marcus Marinelli
Date: Sat, 2 Apr 2011 17:57:31 -0700
Subject: Fix minor typos and improve punctuation in the xmerl_xpath @doc
comment
---
lib/xmerl/src/xmerl_xpath.erl | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
(limited to 'lib')
diff --git a/lib/xmerl/src/xmerl_xpath.erl b/lib/xmerl/src/xmerl_xpath.erl
index e654a8ef1d..c803af3631 100644
--- a/lib/xmerl/src/xmerl_xpath.erl
+++ b/lib/xmerl/src/xmerl_xpath.erl
@@ -19,8 +19,8 @@
%% Description : Implements a search engine based on XPath
-%% @doc The xmerl_xpath module handles the entire XPath 1.0 spec
-%% XPath expressions typically occurs in XML attributes and are used to addres
+%% @doc The xmerl_xpath module handles the entire XPath 1.0 spec.
+%% XPath expressions typically occur in XML attributes and are used to address
%% parts of an XML document.
% The grammar is defined in xmerl_xpath_parse.yrl
.
% The core functions are defined in xmerl_xpath_pred.erl
.
--
cgit v1.2.3
From 8773ee1b029e3443bba5bedd12ba93ba59a6ea78 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Bj=C3=B6rn=20Gustavsson?=
Date: Mon, 21 Mar 2011 14:12:13 +0100
Subject: crashdump_helper: Compile for r12 instead of r11
The r11 option is no longer supported by the compiler (silently
ignored).
---
lib/observer/test/crashdump_helper.erl | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
(limited to 'lib')
diff --git a/lib/observer/test/crashdump_helper.erl b/lib/observer/test/crashdump_helper.erl
index 43b3db738f..6e9d4727ec 100644
--- a/lib/observer/test/crashdump_helper.erl
+++ b/lib/observer/test/crashdump_helper.erl
@@ -19,7 +19,7 @@
-module(crashdump_helper).
-export([n1_proc/2,remote_proc/2]).
--compile(r11).
+-compile(r12).
-include("test_server.hrl").
n1_proc(N2,Creator) ->
--
cgit v1.2.3
From 19ca18fa2425d592e7c340f453b6d44c22e00f9b Mon Sep 17 00:00:00 2001
From: Filipe David Manana
Date: Sun, 27 Mar 2011 17:51:59 +0100
Subject: Fix issue with temporary children introduced by OTP-9064
The temporary child specs are never removed from the supervisor's state, and
have they're MFA component set to {M, F, undefined} instead of the MFA passed
in the supervisor:start_child/2 call. Subsequent calls to supervisor:restart_child/2
may crash. Stack trace example:
{badarg,[{erlang,apply,[gen_server,start_link,undefined]},
{supervisor,do_start_child,2},{supervisor,handle_call,3},
{gen_server,handle_msg,5},
{proc_lib,init_p_do_apply,3}]}
---
lib/stdlib/src/supervisor.erl | 4 ++++
1 file changed, 4 insertions(+)
(limited to 'lib')
diff --git a/lib/stdlib/src/supervisor.erl b/lib/stdlib/src/supervisor.erl
index 3c5800effa..b511545b96 100644
--- a/lib/stdlib/src/supervisor.erl
+++ b/lib/stdlib/src/supervisor.erl
@@ -817,8 +817,12 @@ state_del_child(Child, State) ->
NChildren = del_child(Child#child.name, State#state.children),
State#state{children = NChildren}.
+del_child(Name, [Ch|Chs]) when Ch#child.name =:= Name, Ch#child.restart_type =:= temporary ->
+ [Chs];
del_child(Name, [Ch|Chs]) when Ch#child.name =:= Name ->
[Ch#child{pid = undefined} | Chs];
+del_child(Pid, [Ch|Chs]) when Ch#child.pid =:= Pid, Ch#child.restart_type =:= temporary ->
+ [Chs];
del_child(Pid, [Ch|Chs]) when Ch#child.pid =:= Pid ->
[Ch#child{pid = undefined} | Chs];
del_child(Name, [Ch|Chs]) ->
--
cgit v1.2.3
From 12b417a1cb28799f78ec911bc1dc9dfdb0af6fea Mon Sep 17 00:00:00 2001
From: Ingela Anderton Andin
Date: Thu, 31 Mar 2011 18:00:55 +0200
Subject: Completed bug fix "temporary child specs should not be kept when
child terminates" and improved test suite
The bug fix supplied by Filipe David Manana
did not cover all possible ways that a process may be terminated
as for instance with supervisor:terminate_child. Also there
was a bug in the base case of the patch returning a list of a list instead
of only the list.
Added a timeout for the test cases, eliminated unnecessary sleeps,
improved code.
---
lib/stdlib/src/supervisor.erl | 12 +-
lib/stdlib/test/supervisor_SUITE.erl | 1355 +++++++++++++++-------------------
2 files changed, 610 insertions(+), 757 deletions(-)
(limited to 'lib')
diff --git a/lib/stdlib/src/supervisor.erl b/lib/stdlib/src/supervisor.erl
index b511545b96..368dc2e3e5 100644
--- a/lib/stdlib/src/supervisor.erl
+++ b/lib/stdlib/src/supervisor.erl
@@ -344,8 +344,12 @@ handle_call({delete_child, Name}, _From, State) ->
handle_call({terminate_child, Name}, _From, State) ->
case get_child(Name, State) of
{value, Child} ->
- NChild = do_terminate(Child, State#state.name),
- {reply, ok, replace_child(NChild, State)};
+ case do_terminate(Child, State#state.name) of
+ #child{restart_type = temporary} = NChild ->
+ {reply, ok, state_del_child(NChild, State)};
+ NChild ->
+ {reply, ok, replace_child(NChild, State)}
+ end;
_ ->
{reply, {error, not_found}, State}
end;
@@ -818,11 +822,11 @@ state_del_child(Child, State) ->
State#state{children = NChildren}.
del_child(Name, [Ch|Chs]) when Ch#child.name =:= Name, Ch#child.restart_type =:= temporary ->
- [Chs];
+ Chs;
del_child(Name, [Ch|Chs]) when Ch#child.name =:= Name ->
[Ch#child{pid = undefined} | Chs];
del_child(Pid, [Ch|Chs]) when Ch#child.pid =:= Pid, Ch#child.restart_type =:= temporary ->
- [Chs];
+ Chs;
del_child(Pid, [Ch|Chs]) when Ch#child.pid =:= Pid ->
[Ch#child{pid = undefined} | Chs];
del_child(Name, [Ch|Chs]) ->
diff --git a/lib/stdlib/test/supervisor_SUITE.erl b/lib/stdlib/test/supervisor_SUITE.erl
index 6e927da2ab..f9ceed8f84 100644
--- a/lib/stdlib/test/supervisor_SUITE.erl
+++ b/lib/stdlib/test/supervisor_SUITE.erl
@@ -21,6 +21,7 @@
-module(supervisor_SUITE).
-include_lib("test_server/include/test_server.hrl").
+-define(TIMEOUT, 1000).
%% Testserver specific export
-export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1,
@@ -32,33 +33,34 @@
%% API tests
-export([ sup_start_normal/1, sup_start_ignore_init/1,
- sup_start_ignore_child/1, sup_start_error_return/1,
- sup_start_fail/1, sup_stop_infinity/1,
- sup_stop_timeout/1, sup_stop_brutal_kill/1, child_adm/1,
- child_adm_simple/1, child_specs/1, extra_return/1]).
+ sup_start_ignore_child/1, sup_start_error_return/1,
+ sup_start_fail/1, sup_stop_infinity/1,
+ sup_stop_timeout/1, sup_stop_brutal_kill/1, child_adm/1,
+ child_adm_simple/1, child_specs/1, extra_return/1]).
%% Tests concept permanent, transient and temporary
-export([ permanent_normal/1, transient_normal/1,
- temporary_normal/1,
- permanent_abnormal/1, transient_abnormal/1,
- temporary_abnormal/1]).
+ temporary_normal/1,
+ permanent_abnormal/1, transient_abnormal/1,
+ temporary_abnormal/1]).
%% Restart strategy tests
-export([ one_for_one/1,
- one_for_one_escalation/1, one_for_all/1,
- one_for_all_escalation/1,
- simple_one_for_one/1, simple_one_for_one_escalation/1,
- rest_for_one/1, rest_for_one_escalation/1,
- simple_one_for_one_extra/1]).
+ one_for_one_escalation/1, one_for_all/1,
+ one_for_all_escalation/1,
+ simple_one_for_one/1, simple_one_for_one_escalation/1,
+ rest_for_one/1, rest_for_one_escalation/1,
+ simple_one_for_one_extra/1]).
%% Misc tests
-export([child_unlink/1, tree/1, count_children_memory/1,
- do_not_save_start_parameters_for_temporary_children/1]).
+ do_not_save_start_parameters_for_temporary_children/1,
+ do_not_save_child_specs_for_temporary_children/1]).
-%-------------------------------------------------------------------------
+%%-------------------------------------------------------------------------
-
-suite() -> [{ct_hooks,[ts_install_cth]}].
+suite() ->
+ [{ct_hooks,[ts_install_cth]}].
all() ->
[{group, sup_start}, {group, sup_stop}, child_adm,
@@ -69,7 +71,8 @@ all() ->
{group, restart_rest_for_one},
{group, normal_termination},
{group, abnormal_termination}, child_unlink, tree,
- count_children_memory, do_not_save_start_parameters_for_temporary_children].
+ count_children_memory, do_not_save_start_parameters_for_temporary_children,
+ do_not_save_child_specs_for_temporary_children].
groups() ->
[{sup_start, [],
@@ -94,8 +97,10 @@ groups() ->
{restart_rest_for_one, [],
[rest_for_one, rest_for_one_escalation]}].
-init_per_suite(Config) ->
- Config.
+init_per_suite(Config0) ->
+ Config = lists:keydelete(watchdog, 1, Config0),
+ Dog = test_server:timetrap(?TIMEOUT),
+ [{watchdog, Dog} | Config].
end_per_suite(_Config) ->
ok.
@@ -114,12 +119,13 @@ init_per_testcase(count_children_memory, Config) ->
{skip, "+Meamin used during test; erlang:memory/1 not available"}
end;
init_per_testcase(_Case, Config) ->
+ erlang:display(_Case),
Config.
end_per_testcase(_Case, _Config) ->
ok.
-start(InitResult) ->
+start_link(InitResult) ->
supervisor:start_link({local, sup_test}, ?MODULE, InitResult).
%% Simulate different supervisors callback.
@@ -136,145 +142,87 @@ get_child_counts(Supervisor) ->
proplists:get_value(supervisors, Counts),
proplists:get_value(workers, Counts)].
-%-------------------------------------------------------------------------
-% Test cases starts here.
-%-------------------------------------------------------------------------
+%%-------------------------------------------------------------------------
+%% Test cases starts here.
+%%-------------------------------------------------------------------------
sup_start_normal(doc) ->
["Tests that the supervisor process starts correctly and that it "
- "can be terminated gracefully."];
+ "can be terminated gracefully."];
sup_start_normal(suite) -> [];
sup_start_normal(Config) when is_list(Config) ->
process_flag(trap_exit, true),
- ?line {ok, Pid} = start({ok, {{one_for_one, 2, 3600}, []}}),
- ?line exit(Pid, shutdown),
- receive
- {'EXIT', Pid, shutdown} ->
- ok;
- {'EXIT', Pid, Else} ->
- ?line test_server:fail({bad_exit_reason, Else})
- after
- 2000 ->
- ?line test_server:fail(no_exit_reason)
- end,
- ok.
-%-------------------------------------------------------------------------
+ {ok, Pid} = start_link({ok, {{one_for_one, 2, 3600}, []}}),
+ terminate(Pid, shutdown).
+
+%%-------------------------------------------------------------------------
sup_start_ignore_init(doc) ->
["Tests what happens if init-callback returns ignore"];
sup_start_ignore_init(suite) -> [];
sup_start_ignore_init(Config) when is_list(Config) ->
process_flag(trap_exit, true),
- ?line ignore = start(ignore),
-
- receive
- {'EXIT', _Pid, normal} ->
- ok;
- {'EXIT', _Pid, Else} ->
- ?line test_server:fail({bad_exit_reason, Else})
- after
- 2000 ->
- ?line test_server:fail(no_exit_reason)
- end,
- ok.
+ ignore = start_link(ignore),
+ check_exit_reason(normal).
-
-%-------------------------------------------------------------------------
+%%-------------------------------------------------------------------------
sup_start_ignore_child(doc) ->
["Tests what happens if init-callback returns ignore"];
sup_start_ignore_child(suite) -> [];
sup_start_ignore_child(Config) when is_list(Config) ->
process_flag(trap_exit, true),
- ?line {ok, _Pid} = start({ok, {{one_for_one, 2, 3600}, []}}),
+ {ok, _Pid} = start_link({ok, {{one_for_one, 2, 3600}, []}}),
Child1 = {child1, {supervisor_1, start_child, [ignore]},
permanent, 1000, worker, []},
Child2 = {child2, {supervisor_1, start_child, []}, permanent,
1000, worker, []},
-
- ?line {ok, undefined} = supervisor:start_child(sup_test, Child1),
- ?line {ok, CPid2} = supervisor:start_child(sup_test, Child2),
- ?line [{child2, CPid2, worker, []},{child1, undefined, worker, []}]
- = supervisor:which_children(sup_test),
- ?line [2,1,0,2] = get_child_counts(sup_test),
+ {ok, undefined} = supervisor:start_child(sup_test, Child1),
+ {ok, CPid2} = supervisor:start_child(sup_test, Child2),
- ok.
+ [{child2, CPid2, worker, []},{child1, undefined, worker, []}]
+ = supervisor:which_children(sup_test),
+ [2,1,0,2] = get_child_counts(sup_test).
-%-------------------------------------------------------------------------
+%%-------------------------------------------------------------------------
sup_start_error_return(doc) ->
["Tests what happens if init-callback returns a invalid value"];
sup_start_error_return(suite) -> [];
sup_start_error_return(Config) when is_list(Config) ->
process_flag(trap_exit, true),
- ?line {error, Term} = start(invalid),
-
- receive
- {'EXIT', _Pid, Term} ->
- ok;
- {'EXIT', _Pid, Else} ->
- ?line test_server:fail({bad_exit_reason, Else})
- after
- 2000 ->
- ?line test_server:fail(no_exit_reason)
- end,
- ok.
+ {error, Term} = start_link(invalid),
+ check_exit_reason(Term).
-%-------------------------------------------------------------------------
+%%-------------------------------------------------------------------------
sup_start_fail(doc) ->
["Tests what happens if init-callback fails"];
sup_start_fail(suite) -> [];
sup_start_fail(Config) when is_list(Config) ->
process_flag(trap_exit, true),
- ?line {error, Term} = start(fail),
+ {error, Term} = start_link(fail),
+ check_exit_reason(Term).
- receive
- {'EXIT', _Pid, Term} ->
- ok;
- {'EXIT', _Pid, Else} ->
- ?line test_server:fail({bad_exit_reason, Else})
- after
- 2000 ->
- ?line test_server:fail(no_exit_reason)
- end,
- ok.
-%-------------------------------------------------------------------------
+%%-------------------------------------------------------------------------
sup_stop_infinity(doc) ->
["See sup_stop/1 when Shutdown = infinity, this walue is only allowed "
- "for children of type supervisor"];
+ "for children of type supervisor"];
sup_stop_infinity(suite) -> [];
sup_stop_infinity(Config) when is_list(Config) ->
process_flag(trap_exit, true),
- ?line {ok, Pid} = start({ok, {{one_for_one, 2, 3600}, []}}),
+ {ok, Pid} = start_link({ok, {{one_for_one, 2, 3600}, []}}),
Child1 = {child1, {supervisor_1, start_child, []},
permanent, infinity, supervisor, []},
Child2 = {child2, {supervisor_1, start_child, []}, permanent,
- infinity, worker, []},
- ?line {ok, CPid1} = supervisor:start_child(sup_test, Child1),
+ infinity, worker, []},
+ {ok, CPid1} = supervisor:start_child(sup_test, Child1),
link(CPid1),
- ?line {error, {invalid_shutdown,infinity}} =
- supervisor:start_child(sup_test, Child2),
-
- ?line exit(Pid, shutdown),
+ {error, {invalid_shutdown,infinity}} =
+ supervisor:start_child(sup_test, Child2),
- receive
- {'EXIT', Pid, shutdown} ->
- ok;
- {'EXIT', Pid, Else} ->
- ?line test_server:fail({bad_exit_reason, Else})
- after
- 5000 ->
- ?line test_server:fail(no_exit_reason)
- end,
- receive
- {'EXIT', CPid1, shutdown} -> ok;
- {'EXIT', CPid1, Reason} ->
- ?line test_server:fail({bad_exit_reason, Reason})
- after
- 2000 -> ?line test_server:fail(no_exit_reason)
- end,
- ok.
+ terminate(Pid, shutdown),
+ check_exit_reason(CPid1, shutdown).
-%-------------------------------------------------------------------------
+%%-------------------------------------------------------------------------
sup_stop_timeout(doc) ->
["See sup_stop/1 when Shutdown = 1000"];
@@ -282,93 +230,47 @@ sup_stop_timeout(suite) -> [];
sup_stop_timeout(Config) when is_list(Config) ->
process_flag(trap_exit, true),
- ?line {ok, Pid} = start({ok, {{one_for_one, 2, 3600}, []}}),
+ {ok, Pid} = start_link({ok, {{one_for_one, 2, 3600}, []}}),
Child1 = {child1, {supervisor_1, start_child, []},
permanent, 1000, worker, []},
Child2 = {child2, {supervisor_1, start_child, []}, permanent,
1000, worker, []},
- ?line {ok, CPid1} = supervisor:start_child(sup_test, Child1),
+ {ok, CPid1} = supervisor:start_child(sup_test, Child1),
link(CPid1),
- ?line {ok, CPid2} = supervisor:start_child(sup_test, Child2),
+ {ok, CPid2} = supervisor:start_child(sup_test, Child2),
link(CPid2),
-
+
CPid2 ! {sleep, 200000},
- ?line exit(Pid, shutdown),
+ terminate(Pid, shutdown),
- receive
- {'EXIT', Pid, shutdown} ->
- ok;
- {'EXIT', Pid, Else} ->
- ?line test_server:fail({bad_exit_reason, Else})
- after
- 5000 ->
- ?line test_server:fail(no_exit_reason)
- end,
+ check_exit_reason(CPid1, shutdown),
+ check_exit_reason(CPid2, killed).
- receive
- {'EXIT', CPid1, shutdown} -> ok;
- {'EXIT', CPid1, Reason} ->
- ?line test_server:fail({bad_exit_reason,Reason})
- after
- 2000 -> ?line test_server:fail(no_exit_reason)
- end,
-
- receive
- {'EXIT', CPid2, killed} -> ok;
- {'EXIT', CPid2, Reason2} ->
- ?line test_server:fail({bad_exit_reason, Reason2})
- after
- 2000 -> ?line test_server:fail(no_exit_reason)
- end,
- ok.
-%-------------------------------------------------------------------------
+%%-------------------------------------------------------------------------
sup_stop_brutal_kill(doc) ->
["See sup_stop/1 when Shutdown = brutal_kill"];
sup_stop_brutal_kill(suite) -> [];
sup_stop_brutal_kill(Config) when is_list(Config) ->
process_flag(trap_exit, true),
- ?line {ok, Pid} = start({ok, {{one_for_one, 2, 3600}, []}}),
+ {ok, Pid} = start_link({ok, {{one_for_one, 2, 3600}, []}}),
Child1 = {child1, {supervisor_1, start_child, []},
permanent, 1000, worker, []},
Child2 = {child2, {supervisor_1, start_child, []}, permanent,
brutal_kill, worker, []},
- ?line {ok, CPid1} = supervisor:start_child(sup_test, Child1),
+ {ok, CPid1} = supervisor:start_child(sup_test, Child1),
link(CPid1),
- ?line {ok, CPid2} = supervisor:start_child(sup_test, Child2),
+ {ok, CPid2} = supervisor:start_child(sup_test, Child2),
link(CPid2),
- ?line exit(Pid, shutdown),
-
- receive
- {'EXIT', Pid, shutdown} ->
- ok;
- {'EXIT', Pid, Else} ->
- ?line test_server:fail({bad_exit_reason, Else})
- after
- 5000 ->
- ?line test_server:fail(no_exit_reason)
- end,
+ terminate(Pid, shutdown),
- receive
- {'EXIT', CPid1, shutdown} -> ok;
- {'EXIT', CPid1, Reason} ->
- ?line test_server:fail({bad_exit_reason, Reason})
- after
- 2000 -> ?line test_server:fail(no_exit_reason)
- end,
- receive
- {'EXIT', CPid2, killed} -> ok;
- {'EXIT', CPid2, Reason2} ->
- ?line test_server:fail({bad_exit_reason, Reason2})
- after
- 2000 -> ?line test_server:fail(no_exit_reason)
- end,
- ok.
+ check_exit_reason(CPid1, shutdown),
+ check_exit_reason(CPid2, killed).
-%-------------------------------------------------------------------------
+%%-------------------------------------------------------------------------
extra_return(doc) ->
["The start function provided to start a child may "
"return {ok, Pid} or {ok, Pid, Info}, if it returns "
@@ -382,46 +284,40 @@ extra_return(Config) when is_list(Config) ->
Child = {child1, {supervisor_1, start_child, [extra_return]},
permanent, 1000,
worker, []},
- ?line {ok, _Pid} = start({ok, {{one_for_one, 2, 3600}, [Child]}}),
- ?line [{child1, CPid, worker, []}] = supervisor:which_children(sup_test),
+ {ok, _Pid} = start_link({ok, {{one_for_one, 2, 3600}, [Child]}}),
+ [{child1, CPid, worker, []}] = supervisor:which_children(sup_test),
link(CPid),
- ?line {error, not_found} = supervisor:terminate_child(sup_test, hej),
- ?line {error, not_found} = supervisor:delete_child(sup_test, hej),
- ?line {error, not_found} = supervisor:restart_child(sup_test, hej),
- ?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;
- {'EXIT', CPid, Reason} ->
- ?line test_server:fail({bad_reason, Reason})
- after 1000 ->
- ?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} =
+ {error, not_found} = supervisor:terminate_child(sup_test, hej),
+ {error, not_found} = supervisor:delete_child(sup_test, hej),
+ {error, not_found} = supervisor:restart_child(sup_test, hej),
+ {error, running} = supervisor:delete_child(sup_test, child1),
+ {error, running} = supervisor:restart_child(sup_test, child1),
+ [{child1, CPid, worker, []}] = supervisor:which_children(sup_test),
+ [1,1,0,1] = get_child_counts(sup_test),
+
+ ok = supervisor:terminate_child(sup_test, child1),
+ check_exit_reason(CPid, shutdown),
+ [{child1,undefined,worker,[]}] = supervisor:which_children(sup_test),
+ [1,0,0,1] = get_child_counts(sup_test),
+
+ {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),
+ [{child1, CPid2, worker, []}] = supervisor:which_children(sup_test),
+ [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),
+ ok = supervisor:terminate_child(sup_test, child1),
+ ok = supervisor:terminate_child(sup_test, child1),
+ ok = supervisor:delete_child(sup_test, child1),
+ {error, not_found} = supervisor:restart_child(sup_test, child1),
+ [] = supervisor:which_children(sup_test),
+ [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, CPid3, extra_return} = supervisor:start_child(sup_test, Child),
+ [{child1, CPid3, worker, []}] = supervisor:which_children(sup_test),
+ [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, count_children/1. Only correct "
@@ -432,116 +328,110 @@ child_adm(Config) when is_list(Config) ->
process_flag(trap_exit, true),
Child = {child1, {supervisor_1, start_child, []}, permanent, 1000,
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),
+ {ok, _Pid} = start_link({ok, {{one_for_one, 2, 3600}, [Child]}}),
+ [{child1, CPid, worker, []}] = supervisor:which_children(sup_test),
+ [1,1,0,1] = get_child_counts(sup_test),
link(CPid),
%% Start of an already runnig process
- ?line {error,{already_started, CPid}} =
+ {error,{already_started, CPid}} =
supervisor:start_child(sup_test, Child),
-
+
%% Termination
- ?line {error, not_found} = supervisor:terminate_child(sup_test, hej),
- ?line {'EXIT',{noproc,{gen_server,call, _}}} =
+ {error, not_found} = supervisor:terminate_child(sup_test, hej),
+ {'EXIT',{noproc,{gen_server,call, _}}} =
(catch supervisor:terminate_child(foo, child1)),
- ?line ok = supervisor:terminate_child(sup_test, child1),
- receive
- {'EXIT', CPid, shutdown} -> ok;
- {'EXIT', CPid, Reason} ->
- ?line test_server:fail({bad_reason, Reason})
- after 1000 ->
- ?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),
+ ok = supervisor:terminate_child(sup_test, child1),
+ check_exit_reason(CPid, shutdown),
+ [{child1,undefined,worker,[]}] = supervisor:which_children(sup_test),
+ [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),
+ ok = supervisor:terminate_child(sup_test, child1),
%% Start of already existing but not running process
- ?line {error,already_present} =
+ {error,already_present} =
supervisor:start_child(sup_test, Child),
%% 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),
-
+ {ok, CPid2} = supervisor:restart_child(sup_test, child1),
+ [{child1, CPid2, worker, []}] = supervisor:which_children(sup_test),
+ [1,1,0,1] = get_child_counts(sup_test),
+ {error, running} = supervisor:restart_child(sup_test, child1),
+ {error, not_found} = supervisor:restart_child(sup_test, child2),
+
%% Deletion
- ?line {error, running} = supervisor:delete_child(sup_test, child1),
- ?line {error, not_found} = supervisor:delete_child(sup_test, hej),
- ?line {'EXIT',{noproc,{gen_server,call, _}}} =
+ {error, running} = supervisor:delete_child(sup_test, child1),
+ {error, not_found} = supervisor:delete_child(sup_test, hej),
+ {'EXIT',{noproc,{gen_server,call, _}}} =
(catch supervisor:delete_child(foo, 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),
-
+ ok = supervisor:terminate_child(sup_test, child1),
+ ok = supervisor:delete_child(sup_test, child1),
+ {error, not_found} = supervisor:restart_child(sup_test, child1),
+ [] = supervisor:which_children(sup_test),
+ [0,0,0,0] = get_child_counts(sup_test),
+
%% Start
- ?line {'EXIT',{noproc,{gen_server,call, _}}} =
+ {'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),
+ {ok, CPid3} = supervisor:start_child(sup_test, Child),
+ [{child1, CPid3, worker, []}] = supervisor:which_children(sup_test),
+ [1,1,0,1] = get_child_counts(sup_test),
- ?line {'EXIT',{noproc,{gen_server,call,[foo,which_children,infinity]}}}
+ {'EXIT',{noproc,{gen_server,call,[foo,which_children,infinity]}}}
= (catch supervisor:which_children(foo)),
- ?line {'EXIT',{noproc,{gen_server,call,[foo,count_children,infinity]}}}
+ {'EXIT',{noproc,{gen_server,call,[foo,count_children,infinity]}}}
= (catch supervisor:count_children(foo)),
ok.
-%-------------------------------------------------------------------------
+%%-------------------------------------------------------------------------
child_adm_simple(doc) ->
["The API functions terminate_child/2, delete_child/2 "
"restart_child/2 are not valid for a simple_one_for_one supervisor "
- "check that the correct error message is returned."];
+ "check that the correct error message is returned."];
child_adm_simple(suite) -> [];
child_adm_simple(Config) when is_list(Config) ->
Child = {child, {supervisor_1, start_child, []}, permanent, 1000,
worker, []},
- ?line {ok, _Pid} = start({ok, {{simple_one_for_one, 2, 3600}, [Child]}}),
+ {ok, _Pid} = start_link({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),
-
+ [] = supervisor:which_children(sup_test),
+ [1,0,0,0] = get_child_counts(sup_test),
+
%% Start
- ?line {'EXIT',{noproc,{gen_server,call, _}}} =
+ {'EXIT',{noproc,{gen_server,call, _}}} =
(catch supervisor:start_child(foo, [])),
- ?line {ok, CPid1} = supervisor:start_child(sup_test, []),
- ?line [{undefined, CPid1, worker, []}] =
+ {ok, CPid1} = supervisor:start_child(sup_test, []),
+ [{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),
+ [1,1,0,1] = get_child_counts(sup_test),
+
+ {ok, CPid2} = supervisor:start_child(sup_test, []),
+ Children = supervisor:which_children(sup_test),
+ 2 = length(Children),
+ true = lists:member({undefined, CPid2, worker, []}, Children),
+ true = lists:member({undefined, CPid1, worker, []}, Children),
+ [1,2,0,2] = get_child_counts(sup_test),
%% Termination
- ?line {error, simple_one_for_one} =
+ {error, simple_one_for_one} =
supervisor:terminate_child(sup_test, child1),
%% Restart
- ?line {error, simple_one_for_one} =
+ {error, simple_one_for_one} =
supervisor:restart_child(sup_test, child1),
-
+
%% Deletion
- ?line {error, simple_one_for_one} =
+ {error, simple_one_for_one} =
supervisor:delete_child(sup_test, child1),
ok.
-
-%-------------------------------------------------------------------------
+
+%%-------------------------------------------------------------------------
child_specs(doc) ->
["Tests child specs, invalid formats should be rejected."];
child_specs(suite) -> [];
child_specs(Config) when is_list(Config) ->
process_flag(trap_exit, true),
- ?line {ok, _Pid} = start({ok, {{one_for_one, 2, 3600}, []}}),
- ?line {error, _} = supervisor:start_child(sup_test, hej),
+ {ok, _Pid} = start_link({ok, {{one_for_one, 2, 3600}, []}}),
+ {error, _} = supervisor:start_child(sup_test, hej),
%% Bad child specs
B1 = {child, mfa, permanent, 1000, worker, []},
@@ -551,7 +441,7 @@ child_specs(Config) when is_list(Config) ->
B5 = {child, {m,f,[a]}, permanent, infinity, worker, []},
B6 = {child, {m,f,[a]}, permanent, 1000, worker, dy},
B7 = {child, {m,f,[a]}, permanent, 1000, worker, [1,2,3]},
-
+
%% Correct child specs!
%% (last parameter in a child spec) can be [] as we do
%% not test code upgrade here.
@@ -560,327 +450,261 @@ child_specs(Config) when is_list(Config) ->
C3 = {child, {m,f,[a]}, temporary, 1000, worker, dynamic},
C4 = {child, {m,f,[a]}, transient, 1000, worker, [m]},
- ?line {error, {invalid_mfa,mfa}} = supervisor:start_child(sup_test, B1),
- ?line {error, {invalid_restart_type, prmanent}} =
+ {error, {invalid_mfa,mfa}} = supervisor:start_child(sup_test, B1),
+ {error, {invalid_restart_type, prmanent}} =
supervisor:start_child(sup_test, B2),
- ?line {error, {invalid_shutdown,-10}}
- = supervisor:start_child(sup_test, B3),
- ?line {error, {invalid_child_type,wrker}}
+ {error, {invalid_shutdown,-10}}
+ = supervisor:start_child(sup_test, B3),
+ {error, {invalid_child_type,wrker}}
= supervisor:start_child(sup_test, B4),
- ?line {error, _} = supervisor:start_child(sup_test, B5),
- ?line {error, {invalid_modules,dy}}
+ {error, _} = supervisor:start_child(sup_test, B5),
+ {error, {invalid_modules,dy}}
= supervisor:start_child(sup_test, B6),
-
- ?line {error, {invalid_mfa,mfa}} = supervisor:check_childspecs([B1]),
- ?line {error, {invalid_restart_type,prmanent}} =
+
+ {error, {invalid_mfa,mfa}} = supervisor:check_childspecs([B1]),
+ {error, {invalid_restart_type,prmanent}} =
supervisor:check_childspecs([B2]),
- ?line {error, {invalid_shutdown,-10}} = supervisor:check_childspecs([B3]),
- ?line {error, {invalid_child_type,wrker}}
+ {error, {invalid_shutdown,-10}} = supervisor:check_childspecs([B3]),
+ {error, {invalid_child_type,wrker}}
= supervisor:check_childspecs([B4]),
- ?line {error, _} = supervisor:check_childspecs([B5]),
- ?line {error, {invalid_modules,dy}} = supervisor:check_childspecs([B6]),
- ?line {error, {invalid_module, 1}} =
+ {error, _} = supervisor:check_childspecs([B5]),
+ {error, {invalid_modules,dy}} = supervisor:check_childspecs([B6]),
+ {error, {invalid_module, 1}} =
supervisor:check_childspecs([B7]),
- ?line ok = supervisor:check_childspecs([C1]),
- ?line ok = supervisor:check_childspecs([C2]),
- ?line ok = supervisor:check_childspecs([C3]),
- ?line ok = supervisor:check_childspecs([C4]),
+ ok = supervisor:check_childspecs([C1]),
+ ok = supervisor:check_childspecs([C2]),
+ ok = supervisor:check_childspecs([C3]),
+ ok = supervisor:check_childspecs([C4]),
ok.
-%-------------------------------------------------------------------------
+%%-------------------------------------------------------------------------
permanent_normal(doc) ->
["A permanent child should always be restarted"];
permanent_normal(suite) -> [];
permanent_normal(Config) when is_list(Config) ->
- ?line {ok, _SupPid} = start({ok, {{one_for_one, 2, 3600}, []}}),
+ {ok, SupPid} = start_link({ok, {{one_for_one, 2, 3600}, []}}),
Child1 = {child1, {supervisor_1, start_child, []}, permanent, 1000,
worker, []},
-
- ?line {ok, CPid1} = supervisor:start_child(sup_test, Child1),
-
- CPid1 ! stop,
- test_server:sleep(100),
- ?line [{child1, Pid ,worker,[]}] = supervisor:which_children(sup_test),
+
+ {ok, CPid1} = supervisor:start_child(sup_test, Child1),
+
+ terminate(SupPid, CPid1, child1, normal),
+
+ [{child1, Pid ,worker,[]}] = supervisor:which_children(sup_test),
case is_pid(Pid) of
true ->
ok;
false ->
- ?line test_server:fail({permanent_child_not_restarted, Child1})
+ test_server:fail({permanent_child_not_restarted, Child1})
end,
- ?line [1,1,0,1] = get_child_counts(sup_test),
+ [1,1,0,1] = get_child_counts(sup_test).
- ok.
-%-------------------------------------------------------------------------
+%%-------------------------------------------------------------------------
transient_normal(doc) ->
["A transient child should not be restarted if it exits with "
"reason normal"];
transient_normal(suite) -> [];
transient_normal(Config) when is_list(Config) ->
- ?line {ok, _SupPid} = start({ok, {{one_for_one, 2, 3600}, []}}),
+ {ok, SupPid} = start_link({ok, {{one_for_one, 2, 3600}, []}}),
Child1 = {child1, {supervisor_1, start_child, []}, transient, 1000,
worker, []},
-
- ?line {ok, CPid1} = supervisor:start_child(sup_test, Child1),
-
- CPid1 ! stop,
- test_server:sleep(100),
-
- ?line [{child1,undefined,worker,[]}] = supervisor:which_children(sup_test),
- ?line [1,0,0,1] = get_child_counts(sup_test),
- ok.
-%-------------------------------------------------------------------------
+ {ok, CPid1} = supervisor:start_child(sup_test, Child1),
+
+ terminate(SupPid, CPid1, child1, normal),
+
+ [{child1,undefined,worker,[]}] = supervisor:which_children(sup_test),
+ [1,0,0,1] = get_child_counts(sup_test).
+
+%%-------------------------------------------------------------------------
temporary_normal(doc) ->
["A temporary process should never be restarted"];
temporary_normal(suite) -> [];
temporary_normal(Config) when is_list(Config) ->
- ?line {ok, _SupPid} = start({ok, {{one_for_one, 2, 3600}, []}}),
+ {ok, SupPid} = start_link({ok, {{one_for_one, 2, 3600}, []}}),
Child1 = {child1, {supervisor_1, start_child, []}, temporary, 1000,
worker, []},
-
- ?line {ok, CPid1} = supervisor:start_child(sup_test, Child1),
-
- CPid1 ! stop,
- test_server:sleep(100),
-
- ?line [{child1,undefined,worker,[]}] = supervisor:which_children(sup_test),
- ?line [1,0,0,1] = get_child_counts(sup_test),
- ok.
+ {ok, CPid1} = supervisor:start_child(sup_test, Child1),
+
+ terminate(SupPid, CPid1, child1, normal),
+
+ [] = supervisor:which_children(sup_test),
+ [0,0,0,0] = get_child_counts(sup_test).
-%-------------------------------------------------------------------------
+%%-------------------------------------------------------------------------
permanent_abnormal(doc) ->
["A permanent child should always be restarted"];
permanent_abnormal(suite) -> [];
permanent_abnormal(Config) when is_list(Config) ->
- ?line {ok, _SupPid} = start({ok, {{one_for_one, 2, 3600}, []}}),
+ {ok, SupPid} = start_link({ok, {{one_for_one, 2, 3600}, []}}),
Child1 = {child1, {supervisor_1, start_child, []}, permanent, 1000,
worker, []},
-
- ?line {ok, CPid1} = supervisor:start_child(sup_test, Child1),
-
- CPid1 ! die,
- test_server:sleep(100),
- ?line [{child1, Pid ,worker,[]}] = supervisor:which_children(sup_test),
+
+ {ok, CPid1} = supervisor:start_child(sup_test, Child1),
+ terminate(SupPid, CPid1, child1, abnormal),
+
+ [{child1, Pid ,worker,[]}] = supervisor:which_children(sup_test),
case is_pid(Pid) of
true ->
ok;
false ->
- ?line test_server:fail({permanent_child_not_restarted, Child1})
+ test_server:fail({permanent_child_not_restarted, Child1})
end,
- ?line [1,1,0,1] = get_child_counts(sup_test),
+ [1,1,0,1] = get_child_counts(sup_test).
- ok.
-%-------------------------------------------------------------------------
+%%-------------------------------------------------------------------------
transient_abnormal(doc) ->
["A transient child should be restarted if it exits with "
"reason abnormal"];
transient_abnormal(suite) -> [];
transient_abnormal(Config) when is_list(Config) ->
- ?line {ok, _SupPid} = start({ok, {{one_for_one, 2, 3600}, []}}),
+ {ok, SupPid} = start_link({ok, {{one_for_one, 2, 3600}, []}}),
Child1 = {child1, {supervisor_1, start_child, []}, transient, 1000,
worker, []},
-
- ?line {ok, CPid1} = supervisor:start_child(sup_test, Child1),
-
- CPid1 ! die,
- test_server:sleep(100),
-
- ?line [{child1, Pid ,worker,[]}] = supervisor:which_children(sup_test),
+
+ {ok, CPid1} = supervisor:start_child(sup_test, Child1),
+ terminate(SupPid, CPid1, child1, abnormal),
+
+ [{child1, Pid ,worker,[]}] = supervisor:which_children(sup_test),
case is_pid(Pid) of
true ->
ok;
false ->
- ?line test_server:fail({transient_child_not_restarted, Child1})
+ test_server:fail({transient_child_not_restarted, Child1})
end,
- ?line [1,1,0,1] = get_child_counts(sup_test),
+ [1,1,0,1] = get_child_counts(sup_test).
- ok.
-%-------------------------------------------------------------------------
+%%-------------------------------------------------------------------------
temporary_abnormal(doc) ->
["A temporary process should never be restarted"];
temporary_abnormal(suite) -> [];
temporary_abnormal(Config) when is_list(Config) ->
- ?line {ok, _SupPid} = start({ok, {{one_for_one, 2, 3600}, []}}),
+ {ok, SupPid} = start_link({ok, {{one_for_one, 2, 3600}, []}}),
Child1 = {child1, {supervisor_1, start_child, []}, temporary, 1000,
worker, []},
-
- ?line {ok, CPid1} = supervisor:start_child(sup_test, Child1),
-
- CPid1 ! die,
- test_server:sleep(100),
-
- ?line [{child1,undefined,worker,[]}] = supervisor:which_children(sup_test),
- ?line [1,0,0,1] = get_child_counts(sup_test),
- ok.
-%-------------------------------------------------------------------------
+ {ok, CPid1} = supervisor:start_child(sup_test, Child1),
+ terminate(SupPid, CPid1, child1, abnormal),
+
+ [] = supervisor:which_children(sup_test),
+ [0,0,0,0] = get_child_counts(sup_test).
+
+%%-------------------------------------------------------------------------
one_for_one(doc) ->
["Test the one_for_one base case."];
one_for_one(suite) -> [];
one_for_one(Config) when is_list(Config) ->
process_flag(trap_exit, true),
Child1 = {child1, {supervisor_1, start_child, []}, permanent, 1000,
- worker, []},
+ worker, []},
Child2 = {child2, {supervisor_1, start_child, []}, permanent, 1000,
- worker, []},
- ?line {ok, Pid} = start({ok, {{one_for_one, 2, 3600}, []}}),
- ?line {ok, CPid1} = supervisor:start_child(sup_test, Child1),
- link(CPid1),
- ?line {ok, CPid2} = supervisor:start_child(sup_test, Child2),
- link(CPid2),
- CPid1 ! die,
- receive
- {'EXIT', CPid1, died} -> ok;
- {'EXIT', CPid1, Reason} ->
- ?line test_server:fail({bad_exit_reason, Reason})
- end,
- test_server:sleep(100),
+ worker, []},
+ {ok, SupPid} = start_link({ok, {{one_for_one, 2, 3600}, []}}),
+ {ok, CPid1} = supervisor:start_child(sup_test, Child1),
+ {ok, CPid2} = supervisor:start_child(sup_test, Child2),
+
+ terminate(SupPid, CPid1, child1, abnormal),
Children = supervisor:which_children(sup_test),
if length(Children) == 2 ->
case lists:keysearch(CPid2, 2, Children) of
{value, _} -> ok;
- _ -> ?line test_server:fail(bad_child)
+ _ -> test_server:fail(bad_child)
end;
- true -> ?line test_server:fail({bad_child_list, Children})
+ true -> test_server:fail({bad_child_list, Children})
end,
- ?line [2,2,0,2] = get_child_counts(sup_test),
-
+ [2,2,0,2] = get_child_counts(sup_test),
+
%% Test restart frequency property
- CPid2 ! die,
- receive
- {'EXIT', CPid2, _} -> ok
- end,
- test_server:sleep(100),
- [{_, Pid4, _, _}|_] = supervisor:which_children(sup_test),
- Pid4 ! die,
- receive
- {'EXIT', Pid, _} -> ok
- after 3000 -> ?line test_server:fail(restart_failed)
- end,
- ok.
-%-------------------------------------------------------------------------
+ terminate(SupPid, CPid2, child2, abnormal),
+
+ [{Id4, Pid4, _, _}|_] = supervisor:which_children(sup_test),
+ terminate(SupPid, Pid4, Id4, abnormal),
+ check_exit([SupPid]).
+
+%%-------------------------------------------------------------------------
one_for_one_escalation(doc) ->
["Test restart escalation on a one_for_one supervisor."];
one_for_one_escalation(suite) -> [];
one_for_one_escalation(Config) when is_list(Config) ->
process_flag(trap_exit, true),
+
Child1 = {child1, {supervisor_1, start_child, [error]},
permanent, 1000,
- worker, []},
+ worker, []},
Child2 = {child2, {supervisor_1, start_child, []}, permanent, 1000,
- worker, []},
- ?line {ok, Pid} = start({ok, {{one_for_one, 4, 3600}, []}}),
- ?line {ok, CPid1} = supervisor:start_child(sup_test, Child1),
- link(CPid1),
- ?line {ok, CPid2} = supervisor:start_child(sup_test, Child2),
+ worker, []},
+
+ {ok, SupPid} = start_link({ok, {{one_for_one, 4, 3600}, []}}),
+ {ok, CPid1} = supervisor:start_child(sup_test, Child1),
+ {ok, CPid2} = supervisor:start_child(sup_test, Child2),
link(CPid2),
- CPid1 ! die,
- receive
- {'EXIT', CPid1, died} -> ok;
- {'EXIT', CPid1, Reason} ->
- ?line test_server:fail({bad_exit_reason, Reason})
- end,
- receive
- {'EXIT', Pid, _} -> ok
- after
- 2000 -> ?line test_server:fail(supervisor_alive)
- end,
- receive
- {'EXIT', CPid2, _} -> ok
- after
- 4000 -> ?line test_server:fail(all_not_terminated)
- end,
- ok.
-%-------------------------------------------------------------------------
+
+ terminate(SupPid, CPid1, child1, abnormal),
+ check_exit([SupPid, CPid2]).
+
+
+%%-------------------------------------------------------------------------
one_for_all(doc) ->
["Test the one_for_all base case."];
one_for_all(suite) -> [];
one_for_all(Config) when is_list(Config) ->
process_flag(trap_exit, true),
+
Child1 = {child1, {supervisor_1, start_child, []}, permanent, 1000,
worker, []},
Child2 = {child2, {supervisor_1, start_child, []}, permanent, 1000,
worker, []},
- ?line {ok, Pid} = start({ok, {{one_for_all, 2, 3600}, []}}),
- ?line {ok, CPid1} = supervisor:start_child(sup_test, Child1),
- link(CPid1),
- ?line {ok, CPid2} = supervisor:start_child(sup_test, Child2),
+ {ok, SupPid} = start_link({ok, {{one_for_all, 2, 3600}, []}}),
+ {ok, CPid1} = supervisor:start_child(sup_test, Child1),
+ {ok, CPid2} = supervisor:start_child(sup_test, Child2),
link(CPid2),
- CPid1 ! die,
- receive
- {'EXIT', CPid1, died} -> ok;
- {'EXIT', CPid1, Reason} ->
- ?line test_server:fail({bad_exit_reason, Reason})
- end,
- receive
- {'EXIT', CPid2, _} -> ok
- end,
- test_server:sleep(100),
+
+ terminate(SupPid, CPid1, child1, abnormal),
+ check_exit([CPid2]),
+
Children = supervisor:which_children(sup_test),
if length(Children) == 2 -> ok;
- true -> ?line test_server:fail({bad_child_list, Children})
+ true ->
+ test_server:fail({bad_child_list, Children})
end,
+
%% Test that no old children is still alive
- SCh = lists:map(fun({_,P,_,_}) -> P end, Children),
- case lists:member(CPid1, SCh) of
- true -> ?line test_server:fail(bad_child);
- false -> ok
- end,
- case lists:member(CPid2, SCh) of
- true -> ?line test_server:fail(bad_child);
- false -> ok
- end,
- ?line [2,2,0,2] = get_child_counts(sup_test),
+ not_in_child_list([CPid1, CPid2], lists:map(fun({_,P,_,_}) -> P end, Children)),
+
+ [2,2,0,2] = get_child_counts(sup_test),
%%% Test restart frequency property
- [{_, Pid3, _, _}|_] = supervisor:which_children(sup_test),
- Pid3 ! die,
- test_server:sleep(100),
- [{_, Pid4, _, _}|_] = supervisor:which_children(sup_test),
- Pid4 ! die,
- receive
- {'EXIT', Pid, _} -> ok
- after 3000 -> ?line test_server:fail(restart_failed)
- end,
- exit(Pid, shutdown).
+ [{Id3, Pid3, _, _}|_] = supervisor:which_children(sup_test),
+ terminate(SupPid, Pid3, Id3, abnormal),
+ [{Id4, Pid4, _, _}|_] = supervisor:which_children(sup_test),
+ terminate(SupPid, Pid4, Id4, abnormal),
+ check_exit([SupPid]).
+
-%-------------------------------------------------------------------------
+%%-------------------------------------------------------------------------
one_for_all_escalation(doc) ->
["Test restart escalation on a one_for_all supervisor."];
one_for_all_escalation(suite) -> [];
one_for_all_escalation(Config) when is_list(Config) ->
process_flag(trap_exit, true),
+
Child1 = {child1, {supervisor_1, start_child, []}, permanent, 1000,
worker, []},
Child2 = {child2, {supervisor_1, start_child, [error]},
permanent, 1000,
worker, []},
- ?line {ok, Pid} = start({ok, {{one_for_all, 4, 3600}, []}}),
- ?line {ok, CPid1} = supervisor:start_child(sup_test, Child1),
- link(CPid1),
- ?line {ok, CPid2} = supervisor:start_child(sup_test, Child2),
+ {ok, SupPid} = start_link({ok, {{one_for_all, 4, 3600}, []}}),
+ {ok, CPid1} = supervisor:start_child(sup_test, Child1),
+ {ok, CPid2} = supervisor:start_child(sup_test, Child2),
link(CPid2),
- CPid1 ! die,
- receive
- {'EXIT', CPid1, died} -> ok;
- {'EXIT', CPid1, Reason} ->
- ?line test_server:fail({bad_exit_reason, Reason})
- end,
- receive
- {'EXIT', CPid2, _} -> ok
- after
- 2000 -> ?line test_server:fail(all_not_terminated)
- end,
- receive
- {'EXIT', Pid, _} -> ok
- after
- 4000 -> ?line test_server:fail(supervisor_alive)
- end,
- ok.
-%-------------------------------------------------------------------------
+ terminate(SupPid, CPid1, child1, abnormal),
+ check_exit([CPid2, SupPid]).
+
+
+%%-------------------------------------------------------------------------
simple_one_for_one(doc) ->
["Test the simple_one_for_one base case."];
simple_one_for_one(suite) -> [];
@@ -888,42 +712,31 @@ simple_one_for_one(Config) when is_list(Config) ->
process_flag(trap_exit, true),
Child = {child, {supervisor_1, start_child, []}, permanent, 1000,
worker, []},
- ?line {ok, Pid} = start({ok, {{simple_one_for_one, 2, 3600}, [Child]}}),
- ?line {ok, CPid1} = supervisor:start_child(sup_test, []),
- link(CPid1),
- ?line {ok, CPid2} = supervisor:start_child(sup_test, []),
- link(CPid2),
- CPid1 ! die,
- receive
- {'EXIT', CPid1, died} -> ok;
- {'EXIT', CPid1, Reason} ->
- ?line test_server:fail({bad_exit_reason, Reason})
- end,
- test_server:sleep(100),
+ {ok, SupPid} = start_link({ok, {{simple_one_for_one, 2, 3600}, [Child]}}),
+ {ok, CPid1} = supervisor:start_child(sup_test, []),
+ {ok, CPid2} = supervisor:start_child(sup_test, []),
+
+ terminate(SupPid, CPid1, child1, abnormal),
+
Children = supervisor:which_children(sup_test),
if length(Children) == 2 ->
case lists:keysearch(CPid2, 2, Children) of
{value, _} -> ok;
- _ -> ?line test_server:fail(bad_child)
+ _ -> test_server:fail(bad_child)
end;
- true -> ?line test_server:fail({bad_child_list, Children})
+ true -> test_server:fail({bad_child_list, Children})
end,
- ?line [1,2,0,2] = get_child_counts(sup_test),
+ [1,2,0,2] = get_child_counts(sup_test),
%% Test restart frequency property
- CPid2 ! die,
- receive
- {'EXIT', CPid2, _} -> ok
- end,
- test_server:sleep(100),
- [{_, Pid4, _, _}|_] = supervisor:which_children(sup_test),
- Pid4 ! die,
- receive
- {'EXIT', Pid, _} -> ok
- after 3000 -> ?line test_server:fail(restart_failed)
- end,
- ok.
-%-------------------------------------------------------------------------
+ terminate(SupPid, CPid2, child2, abnormal),
+
+ [{Id4, Pid4, _, _}|_] = supervisor:which_children(sup_test),
+
+ terminate(SupPid, Pid4, Id4, abnormal),
+ check_exit([SupPid]).
+
+%%-------------------------------------------------------------------------
simple_one_for_one_extra(doc) ->
["Tests automatic restart of children "
"who's start function return extra info."];
@@ -932,41 +745,26 @@ simple_one_for_one_extra(Config) when is_list(Config) ->
process_flag(trap_exit, true),
Child = {child, {supervisor_1, start_child, [extra_info]},
permanent, 1000, worker, []},
- ?line {ok, Pid} = start({ok, {{simple_one_for_one, 2, 3600}, [Child]}}),
- ?line {ok, CPid1, extra_info} = supervisor:start_child(sup_test, []),
- link(CPid1),
- ?line {ok, CPid2, extra_info} = supervisor:start_child(sup_test, []),
+ {ok, SupPid} = start_link({ok, {{simple_one_for_one, 2, 3600}, [Child]}}),
+ {ok, CPid1, extra_info} = supervisor:start_child(sup_test, []),
+ {ok, CPid2, extra_info} = supervisor:start_child(sup_test, []),
link(CPid2),
- CPid1 ! die,
- receive
- {'EXIT', CPid1, died} -> ok;
- {'EXIT', CPid1, Reason} ->
- ?line test_server:fail({bad_exit_reason, Reason})
- end,
- test_server:sleep(100),
+ terminate(SupPid, CPid1, child1, abnormal),
Children = supervisor:which_children(sup_test),
if length(Children) == 2 ->
case lists:keysearch(CPid2, 2, Children) of
{value, _} -> ok;
- _ -> ?line test_server:fail(bad_child)
+ _ -> test_server:fail(bad_child)
end;
- true -> ?line test_server:fail({bad_child_list, Children})
+ true -> test_server:fail({bad_child_list, Children})
end,
- ?line [1,2,0,2] = get_child_counts(sup_test),
+ [1,2,0,2] = get_child_counts(sup_test),
+ terminate(SupPid, CPid2, child2, abnormal),
+ [{Id4, Pid4, _, _}|_] = supervisor:which_children(sup_test),
+ terminate(SupPid, Pid4, Id4, abnormal),
+ check_exit([SupPid]).
- CPid2 ! die,
- receive
- {'EXIT', CPid2, _} -> ok
- end,
- test_server:sleep(100),
- [{_, Pid4, _, _}|_] = supervisor:which_children(sup_test),
- Pid4 ! die,
- receive
- {'EXIT', Pid, _} -> ok
- after 3000 -> ?line test_server:fail(restart_failed)
- end,
- ok.
-%-------------------------------------------------------------------------
+%%-------------------------------------------------------------------------
simple_one_for_one_escalation(doc) ->
["Test restart escalation on a simple_one_for_one supervisor."];
simple_one_for_one_escalation(suite) -> [];
@@ -974,29 +772,16 @@ simple_one_for_one_escalation(Config) when is_list(Config) ->
process_flag(trap_exit, true),
Child = {child, {supervisor_1, start_child, []}, permanent, 1000,
worker, []},
- ?line {ok, Pid} = start({ok, {{simple_one_for_one, 4, 3600}, [Child]}}),
- ?line {ok, CPid1} = supervisor:start_child(sup_test, [error]),
+ {ok, SupPid} = start_link({ok, {{simple_one_for_one, 4, 3600}, [Child]}}),
+ {ok, CPid1} = supervisor:start_child(sup_test, [error]),
link(CPid1),
- ?line {ok, CPid2} = supervisor:start_child(sup_test, []),
+ {ok, CPid2} = supervisor:start_child(sup_test, []),
link(CPid2),
- CPid1 ! die,
- receive
- {'EXIT', CPid1, died} -> ok;
- {'EXIT', CPid1, Reason} ->
- ?line test_server:fail({bad_exit_reason, Reason})
- end,
- receive
- {'EXIT', Pid, _} -> ok
- after
- 2000 -> ?line test_server:fail(supervisor_alive)
- end,
- receive
- {'EXIT', CPid2, _} -> ok
- after
- 2000 -> ?line test_server:fail(all_not_terminated)
- end,
- ok.
-%-------------------------------------------------------------------------
+
+ terminate(SupPid, CPid1, child, abnormal),
+ check_exit([SupPid, CPid2]).
+
+%%-------------------------------------------------------------------------
rest_for_one(doc) ->
["Test the rest_for_one base case."];
rest_for_one(suite) -> [];
@@ -1008,70 +793,45 @@ rest_for_one(Config) when is_list(Config) ->
worker, []},
Child3 = {child3, {supervisor_1, start_child, []}, permanent, 1000,
worker, []},
- ?line {ok, Pid} = start({ok, {{rest_for_one, 2, 3600}, []}}),
- ?line {ok, CPid1} = supervisor:start_child(sup_test, Child1),
+ {ok, SupPid} = start_link({ok, {{rest_for_one, 2, 3600}, []}}),
+ {ok, CPid1} = supervisor:start_child(sup_test, Child1),
link(CPid1),
- ?line {ok, CPid2} = supervisor:start_child(sup_test, Child2),
- link(CPid2),
- ?line {ok, CPid3} = supervisor:start_child(sup_test, Child3),
+ {ok, CPid2} = supervisor:start_child(sup_test, Child2),
+ {ok, CPid3} = supervisor:start_child(sup_test, Child3),
link(CPid3),
- ?line [3,3,0,3] = get_child_counts(sup_test),
+ [3,3,0,3] = get_child_counts(sup_test),
+
+ terminate(SupPid, CPid2, child2, abnormal),
- CPid2 ! die,
- receive
- {'EXIT', CPid2, died} -> ok;
- {'EXIT', CPid2, Reason} ->
- ?line test_server:fail({bad_exit_reason, Reason})
- after 2000 ->
- ?line test_server:fail(no_exit)
- end,
%% Check that Cpid3 did die
- receive
- {'EXIT', CPid3, _} -> ok
- after 2000 ->
- ?line test_server:fail(no_exit)
- end,
- %% Check that Cpid1 didn't die
- receive
- {'EXIT', CPid1, _} ->
- ?line test_server:fail(bad_exit)
- after
- 100 -> ok
- end,
+ check_exit([CPid3]),
+
Children = supervisor:which_children(sup_test),
- if length(Children) == 3 -> ok;
- true -> ?line test_server:fail({bad_child_list, Children})
+ is_in_child_list([CPid1], Children),
+
+ if length(Children) == 3 ->
+ ok;
+ true ->
+ test_server:fail({bad_child_list, Children})
end,
- ?line [3,3,0,3] = get_child_counts(sup_test),
+ [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
- true -> ok;
- false -> ?line test_server:fail(bad_child)
- end,
- case lists:member(CPid2, SCh) of
- true -> ?line test_server:fail(bad_child);
- false -> ok
- end,
- case lists:member(CPid3, SCh) of
- true -> ?line test_server:fail(bad_child);
- false -> ok
- end,
-
+ Pids = lists:map(fun({_,P,_,_}) -> P end, Children),
+ not_in_child_list([CPid2, CPid3], Pids),
+ in_child_list([CPid1], Pids),
+
%% Test restart frequency property
[{child3, Pid3, _, _}|_] = supervisor:which_children(sup_test),
- Pid3 ! die,
- test_server:sleep(100),
+
+ terminate(SupPid, Pid3, child3, abnormal),
+
[_,{child2, Pid4, _, _}|_] = supervisor:which_children(sup_test),
- Pid4 ! die,
- receive
- {'EXIT', Pid, _} -> ok
- after 3000 -> ?line test_server:fail(restart_failed)
- end,
- exit(Pid, shutdown).
-%-------------------------------------------------------------------------
+ terminate(SupPid, Pid4, child2, abnormal),
+ check_exit([SupPid]).
+
+%%-------------------------------------------------------------------------
rest_for_one_escalation(doc) ->
["Test restart escalation on a rest_for_one supervisor."];
rest_for_one_escalation(suite) -> [];
@@ -1082,42 +842,29 @@ rest_for_one_escalation(Config) when is_list(Config) ->
Child2 = {child2, {supervisor_1, start_child, [error]},
permanent, 1000,
worker, []},
- ?line {ok, Pid} = start({ok, {{rest_for_one, 4, 3600}, []}}),
- ?line {ok, CPid1} = supervisor:start_child(sup_test, Child1),
- link(CPid1),
- ?line {ok, CPid2} = supervisor:start_child(sup_test, Child2),
+ {ok, SupPid} = start_link({ok, {{rest_for_one, 4, 3600}, []}}),
+ {ok, CPid1} = supervisor:start_child(sup_test, Child1),
+ {ok, CPid2} = supervisor:start_child(sup_test, Child2),
link(CPid2),
- CPid1 ! die,
- receive
- {'EXIT', CPid1, died} -> ok;
- {'EXIT', CPid1, Reason} ->
- ?line test_server:fail({bad_exit_reason, Reason})
- end,
- receive
- {'EXIT', CPid2, _} -> ok
- after
- 2000 -> ?line test_server:fail(not_terminated)
- end,
- receive
- {'EXIT', Pid, _} -> ok
- after
- 4000 -> ?line test_server:fail(supervisor_alive)
- end,
- ok.
-%-------------------------------------------------------------------------
-child_unlink(doc)-> ["Test that the supervisor does not hang forever if "
- "the child unliks and then is terminated by the supervisor."];
-child_unlink(suite) -> [];
+ terminate(SupPid, CPid1, child1, abnormal),
+ check_exit([CPid2, SupPid]).
+
+%%-------------------------------------------------------------------------
+child_unlink(doc)->
+ ["Test that the supervisor does not hang forever if "
+ "the child unliks and then is terminated by the supervisor."];
+child_unlink(suite) ->
+ [];
child_unlink(Config) when is_list(Config) ->
-
- ?line {ok, SupPid} = start({ok, {{one_for_one, 2, 3600}, []}}),
-
+
+ {ok, SupPid} = start_link({ok, {{one_for_one, 2, 3600}, []}}),
+
Child = {naughty_child, {naughty_child,
start_link, [SupPid]}, permanent,
1000, worker, [supervisor_SUITE]},
-
- ?line {ok, _ChildPid} = supervisor:start_child(sup_test, Child),
+
+ {ok, _ChildPid} = supervisor:start_child(sup_test, Child),
Pid = spawn(supervisor, terminate_child, [SupPid, naughty_child]),
@@ -1130,17 +877,16 @@ child_unlink(Config) when is_list(Config) ->
ok;
_ ->
exit(Pid, kill),
- ?line test_server:fail(supervisor_hangs)
+ test_server:fail(supervisor_hangs)
end.
-%-------------------------------------------------------------------------
-
+%%-------------------------------------------------------------------------
tree(doc) ->
["Test a basic supervison tree."];
tree(suite) ->
[];
tree(Config) when is_list(Config) ->
process_flag(trap_exit, true),
-
+
Child1 = {child1, {supervisor_1, start_child, []},
permanent, 1000,
worker, []},
@@ -1166,109 +912,54 @@ tree(Config) when is_list(Config) ->
supervisor, []},
%% Top supervisor
- ?line {ok, Pid} = start({ok, {{one_for_all, 4, 3600}, []}}),
-
+ {ok, SupPid} = start_link({ok, {{one_for_all, 4, 3600}, []}}),
+
%% 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),
-
+ {ok, Sup1} = supervisor:start_child(SupPid, ChildSup1),
+ {ok, Sup2} = supervisor:start_child(SupPid, ChildSup2),
+ [2,2,2,0] = get_child_counts(SupPid),
+
%% Workers
- ?line [{_, CPid2, _, _},{_, CPid1, _, _}] =
+ [{_, CPid2, _, _},{_, CPid1, _, _}] =
supervisor:which_children(Sup1),
- ?line [2,2,0,2] = get_child_counts(Sup1),
- ?line [0,0,0,0] = get_child_counts(Sup2),
-
+ [2,2,0,2] = get_child_counts(Sup1),
+ [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),
- link(CPid1),
- link(CPid2),
- link(CPid3),
- link(CPid4),
-
+ {ok, CPid3} = supervisor:start_child(Sup2, Child3),
+ {ok, CPid4} = supervisor:start_child(Sup2, Child4),
+ [2,2,0,2] = get_child_counts(Sup1),
+ [2,2,0,2] = get_child_counts(Sup2),
+
%% Test that the only the process that dies is restarted
- CPid4 ! die,
-
- receive
- {'EXIT', CPid4, _} -> ?line ok
- after 10000 ->
- ?line test_server:fail(child_was_not_killed)
- end,
-
- test_server:sleep(100),
-
- ?line [{_, CPid2, _, _},{_, CPid1, _, _}] =
+ terminate(Sup2, CPid4, child4, abnormal),
+
+ [{_, CPid2, _, _},{_, CPid1, _, _}] =
supervisor:which_children(Sup1),
- ?line [2,2,0,2] = get_child_counts(Sup1),
-
- ?line [{_, NewCPid4, _, _},{_, CPid3, _, _}] =
+ [2,2,0,2] = get_child_counts(Sup1),
+
+ [{_, NewCPid4, _, _},{_, CPid3, _, _}] =
supervisor:which_children(Sup2),
- ?line [2,2,0,2] = get_child_counts(Sup2),
-
- link(NewCPid4),
+ [2,2,0,2] = get_child_counts(Sup2),
+
+ false = NewCPid4 == CPid4,
%% Test that supervisor tree is restarted, but not dynamic children.
- CPid3 ! die,
+ terminate(Sup2, CPid3, child3, abnormal),
- receive
- {'EXIT', CPid3, died} -> ?line ok;
- {'EXIT', CPid3, Reason} ->
- ?line test_server:fail({bad_exit_reason, Reason})
- after 1000 ->
- ?line test_server:fail(child_was_not_killed)
- end,
+ timer:sleep(1000),
- test_server:sleep(1000),
+ [{supchild2, NewSup2, _, _},{supchild1, NewSup1, _, _}] =
+ supervisor:which_children(SupPid),
+ [2,2,2,0] = get_child_counts(SupPid),
- receive
- {'EXIT', NewCPid4, _} -> ?line ok
- after 1000 ->
- ?line test_server:fail(child_was_not_killed)
- end,
-
- receive
- {'EXIT', Sup2, _} -> ?line ok
- after 1000 ->
- ?line test_server:fail(child_was_not_killed)
- end,
-
- receive
- {'EXIT', CPid1, _} -> ?line ok
- after 1000 ->
- ?line test_server:fail(child_was_not_killed)
- end,
-
- receive
- {'EXIT', CPid2, _} -> ?line ok
- after 1000 ->
- ?line test_server:fail(child_was_not_killed)
- end,
-
- receive
- {'EXIT', Sup1, _} -> ?line ok
- after 1000 ->
- ?line test_server:fail(child_was_not_killed)
- end,
-
- ?line [{supchild2, NewSup2, _, _},{supchild1, NewSup1, _, _}] =
- supervisor:which_children(Pid),
- ?line [2,2,2,0] = get_child_counts(Pid),
-
- ?line [{child2, _, _, _},{child1, _, _, _}] =
+ [{child2, _, _, _},{child1, _, _, _}] =
supervisor:which_children(NewSup1),
- ?line [2,2,0,2] = get_child_counts(NewSup1),
+ [2,2,0,2] = get_child_counts(NewSup1),
- ?line [] = supervisor:which_children(NewSup2),
- ?line [0,0,0,0] = get_child_counts(NewSup2),
-
- ok.
-%-------------------------------------------------------------------------
+ [] = supervisor:which_children(NewSup2),
+ [0,0,0,0] = get_child_counts(NewSup2).
+%%-------------------------------------------------------------------------
count_children_memory(doc) ->
["Test that count_children does not eat memory."];
count_children_memory(suite) ->
@@ -1277,7 +968,7 @@ 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]}}),
+ {ok, SupPid} = start_link({ok, {{simple_one_for_one, 2, 3600}, [Child]}}),
[supervisor:start_child(sup_test, []) || _Ignore <- lists:seq(1,1000)],
garbage_collect(),
@@ -1301,12 +992,12 @@ count_children_memory(Config) when is_list(Config) ->
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,
+ 1000 = length(Children),
+ [1,1000,0,1000] = ChildCount,
+ 2000 = length(Children2),
+ [1,2000,0,2000] = ChildCount2,
+ Children3 = Children2,
+ ChildCount3 = ChildCount2,
%% count_children consumes memory using an accumulator function,
%% but the space can be reclaimed incrementally,
@@ -1314,18 +1005,17 @@ count_children_memory(Config) when is_list(Config) ->
case (Size5 =< Size4) of
true -> ok;
false ->
- ?line test_server:fail({count_children, used_more_memory})
+ 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})
+ test_server:fail({count_children, used_more_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.
+ [terminate(SupPid, Pid, child, kill) || {undefined, Pid, worker, _Modules} <- Children3],
+ [1,0,0,0] = get_child_counts(sup_test).
+
count_children_allocator_test(MemoryState) ->
Allocators = [temp_alloc, eheap_alloc, binary_alloc, ets_alloc,
driver_alloc, sl_alloc, ll_alloc, fix_alloc, std_alloc,
@@ -1336,7 +1026,8 @@ count_children_allocator_test(MemoryState) ->
AllocStates = [lists:keyfind(e, 1, AllocValue)
|| {_Type, AllocValue} <- AllocTypes],
lists:all(fun(State) -> State == {e, true} end, AllocStates).
-%-------------------------------------------------------------------------
+
+%%-------------------------------------------------------------------------
do_not_save_start_parameters_for_temporary_children(doc) ->
["Temporary children shall not be restarted so they should not "
"save start parameters, as it potentially can "
@@ -1350,6 +1041,44 @@ do_not_save_start_parameters_for_temporary_children(Config) when is_list(Config)
dont_save_start_parameters_for_temporary_children(rest_for_one),
dont_save_start_parameters_for_temporary_children(simple_one_for_one).
+start_children(_,_, 0) ->
+ ok;
+start_children(Sup, Args, N) ->
+ Spec = child_spec(Args, N),
+ {ok, _, _} = supervisor:start_child(Sup, Spec),
+ start_children(Sup, Args, N-1).
+
+child_spec([_|_] = SimpleOneForOneArgs, _) ->
+ SimpleOneForOneArgs;
+child_spec({Name, MFA, RestartType, Shutdown, Type, Modules}, N) ->
+ NewName = list_to_atom((atom_to_list(Name) ++ integer_to_list(N))),
+ {NewName, MFA, RestartType, Shutdown, Type, Modules}.
+
+%%-------------------------------------------------------------------------
+do_not_save_child_specs_for_temporary_children(doc) ->
+ ["Temporary children shall not be restarted so supervisors should "
+ "not save their spec when they terminate"];
+do_not_save_child_specs_for_temporary_children(suite) ->
+ [];
+do_not_save_child_specs_for_temporary_children(Config) when is_list(Config) ->
+ process_flag(trap_exit, true),
+ dont_save_child_specs_for_temporary_children(one_for_all, kill),
+ dont_save_child_specs_for_temporary_children(one_for_one, kill),
+ dont_save_child_specs_for_temporary_children(rest_for_one, kill),
+
+ dont_save_child_specs_for_temporary_children(one_for_all, normal),
+ dont_save_child_specs_for_temporary_children(one_for_one, normal),
+ dont_save_child_specs_for_temporary_children(rest_for_one, normal),
+
+ dont_save_child_specs_for_temporary_children(one_for_all, abnormal),
+ dont_save_child_specs_for_temporary_children(one_for_one, abnormal),
+ dont_save_child_specs_for_temporary_children(rest_for_one, abnormal),
+
+ dont_save_child_specs_for_temporary_children(one_for_all, supervisor),
+ dont_save_child_specs_for_temporary_children(one_for_one, supervisor),
+ dont_save_child_specs_for_temporary_children(rest_for_one, supervisor).
+
+%%-------------------------------------------------------------------------
dont_save_start_parameters_for_temporary_children(simple_one_for_one = Type) ->
Permanent = {child, {supervisor_1, start_child, []},
permanent, 1000, worker, []},
@@ -1373,9 +1102,9 @@ dont_save_start_parameters_for_temporary_children(simple_one_for_one = Type) ->
true = (Mem3 < Mem1) and (Mem3 < Mem2),
- exit(Sup1, shutdown),
- exit(Sup2, shutdown),
- exit(Sup3, shutdown);
+ terminate(Sup1, shutdown),
+ terminate(Sup2, shutdown),
+ terminate(Sup3, shutdown);
dont_save_start_parameters_for_temporary_children(Type) ->
{ok, Sup1} = supervisor:start_link(?MODULE, {ok, {{Type, 2, 3600}, []}}),
@@ -1401,19 +1130,139 @@ dont_save_start_parameters_for_temporary_children(Type) ->
true = (Mem3 < Mem1) and (Mem3 < Mem2),
- exit(Sup1, shutdown),
- exit(Sup2, shutdown),
- exit(Sup3, shutdown).
+ terminate(Sup1, shutdown),
+ terminate(Sup2, shutdown),
+ terminate(Sup3, shutdown).
-start_children(_,_, 0) ->
+dont_save_child_specs_for_temporary_children(Type, TerminateHow)->
+ {ok, Sup} =
+ supervisor:start_link(?MODULE, {ok, {{Type, 2, 3600}, []}}),
+
+ Permanent = {child1, {supervisor_1, start_child, []},
+ permanent, 1000, worker, []},
+ Transient = {child2, {supervisor_1, start_child, []},
+ transient, 1000, worker, []},
+ Temporary = {child3, {supervisor_1, start_child, []},
+ temporary, 1000, worker, []},
+
+ permanent_child_spec_saved(Permanent, Sup, TerminateHow),
+
+ transient_child_spec_saved(Transient, Sup, TerminateHow),
+
+ temporary_child_spec_not_saved(Temporary, Sup, TerminateHow),
+
+ terminate(Sup, shutdown).
+
+permanent_child_spec_saved(ChildSpec, Sup, supervisor = TerminateHow) ->
+ already_present(Sup, ChildSpec, TerminateHow);
+
+permanent_child_spec_saved(ChildSpec, Sup, TerminateHow) ->
+ restarted(Sup, ChildSpec, TerminateHow).
+
+transient_child_spec_saved(ChildSpec, Sup, supervisor = TerminateHow) ->
+ already_present(Sup, ChildSpec, TerminateHow);
+
+transient_child_spec_saved(ChildSpec, Sup, normal = TerminateHow) ->
+ already_present(Sup, ChildSpec, TerminateHow);
+
+transient_child_spec_saved(ChildSpec, Sup, TerminateHow) ->
+ restarted(Sup, ChildSpec, TerminateHow).
+
+temporary_child_spec_not_saved({Id, _,_,_,_,_} = ChildSpec, Sup, TerminateHow) ->
+ {ok, Pid} = supervisor:start_child(Sup, ChildSpec),
+ terminate(Sup, Pid, Id, TerminateHow),
+ {ok, _} = supervisor:start_child(Sup, ChildSpec).
+
+already_present(Sup, {Id,_,_,_,_,_} = ChildSpec, TerminateHow) ->
+ {ok, Pid} = supervisor:start_child(Sup, ChildSpec),
+ terminate(Sup, Pid, Id, TerminateHow),
+ {error, already_present} = supervisor:start_child(Sup, ChildSpec),
+ {ok, _} = supervisor:restart_child(Sup, Id).
+
+restarted(Sup, {Id,_,_,_,_,_} = ChildSpec, TerminateHow) ->
+ {ok, Pid} = supervisor:start_child(Sup, ChildSpec),
+ terminate(Sup, Pid, Id, TerminateHow),
+ %% Permanent processes will be restarted by the supervisor
+ %% when not terminated by api
+ {error, {already_started, _}} = supervisor:start_child(Sup, ChildSpec).
+
+
+terminate(Pid, Reason) when Reason =/= supervisor ->
+ terminate(dummy, Pid, dummy, Reason).
+
+terminate(Sup, _, ChildId, supervisor) ->
+ ok = supervisor:terminate_child(Sup, ChildId);
+terminate(_, ChildPid, _, kill) ->
+ Ref = erlang:monitor(process, ChildPid),
+ exit(ChildPid, kill),
+ receive
+ {'DOWN', Ref, process, ChildPid, killed} ->
+ ok
+ end;
+terminate(_, ChildPid, _, shutdown) ->
+ Ref = erlang:monitor(process, ChildPid),
+ exit(ChildPid, shutdown),
+ receive
+ {'DOWN', Ref, process, ChildPid, shutdown} ->
+ ok
+ end;
+terminate(_, ChildPid, _, normal) ->
+ Ref = erlang:monitor(process, ChildPid),
+ ChildPid ! stop,
+ receive
+ {'DOWN', Ref, process, ChildPid, normal} ->
+ ok
+ end;
+terminate(_, ChildPid, _,abnormal) ->
+ Ref = erlang:monitor(process, ChildPid),
+ ChildPid ! die,
+ receive
+ {'DOWN', Ref, process, ChildPid, died} ->
+ ok
+ end.
+
+in_child_list([], _) ->
+ true;
+in_child_list([Pid | Rest], Pids) ->
+ case is_in_child_list(Pid, Pids) of
+ true ->
+ in_child_list(Rest, Pids);
+ false ->
+ test_server:fail(child_should_be_alive)
+ end.
+not_in_child_list([], _) ->
+ true;
+not_in_child_list([Pid | Rest], Pids) ->
+ case is_in_child_list(Pid, Pids) of
+ true ->
+ test_server:fail(child_should_not_be_alive);
+ false ->
+ not_in_child_list(Rest, Pids)
+ end.
+
+is_in_child_list(Pid, ChildPids) ->
+ lists:member(Pid, ChildPids).
+
+check_exit([]) ->
ok;
-start_children(Sup, Args, N) ->
- Spec = child_spec(Args, N),
- {ok, _, _} = supervisor:start_child(Sup, Spec),
- start_children(Sup, Args, N-1).
+check_exit([Pid | Pids]) ->
+ receive
+ {'EXIT', Pid, _} ->
+ check_exit(Pids)
+ end.
-child_spec([_|_] = SimpleOneForOneArgs, _) ->
- SimpleOneForOneArgs;
-child_spec({Name, MFA, RestartType, Shutdown, Type, Modules}, N) ->
- NewName = list_to_atom((atom_to_list(Name) ++ integer_to_list(N))),
- {NewName, MFA, RestartType, Shutdown, Type, Modules}.
+check_exit_reason(Reason) ->
+ receive
+ {'EXIT', _, Reason} ->
+ ok;
+ {'EXIT', _, Else} ->
+ test_server:fail({bad_exit_reason, Else})
+ end.
+
+check_exit_reason(Pid, Reason) ->
+ receive
+ {'EXIT', Pid, Reason} ->
+ ok;
+ {'EXIT', Pid, Else} ->
+ test_server:fail({bad_exit_reason, Else})
+ end.
--
cgit v1.2.3
From 02e09f135b2ef75ff440ee008e3db437b8fc3ff7 Mon Sep 17 00:00:00 2001
From: Dan Gudmundsson
Date: Fri, 25 Mar 2011 13:14:35 +0100
Subject: Mnesia sometimes failed to tell all nodes that it had started.
---
lib/mnesia/src/mnesia_controller.erl | 83 ++++++++++++++++++++++--------------
1 file changed, 50 insertions(+), 33 deletions(-)
(limited to 'lib')
diff --git a/lib/mnesia/src/mnesia_controller.erl b/lib/mnesia/src/mnesia_controller.erl
index 021be8af2a..0254769758 100644
--- a/lib/mnesia/src/mnesia_controller.erl
+++ b/lib/mnesia/src/mnesia_controller.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2010. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2011. 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
@@ -457,7 +457,7 @@ connect_nodes2(Father, Ns, UserFun) ->
New1 = mnesia_lib:intersect(Ns, Connected),
New = New1 -- Current,
process_flag(trap_exit, true),
- Res = try_merge_schema(New, UserFun),
+ Res = try_merge_schema(New, [], UserFun),
Msg = {schema_is_merged, [], late_merge, []},
multicall([node()|Ns], Msg),
After = val({current, db_nodes}),
@@ -471,7 +471,7 @@ connect_nodes2(Father, Ns, UserFun) ->
merge_schema() ->
AllNodes = mnesia_lib:all_nodes(),
- case try_merge_schema(AllNodes, fun default_merge/1) of
+ case try_merge_schema(AllNodes, [node()], fun default_merge/1) of
ok ->
schema_is_merged();
{aborted, {throw, Str}} when is_list(Str) ->
@@ -483,11 +483,17 @@ merge_schema() ->
default_merge(F) ->
F([]).
-try_merge_schema(Nodes, UserFun) ->
+try_merge_schema(Nodes, Told0, UserFun) ->
case mnesia_schema:merge_schema(UserFun) of
{atomic, not_merged} ->
%% No more nodes that we need to merge the schema with
- ok;
+ %% Ensure we have told everybody that we are running
+ case val({current,db_nodes}) -- mnesia_lib:uniq(Told0) of
+ [] -> ok;
+ Tell ->
+ im_running(Tell, [node()]),
+ ok
+ end;
{atomic, {merged, OldFriends, NewFriends}} ->
%% Check if new nodes has been added to the schema
Diff = mnesia_lib:all_nodes() -- [node() | Nodes],
@@ -496,12 +502,18 @@ try_merge_schema(Nodes, UserFun) ->
%% Tell everybody to adopt orphan tables
im_running(OldFriends, NewFriends),
im_running(NewFriends, OldFriends),
-
- try_merge_schema(Nodes, UserFun);
+ Told = case lists:member(node(), NewFriends) of
+ true -> Told0 ++ OldFriends;
+ false -> Told0 ++ NewFriends
+ end,
+ try_merge_schema(Nodes, Told, UserFun);
{atomic, {"Cannot get cstructs", Node, Reason}} ->
dbg_out("Cannot get cstructs, Node ~p ~p~n", [Node, Reason]),
- timer:sleep(1000), % Avoid a endless loop look alike
- try_merge_schema(Nodes, UserFun);
+ timer:sleep(300), % Avoid a endless loop look alike
+ try_merge_schema(Nodes, Told0, UserFun);
+ {aborted, {shutdown, _}} -> %% One of the nodes is going down
+ timer:sleep(300), % Avoid a endless loop look alike
+ try_merge_schema(Nodes, Told0, UserFun);
Other ->
Other
end.
@@ -915,6 +927,7 @@ handle_cast(unblock_controller, State) ->
handle_cast({mnesia_down, Node}, State) ->
maybe_log_mnesia_down(Node),
mnesia_lib:del({current, db_nodes}, Node),
+ mnesia_lib:unset({node_up, Node}),
mnesia_checkpoint:tm_mnesia_down(Node),
Alltabs = val({schema, tables}),
reconfigure_tables(Node, Alltabs),
@@ -977,11 +990,12 @@ handle_cast(Msg, State) when State#state.schema_is_merged /= true ->
%% This must be done after schema_is_merged otherwise adopt_orphan
%% might trigger a table load from wrong nodes as a result of that we don't
%% know which tables we can load safly first.
-handle_cast({im_running, _Node, NewFriends}, State) ->
+handle_cast({im_running, Node, NewFriends}, State) ->
LocalTabs = mnesia_lib:local_active_tables() -- [schema],
RemoveLocalOnly = fun(Tab) -> not val({Tab, local_content}) end,
Tabs = lists:filter(RemoveLocalOnly, LocalTabs),
- Ns = mnesia_lib:intersect(NewFriends, val({current, db_nodes})),
+ Nodes = mnesia_lib:union([Node],val({current, db_nodes})),
+ Ns = mnesia_lib:intersect(NewFriends, Nodes),
abcast(Ns, {adopt_orphans, node(), Tabs}),
noreply(State);
@@ -1042,30 +1056,33 @@ handle_cast({master_nodes_updated, Tab, Masters}, State) ->
end;
handle_cast({adopt_orphans, Node, Tabs}, State) ->
-
State2 = node_has_tabs(Tabs, Node, State),
- %% Register the other node as up and running
- mnesia_recover:log_mnesia_up(Node),
- verbose("Logging mnesia_up ~w~n",[Node]),
- mnesia_lib:report_system_event({mnesia_up, Node}),
-
- %% Load orphan tables
- LocalTabs = val({schema, local_tables}) -- [schema],
- Nodes = val({current, db_nodes}),
- {LocalOrphans, RemoteMasters} =
- orphan_tables(LocalTabs, Node, Nodes, [], []),
- Reason = {adopt_orphan, node()},
- mnesia_late_loader:async_late_disc_load(node(), LocalOrphans, Reason),
-
- Fun =
- fun(N) ->
- RemoteOrphans =
- [Tab || {Tab, Ns} <- RemoteMasters,
- lists:member(N, Ns)],
- mnesia_late_loader:maybe_async_late_disc_load(N, RemoteOrphans, Reason)
- end,
- lists:foreach(Fun, Nodes),
+ case ?catch_val({node_up,Node}) of
+ true -> ignore;
+ _ ->
+ %% Register the other node as up and running
+ set({node_up, Node}, true),
+ mnesia_recover:log_mnesia_up(Node),
+ verbose("Logging mnesia_up ~w~n",[Node]),
+ mnesia_lib:report_system_event({mnesia_up, Node}),
+ %% Load orphan tables
+ LocalTabs = val({schema, local_tables}) -- [schema],
+ Nodes = val({current, db_nodes}),
+ {LocalOrphans, RemoteMasters} =
+ orphan_tables(LocalTabs, Node, Nodes, [], []),
+ Reason = {adopt_orphan, node()},
+ mnesia_late_loader:async_late_disc_load(node(), LocalOrphans, Reason),
+
+ Fun =
+ fun(N) ->
+ RemoteOrphans =
+ [Tab || {Tab, Ns} <- RemoteMasters,
+ lists:member(N, Ns)],
+ mnesia_late_loader:maybe_async_late_disc_load(N, RemoteOrphans, Reason)
+ end,
+ lists:foreach(Fun, Nodes)
+ end,
noreply(State2);
handle_cast(Msg, State) ->
--
cgit v1.2.3
From 12634a96eaa9ab3e46ee5d4de771be9a8ddeab28 Mon Sep 17 00:00:00 2001
From: Dan Gudmundsson
Date: Mon, 4 Apr 2011 14:52:23 +0200
Subject: Prepare release
---
lib/mnesia/src/mnesia.appup.src | 30 +++++++++++++++++++-----------
lib/mnesia/vsn.mk | 2 +-
2 files changed, 20 insertions(+), 12 deletions(-)
(limited to 'lib')
diff --git a/lib/mnesia/src/mnesia.appup.src b/lib/mnesia/src/mnesia.appup.src
index 0eff761b61..7bad6c4ea6 100644
--- a/lib/mnesia/src/mnesia.appup.src
+++ b/lib/mnesia/src/mnesia.appup.src
@@ -1,25 +1,33 @@
%% -*- erlang -*-
{"%VSN%",
[
- {"4.4.16",[
- {update, mnesia_frag, soft, soft_purge, soft_purge, []},
- {update, mnesia_schema, soft, soft_purge, soft_purge, []}
+ {"4.4.17",[
+ {update, mnesia_controller, soft, soft_purge, soft_purge, []}
]},
- {"4.4.15",[
- {update, mnesia_frag, soft, soft_purge, soft_purge, []},
- {update, mnesia, soft, soft_purge, soft_purge, []},
- {update, mnesia_dumper, soft, soft_purge, soft_purge, []}
- ]}
- ],
- [
{"4.4.16",[
+ {update, mnesia_controller, soft, soft_purge, soft_purge, []},
{update, mnesia_frag, soft, soft_purge, soft_purge, []},
{update, mnesia_schema, soft, soft_purge, soft_purge, []}
]},
{"4.4.15",[
+ {update, mnesia_controller, soft, soft_purge, soft_purge, []},
{update, mnesia_frag, soft, soft_purge, soft_purge, []},
{update, mnesia, soft, soft_purge, soft_purge, []},
{update, mnesia_dumper, soft, soft_purge, soft_purge, []}
]}
- ]
+ ],
+ {"4.4.17",[
+ {update, mnesia_controller, soft, soft_purge, soft_purge, []}
+ ]},
+ {"4.4.16",[
+ {update, mnesia_controller, soft, soft_purge, soft_purge, []},
+ {update, mnesia_frag, soft, soft_purge, soft_purge, []},
+ {update, mnesia_schema, soft, soft_purge, soft_purge, []}
+ ]},
+ {"4.4.15",[
+ {update, mnesia_controller, soft, soft_purge, soft_purge, []},
+ {update, mnesia_frag, soft, soft_purge, soft_purge, []},
+ {update, mnesia, soft, soft_purge, soft_purge, []},
+ {update, mnesia_dumper, soft, soft_purge, soft_purge, []}
+ ]}
}.
diff --git a/lib/mnesia/vsn.mk b/lib/mnesia/vsn.mk
index 5247657b68..38e1a94545 100644
--- a/lib/mnesia/vsn.mk
+++ b/lib/mnesia/vsn.mk
@@ -1 +1 @@
-MNESIA_VSN = 4.4.17
+MNESIA_VSN = 4.4.18
--
cgit v1.2.3
From 6a3ff7ea9207bc18d2ca13666dcc286cbafa7de6 Mon Sep 17 00:00:00 2001
From: Erlang/OTP
Date: Mon, 4 Apr 2011 15:31:36 +0200
Subject: Update release notes
---
lib/mnesia/doc/src/notes.xml | 30 +++++++++++++++++++++++++++++-
1 file changed, 29 insertions(+), 1 deletion(-)
(limited to 'lib')
diff --git a/lib/mnesia/doc/src/notes.xml b/lib/mnesia/doc/src/notes.xml
index ccf70b8373..19574a1434 100644
--- a/lib/mnesia/doc/src/notes.xml
+++ b/lib/mnesia/doc/src/notes.xml
@@ -38,7 +38,35 @@
thus constitutes one section in this document. The title of each
section is the version number of Mnesia.
- Mnesia 4.4.17
+ Mnesia 4.4.18
+
+ Fixed Bugs and Malfunctions
+
+ -
+
+ Call chmod without the "-f" flag
+
+ "-f" is a non-standard chmod option which at least SGI
+ IRIX and HP UX do not support. As the only effect of the
+ "-f" flag is to suppress warning messages, it can be
+ safely omitted. (Thanks to Holger Weiß)
+
+ Own Id: OTP-9170
+
+ -
+
+ Mnesia sometimes failed to update meta-information in
+ large systems, which could cause table content to be
+ inconsistent between nodes.
+
+ Own Id: OTP-9186 Aux Id: seq11728
+
+
+
+
+
+
+Mnesia 4.4.17
Fixed Bugs and Malfunctions
--
cgit v1.2.3