diff options
405 files changed, 7849 insertions, 4148 deletions
diff --git a/.gitignore b/.gitignore index 409be555fb..b35a6c1c31 100644 --- a/.gitignore +++ b/.gitignore @@ -179,6 +179,7 @@ make/win32/ # common_test +/lib/common_test/doc/src/ct_slave.xml /lib/common_test/priv/install.sh # compiler diff --git a/bootstrap/bin/start.boot b/bootstrap/bin/start.boot Binary files differindex 19185aed5b..875f1b1c8b 100644 --- a/bootstrap/bin/start.boot +++ b/bootstrap/bin/start.boot diff --git a/bootstrap/bin/start.script b/bootstrap/bin/start.script index a95c743f22..ba1aed08e7 100644 --- a/bootstrap/bin/start.script +++ b/bootstrap/bin/start.script @@ -1,6 +1,6 @@ -%% script generated at {2011,3,11} {15,30,43} +%% script generated at {2011,3,30} {10,45,5} {script, - {"OTP APN 181 01","R14B02"}, + {"OTP APN 181 01","R14B03"}, [{preLoaded, [erl_prim_loader,erlang,init,otp_ring0,prim_file,prim_inet,prim_zip, zlib]}, @@ -43,7 +43,7 @@ {application_controller,start, [{application,kernel, [{description,"ERTS CXC 138 10"}, - {vsn,"2.14.3"}, + {vsn,"2.14.4"}, {id,[]}, {modules, [application,application_controller,application_master, @@ -80,7 +80,7 @@ {application,load, [{application,stdlib, [{description,"ERTS CXC 138 10"}, - {vsn,"1.17.3"}, + {vsn,"1.17.4"}, {id,[]}, {modules, [array,base64,beam_lib,binary,c,calendar,dets, diff --git a/bootstrap/bin/start_clean.boot b/bootstrap/bin/start_clean.boot Binary files differindex 19185aed5b..875f1b1c8b 100644 --- a/bootstrap/bin/start_clean.boot +++ b/bootstrap/bin/start_clean.boot diff --git a/bootstrap/bin/start_clean.script b/bootstrap/bin/start_clean.script index a95c743f22..ba1aed08e7 100644 --- a/bootstrap/bin/start_clean.script +++ b/bootstrap/bin/start_clean.script @@ -1,6 +1,6 @@ -%% script generated at {2011,3,11} {15,30,43} +%% script generated at {2011,3,30} {10,45,5} {script, - {"OTP APN 181 01","R14B02"}, + {"OTP APN 181 01","R14B03"}, [{preLoaded, [erl_prim_loader,erlang,init,otp_ring0,prim_file,prim_inet,prim_zip, zlib]}, @@ -43,7 +43,7 @@ {application_controller,start, [{application,kernel, [{description,"ERTS CXC 138 10"}, - {vsn,"2.14.3"}, + {vsn,"2.14.4"}, {id,[]}, {modules, [application,application_controller,application_master, @@ -80,7 +80,7 @@ {application,load, [{application,stdlib, [{description,"ERTS CXC 138 10"}, - {vsn,"1.17.3"}, + {vsn,"1.17.4"}, {id,[]}, {modules, [array,base64,beam_lib,binary,c,calendar,dets, diff --git a/bootstrap/lib/compiler/ebin/beam_asm.beam b/bootstrap/lib/compiler/ebin/beam_asm.beam Binary files differindex e31cf11d61..5719592cae 100644 --- a/bootstrap/lib/compiler/ebin/beam_asm.beam +++ b/bootstrap/lib/compiler/ebin/beam_asm.beam diff --git a/bootstrap/lib/compiler/ebin/beam_dict.beam b/bootstrap/lib/compiler/ebin/beam_dict.beam Binary files differindex 6e3c32607e..b65ebca3cd 100644 --- a/bootstrap/lib/compiler/ebin/beam_dict.beam +++ b/bootstrap/lib/compiler/ebin/beam_dict.beam diff --git a/bootstrap/lib/compiler/ebin/compiler.app b/bootstrap/lib/compiler/ebin/compiler.app index 634f5c9a80..b7518ff62f 100644 --- a/bootstrap/lib/compiler/ebin/compiler.app +++ b/bootstrap/lib/compiler/ebin/compiler.app @@ -1,7 +1,7 @@ % This is an -*- erlang -*- file. %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1997-2011. All Rights Reserved. +%% Copyright Ericsson AB 1997-2010. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -18,7 +18,7 @@ {application, compiler, [{description, "ERTS CXC 138 10"}, - {vsn, "4.7.2"}, + {vsn, "4.7.3"}, {modules, [ beam_asm, beam_block, diff --git a/bootstrap/lib/compiler/ebin/sys_core_fold.beam b/bootstrap/lib/compiler/ebin/sys_core_fold.beam Binary files differindex f780a2fae6..c7b247762c 100644 --- a/bootstrap/lib/compiler/ebin/sys_core_fold.beam +++ b/bootstrap/lib/compiler/ebin/sys_core_fold.beam diff --git a/bootstrap/lib/compiler/ebin/v3_core.beam b/bootstrap/lib/compiler/ebin/v3_core.beam Binary files differindex 7a60d7b23d..87cb60e41c 100644 --- a/bootstrap/lib/compiler/ebin/v3_core.beam +++ b/bootstrap/lib/compiler/ebin/v3_core.beam diff --git a/bootstrap/lib/compiler/egen/core_parse.erl b/bootstrap/lib/compiler/egen/core_parse.erl index 702c1a1f29..b99bc0dbc3 100644 --- a/bootstrap/lib/compiler/egen/core_parse.erl +++ b/bootstrap/lib/compiler/egen/core_parse.erl @@ -13,11 +13,11 @@ tok_val(T) -> element(3, T). tok_line(T) -> element(2, T). --file("/usr/local/otp/releases/sles10_32_R14B01_patched/lib/parsetools-2.0.5/include/yeccpre.hrl", 0). +-file("/usr/local/otp/releases/sles10_32_R14B02_patched/lib/parsetools-2.0.5/include/yeccpre.hrl", 0). %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2011. All Rights Reserved. +%% Copyright Ericsson AB 1996-2010. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -196,7 +196,7 @@ yecctoken2string(Other) -> --file("/ldisk/egil/git/otp/bootstrap/lib/compiler/egen/core_parse.erl", 199). +-file("/ldisk/bjorn/otp/bootstrap/lib/compiler/egen/core_parse.erl", 199). yeccpars2(0=S, Cat, Ss, Stack, T, Ts, Tzr) -> yeccpars2_0(S, Cat, Ss, Stack, T, Ts, Tzr); diff --git a/bootstrap/lib/kernel/ebin/hipe_unified_loader.beam b/bootstrap/lib/kernel/ebin/hipe_unified_loader.beam Binary files differindex 5819c340b3..0bab2d23c7 100644 --- a/bootstrap/lib/kernel/ebin/hipe_unified_loader.beam +++ b/bootstrap/lib/kernel/ebin/hipe_unified_loader.beam diff --git a/bootstrap/lib/kernel/ebin/kernel.app b/bootstrap/lib/kernel/ebin/kernel.app index 920213d720..296382abc2 100644 --- a/bootstrap/lib/kernel/ebin/kernel.app +++ b/bootstrap/lib/kernel/ebin/kernel.app @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2011. All Rights Reserved. +%% Copyright Ericsson AB 1996-2009. 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 @@ -21,7 +21,7 @@ {application, kernel, [ {description, "ERTS CXC 138 10"}, - {vsn, "2.14.3"}, + {vsn, "2.14.4"}, {modules, [application, application_controller, application_master, diff --git a/bootstrap/lib/kernel/include/inet.hrl b/bootstrap/lib/kernel/include/inet.hrl index 4afe935a03..929b2ee294 100644 --- a/bootstrap/lib/kernel/include/inet.hrl +++ b/bootstrap/lib/kernel/include/inet.hrl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1997-2011. All Rights Reserved. +%% Copyright Ericsson AB 1997-2009. 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 diff --git a/bootstrap/lib/kernel/include/inet_sctp.hrl b/bootstrap/lib/kernel/include/inet_sctp.hrl index 3c072cc1db..169ba013aa 100644 --- a/bootstrap/lib/kernel/include/inet_sctp.hrl +++ b/bootstrap/lib/kernel/include/inet_sctp.hrl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2007-2011. All Rights Reserved. +%% Copyright Ericsson AB 2007-2009. 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 diff --git a/bootstrap/lib/orber/include/Makefile b/bootstrap/lib/orber/include/Makefile index 5aaeed1015..219b7085e6 100644 --- a/bootstrap/lib/orber/include/Makefile +++ b/bootstrap/lib/orber/include/Makefile @@ -1,7 +1,7 @@ # # %CopyrightBegin% # -# Copyright Ericsson AB 1998-2011. All Rights Reserved. +# Copyright Ericsson AB 1998-2009. 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 diff --git a/bootstrap/lib/orber/include/corba.hrl b/bootstrap/lib/orber/include/corba.hrl index 526662d59d..b9869855bf 100644 --- a/bootstrap/lib/orber/include/corba.hrl +++ b/bootstrap/lib/orber/include/corba.hrl @@ -2,7 +2,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1997-2011. All Rights Reserved. +%% Copyright Ericsson AB 1997-2009. 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 diff --git a/bootstrap/lib/orber/include/orber_pi.hrl b/bootstrap/lib/orber/include/orber_pi.hrl index 69f14a5165..84231758fe 100644 --- a/bootstrap/lib/orber/include/orber_pi.hrl +++ b/bootstrap/lib/orber/include/orber_pi.hrl @@ -2,7 +2,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2000-2011. All Rights Reserved. +%% Copyright Ericsson AB 2000-2009. 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 diff --git a/bootstrap/lib/stdlib/ebin/erl_parse.beam b/bootstrap/lib/stdlib/ebin/erl_parse.beam Binary files differindex 5d62fa70df..753080584f 100644 --- a/bootstrap/lib/stdlib/ebin/erl_parse.beam +++ b/bootstrap/lib/stdlib/ebin/erl_parse.beam diff --git a/bootstrap/lib/stdlib/ebin/erl_pp.beam b/bootstrap/lib/stdlib/ebin/erl_pp.beam Binary files differindex 2b6f0a5bd6..8036376515 100644 --- a/bootstrap/lib/stdlib/ebin/erl_pp.beam +++ b/bootstrap/lib/stdlib/ebin/erl_pp.beam diff --git a/bootstrap/lib/stdlib/ebin/log_mf_h.beam b/bootstrap/lib/stdlib/ebin/log_mf_h.beam Binary files differindex 70b887857c..04c1bf5824 100644 --- a/bootstrap/lib/stdlib/ebin/log_mf_h.beam +++ b/bootstrap/lib/stdlib/ebin/log_mf_h.beam diff --git a/bootstrap/lib/stdlib/ebin/stdlib.app b/bootstrap/lib/stdlib/ebin/stdlib.app index 629a0c5517..ac8b4ec113 100644 --- a/bootstrap/lib/stdlib/ebin/stdlib.app +++ b/bootstrap/lib/stdlib/ebin/stdlib.app @@ -2,7 +2,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2011. All Rights Reserved. +%% Copyright Ericsson AB 1996-2010. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -19,7 +19,7 @@ %% {application, stdlib, [{description, "ERTS CXC 138 10"}, - {vsn, "1.17.3"}, + {vsn, "1.17.4"}, {modules, [array, base64, beam_lib, diff --git a/bootstrap/lib/stdlib/egen/erl_parse.erl b/bootstrap/lib/stdlib/egen/erl_parse.erl index d6c13ba20a..9999fad385 100644 --- a/bootstrap/lib/stdlib/egen/erl_parse.erl +++ b/bootstrap/lib/stdlib/egen/erl_parse.erl @@ -258,7 +258,8 @@ record_fields([{typed,Expr,TypeInfo}|Fields]) -> {atom, La, _} -> case has_undefined(TypeInfo) of false -> - lift_unions(abstract(undefined, La), TypeInfo); + TypeInfo2 = maybe_add_paren(TypeInfo), + lift_unions(abstract(undefined, La), TypeInfo2); true -> TypeInfo end @@ -279,6 +280,11 @@ has_undefined({type,_,union,Ts}) -> has_undefined(_) -> false. +maybe_add_paren({ann_type,L,T}) -> + {paren_type,L,[{ann_type,L,T}]}; +maybe_add_paren(T) -> + T. + term(Expr) -> try normalise(Expr) catch _:_R -> ret_err(?line(Expr), "bad attribute") @@ -556,11 +562,11 @@ get_attribute(L, Name) -> get_attributes(L) -> erl_scan:attributes_info(L). --file("/usr/local/otp/releases/sles10_32_R14B01_patched/lib/parsetools-2.0.5/include/yeccpre.hrl", 0). +-file("/usr/local/otp/releases/sles10_32_R14B02_patched/lib/parsetools-2.0.5/include/yeccpre.hrl", 0). %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2011. All Rights Reserved. +%% Copyright Ericsson AB 1996-2010. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -739,7 +745,7 @@ yecctoken2string(Other) -> --file("/ldisk/egil/git/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 742). +-file("/ldisk/bjorn/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 748). yeccpars2(0=S, Cat, Ss, Stack, T, Ts, Tzr) -> yeccpars2_0(S, Cat, Ss, Stack, T, Ts, Tzr); @@ -8195,7 +8201,7 @@ yeccpars2_39_(__Stack0) -> [ __1 ] end | __Stack]. --file("/ldisk/egil/git/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 8198). +-file("/ldisk/bjorn/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 8204). -compile({inline,yeccpars2_46_/1}). -file("erl_parse.yrl", 434). yeccpars2_46_(__Stack0) -> @@ -8204,7 +8210,7 @@ yeccpars2_46_(__Stack0) -> { [ ] , ? line ( __1 ) } end | __Stack]. --file("/ldisk/egil/git/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 8207). +-file("/ldisk/bjorn/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 8213). -compile({inline,yeccpars2_70_/1}). -file("erl_parse.yrl", 325). yeccpars2_70_(__Stack0) -> @@ -8213,7 +8219,7 @@ yeccpars2_70_(__Stack0) -> { tuple , ? line ( __1 ) , [ ] } end | __Stack]. --file("/ldisk/egil/git/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 8216). +-file("/ldisk/bjorn/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 8222). -compile({inline,yeccpars2_71_/1}). -file("erl_parse.yrl", 326). yeccpars2_71_(__Stack0) -> @@ -8222,7 +8228,7 @@ yeccpars2_71_(__Stack0) -> { tuple , ? line ( __1 ) , __2 } end | __Stack]. --file("/ldisk/egil/git/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 8225). +-file("/ldisk/bjorn/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 8231). -compile({inline,yeccpars2_73_/1}). -file("erl_parse.yrl", 408). yeccpars2_73_(__Stack0) -> @@ -8254,7 +8260,7 @@ yeccpars2_81_(__Stack0) -> [ __1 | __3 ] end | __Stack]. --file("/ldisk/egil/git/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 8257). +-file("/ldisk/bjorn/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 8263). -compile({inline,yeccpars2_82_/1}). -file("erl_parse.yrl", 406). yeccpars2_82_(__Stack0) -> @@ -8287,7 +8293,7 @@ yeccpars2_88_(__Stack0) -> [ __1 | __3 ] end | __Stack]. --file("/ldisk/egil/git/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 8290). +-file("/ldisk/bjorn/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 8296). -compile({inline,yeccpars2_89_/1}). -file("erl_parse.yrl", 381). yeccpars2_89_(__Stack0) -> @@ -8326,7 +8332,7 @@ yeccpars2_98_(__Stack0) -> [ ] end | __Stack0]. --file("/ldisk/egil/git/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 8329). +-file("/ldisk/bjorn/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 8335). -compile({inline,yeccpars2_100_/1}). -file("erl_parse.yrl", 427). yeccpars2_100_(__Stack0) -> @@ -8343,7 +8349,7 @@ yeccpars2_102_(__Stack0) -> [ ] end | __Stack0]. --file("/ldisk/egil/git/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 8346). +-file("/ldisk/bjorn/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 8352). -compile({inline,yeccpars2_104_/1}). -file("erl_parse.yrl", 424). yeccpars2_104_(__Stack0) -> @@ -8353,7 +8359,7 @@ yeccpars2_104_(__Stack0) -> { clause , L , [ { tuple , L , [ __1 , __3 , { var , L , '_' } ] } ] , __4 , __5 } end | __Stack]. --file("/ldisk/egil/git/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 8356). +-file("/ldisk/bjorn/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 8362). -compile({inline,yeccpars2_106_/1}). -file("erl_parse.yrl", 421). yeccpars2_106_(__Stack0) -> @@ -8395,7 +8401,7 @@ yeccpars2_114_(__Stack0) -> { [ ] , __2 } end | __Stack]. --file("/ldisk/egil/git/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 8398). +-file("/ldisk/bjorn/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 8404). -compile({inline,yeccpars2_115_/1}). -file("erl_parse.yrl", 452). yeccpars2_115_(__Stack0) -> @@ -8404,7 +8410,7 @@ yeccpars2_115_(__Stack0) -> { string , ? line ( __1 ) , element ( 3 , __1 ) ++ element ( 3 , __2 ) } end | __Stack]. --file("/ldisk/egil/git/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 8407). +-file("/ldisk/bjorn/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 8413). -compile({inline,yeccpars2_120_/1}). -file("erl_parse.yrl", 386). yeccpars2_120_(__Stack0) -> @@ -8413,7 +8419,7 @@ yeccpars2_120_(__Stack0) -> { 'receive' , ? line ( __1 ) , [ ] , __3 , __4 } end | __Stack]. --file("/ldisk/egil/git/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 8416). +-file("/ldisk/bjorn/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 8422). -compile({inline,yeccpars2_122_/1}). -file("erl_parse.yrl", 384). yeccpars2_122_(__Stack0) -> @@ -8422,7 +8428,7 @@ yeccpars2_122_(__Stack0) -> { 'receive' , ? line ( __1 ) , __2 } end | __Stack]. --file("/ldisk/egil/git/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 8425). +-file("/ldisk/bjorn/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 8431). -compile({inline,yeccpars2_125_/1}). -file("erl_parse.yrl", 388). yeccpars2_125_(__Stack0) -> @@ -8439,7 +8445,7 @@ yeccpars2_131_(__Stack0) -> [ __1 ] end | __Stack]. --file("/ldisk/egil/git/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 8442). +-file("/ldisk/bjorn/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 8448). -compile({inline,yeccpars2_135_/1}). -file("erl_parse.yrl", 323). yeccpars2_135_(__Stack0) -> @@ -8448,7 +8454,7 @@ yeccpars2_135_(__Stack0) -> { b_generate , ? line ( __2 ) , __1 , __3 } end | __Stack]. --file("/ldisk/egil/git/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 8451). +-file("/ldisk/bjorn/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 8457). -compile({inline,yeccpars2_137_/1}). -file("erl_parse.yrl", 322). yeccpars2_137_(__Stack0) -> @@ -8465,7 +8471,7 @@ yeccpars2_139_(__Stack0) -> [ __1 | __3 ] end | __Stack]. --file("/ldisk/egil/git/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 8468). +-file("/ldisk/bjorn/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 8474). -compile({inline,yeccpars2_140_/1}). -file("erl_parse.yrl", 315). yeccpars2_140_(__Stack0) -> @@ -8474,7 +8480,7 @@ yeccpars2_140_(__Stack0) -> { lc , ? line ( __1 ) , __2 , __4 } end | __Stack]. --file("/ldisk/egil/git/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 8477). +-file("/ldisk/bjorn/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 8483). -compile({inline,yeccpars2_141_/1}). -file("erl_parse.yrl", 431). yeccpars2_141_(__Stack0) -> @@ -8491,7 +8497,7 @@ yeccpars2_143_(__Stack0) -> [ __1 ] end | __Stack]. --file("/ldisk/egil/git/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 8494). +-file("/ldisk/bjorn/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 8500). -compile({inline,yeccpars2_145_/1}). -file("erl_parse.yrl", 371). yeccpars2_145_(__Stack0) -> @@ -8508,7 +8514,7 @@ yeccpars2_147_(__Stack0) -> [ __1 | __3 ] end | __Stack]. --file("/ldisk/egil/git/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 8511). +-file("/ldisk/bjorn/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 8517). -compile({inline,yeccpars2_148_/1}). -file("erl_parse.yrl", 365). yeccpars2_148_(__Stack0) -> @@ -8532,7 +8538,7 @@ yeccpars2_151_(__Stack0) -> [ ] end | __Stack0]. --file("/ldisk/egil/git/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 8535). +-file("/ldisk/bjorn/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 8541). -compile({inline,yeccpars2_157_/1}). -file("erl_parse.yrl", 394). yeccpars2_157_(__Stack0) -> @@ -8541,7 +8547,7 @@ yeccpars2_157_(__Stack0) -> { 'fun' , ? line ( __1 ) , { function , element ( 3 , __2 ) , element ( 3 , __4 ) , element ( 3 , __6 ) } } end | __Stack]. --file("/ldisk/egil/git/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 8544). +-file("/ldisk/bjorn/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 8550). -compile({inline,yeccpars2_158_/1}). -file("erl_parse.yrl", 392). yeccpars2_158_(__Stack0) -> @@ -8567,7 +8573,7 @@ yeccpars2_162_(__Stack0) -> [ __1 | __3 ] end | __Stack]. --file("/ldisk/egil/git/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 8570). +-file("/ldisk/bjorn/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 8576). -compile({inline,yeccpars2_163_/1}). -file("erl_parse.yrl", 396). yeccpars2_163_(__Stack0) -> @@ -8576,7 +8582,7 @@ yeccpars2_163_(__Stack0) -> build_fun ( ? line ( __1 ) , __2 ) end | __Stack]. --file("/ldisk/egil/git/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 8579). +-file("/ldisk/bjorn/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 8585). -compile({inline,yeccpars2_164_/1}). -file("erl_parse.yrl", 214). yeccpars2_164_(__Stack0) -> @@ -8585,7 +8591,7 @@ yeccpars2_164_(__Stack0) -> { 'catch' , ? line ( __1 ) , __2 } end | __Stack]. --file("/ldisk/egil/git/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 8588). +-file("/ldisk/bjorn/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 8594). -compile({inline,yeccpars2_168_/1}). -file("erl_parse.yrl", 375). yeccpars2_168_(__Stack0) -> @@ -8594,7 +8600,7 @@ yeccpars2_168_(__Stack0) -> { 'case' , ? line ( __1 ) , __2 , __4 } end | __Stack]. --file("/ldisk/egil/git/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 8597). +-file("/ldisk/bjorn/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 8603). -compile({inline,yeccpars2_170_/1}). -file("erl_parse.yrl", 270). yeccpars2_170_(__Stack0) -> @@ -8603,7 +8609,7 @@ yeccpars2_170_(__Stack0) -> { block , ? line ( __1 ) , __2 } end | __Stack]. --file("/ldisk/egil/git/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 8606). +-file("/ldisk/bjorn/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 8612). -compile({inline,yeccpars2_172_/1}). -file("erl_parse.yrl", 279). yeccpars2_172_(__Stack0) -> @@ -8612,7 +8618,7 @@ yeccpars2_172_(__Stack0) -> { nil , ? line ( __1 ) } end | __Stack]. --file("/ldisk/egil/git/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 8615). +-file("/ldisk/bjorn/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 8621). -compile({inline,yeccpars2_173_/1}). -file("erl_parse.yrl", 280). yeccpars2_173_(__Stack0) -> @@ -8621,7 +8627,7 @@ yeccpars2_173_(__Stack0) -> { cons , ? line ( __1 ) , __2 , __3 } end | __Stack]. --file("/ldisk/egil/git/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 8624). +-file("/ldisk/bjorn/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 8630). -compile({inline,yeccpars2_175_/1}). -file("erl_parse.yrl", 282). yeccpars2_175_(__Stack0) -> @@ -8638,7 +8644,7 @@ yeccpars2_178_(__Stack0) -> __2 end | __Stack]. --file("/ldisk/egil/git/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 8641). +-file("/ldisk/bjorn/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 8647). -compile({inline,yeccpars2_180_/1}). -file("erl_parse.yrl", 284). yeccpars2_180_(__Stack0) -> @@ -8662,7 +8668,7 @@ yeccpars2_186_(__Stack0) -> [ __1 ] end | __Stack]. --file("/ldisk/egil/git/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 8665). +-file("/ldisk/bjorn/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 8671). -compile({inline,yeccpars2_187_/1}). -file("erl_parse.yrl", 287). yeccpars2_187_(__Stack0) -> @@ -8679,7 +8685,7 @@ yeccpars2_189_(__Stack0) -> [ __1 | __3 ] end | __Stack]. --file("/ldisk/egil/git/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 8682). +-file("/ldisk/bjorn/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 8688). -compile({inline,yeccpars2_190_/1}). -file("erl_parse.yrl", 288). yeccpars2_190_(__Stack0) -> @@ -8688,7 +8694,7 @@ yeccpars2_190_(__Stack0) -> { bin , ? line ( __1 ) , __2 } end | __Stack]. --file("/ldisk/egil/git/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 8691). +-file("/ldisk/bjorn/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 8697). -compile({inline,yeccpars2_193_/1}). -file("erl_parse.yrl", 317). yeccpars2_193_(__Stack0) -> @@ -8712,7 +8718,7 @@ yeccpars2_197_(__Stack0) -> __2 end | __Stack]. --file("/ldisk/egil/git/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 8715). +-file("/ldisk/bjorn/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 8721). -compile({inline,yeccpars2_198_/1}). -file("erl_parse.yrl", 294). yeccpars2_198_(__Stack0) -> @@ -8761,7 +8767,7 @@ yeccpars2_206_(__Stack0) -> [ __1 | __3 ] end | __Stack]. --file("/ldisk/egil/git/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 8764). +-file("/ldisk/bjorn/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 8770). -compile({inline,yeccpars2_207_/1}). -file("erl_parse.yrl", 296). yeccpars2_207_(__Stack0) -> @@ -8770,7 +8776,7 @@ yeccpars2_207_(__Stack0) -> ? mkop1 ( __1 , __2 ) end | __Stack]. --file("/ldisk/egil/git/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 8773). +-file("/ldisk/bjorn/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 8779). -compile({inline,yeccpars2_208_/1}). -file("erl_parse.yrl", 256). yeccpars2_208_(__Stack0) -> @@ -8787,7 +8793,7 @@ yeccpars2_210_(__Stack0) -> __2 end | __Stack]. --file("/ldisk/egil/git/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 8790). +-file("/ldisk/bjorn/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 8796). -compile({inline,yeccpars2_212_/1}). -file("erl_parse.yrl", 340). yeccpars2_212_(__Stack0) -> @@ -8812,7 +8818,7 @@ yeccpars2_219_(__Stack0) -> [ ] end | __Stack]. --file("/ldisk/egil/git/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 8815). +-file("/ldisk/bjorn/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 8821). -compile({inline,yeccpars2_221_/1}). -file("erl_parse.yrl", 356). yeccpars2_221_(__Stack0) -> @@ -8821,7 +8827,7 @@ yeccpars2_221_(__Stack0) -> { record_field , ? line ( __1 ) , __1 , __3 } end | __Stack]. --file("/ldisk/egil/git/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 8824). +-file("/ldisk/bjorn/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 8830). -compile({inline,yeccpars2_223_/1}). -file("erl_parse.yrl", 357). yeccpars2_223_(__Stack0) -> @@ -8846,7 +8852,7 @@ yeccpars2_226_(__Stack0) -> __2 end | __Stack]. --file("/ldisk/egil/git/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 8849). +-file("/ldisk/bjorn/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 8855). -compile({inline,yeccpars2_227_/1}). -file("erl_parse.yrl", 338). yeccpars2_227_(__Stack0) -> @@ -8863,7 +8869,7 @@ yeccpars2_229_(__Stack0) -> [ __1 | __3 ] end | __Stack]. --file("/ldisk/egil/git/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 8866). +-file("/ldisk/bjorn/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 8872). -compile({inline,yeccpars2_232_/1}). -file("erl_parse.yrl", 217). yeccpars2_232_(__Stack0) -> @@ -8872,7 +8878,7 @@ yeccpars2_232_(__Stack0) -> { match , ? line ( __2 ) , __1 , __3 } end | __Stack]. --file("/ldisk/egil/git/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 8875). +-file("/ldisk/bjorn/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 8881). -compile({inline,yeccpars2_233_/1}). -file("erl_parse.yrl", 218). yeccpars2_233_(__Stack0) -> @@ -8881,7 +8887,7 @@ yeccpars2_233_(__Stack0) -> ? mkop2 ( __1 , __2 , __3 ) end | __Stack]. --file("/ldisk/egil/git/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 8884). +-file("/ldisk/bjorn/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 8890). -compile({inline,yeccpars2_235_/1}). -file("erl_parse.yrl", 221). yeccpars2_235_(__Stack0) -> @@ -8890,7 +8896,7 @@ yeccpars2_235_(__Stack0) -> ? mkop2 ( __1 , __2 , __3 ) end | __Stack]. --file("/ldisk/egil/git/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 8893). +-file("/ldisk/bjorn/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 8899). -compile({inline,yeccpars2_237_/1}). -file("erl_parse.yrl", 224). yeccpars2_237_(__Stack0) -> @@ -8899,7 +8905,7 @@ yeccpars2_237_(__Stack0) -> ? mkop2 ( __1 , __2 , __3 ) end | __Stack]. --file("/ldisk/egil/git/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 8902). +-file("/ldisk/bjorn/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 8908). -compile({inline,yeccpars2_247_/1}). -file("erl_parse.yrl", 228). yeccpars2_247_(__Stack0) -> @@ -8908,7 +8914,7 @@ yeccpars2_247_(__Stack0) -> ? mkop2 ( __1 , __2 , __3 ) end | __Stack]. --file("/ldisk/egil/git/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 8911). +-file("/ldisk/bjorn/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 8917). -compile({inline,yeccpars2_260_/1}). -file("erl_parse.yrl", 236). yeccpars2_260_(__Stack0) -> @@ -8917,7 +8923,7 @@ yeccpars2_260_(__Stack0) -> ? mkop2 ( __1 , __2 , __3 ) end | __Stack]. --file("/ldisk/egil/git/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 8920). +-file("/ldisk/bjorn/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 8926). -compile({inline,yeccpars2_268_/1}). -file("erl_parse.yrl", 240). yeccpars2_268_(__Stack0) -> @@ -8926,7 +8932,7 @@ yeccpars2_268_(__Stack0) -> ? mkop2 ( __1 , __2 , __3 ) end | __Stack]. --file("/ldisk/egil/git/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 8929). +-file("/ldisk/bjorn/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 8935). -compile({inline,yeccpars2_269_/1}). -file("erl_parse.yrl", 232). yeccpars2_269_(__Stack0) -> @@ -8935,7 +8941,7 @@ yeccpars2_269_(__Stack0) -> ? mkop2 ( __1 , __2 , __3 ) end | __Stack]. --file("/ldisk/egil/git/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 8938). +-file("/ldisk/bjorn/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 8944). -compile({inline,yeccpars2_270_/1}). -file("erl_parse.yrl", 362). yeccpars2_270_(__Stack0) -> @@ -8944,7 +8950,7 @@ yeccpars2_270_(__Stack0) -> { call , ? line ( __1 ) , __1 , element ( 1 , __2 ) } end | __Stack]. --file("/ldisk/egil/git/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 8947). +-file("/ldisk/bjorn/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 8953). -compile({inline,yeccpars2_273_/1}). -file("erl_parse.yrl", 252). yeccpars2_273_(__Stack0) -> @@ -8953,7 +8959,7 @@ yeccpars2_273_(__Stack0) -> { remote , ? line ( __2 ) , __1 , __3 } end | __Stack]. --file("/ldisk/egil/git/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 8956). +-file("/ldisk/bjorn/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 8962). -compile({inline,yeccpars2_274_/1}). -file("erl_parse.yrl", 258). yeccpars2_274_(__Stack0) -> @@ -8962,7 +8968,7 @@ yeccpars2_274_(__Stack0) -> { record_field , ? line ( __2 ) , __1 , __3 } end | __Stack]. --file("/ldisk/egil/git/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 8965). +-file("/ldisk/bjorn/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 8971). -compile({inline,yeccpars2_277_/1}). -file("erl_parse.yrl", 344). yeccpars2_277_(__Stack0) -> @@ -8971,7 +8977,7 @@ yeccpars2_277_(__Stack0) -> { record , ? line ( __2 ) , __1 , element ( 3 , __3 ) , __4 } end | __Stack]. --file("/ldisk/egil/git/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 8974). +-file("/ldisk/bjorn/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 8980). -compile({inline,yeccpars2_279_/1}). -file("erl_parse.yrl", 342). yeccpars2_279_(__Stack0) -> @@ -8980,7 +8986,7 @@ yeccpars2_279_(__Stack0) -> { record_field , ? line ( __2 ) , __1 , element ( 3 , __3 ) , __5 } end | __Stack]. --file("/ldisk/egil/git/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 8983). +-file("/ldisk/bjorn/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 8989). -compile({inline,yeccpars2_280_/1}). -file("erl_parse.yrl", 435). yeccpars2_280_(__Stack0) -> @@ -8989,7 +8995,7 @@ yeccpars2_280_(__Stack0) -> { __2 , ? line ( __1 ) } end | __Stack]. --file("/ldisk/egil/git/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 8992). +-file("/ldisk/bjorn/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 8998). -compile({inline,yeccpars2_281_/1}). -file("erl_parse.yrl", 244). yeccpars2_281_(__Stack0) -> @@ -8998,7 +9004,7 @@ yeccpars2_281_(__Stack0) -> ? mkop1 ( __1 , __2 ) end | __Stack]. --file("/ldisk/egil/git/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 9001). +-file("/ldisk/bjorn/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 9007). -compile({inline,yeccpars2_284_/1}). -file("erl_parse.yrl", 348). yeccpars2_284_(__Stack0) -> @@ -9007,7 +9013,7 @@ yeccpars2_284_(__Stack0) -> { record , ? line ( __2 ) , __1 , element ( 3 , __3 ) , __4 } end | __Stack]. --file("/ldisk/egil/git/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 9010). +-file("/ldisk/bjorn/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 9016). -compile({inline,yeccpars2_286_/1}). -file("erl_parse.yrl", 346). yeccpars2_286_(__Stack0) -> @@ -9016,7 +9022,7 @@ yeccpars2_286_(__Stack0) -> { record_field , ? line ( __2 ) , __1 , element ( 3 , __3 ) , __5 } end | __Stack]. --file("/ldisk/egil/git/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 9019). +-file("/ldisk/bjorn/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 9025). -compile({inline,yeccpars2_288_/1}). -file("erl_parse.yrl", 493). yeccpars2_288_(__Stack0) -> @@ -9025,7 +9031,7 @@ yeccpars2_288_(__Stack0) -> { clause , ? line ( __1 ) , element ( 3 , __1 ) , __2 , __3 , __4 } end | __Stack]. --file("/ldisk/egil/git/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 9028). +-file("/ldisk/bjorn/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 9034). -compile({inline,yeccpars2_289_/1}). -file("erl_parse.yrl", 203). yeccpars2_289_(__Stack0) -> @@ -9090,7 +9096,7 @@ yeccpars2_318_(__Stack0) -> [ __1 ] end | __Stack]. --file("/ldisk/egil/git/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 9093). +-file("/ldisk/bjorn/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 9099). -compile({inline,yeccpars2_332_/1}). -file("erl_parse.yrl", 152). yeccpars2_332_(__Stack0) -> @@ -9099,7 +9105,7 @@ yeccpars2_332_(__Stack0) -> { type , ? line ( __1 ) , tuple , [ ] } end | __Stack]. --file("/ldisk/egil/git/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 9102). +-file("/ldisk/bjorn/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 9108). -compile({inline,yeccpars2_333_/1}). -file("erl_parse.yrl", 153). yeccpars2_333_(__Stack0) -> @@ -9108,7 +9114,7 @@ yeccpars2_333_(__Stack0) -> { type , ? line ( __1 ) , tuple , __2 } end | __Stack]. --file("/ldisk/egil/git/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 9111). +-file("/ldisk/bjorn/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 9117). -compile({inline,yeccpars2_335_/1}). -file("erl_parse.yrl", 116). yeccpars2_335_(__Stack0) -> @@ -9117,7 +9123,7 @@ yeccpars2_335_(__Stack0) -> { ann_type , ? line ( __1 ) , [ __1 , __3 ] } end | __Stack]. --file("/ldisk/egil/git/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 9120). +-file("/ldisk/bjorn/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 9126). -compile({inline,yeccpars2_341_/1}). -file("erl_parse.yrl", 159). yeccpars2_341_(__Stack0) -> @@ -9126,7 +9132,7 @@ yeccpars2_341_(__Stack0) -> { type , ? line ( __1 ) , 'fun' , [ ] } end | __Stack]. --file("/ldisk/egil/git/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 9129). +-file("/ldisk/bjorn/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 9135). -compile({inline,yeccpars2_345_/1}). -file("erl_parse.yrl", 163). yeccpars2_345_(__Stack0) -> @@ -9144,7 +9150,7 @@ yeccpars2_346_(__Stack0) -> __3 end | __Stack]. --file("/ldisk/egil/git/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 9147). +-file("/ldisk/bjorn/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 9153). -compile({inline,yeccpars2_352_/1}). -file("erl_parse.yrl", 144). yeccpars2_352_(__Stack0) -> @@ -9154,7 +9160,7 @@ yeccpars2_352_(__Stack0) -> [ __1 , __3 , [ ] ] } end | __Stack]. --file("/ldisk/egil/git/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 9157). +-file("/ldisk/bjorn/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 9163). -compile({inline,yeccpars2_353_/1}). -file("erl_parse.yrl", 146). yeccpars2_353_(__Stack0) -> @@ -9172,7 +9178,7 @@ yeccpars2_355_(__Stack0) -> build_gen_type ( __1 ) end | __Stack]. --file("/ldisk/egil/git/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 9175). +-file("/ldisk/bjorn/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 9181). -compile({inline,yeccpars2_356_/1}). -file("erl_parse.yrl", 142). yeccpars2_356_(__Stack0) -> @@ -9182,7 +9188,7 @@ yeccpars2_356_(__Stack0) -> normalise ( __1 ) , __3 } end | __Stack]. --file("/ldisk/egil/git/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 9185). +-file("/ldisk/bjorn/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 9191). -compile({inline,yeccpars2_358_/1}). -file("erl_parse.yrl", 148). yeccpars2_358_(__Stack0) -> @@ -9191,7 +9197,7 @@ yeccpars2_358_(__Stack0) -> { type , ? line ( __1 ) , nil , [ ] } end | __Stack]. --file("/ldisk/egil/git/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 9194). +-file("/ldisk/bjorn/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 9200). -compile({inline,yeccpars2_360_/1}). -file("erl_parse.yrl", 149). yeccpars2_360_(__Stack0) -> @@ -9200,7 +9206,7 @@ yeccpars2_360_(__Stack0) -> { type , ? line ( __1 ) , list , [ __2 ] } end | __Stack]. --file("/ldisk/egil/git/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 9203). +-file("/ldisk/bjorn/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 9209). -compile({inline,yeccpars2_362_/1}). -file("erl_parse.yrl", 150). yeccpars2_362_(__Stack0) -> @@ -9210,7 +9216,7 @@ yeccpars2_362_(__Stack0) -> nonempty_list , [ __2 ] } end | __Stack]. --file("/ldisk/egil/git/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 9213). +-file("/ldisk/bjorn/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 9219). -compile({inline,yeccpars2_365_/1}). -file("erl_parse.yrl", 179). yeccpars2_365_(__Stack0) -> @@ -9237,7 +9243,7 @@ yeccpars2_371_(__Stack0) -> build_bin_type ( [ __1 , __3 ] , __5 ) end | __Stack]. --file("/ldisk/egil/git/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 9240). +-file("/ldisk/bjorn/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 9246). -compile({inline,yeccpars2_373_/1}). -file("erl_parse.yrl", 182). yeccpars2_373_(__Stack0) -> @@ -9247,7 +9253,7 @@ yeccpars2_373_(__Stack0) -> [ __2 , abstract ( 0 , ? line ( __1 ) ) ] } end | __Stack]. --file("/ldisk/egil/git/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 9250). +-file("/ldisk/bjorn/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 9256). -compile({inline,yeccpars2_378_/1}). -file("erl_parse.yrl", 187). yeccpars2_378_(__Stack0) -> @@ -9256,7 +9262,7 @@ yeccpars2_378_(__Stack0) -> { type , ? line ( __1 ) , binary , [ __2 , __4 ] } end | __Stack]. --file("/ldisk/egil/git/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 9259). +-file("/ldisk/bjorn/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 9265). -compile({inline,yeccpars2_379_/1}). -file("erl_parse.yrl", 184). yeccpars2_379_(__Stack0) -> @@ -9266,7 +9272,7 @@ yeccpars2_379_(__Stack0) -> [ abstract ( 0 , ? line ( __1 ) ) , __2 ] } end | __Stack]. --file("/ldisk/egil/git/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 9269). +-file("/ldisk/bjorn/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 9275). -compile({inline,yeccpars2_381_/1}). -file("erl_parse.yrl", 167). yeccpars2_381_(__Stack0) -> @@ -9276,7 +9282,7 @@ yeccpars2_381_(__Stack0) -> [ { type , ? line ( __1 ) , product , [ ] } , __4 ] } end | __Stack]. --file("/ldisk/egil/git/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 9279). +-file("/ldisk/bjorn/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 9285). -compile({inline,yeccpars2_383_/1}). -file("erl_parse.yrl", 138). yeccpars2_383_(__Stack0) -> @@ -9293,7 +9299,7 @@ yeccpars2_387_(__Stack0) -> [ __1 ] end | __Stack]. --file("/ldisk/egil/git/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 9296). +-file("/ldisk/bjorn/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 9302). -compile({inline,yeccpars2_389_/1}). -file("erl_parse.yrl", 154). yeccpars2_389_(__Stack0) -> @@ -9302,7 +9308,7 @@ yeccpars2_389_(__Stack0) -> { type , ? line ( __1 ) , record , [ __2 ] } end | __Stack]. --file("/ldisk/egil/git/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 9305). +-file("/ldisk/bjorn/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 9311). -compile({inline,yeccpars2_391_/1}). -file("erl_parse.yrl", 176). yeccpars2_391_(__Stack0) -> @@ -9320,7 +9326,7 @@ yeccpars2_393_(__Stack0) -> [ __1 | __3 ] end | __Stack]. --file("/ldisk/egil/git/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 9323). +-file("/ldisk/bjorn/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 9329). -compile({inline,yeccpars2_394_/1}). -file("erl_parse.yrl", 155). yeccpars2_394_(__Stack0) -> @@ -9330,7 +9336,7 @@ yeccpars2_394_(__Stack0) -> record , [ __2 | __4 ] } end | __Stack]. --file("/ldisk/egil/git/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 9333). +-file("/ldisk/bjorn/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 9339). -compile({inline,yeccpars2_395_/1}). -file("erl_parse.yrl", 135). yeccpars2_395_(__Stack0) -> @@ -9347,7 +9353,7 @@ yeccpars2_397_(__Stack0) -> [ __1 | __3 ] end | __Stack]. --file("/ldisk/egil/git/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 9350). +-file("/ldisk/bjorn/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 9356). -compile({inline,yeccpars2_400_/1}). -file("erl_parse.yrl", 170). yeccpars2_400_(__Stack0) -> @@ -9365,7 +9371,7 @@ yeccpars2_402_(__Stack0) -> lift_unions ( __1 , __3 ) end | __Stack]. --file("/ldisk/egil/git/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 9368). +-file("/ldisk/bjorn/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 9374). -compile({inline,yeccpars2_405_/1}). -file("erl_parse.yrl", 122). yeccpars2_405_(__Stack0) -> @@ -9376,7 +9382,7 @@ yeccpars2_405_(__Stack0) -> skip_paren ( __3 ) ] } end | __Stack]. --file("/ldisk/egil/git/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 9379). +-file("/ldisk/bjorn/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 9385). -compile({inline,yeccpars2_406_/1}). -file("erl_parse.yrl", 127). yeccpars2_406_(__Stack0) -> @@ -9386,7 +9392,7 @@ yeccpars2_406_(__Stack0) -> __2 , skip_paren ( __3 ) ) end | __Stack]. --file("/ldisk/egil/git/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 9389). +-file("/ldisk/bjorn/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 9395). -compile({inline,yeccpars2_408_/1}). -file("erl_parse.yrl", 131). yeccpars2_408_(__Stack0) -> @@ -9396,7 +9402,7 @@ yeccpars2_408_(__Stack0) -> __2 , skip_paren ( __3 ) ) end | __Stack]. --file("/ldisk/egil/git/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 9399). +-file("/ldisk/bjorn/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 9405). -compile({inline,yeccpars2_410_/1}). -file("erl_parse.yrl", 103). yeccpars2_410_(__Stack0) -> @@ -9422,7 +9428,7 @@ yeccpars2_415_(__Stack0) -> build_def ( __1 , __3 ) end | __Stack]. --file("/ldisk/egil/git/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 9425). +-file("/ldisk/bjorn/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 9431). -compile({inline,yeccpars2_418_/1}). -file("erl_parse.yrl", 109). yeccpars2_418_(__Stack0) -> @@ -9552,7 +9558,7 @@ yeccpars2_446_(__Stack0) -> [ __1 | __3 ] end | __Stack]. --file("/ldisk/egil/git/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 9555). +-file("/ldisk/bjorn/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 9561). -compile({inline,yeccpars2_447_/1}). -file("erl_parse.yrl", 90). yeccpars2_447_(__Stack0) -> @@ -9640,4 +9646,4 @@ yeccpars2_463_(__Stack0) -> end | __Stack0]. --file("erl_parse.yrl", 1057). +-file("erl_parse.yrl", 1063). diff --git a/bootstrap/lib/stdlib/include/erl_bits.hrl b/bootstrap/lib/stdlib/include/erl_bits.hrl index aca213c08c..54ebe58585 100644 --- a/bootstrap/lib/stdlib/include/erl_bits.hrl +++ b/bootstrap/lib/stdlib/include/erl_bits.hrl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1999-2011. All Rights Reserved. +%% Copyright Ericsson AB 1999-2009. 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 diff --git a/bootstrap/lib/stdlib/include/erl_compile.hrl b/bootstrap/lib/stdlib/include/erl_compile.hrl index 2e0d90dfad..f779c4382c 100644 --- a/bootstrap/lib/stdlib/include/erl_compile.hrl +++ b/bootstrap/lib/stdlib/include/erl_compile.hrl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1997-2011. All Rights Reserved. +%% Copyright Ericsson AB 1997-2009. 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 diff --git a/bootstrap/lib/stdlib/include/ms_transform.hrl b/bootstrap/lib/stdlib/include/ms_transform.hrl index 2b89a4df2f..9937d48fef 100644 --- a/bootstrap/lib/stdlib/include/ms_transform.hrl +++ b/bootstrap/lib/stdlib/include/ms_transform.hrl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2002-2011. All Rights Reserved. +%% Copyright Ericsson AB 2002-2009. 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 diff --git a/bootstrap/lib/stdlib/include/qlc.hrl b/bootstrap/lib/stdlib/include/qlc.hrl index cccedcbd2c..067fb83060 100644 --- a/bootstrap/lib/stdlib/include/qlc.hrl +++ b/bootstrap/lib/stdlib/include/qlc.hrl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2004-2011. All Rights Reserved. +%% Copyright Ericsson AB 2004-2009. 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 diff --git a/bootstrap/lib/stdlib/include/zip.hrl b/bootstrap/lib/stdlib/include/zip.hrl index 07e182dc3f..2b5ddc1dfe 100644 --- a/bootstrap/lib/stdlib/include/zip.hrl +++ b/bootstrap/lib/stdlib/include/zip.hrl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2006-2011. All Rights Reserved. +%% Copyright Ericsson AB 2006-2009. 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 diff --git a/erts/configure.in b/erts/configure.in index 627f734409..31d1d55b8a 100644 --- a/erts/configure.in +++ b/erts/configure.in @@ -2,7 +2,7 @@ dnl Process this file with autoconf to produce a configure script. -*-m4-*- dnl %CopyrightBegin% dnl -dnl Copyright Ericsson AB 1997-2010. All Rights Reserved. +dnl Copyright Ericsson AB 1997-2011. All Rights Reserved. dnl dnl The contents of this file are subject to the Erlang Public License, dnl Version 1.1, (the "License"); you may not use this file except in @@ -1793,7 +1793,7 @@ AC_CHECK_FUNCS([getipnodebyname getipnodebyaddr gethostbyname2]) AC_CHECK_FUNCS([ieee_handler fpsetmask finite isnan isinf res_gethostbyname dlopen \ pread pwrite writev memmove strerror strerror_r strncasecmp \ - gethrtime localtime_r gmtime_r mmap mremap memcpy mallopt \ + gethrtime localtime_r gmtime_r inet_pton mmap mremap memcpy mallopt \ sbrk _sbrk __sbrk brk _brk __brk \ flockfile fstat strlcpy strlcat setsid posix2time setlocale nl_langinfo poll]) @@ -2399,9 +2399,15 @@ if test "$cross_compiling" != "yes" && test X${enable_hipe} != Xno; then if test -z "$M4"; then enable_hipe=no AC_MSG_NOTICE([HiPE disabled as no valid m4 is found in PATH]) + elif test "$enable_halfword_emulator" = "yes"; then + if test X${enable_hipe} = Xyes; then + AC_MSG_ERROR([HiPE can not be combined with halfword emulator (yet)]) + else + AC_MSG_NOTICE([HiPE auto-disabled on halfword emulator]) + fi else case "$ARCH-$OPSYS" in - x86-linux|amd64-linux|x86-darwin*|amd64-darwin*|ppc-linux|ppc-darwin|arm-linux|amd64-freebsd|x86-freebsd|x86-sol2|amd64-sol2|ultrasparc-linux) + x86-linux|amd64-linux|x86-darwin*|amd64-darwin*|ppc-linux|ppc64-linux|ppc-darwin|arm-linux|amd64-freebsd|x86-freebsd|x86-sol2|amd64-sol2|ultrasparc-linux) enable_hipe=yes ;; esac @@ -3660,6 +3666,12 @@ case "$erl_xcomp_without_sysroot-$with_ssl" in urp="uninstall/openssl_is1/inno setup: app path" rp="$wrp$urp" if regtool -q get "$rp" > /dev/null; then + true + else + urp="uninstall/openssl (32-bit)_is1/inno setup: app path" + rp="$wrp$urp" + fi + if regtool -q get "$rp" > /dev/null; then ssl_install_dir=`regtool -q get "$rp"` # Try hard to get rid of spaces... if cygpath -d "$ssl_install_dir" > /dev/null 2>&1; then diff --git a/erts/doc/src/driver.xml b/erts/doc/src/driver.xml index db455312ec..2b1ed398ee 100644 --- a/erts/doc/src/driver.xml +++ b/erts/doc/src/driver.xml @@ -63,7 +63,8 @@ <p>This is a simple driver for accessing a postgres database using the libpq C client library. Postgres is used because it's free and open source. For information - on postgres, refer to the website www.postgres.org.</p> + on postgres, refer to the website + <url href="http://www.postgres.org">www.postgres.org</url>.</p> <p>The driver is synchronous, it uses the synchronous calls of the client library. This is only for simplicity, and is generally not good, since it will @@ -210,7 +211,7 @@ static void stop(ErlDrvData drv_data) input data is a string paramater for <c><![CDATA[connect]]></c> and <c><![CDATA[select]]></c>. The returned data consists of Erlang terms.</p> <p>The functions <c><![CDATA[get_s]]></c> and <c><![CDATA[ei_x_to_new_binary]]></c> are - utilities that is used to make the code shorter. <c><![CDATA[get_s]]></c> + utilities that are used to make the code shorter. <c><![CDATA[get_s]]></c> duplicates the string and zero-terminates it, since the postgres client library wants that. <c><![CDATA[ei_x_to_new_binary]]></c> takes an <c><![CDATA[ei_x_buff]]></c> buffer and allocates a binary and @@ -244,7 +245,7 @@ static int control(ErlDrvData drv_data, unsigned int command, char *buf, return r; } ]]></code> - <p>In <c><![CDATA[do_connect]]></c> is where we log in to the database. If the connection + <p><c><![CDATA[do_connect]]></c> is where we log in to the database. If the connection was successful we store the connection handle in our driver data, and return ok. Otherwise, we return the error message from postgres, and store <c><![CDATA[NULL]]></c> in the driver data.</p> @@ -264,7 +265,7 @@ static int do_connect(const char *s, our_data_t* data, ei_x_buff* x) } ]]></code> <p>If we are connected (if the connection handle is not <c><![CDATA[NULL]]></c>), - we log out from the database. We need to check if a we should + we log out from the database. We need to check if we should encode an ok, since we might get here from the <c><![CDATA[stop]]></c> function, which doesn't return data to the emulator.</p> <code type="none"><![CDATA[ @@ -279,7 +280,7 @@ static int do_disconnect(our_data_t* data, ei_x_buff* x) return 0; } ]]></code> - <p>We execute a query and encodes the result. Encoding is done + <p>We execute a query and encode the result. Encoding is done in another C module, <c><![CDATA[pg_encode.c]]></c> which is also provided as sample code.</p> <code type="none"><![CDATA[ @@ -291,7 +292,7 @@ static int do_select(const char* s, our_data_t* data, ei_x_buff* x) return 0; } ]]></code> - <p>Here we simply checks the result from postgres, and + <p>Here we simply check the result from postgres, and if it's data we encode it as lists of lists with column data. Everything from postgres is C strings, so we just use <c><![CDATA[ei_x_encode_string]]></c> to send @@ -392,7 +393,7 @@ disconnect(Port) -> select(Port, Query) -> binary_to_term(port_control(Port, ?DRV_SELECT, Query)). ]]></code> - <p>The api is simple: <c><![CDATA[connect/1]]></c> loads the driver, opens it + <p>The API is simple: <c><![CDATA[connect/1]]></c> loads the driver, opens it and logs on to the database, returning the Erlang port if successful, <c><![CDATA[select/2]]></c> sends a query to the driver, and returns the result, <c><![CDATA[disconnect/1]]></c> closes the @@ -417,7 +418,7 @@ select(Port, Query) -> <p>Sometimes database queries can take long time to complete, in our <c><![CDATA[pg_sync]]></c> driver, the emulator halts while the driver is doing its job. This is - often not acceptable, since no other Erlang processes + often not acceptable, since no other Erlang process gets a chance to do anything. To improve on our postgres driver, we reimplement it using the asynchronous calls in LibPQ.</p> @@ -472,7 +473,7 @@ typedef struct our_data_t { whether the driver is waiting for a connection or waiting for the result of a query. (This is needed since the entry <c><![CDATA[ready_io]]></c> will be called both when connecting and - when there is query result.)</p> + when there is a query result.)</p> <code type="none"><![CDATA[ static int do_connect(const char *s, our_data_t* data) { @@ -571,7 +572,7 @@ static void ready_io(ErlDrvData drv_data, ErlDrvEvent event) connection is successful, or error if it's not. If the connection is not yet established, we simply return; <c><![CDATA[ready_io]]></c> will be called again.</p> - <p>If we have result from a connect, indicated that we have data in + <p>If we have a result from a connect, indicated by having data in the <c><![CDATA[x]]></c> buffer, we no longer need to select on output (<c><![CDATA[ready_output]]></c>), so we remove this by calling <c><![CDATA[driver_select]]></c>.</p> @@ -630,9 +631,9 @@ return_port_data(Port) -> message queue. The function <c><![CDATA[return_port_data]]></c> above receives data from the port. Since the data is in binary format, we use <c><![CDATA[binary_to_term/1]]></c> to convert - it to Erlang term. Note that the driver is opened in - binary mode, <c><![CDATA[open_port/2]]></c> is called with the option - <c><![CDATA[[binary]]]></c>. This means that data sent from the driver + it to an Erlang term. Note that the driver is opened in + binary mode (<c><![CDATA[open_port/2]]></c> is called with the option + <c><![CDATA[[binary]]]></c>). This means that data sent from the driver to the emulator is sent as binaries. Without the <c><![CDATA[binary]]></c> option, they would have been lists of integers.</p> </section> @@ -646,15 +647,15 @@ return_port_data(Port) -> of a list of integers. For large lists (more than 100000 elements), this will take some time, so we will perform this as an asynchronous task.</p> - <p>The asynchronous api for drivers are quite complicated. First + <p>The asynchronous API for drivers is quite complicated. First of all, the work must be prepared. In our example we do this in <c><![CDATA[output]]></c>. We could have used <c><![CDATA[control]]></c> just as well, but we want some variation in our examples. In our driver, we allocate - a structure that contains all needed for the asynchronous task + a structure that contains anything that's needed for the asynchronous task to do the work. This is done in the main emulator thread. Then the asynchronous function is called from a driver thread, - separate from the main emulator thread. Note that the driver- - functions are not reentrant, so they shouldn't be used. + separate from the main emulator thread. Note that the driver-functions + are not reentrant, so they shouldn't be used. Finally, after the function is completed, the driver callback <c><![CDATA[ready_async]]></c> is called from the main emulator thread, this is where we return the result to Erlang. (We can't @@ -692,7 +693,7 @@ static ErlDrvEntry next_perm_driver_entry = { be sent later from the <c><![CDATA[ready_async]]></c> call-back.</p> <p>The <c><![CDATA[async_data]]></c> will be passed to the <c><![CDATA[do_perm]]></c> function. We do not use a <c><![CDATA[async_free]]></c> function (the last argument to - <c><![CDATA[driver_async]]></c>, it's only used if the task is cancelled + <c><![CDATA[driver_async]]></c>), it's only used if the task is cancelled programmatically.</p> <code type="none"><![CDATA[ struct our_async_data { @@ -743,7 +744,7 @@ static void ready_async(ErlDrvData drv_data, ErlDrvThreadData async_data) ErlDrvPort port = reinterpret_cast<ErlDrvPort>(drv_data); our_async_data* d = reinterpret_cast<our_async_data*>(async_data); int n = d->data.size(), result_n = n*2 + 3; - ErlDrvTermData* result = new ErlDrvTermData[result_n], * rp = result; + ErlDrvTermData *result = new ErlDrvTermData[result_n], *rp = result; for (vector<int>::iterator i = d->data.begin(); i != d->data.end(); ++i) { *rp++ = ERL_DRV_INT; diff --git a/erts/doc/src/driver_entry.xml b/erts/doc/src/driver_entry.xml index dfddbb18ea..8bdd154cb9 100644 --- a/erts/doc/src/driver_entry.xml +++ b/erts/doc/src/driver_entry.xml @@ -121,7 +121,7 @@ typedef struct erl_drv_entry { the port */ void (*ready_input)(ErlDrvData drv_data, ErlDrvEvent event); /* called when we have input from one of - the driver's handles) */ + the driver's handles */ void (*ready_output)(ErlDrvData drv_data, ErlDrvEvent event); /* called when output is possible to one of the driver's handles */ @@ -133,7 +133,7 @@ typedef struct erl_drv_entry { int (*control)(ErlDrvData drv_data, unsigned int command, char *buf, int len, char **rbuf, int rlen); /* "ioctl" for drivers - invoked by - port_control/3) */ + port_control/3 */ void (*timeout)(ErlDrvData drv_data); /* Handling of timeout in driver */ void (*outputv)(ErlDrvData drv_data, ErlIOVec *ev); /* called when we have output from erlang @@ -146,7 +146,7 @@ typedef struct erl_drv_entry { before 'stop' can be called */ int (*call)(ErlDrvData drv_data, unsigned int command, char *buf, int len, char **rbuf, int rlen, unsigned int *flags); - /* Works mostly like 'control', a syncronous + /* Works mostly like 'control', a synchronous call into the driver. */ void (*event)(ErlDrvData drv_data, ErlDrvEvent event, ErlDrvEventData event_data); diff --git a/erts/doc/src/epmd.xml b/erts/doc/src/epmd.xml index 474230cb38..8c3c1e5237 100644 --- a/erts/doc/src/epmd.xml +++ b/erts/doc/src/epmd.xml @@ -116,6 +116,16 @@ <p>These options are available when starting the actual name server. The name server is normally started automatically by the <c>erl</c> command (if not already available), but it can also be started at i.e. system start-up.</p> <taglist> + <tag><c><![CDATA[-address List]]></c></tag> + <item> + <p>Let this instance of <c>epmd</c> listen only on the + comma-separated list of IP addresses and on the loopback address + (which is implicitely added to the list if it has not been + specified). This can also be set using the + <c><![CDATA[ERL_EPMD_ADDRESS]]></c> environment variable, see the + section <seealso marker="#environment_variables">Environment + variables</seealso> below.</p> + </item> <tag><c><![CDATA[-port No]]></c></tag> <item> <p>Let this instance of epmd listen to another TCP port than @@ -228,6 +238,15 @@ <marker id="environment_variables"></marker> <title>Environment variables</title> <taglist> + <tag><c><![CDATA[ERL_EPMD_ADDRESS]]></c></tag> + <item> + <p>This environment variable may be set to a comma-separated + list of IP addresses, in which case the <c>epmd</c> daemon + will listen only on the specified address(es) and on the + loopback address (which is implicitely added to the list if it + has not been specified). The default behaviour is to listen on + all available IP addresses.</p> + </item> <tag><c><![CDATA[ERL_EPMD_PORT]]></c></tag> <item> <p>This environment variable can contain the port number epmd will use. diff --git a/erts/doc/src/erl.xml b/erts/doc/src/erl.xml index a66d273438..514ee5ffaf 100644 --- a/erts/doc/src/erl.xml +++ b/erts/doc/src/erl.xml @@ -1004,6 +1004,15 @@ add to the code path. See <seealso marker="kernel:code">code(3)</seealso>.</p> </item> + <tag><c><![CDATA[ERL_EPMD_ADDRESS]]></c></tag> + <item> + <p>This environment variable may be set to a comma-separated + list of IP addresses, in which case the + <seealso marker="epmd">epmd</seealso> daemon + will listen only on the specified address(es) and on the + loopback address (which is implicitely added to the list if it + has not been specified).</p> + </item> <tag><c><![CDATA[ERL_EPMD_PORT]]></c></tag> <item> <p>This environment variable can contain the port number to use when @@ -1016,6 +1025,49 @@ </section> <section> + <marker id="configuration"></marker> + <title>Configuration</title> + <p>The standard Erlang/OTP system can be re-configured to change the default + behavior on start-up.</p> + <taglist> + <tag>The .erlang Start-up File</tag> + <item> + <p>When Erlang/OTP is started, the system searches for a file named .erlang + in the directory where Erlang/OTP is started. If not found, the user's home + directory is searched for an .erlang file.</p> + <p>If an .erlang file is found, it is assumed to contain valid Erlang expressions. + These expressions are evaluated as if they were input to the shell.</p> + <p>A typical .erlang file contains a set of search paths, for example:</p> + <code type="none"><![CDATA[ + io:format("executing user profile in HOME/.erlang\n",[]). + code:add_path("/home/calvin/test/ebin"). + code:add_path("/home/hobbes/bigappl-1.2/ebin"). + io:format(".erlang rc finished\n",[]). + ]]></code> + </item> + <tag>user_default and shell_default</tag> + <item> + <p>Functions in the shell which are not prefixed by a module name are assumed + to be functional objects (Funs), built-in functions (BIFs), or belong to the + module user_default or shell_default.</p> + <p>To include private shell commands, define them in a module user_default and + add the following argument as the first line in the .erlang file.</p> + <code type="none"><![CDATA[ + code:load_abs("..../user_default"). + ]]></code> + </item> + <tag>erl</tag> + <item> + <p>If the contents of .erlang are changed and a private version of + user_default is defined, it is possible to customize the Erlang/OTP environment. + More powerful changes can be made by supplying command line arguments in the + start-up script erl. Refer to erl(1) and <seealso marker="init">init(3)</seealso> + for further information.</p> + </item> + </taglist> + </section> + + <section> <title>SEE ALSO</title> <p><seealso marker="init">init(3)</seealso>, <seealso marker="erl_prim_loader">erl_prim_loader(3)</seealso>, diff --git a/erts/doc/src/erl_driver.xml b/erts/doc/src/erl_driver.xml index 497a2fa01d..066a2a4b92 100644 --- a/erts/doc/src/erl_driver.xml +++ b/erts/doc/src/erl_driver.xml @@ -56,16 +56,16 @@ instance is connected to an Erlang port. Every port has a port owner process. Communication with the port is normally done through the port owner process.</p> - <p>Most of the functions takes the <c>port</c> handle as an + <p>Most of the functions take the <c>port</c> handle as an argument. This identifies the driver instance. Note that this port handle must be stored by the driver, it is not given when the driver is called from the emulator (see <seealso marker="driver_entry#emulator">driver_entry</seealso>).</p> - <p>Some of the functions takes a parameter of type + <p>Some of the functions take a parameter of type <c>ErlDrvBinary</c>, a driver binary. It should be both - allocated and freed by the caller. Using a binary directly avoid + allocated and freed by the caller. Using a binary directly avoids one extra copying of data.</p> - <p>Many of the output functions has a "header buffer", with + <p>Many of the output functions have a "header buffer", with <c>hbuf</c> and <c>hlen</c> parameters. This buffer is sent as a list before the binary (or list, depending on port mode) that is sent. This is convenient when matching on messages received from @@ -92,7 +92,7 @@ with SMP support without being rewritten if driver level locking is used.</p> <note> - <p>It is assumed that drivers does not access other drivers. If + <p>It is assumed that drivers do not access other drivers. If drivers should access each other they have to provide their own mechanism for thread safe synchronization. Such "inter driver communication" is strongly discouraged.</p> @@ -113,12 +113,12 @@ call-backs may be made from different threads.</p> </note> <p>Most functions in this API are <em>not</em> thread-safe, i.e., - they may <em>not</em> be called from an arbitrary thread. Function + they may <em>not</em> be called from an arbitrary thread. Functions that are not documented as thread-safe may only be called from driver call-backs or function calls descending from a driver call-back call. Note that driver call-backs may be called from different threads. This, however, is not a problem for any - functions in this API, since the emulator have control over + function in this API, since the emulator has control over these threads.</p> <note> <p>Functions not explicitly documented as thread-safe are @@ -155,10 +155,10 @@ more information.</p> </item> <tag>Output functions</tag> - <item>With the output functions, the driver sends data back + <item>With the output functions, the driver sends data back to the emulator. They will be received as messages by the port owner process, see <c>open_port/2</c>. The vector function and the - function taking a driver binary is faster, because that avoid + function taking a driver binary are faster, because they avoid copying the data buffer. There is also a fast way of sending terms from the driver, without going through the binary term format.</item> @@ -193,14 +193,14 @@ use functionality from the POSIX thread API or the Windows native thread API. </p> - <p>The Erlang driver thread API only return error codes when it is + <p>The Erlang driver thread API only returns error codes when it is reasonable to recover from an error condition. If it isn't reasonable to recover from an error condition, the whole runtime system is terminated. For example, if a create mutex operation fails, an error code is returned, but if a lock operation on a mutex fails, the whole runtime system is terminated. </p> - <p>Note that there exist no "condition variable wait with timeout" in + <p>Note that there exists no "condition variable wait with timeout" in the Erlang driver thread API. This is due to issues with <c>pthread_cond_timedwait()</c>. When the system clock suddenly is changed, it isn't always guaranteed that you will wake up from @@ -241,7 +241,7 @@ to give you better error reports. </p> </item> - <tag>Adding / remove drivers</tag> + <tag>Adding / removing drivers</tag> <item>A driver can add and later remove drivers.</item> <tag>Monitoring processes</tag> <item>A driver can monitor a process that does not own a port.</item> @@ -262,7 +262,7 @@ could, under rare circumstances, mean that drivers have to be slightly modified. If so, this will of course be documented. <c>ERL_DRV_EXTENDED_MINOR_VERSION</c> will be incremented when - new features are added. The runtime system use the minor version + new features are added. The runtime system uses the minor version of the driver to determine what features to use. The runtime system will refuse to load a driver if the major versions differ, or if the major versions are equal and the @@ -273,7 +273,7 @@ It can, however, not make sure that it isn't incompatible. Therefore, when loading a driver that doesn't use the extended driver interface, there is a risk that it will be loaded also when - the driver is incompatible. When the driver use the extended driver + the driver is incompatible. When the driver uses the extended driver interface, the emulator can verify that it isn't of an incompatible driver version. You are therefore advised to use the extended driver interface.</p> @@ -309,7 +309,7 @@ typedef struct ErlDrvSysInfo { <seealso marker="#driver_system_info">driver_system_info()</seealso> will write the system information when passed a reference to a <c>ErlDrvSysInfo</c> structure. A description of the - fields in the structure follow: + fields in the structure follows: </p> <taglist> <tag><c>driver_major_version</c></tag> @@ -347,14 +347,6 @@ typedef struct ErlDrvSysInfo { <item>A value <c>!= 0</c> if the runtime system has SMP support; otherwise, <c>0</c>. </item> - <tag><c>thread_support</c></tag> - <item>A value <c>!= 0</c> if the runtime system has thread support; - otherwise, <c>0</c>. - </item> - <tag><c>smp_support</c></tag> - <item>A value <c>!= 0</c> if the runtime system has SMP support; - otherwise, <c>0</c>. - </item> <tag><c>async_threads</c></tag> <item>The number of async threads in the async thread pool used by <seealso marker="#driver_async">driver_async()</seealso> @@ -401,8 +393,8 @@ typedef struct ErlDrvBinary { <seealso marker="#driver_binary_dec_refc">driver_binary_dec_refc()</seealso>.</p> </note> <p>Some driver calls, such as <c>driver_enq_binary</c>, - increments the driver reference count, and others, such as - <c>driver_deq</c> decrements it.</p> + increment the driver reference count, and others, such as + <c>driver_deq</c> decrement it.</p> <p>Using a driver binary instead of a normal buffer, is often faster, since the emulator doesn't need to copy the data, only the pointer is used.</p> @@ -415,7 +407,7 @@ typedef struct ErlDrvBinary { <c>driver_outputv</c> calls, and in the queue. Also the driver call-back <seealso marker="driver_entry#outputv">outputv</seealso> uses driver binaries.</p> - <p>If the driver of some reason or another, wants to keep a + <p>If the driver for some reason or another, wants to keep a driver binary around, in a static variable for instance, the reference count should be incremented, and the binary can later be freed in the <seealso marker="driver_entry#stop">stop</seealso> call-back, with @@ -423,7 +415,7 @@ typedef struct ErlDrvBinary { <p>Note that since a driver binary is shared by the driver and the emulator, a binary received from the emulator or sent to the emulator, must not be changed by the driver.</p> - <p>From erts version 5.5 (OTP release R11B), orig_bytes is + <p>Since erts version 5.5 (OTP release R11B), orig_bytes is guaranteed to be properly aligned for storage of an array of doubles (usually 8-byte aligned).</p> </item> @@ -447,7 +439,7 @@ typedef struct ErlIOVec { int vsize; int size; SysIOVec* iov; - >ErlDrvBinary** binv; + ErlDrvBinary** binv; } ErlIOVec; </code> <p>The I/O vector used by the emulator and drivers, is a list @@ -495,17 +487,17 @@ typedef struct ErlIOVec { Currently, the only port specific data that the emulator associates with the port data lock is the driver queue.</p> <p>Normally a driver instance does not have a port data lock. If - the driver instance want to use a port data lock, it has to + the driver instance wants to use a port data lock, it has to create the port data lock by calling <seealso marker="#driver_pdl_create">driver_pdl_create()</seealso>. <em>NOTE</em>: Once the port data lock has been created, every - access to data associated with the port data lock have to be done + access to data associated with the port data lock has to be done while having the port data lock locked. The port data lock is locked, and unlocked, respectively, by use of <seealso marker="#driver_pdl_lock">driver_pdl_lock()</seealso>, and <seealso marker="#driver_pdl_unlock">driver_pdl_unlock()</seealso>.</p> <p>A port data lock is reference counted, and when the reference - count reach zero, it will be destroyed. The emulator will at + count reaches zero, it will be destroyed. The emulator will at least increment the reference count once when the lock is created and decrement it once when the port associated with the lock terminates. The emulator will also increment the @@ -545,7 +537,7 @@ typedef struct ErlIOVec { </p> <taglist> <tag>suggested_stack_size</tag> - <item>A suggestion, in kilo-words, on how large stack to use. A value less + <item>A suggestion, in kilo-words, on how large a stack to use. A value less than zero means default size. </item> </taglist> @@ -648,7 +640,7 @@ typedef struct ErlIOVec { opened.</p> <p>The data is queued in the port owner process' message queue. Note that this does not yield to the emulator. (Since - the driver and the emulator runs in the same thread.)</p> + the driver and the emulator run in the same thread.)</p> <p>The parameter <c>buf</c> points to the data to send, and <c>len</c> is the number of bytes.</p> <p>The return value for all output functions is 0. (Unless the @@ -749,7 +741,7 @@ typedef struct ErlIOVec { function <seealso marker="driver_entry#emulator">timeout</seealso> is called.</p> <p>Note that there is only one timer on each driver instance; setting a new timer will replace an older one.</p> - <p>Return value i 0 (-1 only when the <c>timeout</c> driver + <p>Return value is 0 (-1 only when the <c>timeout</c> driver function is <c>NULL</c>).</p> </desc> </func> @@ -799,20 +791,20 @@ typedef struct ErlIOVec { event object must be a socket or pipe (or other object that <c>select</c>/<c>poll</c> can use). On windows, the Win32 API function <c>WaitForMultipleObjects</c> - is used. This places other restriction on the event object. + is used. This places other restrictions on the event object. Refer to the Win32 SDK documentation.</p> <p>The <c>on</c> parameter should be <c>1</c> for setting events and <c>0</c> for clearing them.</p> - <p>The <c>mode</c> argument is bitwise-or combination of + <p>The <c>mode</c> argument is a bitwise-or combination of <c>ERL_DRV_READ</c>, <c>ERL_DRV_WRITE</c> and <c>ERL_DRV_USE</c>. - The first two specifies whether to wait for read events and/or write + The first two specify whether to wait for read events and/or write events. A fired read event will call <seealso marker="driver_entry#ready_input">ready_input</seealso> while a fired write event will call <seealso marker="driver_entry#ready_output">ready_output</seealso>. </p> <note> - <p>Some OS (Windows) does not differ between read and write events. + <p>Some OS (Windows) do not differentiate between read and write events. The call-back for a fired event then only depends on the value of <c>mode</c>.</p> </note> <p><c>ERL_DRV_USE</c> specifies if we are using the event object or if we want to close it. @@ -834,9 +826,9 @@ typedef struct ErlIOVec { as before. But it is recommended to update them to use <c>ERL_DRV_USE</c> and <c>stop_select</c> to make sure that event objects are closed in a safe way.</p> </note> - <p>The return value is 0 (Failure, -1, only if the + <p>The return value is 0 (failure, -1, only if the <c>ready_input</c>/<c>ready_output</c> is - <c>NULL</c>.</p> + <c>NULL</c>).</p> </desc> </func> <func> @@ -1076,7 +1068,7 @@ typedef struct ErlIOVec { array of <c>SysIOVec</c>s. It also returns the number of elements in <c>vlen</c>. This is the only way to get data out of the queue.</p> - <p>Nothing is remove from the queue by this function, that must be done + <p>Nothing is removed from the queue by this function, that must be done with <c>driver_deq</c>.</p> <p>The returned array is suitable to use with the Unix system call <c>writev</c>.</p> @@ -1209,7 +1201,7 @@ typedef struct ErlIOVec { <fsummary>Stop monitoring a process from a driver</fsummary> <desc> <marker id="driver_demonitor_process"></marker> - <p>This function cancels an monitor created earlier. </p> + <p>This function cancels a monitor created earlier. </p> <p>The function returns 0 if a monitor was removed and > 0 if the monitor did no longer exist.</p> </desc> @@ -1326,7 +1318,7 @@ typedef struct ErlIOVec { <p>This function signals to erlang that the driver has encountered an EOF and should be closed, unless the port was opened with the <c>eof</c> option, in that case eof is sent - to the port. Otherwise, the port is close and an + to the port. Otherwise, the port is closed and an <c>'EXIT'</c> message is sent to the port owner process.</p> <p>The return value is 0.</p> </desc> @@ -1349,8 +1341,8 @@ typedef struct ErlIOVec { (<c>driver_failure</c>).</p> <p>The driver should fail only when in severe error situations, when the driver cannot possibly keep open, for instance - buffer allocation gets out of memory. Normal errors is more - appropriate to handle with sending error codes with + buffer allocation gets out of memory. For normal errors + it is more appropriate to send error codes with <c>driver_output</c>.</p> <p>The return value is 0.</p> </desc> @@ -1371,7 +1363,7 @@ typedef struct ErlIOVec { <p>This function returns the process id of the process that made the current call to the driver. The process id can be used with <c>driver_send_term</c> to send back data to the - caller. <c>driver_caller()</c> only return valid data + caller. <c>driver_caller()</c> only returns valid data when currently executing in one of the following driver callbacks:</p> <taglist> @@ -1409,7 +1401,7 @@ typedef struct ErlIOVec { tuple, the elements are given first, and then the tuple term, with a count. Likewise for lists.</p> <p>A tuple must be specified with the number of elements. (The - elements precedes the <c>ERL_DRV_TUPLE</c> term.)</p> + elements precede the <c>ERL_DRV_TUPLE</c> term.)</p> <p>A list must be specified with the number of elements, including the tail, which is the last term preceding <c>ERL_DRV_LIST</c>.</p> @@ -1518,7 +1510,7 @@ ERL_DRV_EXT2TERM char *buf, ErlDrvUInt len }; driver_output_term(port, spec, sizeof(spec) / sizeof(spec[0])); ]]></code> - <p>If you want to pass a binary and doesn't already have the content + <p>If you want to pass a binary and don't already have the content of the binary in an <c>ErlDrvBinary</c>, you can benefit from using <c>ERL_DRV_BUF2BINARY</c> instead of creating an <c>ErlDrvBinary</c> via <c>driver_alloc_binary()</c> and then pass the binary via @@ -1565,7 +1557,7 @@ ERL_DRV_EXT2TERM char *buf, ErlDrvUInt len <em>other</em> processes than the port owner process. The <c>receiver</c> parameter specifies the process to receive the data.</p> - <p>The parameters <c>term</c> and <c>n</c> does the same thing + <p>The parameters <c>term</c> and <c>n</c> do the same thing as in <seealso marker="#driver_output_term">driver_output_term</seealso>.</p> <p>This function is only thread-safe when the emulator with SMP support is used.</p> @@ -1660,7 +1652,7 @@ ERL_DRV_EXT2TERM char *buf, ErlDrvUInt len <desc> <marker id="driver_lock_driver"></marker> <p>This function locks the driver used by the port <c>port</c> - in memory for the rest of the emulator process + in memory for the rest of the emulator process' lifetime. After this call, the driver behaves as one of Erlang's statically linked in drivers.</p> </desc> @@ -1904,7 +1896,7 @@ ERL_DRV_EXT2TERM char *buf, ErlDrvUInt len corresponding to one of the involved thread identifiers has terminated since the thread identifier was saved, the result of <c>erl_drv_equal_tids()</c> might not give - expected result. + the expected result. </p></note> <p>This function is thread-safe.</p> </desc> diff --git a/erts/doc/src/erl_nif.xml b/erts/doc/src/erl_nif.xml index 4bbd4e2a54..cdce4ec0b8 100644 --- a/erts/doc/src/erl_nif.xml +++ b/erts/doc/src/erl_nif.xml @@ -688,6 +688,10 @@ typedef enum { <fsummary>Determine if a term is an empty list</fsummary> <desc><p>Return true if <c>term</c> is an empty list.</p></desc> </func> + <marker id="enif_is_exception"/><func><name><ret>int</ret><nametext>enif_is_exception(ErlNifEnv* env, ERL_NIF_TERM term)</nametext></name> + <fsummary>Determine if a term is an exception</fsummary> + <desc><p>Return true if <c>term</c> is an exception.</p></desc> + </func> <func><name><ret>int</ret><nametext>enif_is_fun(ErlNifEnv* env, ERL_NIF_TERM term)</nametext></name> <fsummary>Determine if a term is a fun</fsummary> <desc><p>Return true if <c>term</c> is a fun.</p></desc> @@ -738,7 +742,14 @@ typedef enum { </func> <func><name><ret>ERL_NIF_TERM</ret><nametext>enif_make_badarg(ErlNifEnv* env)</nametext></name> <fsummary>Make a badarg exception.</fsummary> - <desc><p>Make a badarg exception to be returned from a NIF.</p></desc> + <desc><p>Make a badarg exception to be returned from a NIF, and set + an associated exception reason in <c>env</c>. If + <c>enif_make_badarg</c> is called, the term it returns <em>must</em> + be returned from the function that called it. No other return value + is allowed. Also, the term returned from <c>enif_make_badarg</c> may + be passed only to + <seealso marker="#enif_is_exception">enif_is_exception</seealso> and + not to any other NIF API function.</p></desc> </func> <func><name><ret>ERL_NIF_TERM</ret><nametext>enif_make_binary(ErlNifEnv* env, ErlNifBinary* bin)</nametext></name> <fsummary>Make a binary term.</fsummary> diff --git a/erts/doc/src/init.xml b/erts/doc/src/init.xml index 33364c709a..0e828389f6 100644 --- a/erts/doc/src/init.xml +++ b/erts/doc/src/init.xml @@ -67,19 +67,6 @@ </desc> </func> <func> - <name>get_args() -> [Arg]</name> - <fsummary>Get all non-flag command line arguments</fsummary> - <type> - <v>Arg = atom()</v> - </type> - <desc> - <p>Returns any plain command line arguments as a list of atoms - (possibly empty). It is recommended that - <c>get_plain_arguments/1</c> is used instead, because of - the limited length of atoms.</p> - </desc> - </func> - <func> <name>get_argument(Flag) -> {ok, Arg} | error</name> <fsummary>Get the values associated with a command line user flag</fsummary> <type> diff --git a/erts/doc/src/notes.xml b/erts/doc/src/notes.xml index 102fa43c1f..f5607945a8 100644 --- a/erts/doc/src/notes.xml +++ b/erts/doc/src/notes.xml @@ -30,6 +30,55 @@ </header> <p>This document describes the changes made to the ERTS application.</p> +<section><title>Erts 5.8.3.2</title> + + <section><title>Known Bugs and Problems</title> + <list> + <item> + <p> + Fix halfword emulator bug in <c>ets:select_delete</c> for + <c>ordered_set</c> that caused emulator to crash.</p> + <p> + Own Id: OTP-9258 Aux Id: seq11836 </p> + </item> + </list> + </section> + +</section> + +<section><title>Erts 5.8.3.1</title> + + <section><title>Fixed Bugs and Malfunctions</title> + <list> + <item> + <p> + Ets table type ordered_set could order large integer keys + wrongly on pure 64bit platforms. This is now corrected.</p> + <p> + Own Id: OTP-9181</p> + </item> + <item> + <p> + The status of a process was unnecessarily set to waiting + before a process was enqueued in a run queue. This bug + was harmless up until OTP-R14B01. In OTP-R14B02 + <c>erlang:hibernate/3</c> was fixed (OTP-9125). After the + introduction of OTP-9125, the previously harmless process + status bug sometimes caused erroneous badarg exceptions + from <c>process_info()</c>.</p> + <p> + OTP-9125 also introduced a thread unsafe access to the + status field of a process which now also have been fixed.</p> + <p> + *** INCOMPATIBILITY with noxs ***</p> + <p> + Own Id: OTP-9197</p> + </item> + </list> + </section> + +</section> + <section><title>Erts 5.8.3</title> <section><title>Fixed Bugs and Malfunctions</title> diff --git a/erts/emulator/Makefile.in b/erts/emulator/Makefile.in index f04df354a8..c9076a9d64 100644 --- a/erts/emulator/Makefile.in +++ b/erts/emulator/Makefile.in @@ -515,11 +515,12 @@ $(TTF_DIR)/beam_opcodes.h $(TTF_DIR)/beam_opcodes.c: $(OPCODE_TABLES) utils/beam ATOMS= beam/atom.names BIFS = beam/bif.tab ifdef HIPE_ENABLED +HIPE_ARCH64_TAB=hipe/hipe_bif64.tab HIPE_x86_TAB=hipe/hipe_x86.tab -HIPE_amd64_TAB=hipe/hipe_amd64.tab +HIPE_amd64_TAB=hipe/hipe_amd64.tab $(HIPE_ARCH64_TAB) HIPE_ultrasparc_TAB=hipe/hipe_sparc.tab HIPE_ppc_TAB=hipe/hipe_ppc.tab -HIPE_ppc64_TAB=hipe/hipe_ppc64.tab +HIPE_ppc64_TAB=hipe/hipe_ppc64.tab $(HIPE_ARCH64_TAB) HIPE_arm_TAB=hipe/hipe_arm.tab HIPE_ARCH_TAB=$(HIPE_$(ARCH)_TAB) BIFS += hipe/hipe_bif0.tab hipe/hipe_bif1.tab hipe/hipe_bif2.tab $(HIPE_ARCH_TAB) @@ -801,12 +802,14 @@ OS_OBJS += $(OBJDIR)/erl_mseg.o \ $(OBJDIR)/erl_mtrace_sys_wrap.o \ $(OBJDIR)/erl_sys_common_misc.o +HIPE_ARCH64_OBJS=$(OBJDIR)/hipe_bif64.o + HIPE_x86_OS_OBJS=$(HIPE_x86_$(OPSYS)_OBJS) HIPE_x86_OBJS=$(OBJDIR)/hipe_x86.o $(OBJDIR)/hipe_x86_glue.o $(OBJDIR)/hipe_x86_bifs.o $(OBJDIR)/hipe_x86_signal.o $(OBJDIR)/hipe_x86_stack.o $(HIPE_x86_OS_OBJS) -HIPE_amd64_OBJS=$(OBJDIR)/hipe_amd64.o $(OBJDIR)/hipe_amd64_glue.o $(OBJDIR)/hipe_amd64_bifs.o $(OBJDIR)/hipe_x86_signal.o $(OBJDIR)/hipe_x86_stack.o +HIPE_amd64_OBJS=$(OBJDIR)/hipe_amd64.o $(OBJDIR)/hipe_amd64_glue.o $(OBJDIR)/hipe_amd64_bifs.o $(OBJDIR)/hipe_x86_signal.o $(OBJDIR)/hipe_x86_stack.o $(HIPE_ARCH64_OBJS) HIPE_ultrasparc_OBJS=$(OBJDIR)/hipe_sparc.o $(OBJDIR)/hipe_sparc_glue.o $(OBJDIR)/hipe_sparc_bifs.o $(OBJDIR)/hipe_risc_stack.o HIPE_ppc_OBJS=$(OBJDIR)/hipe_ppc.o $(OBJDIR)/hipe_ppc_glue.o $(OBJDIR)/hipe_ppc_bifs.o $(OBJDIR)/hipe_risc_stack.o -HIPE_ppc64_OBJS=$(HIPE_ppc_OBJS) +HIPE_ppc64_OBJS=$(HIPE_ppc_OBJS) $(HIPE_ARCH64_OBJS) HIPE_arm_OBJS=$(OBJDIR)/hipe_arm.o $(OBJDIR)/hipe_arm_glue.o $(OBJDIR)/hipe_arm_bifs.o $(OBJDIR)/hipe_risc_stack.o HIPE_noarch_OBJS= HIPE_ARCH_OBJS=$(HIPE_$(ARCH)_OBJS) diff --git a/erts/emulator/beam/beam_bif_load.c b/erts/emulator/beam/beam_bif_load.c index 6ae9736141..1ca405961f 100644 --- a/erts/emulator/beam/beam_bif_load.c +++ b/erts/emulator/beam/beam_bif_load.c @@ -472,9 +472,6 @@ check_process_code(Process* rp, Module* modp) for (oh = MSO(rp).first; oh; oh = oh->next) { if (thing_subtag(oh->thing_word) == FUN_SUBTAG) { ErlFunThing* funp = (ErlFunThing*) oh; - BeamInstr* fun_code; - - fun_code = funp->fe->address; if (INSIDE((BeamInstr *) funp->fe->address)) { if (done_gc) { diff --git a/erts/emulator/beam/beam_debug.c b/erts/emulator/beam/beam_debug.c index 8a48049921..fffb172c68 100644 --- a/erts/emulator/beam/beam_debug.c +++ b/erts/emulator/beam/beam_debug.c @@ -291,7 +291,7 @@ dbg_bt(Process* p, Eterm* sp) if (addr) erts_fprintf(stderr, HEXF ": %T:%T/%bpu\n", - addr, (Eterm) addr[0], (Eterm) addr[1], (Uint) addr[2]); + addr, (Eterm) addr[0], (Eterm) addr[1], addr[2]); } sp++; } @@ -484,7 +484,7 @@ print_op(int to, void *to_arg, int op, int size, BeamInstr* addr) if (f+3 != (BeamInstr *) *ap) { erts_print(to, to_arg, "f(" HEXF ")", *ap); } else { - erts_print(to, to_arg, "%T:%T/%bpu", (Eterm) f[0], (Eterm) f[1], (Eterm) f[2]); + erts_print(to, to_arg, "%T:%T/%bpu", (Eterm) f[0], (Eterm) f[1], f[2]); } ap++; } @@ -495,7 +495,7 @@ print_op(int to, void *to_arg, int op, int size, BeamInstr* addr) if (f+3 != (BeamInstr *) *ap) { erts_print(to, to_arg, "p(" HEXF ")", *ap); } else { - erts_print(to, to_arg, "%T:%T/%bpu", (Eterm) f[0], (Eterm) f[1], (Eterm) f[2]); + erts_print(to, to_arg, "%T:%T/%bpu", (Eterm) f[0], (Eterm) f[1], f[2]); } ap++; } @@ -508,7 +508,7 @@ print_op(int to, void *to_arg, int op, int size, BeamInstr* addr) { Export* ex = (Export *) *ap; erts_print(to, to_arg, - "%T:%T/%bpu", (Eterm) ex->code[0], (Eterm) ex->code[1], (Uint) ex->code[2]); + "%T:%T/%bpu", (Eterm) ex->code[0], (Eterm) ex->code[1], ex->code[2]); ap++; } break; diff --git a/erts/emulator/beam/beam_emu.c b/erts/emulator/beam/beam_emu.c index 7b2aac0908..32ea8588d2 100644 --- a/erts/emulator/beam/beam_emu.c +++ b/erts/emulator/beam/beam_emu.c @@ -3413,13 +3413,15 @@ void process_main(void) r(0) = nif_bif_result; CHECK_TERM(r(0)); SET_I(c_p->cp); + c_p->cp = 0; Goto(*I); } else if (c_p->freason == TRAP) { SET_I(*((BeamInstr **) (UWord) ((c_p)->def_arg_reg + 3))); r(0) = c_p->def_arg_reg[0]; x(1) = c_p->def_arg_reg[1]; x(2) = c_p->def_arg_reg[2]; - if (c_p->status == P_WAITING) { + if (c_p->flags & F_HIBERNATE_SCHED) { + c_p->flags &= ~F_HIBERNATE_SCHED; goto do_schedule; } Dispatch(); @@ -5224,6 +5226,7 @@ void process_main(void) OpCase(i_hibernate): { SWAPOUT; if (erts_hibernate(c_p, r(0), x(1), x(2), reg)) { + c_p->flags &= ~F_HIBERNATE_SCHED; goto do_schedule; } else { I = handle_error(c_p, I, reg, hibernate_3); @@ -6276,15 +6279,17 @@ erts_hibernate(Process* c_p, Eterm module, Eterm function, Eterm args, Eterm* re PROCESS_MAIN_CHK_LOCKS(c_p); erts_smp_proc_lock(c_p, ERTS_PROC_LOCK_MSGQ|ERTS_PROC_LOCK_STATUS); ASSERT(!ERTS_PROC_IS_EXITING(c_p)); - c_p->status = P_WAITING; #ifdef ERTS_SMP ERTS_SMP_MSGQ_MV_INQ2PRIVQ(c_p); if (c_p->msg.len > 0) erts_add_to_runq(c_p); + else #endif + c_p->status = P_WAITING; } erts_smp_proc_unlock(c_p, ERTS_PROC_LOCK_MSGQ|ERTS_PROC_LOCK_STATUS); c_p->current = bif_export[BIF_hibernate_3]->code; + c_p->flags |= F_HIBERNATE_SCHED; /* Needed also when woken! */ return 1; } diff --git a/erts/emulator/beam/beam_load.c b/erts/emulator/beam/beam_load.c index 788cb4209c..57fe25453d 100644 --- a/erts/emulator/beam/beam_load.c +++ b/erts/emulator/beam/beam_load.c @@ -480,8 +480,6 @@ static GenOp* gen_select_literals(LoaderState* stp, GenOpArg S, GenOpArg* Rest); static GenOp* const_select_val(LoaderState* stp, GenOpArg S, GenOpArg Fail, GenOpArg Size, GenOpArg* Rest); -static GenOp* gen_func_info(LoaderState* stp, GenOpArg mod, GenOpArg Func, - GenOpArg arity, GenOpArg label); static int freeze_code(LoaderState* stp); @@ -1413,7 +1411,6 @@ static int load_code(LoaderState* stp) { int i; - int tmp; int ci; int last_func_start = 0; char* sign; @@ -1933,7 +1930,6 @@ load_code(LoaderState* stp) case 'P': /* Byte offset into tuple or stack */ case 'Q': /* Like 'P', but packable */ VerifyTag(stp, tag, TAG_u); - tmp = tmp_op->a[arg].val; code[ci++] = (BeamInstr) ((tmp_op->a[arg].val+1) * sizeof(Eterm)); break; case 'l': /* Floating point register. */ @@ -3401,36 +3397,6 @@ const_select_val(LoaderState* stp, GenOpArg S, GenOpArg Fail, return op; } - -static GenOp* -gen_func_info(LoaderState* stp, GenOpArg mod, GenOpArg func, - GenOpArg arity, GenOpArg label) -{ - GenOp* fi; - GenOp* op; - - NEW_GENOP(stp, fi); - fi->op = genop_i_func_info_4; - fi->arity = 4; - fi->a[0].type = TAG_u; /* untagged Zero */ - fi->a[0].val = 0; - fi->a[1] = mod; - fi->a[2] = func; - fi->a[3] = arity; - - NEW_GENOP(stp, op); - op->op = genop_label_1; - op->arity = 1; - op->a[0] = label; - - fi->next = op; - op->next = NULL; - - return fi; -} - - - static GenOp* gen_make_fun2(LoaderState* stp, GenOpArg idx) { diff --git a/erts/emulator/beam/bif.c b/erts/emulator/beam/bif.c index f01580eb2b..b3325d635b 100644 --- a/erts/emulator/beam/bif.c +++ b/erts/emulator/beam/bif.c @@ -368,7 +368,6 @@ static int demonitor(Process *c_p, Eterm ref) ErtsMonitor *mon = NULL; /* The monitor entry to delete */ Process *rp; /* Local target process */ Eterm to = NIL; /* Monitor link traget */ - Eterm ref_p; /* Pid of this end */ DistEntry *dep = NULL; /* Target's distribution entry */ int deref_de = 0; int res; @@ -381,7 +380,6 @@ static int demonitor(Process *c_p, Eterm ref) res = ERTS_DEMONITOR_BADARG; goto done; /* Cannot be this monitor's ref */ } - ref_p = c_p->id; mon = erts_lookup_monitor(c_p->monitors, ref); if (!mon) { @@ -3362,7 +3360,7 @@ BIF_RETTYPE erts_debug_display_1(BIF_ALIST_1) erts_dsprintf_buf_t *dsbufp = erts_create_tmp_dsbuf(64); pres = erts_dsprintf(dsbufp, "%.*T\n", INT_MAX, BIF_ARG_1); if (pres < 0) - erl_exit(1, "Failed to convert term to string: %d (s)\n", + erl_exit(1, "Failed to convert term to string: %d (%s)\n", -pres, erl_errno_id(-pres)); hp = HAlloc(BIF_P, 2*dsbufp->str_len); /* we need length * 2 heap words */ res = buf_to_intlist(&hp, dsbufp->str, dsbufp->str_len, NIL); @@ -3480,7 +3478,7 @@ term2list_dsprintf(Process *p, Eterm term) erts_dsprintf_buf_t *dsbufp = erts_create_tmp_dsbuf(64); pres = erts_dsprintf(dsbufp, "%T", term); if (pres < 0) - erl_exit(1, "Failed to convert term to list: %d (s)\n", + erl_exit(1, "Failed to convert term to list: %d (%s)\n", -pres, erl_errno_id(-pres)); hp = HAlloc(p, 2*dsbufp->str_len); /* we need length * 2 heap words */ res = buf_to_intlist(&hp, dsbufp->str, dsbufp->str_len, NIL); diff --git a/erts/emulator/beam/break.c b/erts/emulator/beam/break.c index d255cf3558..b8889e6206 100644 --- a/erts/emulator/beam/break.c +++ b/erts/emulator/beam/break.c @@ -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 @@ -266,7 +266,7 @@ print_process_info(int to, void *to_arg, Process *p) } erts_print(to, to_arg, "Number of heap fragments: %d\n", frags); } - erts_print(to, to_arg, "Heap fragment data: %bpu\n", MBUF_SIZE(p)); + erts_print(to, to_arg, "Heap fragment data: %beu\n", MBUF_SIZE(p)); scb = ERTS_PROC_GET_SAVED_CALLS_BUF(p); if (scb) { @@ -313,12 +313,11 @@ print_process_info(int to, void *to_arg, Process *p) } /* print the number of reductions etc */ - erts_print(to, to_arg, "Reductions: %bpu\n", p->reds); + erts_print(to, to_arg, "Reductions: %beu\n", p->reds); - erts_print(to, to_arg, "Stack+heap: %bpu\n", p->heap_sz); + erts_print(to, to_arg, "Stack+heap: %beu\n", p->heap_sz); erts_print(to, to_arg, "OldHeap: %bpu\n", - (OLD_HEAP(p) == NULL) ? 0 : - (unsigned)(OLD_HEND(p) - OLD_HEAP(p)) ); + (OLD_HEAP(p) == NULL) ? 0 : (OLD_HEND(p) - OLD_HEAP(p)) ); erts_print(to, to_arg, "Heap unused: %bpu\n", (p->hend - p->htop)); erts_print(to, to_arg, "OldHeap unused: %bpu\n", (OLD_HEAP(p) == NULL) ? 0 : (OLD_HEND(p) - OLD_HTOP(p)) ); diff --git a/erts/emulator/beam/copy.c b/erts/emulator/beam/copy.c index 243e8973cf..90201f3a90 100644 --- a/erts/emulator/beam/copy.c +++ b/erts/emulator/beam/copy.c @@ -477,7 +477,7 @@ Eterm copy_struct(Eterm obj, Uint sz, Eterm** hpp, ErlOffHeap* off_heap) if (htop != hbot) erl_exit(ERTS_ABORT_EXIT, "Internal error in copy_struct() when copying %T:" - " htop=%p != hbot=%p (sz=%bpu)\n", + " htop=%p != hbot=%p (sz=%beu)\n", org_obj, htop, hbot, org_sz); #else if (htop > hbot) { diff --git a/erts/emulator/beam/dist.c b/erts/emulator/beam/dist.c index 02910fad90..b1cdd0660a 100644 --- a/erts/emulator/beam/dist.c +++ b/erts/emulator/beam/dist.c @@ -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 @@ -864,11 +864,15 @@ erts_dsig_send_group_leader(ErtsDSigData *dsdp, Eterm leader, Eterm remote) #include <valgrind/valgrind.h> #include <valgrind/memcheck.h> +#ifndef HAVE_VALGRIND_PRINTF_XML +#define VALGRIND_PRINTF_XML VALGRIND_PRINTF +#endif + # define PURIFY_MSG(msg) \ do { \ char buf__[1]; size_t bufsz__ = sizeof(buf__); \ if (erts_sys_getenv("VALGRIND_LOG_XML", buf__, &bufsz__) >= 0) { \ - VALGRIND_PRINTF("<erlang_error_log>" \ + VALGRIND_PRINTF_XML("<erlang_error_log>" \ "%s, line %d: %s</erlang_error_log>\n", \ __FILE__, __LINE__, msg); \ } else { \ @@ -900,7 +904,6 @@ int erts_net_message(Port *prt, ErtsDistExternal ede; byte *t; Sint ctl_len; - int orig_ctl_len; Eterm arg; Eterm from, to; Eterm watcher, watched; @@ -981,7 +984,6 @@ int erts_net_message(Port *prt, PURIFY_MSG("data error"); goto data_error; } - orig_ctl_len = ctl_len; if (ctl_len > DIST_CTL_DEFAULT_SIZE) { ctl = erts_alloc(ERTS_ALC_T_DCTRL_BUF, ctl_len * sizeof(Eterm)); @@ -1685,7 +1687,7 @@ dist_port_command(Port *prt, ErtsDistOutputBuf *obuf) if (size > (Uint) INT_MAX) erl_exit(ERTS_ABORT_EXIT, "Absurdly large distribution output data buffer " - "(%bpu bytes) passed.\n", + "(%beu bytes) passed.\n", size); prt->caller = NIL; @@ -1712,7 +1714,7 @@ dist_port_commandv(Port *prt, ErtsDistOutputBuf *obuf) if (size > (Uint) INT_MAX) erl_exit(ERTS_ABORT_EXIT, "Absurdly large distribution output data buffer " - "(%bpu bytes) passed.\n", + "(%beu bytes) passed.\n", size); iov[0].iov_base = NULL; diff --git a/erts/emulator/beam/erl_alloc.c b/erts/emulator/beam/erl_alloc.c index 775f4435a9..673eac7fea 100644 --- a/erts/emulator/beam/erl_alloc.c +++ b/erts/emulator/beam/erl_alloc.c @@ -1913,7 +1913,7 @@ erts_memory(int *print_to_p, void *print_to_arg, void *proc, Eterm earg) /* Print result... */ erts_print(to, arg, "=memory\n"); for (i = 0; i < length; i++) - erts_print(to, arg, "%T: %bpu\n", atoms[i], *uintps[i]); + erts_print(to, arg, "%T: %beu\n", atoms[i], *uintps[i]); } if (proc) { @@ -2107,11 +2107,11 @@ erts_allocated_areas(int *print_to_p, void *print_to_arg, void *proc) for (i = 0; i < length; i++) { switch (values[i].arity) { case 2: - erts_print(to, arg, "%s: %bpu\n", + erts_print(to, arg, "%s: %beu\n", values[i].name, values[i].ui[0]); break; case 3: - erts_print(to, arg, "%s: %bpu %bpu\n", + erts_print(to, arg, "%s: %beu %beu\n", values[i].name, values[i].ui[0], values[i].ui[1]); break; default: diff --git a/erts/emulator/beam/erl_alloc_util.c b/erts/emulator/beam/erl_alloc_util.c index 1394b7e829..84c72439a3 100644 --- a/erts/emulator/beam/erl_alloc_util.c +++ b/erts/emulator/beam/erl_alloc_util.c @@ -1877,7 +1877,7 @@ sz_info_carriers(Allctr_t *allctr, cs->blocks.max_ever.size); erts_print(to, arg, - "%scarriers size: %bpu %bpu %bpu\n", + "%scarriers size: %beu %bpu %bpu\n", prefix, curr_size, cs->max.size, @@ -1933,7 +1933,7 @@ info_carriers(Allctr_t *allctr, cs->blocks.max_ever.size); erts_print(to, arg, - "%scarriers: %bpu %bpu %bpu\n", + "%scarriers: %beu %bpu %bpu\n", prefix, curr_no, cs->max.no, @@ -1952,7 +1952,7 @@ info_carriers(Allctr_t *allctr, cs->curr_sys_alloc.no); erts_print(to, arg, - "%scarriers size: %bpu %bpu %bpu\n", + "%scarriers size: %beu %bpu %bpu\n", prefix, curr_size, cs->max.size, @@ -2053,15 +2053,15 @@ info_calls(Allctr_t *allctr, #define PRINT_CC_4(TO, TOA, NAME, CC) \ if ((CC).giga_no == 0) \ - erts_print(TO, TOA, "%s calls: %bpu\n", NAME, CC.no); \ + erts_print(TO, TOA, "%s calls: %b32u\n", NAME, CC.no); \ else \ - erts_print(TO, TOA, "%s calls: %bpu%09lu\n", NAME, CC.giga_no, CC.no) + erts_print(TO, TOA, "%s calls: %b32u%09lu\n", NAME, CC.giga_no, CC.no) #define PRINT_CC_5(TO, TOA, PRFX, NAME, CC) \ if ((CC).giga_no == 0) \ - erts_print(TO, TOA, "%s%s calls: %bpu\n",PRFX,NAME,CC.no); \ + erts_print(TO, TOA, "%s%s calls: %b32u\n",PRFX,NAME,CC.no); \ else \ - erts_print(TO, TOA, "%s%s calls: %bpu%09lu\n",PRFX,NAME,CC.giga_no,CC.no) + erts_print(TO, TOA, "%s%s calls: %b32u%09lu\n",PRFX,NAME,CC.giga_no,CC.no) char *prefix = allctr->name_prefix; int to = *print_to_p; @@ -2168,21 +2168,21 @@ info_options(Allctr_t *allctr, "option e: true\n" "option t: %s\n" "option ramv: %s\n" - "option sbct: %bpu\n" + "option sbct: %beu\n" #if HAVE_ERTS_MSEG "option asbcst: %bpu\n" "option rsbcst: %bpu\n" #endif - "option rsbcmt: %bpu\n" - "option rmbcmt: %bpu\n" - "option mmbcs: %bpu\n" + "option rsbcmt: %beu\n" + "option rmbcmt: %beu\n" + "option mmbcs: %beu\n" #if HAVE_ERTS_MSEG - "option mmsbc: %bpu\n" - "option mmmbc: %bpu\n" + "option mmsbc: %beu\n" + "option mmmbc: %beu\n" #endif - "option lmbcs: %bpu\n" - "option smbcs: %bpu\n" - "option mbcgs: %bpu\n", + "option lmbcs: %beu\n" + "option smbcs: %beu\n" + "option mbcgs: %beu\n", topt, allctr->ramv ? "true" : "false", allctr->sbc_threshold, @@ -2292,9 +2292,9 @@ erts_alcu_au_info_options(int *print_to_p, void *print_to_arg, erts_print(*print_to_p, print_to_arg, #if HAVE_ERTS_MSEG - "option mmc: %bpu\n" + "option mmc: %beu\n" #endif - "option ycs: %bpu\n", + "option ycs: %beu\n", #if HAVE_ERTS_MSEG max_mseg_carriers, #endif diff --git a/erts/emulator/beam/erl_bif_info.c b/erts/emulator/beam/erl_bif_info.c index e06fbde9fb..e50fc18e64 100644 --- a/erts/emulator/beam/erl_bif_info.c +++ b/erts/emulator/beam/erl_bif_info.c @@ -71,9 +71,9 @@ static char erts_system_version[] = ("Erlang " ERLANG_OTP_RELEASE #endif #endif #ifdef ERTS_SMP - " [smp:%bpu:%bpu]" + " [smp:%beu:%beu]" #endif - " [rq:%bpu]" + " [rq:%beu]" #ifdef USE_THREADS " [async-threads:%d]" #endif @@ -1723,8 +1723,14 @@ info_1_tuple(Process* BIF_P, /* Pointer to current process. */ } else if (is_list(*tp)) { #if defined(PURIFY) #define ERTS_ERROR_CHECKER_PRINTF purify_printf +#define ERTS_ERROR_CHECKER_PRINTF_XML purify_printf #elif defined(VALGRIND) #define ERTS_ERROR_CHECKER_PRINTF VALGRIND_PRINTF +# ifndef HAVE_VALGRIND_PRINTF_XML +# define ERTS_ERROR_CHECKER_PRINTF_XML VALGRIND_PRINTF +# else +# define ERTS_ERROR_CHECKER_PRINTF_XML VALGRIND_PRINTF_XML +# endif #endif int buf_size = 8*1024; /* Try with 8KB first */ char *buf = erts_alloc(ERTS_ALC_T_TMP, buf_size); @@ -1741,8 +1747,8 @@ info_1_tuple(Process* BIF_P, /* Pointer to current process. */ } buf[buf_size - 1 - r] = '\0'; if (check_if_xml()) { - ERTS_ERROR_CHECKER_PRINTF("<erlang_info_log>" - "%s</erlang_info_log>\n", buf); + ERTS_ERROR_CHECKER_PRINTF_XML("<erlang_info_log>" + "%s</erlang_info_log>\n", buf); } else { ERTS_ERROR_CHECKER_PRINTF("%s\n", buf); } diff --git a/erts/emulator/beam/erl_bits.c b/erts/emulator/beam/erl_bits.c index 6f8a7436d5..0174e5fc43 100644 --- a/erts/emulator/beam/erl_bits.c +++ b/erts/emulator/beam/erl_bits.c @@ -177,7 +177,6 @@ erts_bs_get_integer_2(Process *p, Uint num_bits, unsigned flags, ErlBinMatchBuff byte* LSB; byte* MSB; Uint* hp; - Uint* hp_end; Uint words_needed; Uint actual; Uint v32; @@ -405,7 +404,6 @@ erts_bs_get_integer_2(Process *p, Uint num_bits, unsigned flags, ErlBinMatchBuff default: words_needed = 1+WSIZE(bytes); hp = HeapOnlyAlloc(p, words_needed); - hp_end = hp + words_needed; res = bytes_to_big(LSB, bytes, sgn, hp); if (is_small(res)) { p->htop = hp; @@ -425,7 +423,6 @@ Eterm erts_bs_get_binary_2(Process *p, Uint num_bits, unsigned flags, ErlBinMatchBuffer* mb) { ErlSubBin* sb; - size_t num_bytes; /* Number of bytes in binary. */ if (mb->size - mb->offset < num_bits) { /* Asked for too many bits. */ return THE_NON_VALUE; @@ -435,7 +432,6 @@ erts_bs_get_binary_2(Process *p, Uint num_bits, unsigned flags, ErlBinMatchBuffe * From now on, we can't fail. */ - num_bytes = NBYTES(num_bits); sb = (ErlSubBin *) HeapOnlyAlloc(p, ERL_SUB_BIN_SIZE); sb->thing_word = HEADER_SUB_BIN; @@ -1557,7 +1553,6 @@ Uint32 erts_bs_get_unaligned_uint32(ErlBinMatchBuffer* mb) { Uint bytes; - Uint bits; Uint offs; byte bigbuf[4]; byte* LSB; @@ -1567,7 +1562,6 @@ erts_bs_get_unaligned_uint32(ErlBinMatchBuffer* mb) ASSERT(mb->size - mb->offset >= 32); bytes = 4; - bits = 8; offs = 0; LSB = bigbuf; diff --git a/erts/emulator/beam/erl_db.c b/erts/emulator/beam/erl_db.c index 61e8a595be..e0a6aa05c6 100644 --- a/erts/emulator/beam/erl_db.c +++ b/erts/emulator/beam/erl_db.c @@ -3737,7 +3737,7 @@ static void print_table(int to, void *to_arg, int show, DbTable* tb) erts_print(to, to_arg, "Objects: %d\n", (int)erts_smp_atomic_read(&tb->common.nitems)); erts_print(to, to_arg, "Words: %bpu\n", - (Uint) ((erts_smp_atomic_read(&tb->common.memory_size) + (UWord) ((erts_smp_atomic_read(&tb->common.memory_size) + sizeof(Uint) - 1) / sizeof(Uint))); diff --git a/erts/emulator/beam/erl_db_tree.c b/erts/emulator/beam/erl_db_tree.c index 6cdbec3213..a59c0c258d 100644 --- a/erts/emulator/beam/erl_db_tree.c +++ b/erts/emulator/beam/erl_db_tree.c @@ -575,7 +575,7 @@ static int db_prev_tree(Process *p, DbTable *tbl, Eterm key, Eterm *ret) return DB_ERROR_NONE; } -static ERTS_INLINE int cmp_key(DbTableTree* tb, Eterm key, Eterm* key_base, +static ERTS_INLINE Sint cmp_key(DbTableTree* tb, Eterm key, Eterm* key_base, TreeDbTerm* obj) { return cmp_rel(key, key_base, diff --git a/erts/emulator/beam/erl_db_util.c b/erts/emulator/beam/erl_db_util.c index 0b63ab9ba0..c3b074f782 100644 --- a/erts/emulator/beam/erl_db_util.c +++ b/erts/emulator/beam/erl_db_util.c @@ -5046,31 +5046,31 @@ void db_match_dis(Binary *bp) ++t; n = *t; ++t; - erts_printf("TryMeElse\t%bpu\n", n); + erts_printf("TryMeElse\t%beu\n", n); break; case matchArray: ++t; n = *t; ++t; - erts_printf("Array\t%bpu\n", n); + erts_printf("Array\t%beu\n", n); break; case matchArrayBind: ++t; n = *t; ++t; - erts_printf("ArrayBind\t%bpu\n", n); + erts_printf("ArrayBind\t%beu\n", n); break; case matchTuple: ++t; n = *t; ++t; - erts_printf("Tuple\t%bpu\n", n); + erts_printf("Tuple\t%beu\n", n); break; case matchPushT: ++t; n = *t; ++t; - erts_printf("PushT\t%bpu\n", n); + erts_printf("PushT\t%beu\n", n); break; case matchPushL: ++t; @@ -5084,13 +5084,13 @@ void db_match_dis(Binary *bp) ++t; n = *t; ++t; - erts_printf("Bind\t%bpu\n", n); + erts_printf("Bind\t%beu\n", n); break; case matchCmp: ++t; n = *t; ++t; - erts_printf("Cmp\t%bpu\n", n); + erts_printf("Cmp\t%beu\n", n); break; case matchEqBin: ++t; @@ -5112,9 +5112,9 @@ void db_match_dis(Binary *bp) else erts_printf(", "); #if defined(ARCH_64) && !HALFWORD_HEAP - erts_printf("0x%016bpx", rt->data.ui[ri]); + erts_printf("0x%016bex", rt->data.ui[ri]); #else - erts_printf("0x%08bpx", rt->data.ui[ri]); + erts_printf("0x%08bex", rt->data.ui[ri]); #endif } } @@ -5136,9 +5136,9 @@ void db_match_dis(Binary *bp) else erts_printf(", "); #if defined(ARCH_64) && !HALFWORD_HEAP - erts_printf("0x%016bpx", *et); + erts_printf("0x%016bex", *et); #else - erts_printf("0x%08bpx", *et); + erts_printf("0x%08bex", *et); #endif ++et; } @@ -5190,31 +5190,31 @@ void db_match_dis(Binary *bp) ++t; n = *t; ++t; - erts_printf("MkTuple\t%bpu\n", n); + erts_printf("MkTuple\t%beu\n", n); break; case matchOr: ++t; n = *t; ++t; - erts_printf("Or\t%bpu\n", n); + erts_printf("Or\t%beu\n", n); break; case matchAnd: ++t; n = *t; ++t; - erts_printf("And\t%bpu\n", n); + erts_printf("And\t%beu\n", n); break; case matchOrElse: ++t; n = *t; ++t; - erts_printf("OrElse\t%bpu\n", n); + erts_printf("OrElse\t%beu\n", n); break; case matchAndAlso: ++t; n = *t; ++t; - erts_printf("AndAlso\t%bpu\n", n); + erts_printf("AndAlso\t%beu\n", n); break; case matchCall0: ++t; @@ -5244,19 +5244,19 @@ void db_match_dis(Binary *bp) ++t; n = (Uint) *t; ++t; - erts_printf("PushV\t%bpu\n", n); + erts_printf("PushV\t%beu\n", n); break; #if HALFWORD_HEAP case matchPushVGuard: n = (Uint) *++t; ++t; - erts_printf("PushVGuard\t%bpu\n", n); + erts_printf("PushVGuard\t%beu\n", n); break; #endif case matchPushVResult: n = (Uint) *++t; ++t; - erts_printf("PushVResult\t%bpu\n", n); + erts_printf("PushVResult\t%beu\n", n); break; case matchTrue: ++t; @@ -5367,8 +5367,8 @@ void db_match_dis(Binary *bp) } erts_printf("}\n"); erts_printf("num_bindings: %d\n", prog->num_bindings); - erts_printf("heap_size: %bpu\n", prog->heap_size); - erts_printf("stack_offset: %bpu\n", prog->stack_offset); + erts_printf("heap_size: %beu\n", prog->heap_size); + erts_printf("stack_offset: %beu\n", prog->stack_offset); erts_printf("text: 0x%08x\n", (unsigned long) prog->text); erts_printf("stack_size: %d (words)\n", prog->heap_size-prog->stack_offset); diff --git a/erts/emulator/beam/erl_driver.h b/erts/emulator/beam/erl_driver.h index 13a73e01bb..069b71ab0d 100644 --- a/erts/emulator/beam/erl_driver.h +++ b/erts/emulator/beam/erl_driver.h @@ -282,7 +282,7 @@ typedef struct erl_drv_entry { the port */ void (*ready_input)(ErlDrvData drv_data, ErlDrvEvent event); /* called when we have input from one of - the driver's handles) */ + the driver's handles */ void (*ready_output)(ErlDrvData drv_data, ErlDrvEvent event); /* called when output is possible to one of the driver's handles */ @@ -294,7 +294,7 @@ typedef struct erl_drv_entry { int (*control)(ErlDrvData drv_data, unsigned int command, char *buf, int len, char **rbuf, int rlen); /* "ioctl" for drivers - invoked by - port_control/3) */ + port_control/3 */ void (*timeout)(ErlDrvData drv_data); /* Handling of timeout in driver */ void (*outputv)(ErlDrvData drv_data, ErlIOVec *ev); /* called when we have output from erlang @@ -307,7 +307,7 @@ typedef struct erl_drv_entry { before 'stop' can be called */ int (*call)(ErlDrvData drv_data, unsigned int command, char *buf, int len, char **rbuf, int rlen, unsigned int *flags); - /* Works mostly like 'control', a syncronous + /* Works mostly like 'control', a synchronous call into the driver. */ void (*event)(ErlDrvData drv_data, ErlDrvEvent event, ErlDrvEventData event_data); diff --git a/erts/emulator/beam/erl_gc.c b/erts/emulator/beam/erl_gc.c index d9150d86fe..5edcd667e7 100644 --- a/erts/emulator/beam/erl_gc.c +++ b/erts/emulator/beam/erl_gc.c @@ -215,7 +215,7 @@ erts_next_heap_size(Uint size, Uint offset) low = mid + 1; } } - erl_exit(1, "no next heap size found: %d, offset %d\n", size, offset); + erl_exit(1, "no next heap size found: %lu, offset %lu\n", (unsigned long)size, (unsigned long)offset); } return 0; } @@ -455,7 +455,6 @@ erts_garbage_collect_hibernate(Process* p) Eterm* heap; Eterm* htop; Rootset rootset; - int n; char* src; Uint src_size; Uint actual_size; @@ -486,7 +485,7 @@ erts_garbage_collect_hibernate(Process* p) sizeof(Eterm)*heap_size); htop = heap; - n = setup_rootset(p, p->arg_reg, p->arity, &rootset); + (void) setup_rootset(p, p->arg_reg, p->arity, &rootset); #if HIPE hipe_empty_nstack(p); #endif diff --git a/erts/emulator/beam/erl_nif.c b/erts/emulator/beam/erl_nif.c index 135c6b0ccc..8b48444904 100644 --- a/erts/emulator/beam/erl_nif.c +++ b/erts/emulator/beam/erl_nif.c @@ -430,6 +430,11 @@ int enif_is_list(ErlNifEnv* env, ERL_NIF_TERM term) return is_list(term) || is_nil(term); } +int enif_is_exception(ErlNifEnv* env, ERL_NIF_TERM term) +{ + return term == THE_NON_VALUE; +} + static void aligned_binary_dtor(struct enif_tmp_obj_t* obj) { erts_free_aligned_binary_bytes_extra((byte*)obj,ERTS_ALC_T_TMP); diff --git a/erts/emulator/beam/erl_nif.h b/erts/emulator/beam/erl_nif.h index 8050b3640a..d028567faf 100644 --- a/erts/emulator/beam/erl_nif.h +++ b/erts/emulator/beam/erl_nif.h @@ -31,9 +31,10 @@ ** 1.0: R13B04 ** 2.0: R14A ** 2.1: R14B02 "vm_variant" +** 2.2: R14B03 enif_is_exception */ #define ERL_NIF_MAJOR_VERSION 2 -#define ERL_NIF_MINOR_VERSION 1 +#define ERL_NIF_MINOR_VERSION 2 #include <stdlib.h> diff --git a/erts/emulator/beam/erl_nif_api_funcs.h b/erts/emulator/beam/erl_nif_api_funcs.h index eca506593d..c991b61abe 100644 --- a/erts/emulator/beam/erl_nif_api_funcs.h +++ b/erts/emulator/beam/erl_nif_api_funcs.h @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 2009-2010. All Rights Reserved. + * Copyright Ericsson AB 2009-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 @@ -21,6 +21,13 @@ # error This file should not be included directly #endif +/* +** WARNING: add new ERL_NIF_API_FUNC_DECL entries at the bottom of the list +** to keep compatibility on Windows!!! +** +** And don't forget to increase ERL_NIF_MINOR_VERSION in erl_nif.h +** when adding functions to the API. +*/ #ifdef ERL_NIF_API_FUNC_DECL ERL_NIF_API_FUNC_DECL(void*,enif_priv_data,(ErlNifEnv*)); ERL_NIF_API_FUNC_DECL(void*,enif_alloc,(size_t size)); @@ -128,12 +135,17 @@ ERL_NIF_API_FUNC_DECL(int,enif_get_uint64,(ErlNifEnv*, ERL_NIF_TERM term, ErlNif ERL_NIF_API_FUNC_DECL(ERL_NIF_TERM,enif_make_int64,(ErlNifEnv*, ErlNifSInt64)); ERL_NIF_API_FUNC_DECL(ERL_NIF_TERM,enif_make_uint64,(ErlNifEnv*, ErlNifUInt64)); #endif +ERL_NIF_API_FUNC_DECL(int,enif_is_exception,(ErlNifEnv*, ERL_NIF_TERM term)); /* -** Add last to keep compatibility on Windows!!! +** Add new entries here to keep compatibility on Windows!!! */ #endif +/* +** Please keep the ERL_NIF_API_FUNC_MACRO list below in the same order +** as the ERL_NIF_API_FUNC_DECL list above +*/ #ifdef ERL_NIF_API_FUNC_MACRO # define enif_priv_data ERL_NIF_API_FUNC_MACRO(enif_priv_data) # define enif_alloc ERL_NIF_API_FUNC_MACRO(enif_alloc) @@ -243,6 +255,11 @@ ERL_NIF_API_FUNC_DECL(ERL_NIF_TERM,enif_make_uint64,(ErlNifEnv*, ErlNifUInt64)); # define enif_make_uint64 ERL_NIF_API_FUNC_MACRO(enif_make_uint64) #endif +# define enif_is_exception ERL_NIF_API_FUNC_MACRO(enif_is_exception) + +/* +** Add new entries here +*/ #endif #ifndef enif_make_list1 diff --git a/erts/emulator/beam/erl_printf_term.c b/erts/emulator/beam/erl_printf_term.c index d9f132f067..b71404fd27 100644 --- a/erts/emulator/beam/erl_printf_term.c +++ b/erts/emulator/beam/erl_printf_term.c @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 2005-2010. All Rights Reserved. + * Copyright Ericsson AB 2005-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 @@ -216,233 +216,289 @@ static int print_atom_name(fmtfn_t fn, void* arg, Eterm atom, long *dcount) } +#define PRT_BAR ((Eterm) 0) +#define PRT_COMMA ((Eterm) 1) +#define PRT_CLOSE_LIST ((Eterm) 2) +#define PRT_CLOSE_TUPLE ((Eterm) 3) +#define PRT_TERM ((Eterm) 4) +#define PRT_ONE_CONS ((Eterm) 5) +#define PRT_PATCH_FUN_SIZE ((Eterm) 6) +#define PRT_LAST_ARRAY_ELEMENT ((Eterm) 7) /* Note! Must be last... */ static int print_term(fmtfn_t fn, void* arg, Eterm obj, long *dcount) { + DECLARE_WSTACK(s); int res; int i; + Eterm val; Uint32 *ref_num; Eterm* nobj; +#if HALFWORD_HEAP + UWord wobj; +#endif res = 0; - if ((*dcount)-- <= 0) - return res; - -#ifdef HYBRID___NOT_ACTIVE - /* Color coded output based on memory location */ - if(ptr_val(obj) >= global_heap && ptr_val(obj) < global_hend) - PRINT_STRING(res, fn, arg, "\033[32m"); -#ifdef INCREMENTAL - else if(ptr_val(obj) >= inc_fromspc && ptr_val(obj) < inc_fromend) - PRINT_STRING(res, fn, arg, "\033[33m"); + goto L_jump_start; + + L_outer_loop: + while (!WSTACK_ISEMPTY(s)) { + switch (val = WSTACK_POP(s)) { + case PRT_COMMA: + PRINT_CHAR(res, fn, arg, ','); + goto L_outer_loop; + case PRT_BAR: + PRINT_CHAR(res, fn, arg, '|'); + goto L_outer_loop; + case PRT_CLOSE_LIST: + PRINT_CHAR(res, fn, arg, ']'); + goto L_outer_loop; + case PRT_CLOSE_TUPLE: + PRINT_CHAR(res, fn, arg, '}'); + goto L_outer_loop; + default: +#if HALFWORD_HEAP + obj = (Eterm) (wobj = WSTACK_POP(s)); +#else + obj = WSTACK_POP(s); #endif - else if(IS_CONST(obj)) - PRINT_STRING(res, fn, arg, "\033[34m"); - else - PRINT_STRING(res, fn, arg, "\033[31m"); + switch (val) { + case PRT_TERM: + break; + case PRT_ONE_CONS: + L_print_one_cons: + { + Eterm* cons = list_val(obj); + Eterm tl; + + obj = CAR(cons); + tl = CDR(cons); + if (is_not_nil(tl)) { + if (is_list(tl)) { + WSTACK_PUSH(s, tl); + WSTACK_PUSH(s, PRT_ONE_CONS); + WSTACK_PUSH(s, PRT_COMMA); + } else { + WSTACK_PUSH(s, tl); + WSTACK_PUSH(s, PRT_TERM); + WSTACK_PUSH(s, PRT_BAR); + } + } + } + break; + case PRT_LAST_ARRAY_ELEMENT: + { +#if HALFWORD_HEAP + Eterm* ptr = (Eterm *) wobj; +#else + Eterm* ptr = (Eterm *) obj; #endif + obj = *ptr; + } + break; + default: /* PRT_LAST_ARRAY_ELEMENT+1 and upwards */ + { +#if HALFWORD_HEAP + Eterm* ptr = (Eterm *) wobj; +#else + Eterm* ptr = (Eterm *) obj; +#endif + obj = *ptr++; + WSTACK_PUSH(s, (UWord) ptr); + WSTACK_PUSH(s, val-1); + WSTACK_PUSH(s, PRT_COMMA); + } + break; + } + break; + } - if (is_CP(obj)) { - PRINT_STRING(res, fn, arg, "<cp/header:"); - PRINT_POINTER(res, fn, arg, cp_val(obj)); - PRINT_CHAR(res, fn, arg, '>'); - return res; - } + L_jump_start: - switch (tag_val_def(obj)) { - case NIL_DEF: - PRINT_STRING(res, fn, arg, "[]"); - break; - case ATOM_DEF: { - int tres = print_atom_name(fn, arg, obj, dcount); - if (tres < 0) - return tres; - res += tres; - if (*dcount <= 0) - return res; - break; - } - case SMALL_DEF: - PRINT_SLONG(res, fn, arg, 'd', 0, 1, (signed long) signed_val(obj)); - break; - case BIG_DEF: { - int print_res; - char def_buf[64]; - char *buf, *big_str; - Uint sz = (Uint) big_decimal_estimate(obj); - sz++; - if (sz <= 64) - buf = &def_buf[0]; - else - buf = erts_alloc(ERTS_ALC_T_TMP, sz); - big_str = erts_big_to_string(obj, buf, sz); - print_res = erts_printf_string(fn, arg, big_str); - if (buf != &def_buf[0]) - erts_free(ERTS_ALC_T_TMP, (void *) buf); - if (print_res < 0) - return print_res; - res += print_res; - break; - } - case REF_DEF: - case EXTERNAL_REF_DEF: - PRINT_STRING(res, fn, arg, "#Ref<"); - PRINT_ULONG(res, fn, arg, 'u', 0, 1, - (unsigned long) ref_channel_no(obj)); - ref_num = ref_numbers(obj); - for (i = ref_no_of_numbers(obj)-1; i >= 0; i--) { - PRINT_CHAR(res, fn, arg, '.'); - PRINT_ULONG(res, fn, arg, 'u', 0, 1, (unsigned long) ref_num[i]); + if ((*dcount)-- <= 0) + goto L_done; + + if (is_CP(obj)) { + PRINT_STRING(res, fn, arg, "<cp/header:"); + PRINT_POINTER(res, fn, arg, cp_val(obj)); + PRINT_CHAR(res, fn, arg, '>'); + goto L_done; } - PRINT_CHAR(res, fn, arg, '>'); - break; - case PID_DEF: - case EXTERNAL_PID_DEF: - PRINT_CHAR(res, fn, arg, '<'); - PRINT_ULONG(res, fn, arg, 'u', 0, 1, - (unsigned long) pid_channel_no(obj)); - PRINT_CHAR(res, fn, arg, '.'); - PRINT_ULONG(res, fn, arg, 'u', 0, 1, - (unsigned long) pid_number(obj)); - PRINT_CHAR(res, fn, arg, '.'); - PRINT_ULONG(res, fn, arg, 'u', 0, 1, - (unsigned long) pid_serial(obj)); - PRINT_CHAR(res, fn, arg, '>'); - break; - case PORT_DEF: - case EXTERNAL_PORT_DEF: - PRINT_STRING(res, fn, arg, "#Port<"); - PRINT_ULONG(res, fn, arg, 'u', 0, 1, - (unsigned long) port_channel_no(obj)); - PRINT_CHAR(res, fn, arg, '.'); - PRINT_ULONG(res, fn, arg, 'u', 0, 1, - (unsigned long) port_number(obj)); - PRINT_CHAR(res, fn, arg, '>'); - break; - case LIST_DEF: - if (is_printable_string(obj)) { - int c; - PRINT_CHAR(res, fn, arg, '"'); - nobj = list_val(obj); - while (1) { - if ((*dcount)-- <= 0) - return res; - c = signed_val(*nobj++); - if (c == '\n') - PRINT_STRING(res, fn, arg, "\\n"); - else { - if (c == '"') - PRINT_CHAR(res, fn, arg, '\\'); - PRINT_CHAR(res, fn, arg, (char) c); - } - if (is_not_list(*nobj)) - break; - nobj = list_val(*nobj); - } - PRINT_CHAR(res, fn, arg, '"'); - } else { - PRINT_CHAR(res, fn, arg, '['); - nobj = list_val(obj); - while (1) { - int tres = print_term(fn, arg, *nobj++, dcount); - if (tres < 0) - return tres; - res += tres; - if (*dcount <= 0) - return res; - if (is_not_list(*nobj)) - break; - PRINT_CHAR(res, fn, arg, ','); - nobj = list_val(*nobj); - } - if (is_not_nil(*nobj)) { - int tres; - PRINT_CHAR(res, fn, arg, '|'); - tres = print_term(fn, arg, *nobj, dcount); - if (tres < 0) - return tres; - res += tres; - if (*dcount <= 0) - return res; + + switch (tag_val_def(obj)) { + case NIL_DEF: + PRINT_STRING(res, fn, arg, "[]"); + break; + case ATOM_DEF: { + int tres = print_atom_name(fn, arg, obj, dcount); + if (tres < 0) { + res = tres; + goto L_done; } - PRINT_CHAR(res, fn, arg, ']'); - } - break; - case TUPLE_DEF: - nobj = tuple_val(obj); /* pointer to arity */ - i = arityval(*nobj); /* arity */ - PRINT_CHAR(res, fn, arg, '{'); - while (i--) { - int tres = print_term(fn, arg, *++nobj, dcount); - if (tres < 0) - return tres; res += tres; if (*dcount <= 0) - return res; - if (i >= 1) - PRINT_CHAR(res, fn, arg, ','); - } - PRINT_CHAR(res, fn, arg, '}'); - break; - case FLOAT_DEF: { - FloatDef ff; - GET_DOUBLE(obj, ff); - PRINT_DOUBLE(res, fn, arg, 'e', 6, 0, ff.fd); + goto L_done; + break; } - break; - case BINARY_DEF: - { - ProcBin* pb = (ProcBin *) binary_val(obj); - if (pb->size == 1) - PRINT_STRING(res, fn, arg, "<<1 byte>>"); - else { - PRINT_STRING(res, fn, arg, "<<"); - PRINT_ULONG(res, fn, arg, 'u', 0, 1, (unsigned long) pb->size); - PRINT_STRING(res, fn, arg, " bytes>>"); + case SMALL_DEF: + PRINT_SLONG(res, fn, arg, 'd', 0, 1, (signed long) signed_val(obj)); + break; + case BIG_DEF: { + int print_res; + char def_buf[64]; + char *buf, *big_str; + Uint sz = (Uint) big_decimal_estimate(obj); + sz++; + if (sz <= 64) + buf = &def_buf[0]; + else + buf = erts_alloc(ERTS_ALC_T_TMP, sz); + big_str = erts_big_to_string(obj, buf, sz); + print_res = erts_printf_string(fn, arg, big_str); + if (buf != &def_buf[0]) + erts_free(ERTS_ALC_T_TMP, (void *) buf); + if (print_res < 0) { + res = print_res; + goto L_done; } + res += print_res; + break; } - break; - case EXPORT_DEF: - { - Export* ep = *((Export **) (export_val(obj) + 1)); - Atom* module = atom_tab(atom_val(ep->code[0])); - Atom* name = atom_tab(atom_val(ep->code[1])); - - PRINT_STRING(res, fn, arg, "#Fun<"); - PRINT_BUF(res, fn, arg, module->name, module->len); + case REF_DEF: + case EXTERNAL_REF_DEF: + PRINT_STRING(res, fn, arg, "#Ref<"); + PRINT_ULONG(res, fn, arg, 'u', 0, 1, + (unsigned long) ref_channel_no(obj)); + ref_num = ref_numbers(obj); + for (i = ref_no_of_numbers(obj)-1; i >= 0; i--) { + PRINT_CHAR(res, fn, arg, '.'); + PRINT_ULONG(res, fn, arg, 'u', 0, 1, (unsigned long) ref_num[i]); + } + PRINT_CHAR(res, fn, arg, '>'); + break; + case PID_DEF: + case EXTERNAL_PID_DEF: + PRINT_CHAR(res, fn, arg, '<'); + PRINT_ULONG(res, fn, arg, 'u', 0, 1, + (unsigned long) pid_channel_no(obj)); PRINT_CHAR(res, fn, arg, '.'); - PRINT_BUF(res, fn, arg, name->name, name->len); + PRINT_ULONG(res, fn, arg, 'u', 0, 1, + (unsigned long) pid_number(obj)); PRINT_CHAR(res, fn, arg, '.'); - PRINT_SLONG(res, fn, arg, 'd', 0, 1, - (signed long) ep->code[2]); + PRINT_ULONG(res, fn, arg, 'u', 0, 1, + (unsigned long) pid_serial(obj)); PRINT_CHAR(res, fn, arg, '>'); - } - break; - case FUN_DEF: - { - ErlFunThing *funp = (ErlFunThing *) fun_val(obj); - Atom *ap = atom_tab(atom_val(funp->fe->module)); - - PRINT_STRING(res, fn, arg, "#Fun<"); - PRINT_BUF(res, fn, arg, ap->name, ap->len); - PRINT_CHAR(res, fn, arg, '.'); - PRINT_SLONG(res, fn, arg, 'd', 0, 1, - (signed long) funp->fe->old_index); + break; + case PORT_DEF: + case EXTERNAL_PORT_DEF: + PRINT_STRING(res, fn, arg, "#Port<"); + PRINT_ULONG(res, fn, arg, 'u', 0, 1, + (unsigned long) port_channel_no(obj)); PRINT_CHAR(res, fn, arg, '.'); - PRINT_SLONG(res, fn, arg, 'd', 0, 1, - (signed long) funp->fe->old_uniq); + PRINT_ULONG(res, fn, arg, 'u', 0, 1, + (unsigned long) port_number(obj)); PRINT_CHAR(res, fn, arg, '>'); + break; + case LIST_DEF: + if (is_printable_string(obj)) { + int c; + PRINT_CHAR(res, fn, arg, '"'); + nobj = list_val(obj); + while (1) { + if ((*dcount)-- <= 0) + goto L_done; + c = signed_val(*nobj++); + if (c == '\n') + PRINT_STRING(res, fn, arg, "\\n"); + else { + if (c == '"') + PRINT_CHAR(res, fn, arg, '\\'); + PRINT_CHAR(res, fn, arg, (char) c); + } + if (is_not_list(*nobj)) + break; + nobj = list_val(*nobj); + } + PRINT_CHAR(res, fn, arg, '"'); + } else { + PRINT_CHAR(res, fn, arg, '['); + WSTACK_PUSH(s,PRT_CLOSE_LIST); + goto L_print_one_cons; + } + break; + case TUPLE_DEF: + nobj = tuple_val(obj); /* pointer to arity */ + i = arityval(*nobj); /* arity */ + PRINT_CHAR(res, fn, arg, '{'); + WSTACK_PUSH(s,PRT_CLOSE_TUPLE); + ++nobj; + if (i > 0) { + WSTACK_PUSH(s, (UWord) nobj); + WSTACK_PUSH(s, PRT_LAST_ARRAY_ELEMENT+i-1); + } + break; + case FLOAT_DEF: { + FloatDef ff; + GET_DOUBLE(obj, ff); + PRINT_DOUBLE(res, fn, arg, 'e', 6, 0, ff.fd); + } + break; + case BINARY_DEF: + { + ProcBin* pb = (ProcBin *) binary_val(obj); + if (pb->size == 1) + PRINT_STRING(res, fn, arg, "<<1 byte>>"); + else { + PRINT_STRING(res, fn, arg, "<<"); + PRINT_ULONG(res, fn, arg, 'u', 0, 1, (unsigned long) pb->size); + PRINT_STRING(res, fn, arg, " bytes>>"); + } + } + break; + case EXPORT_DEF: + { + Export* ep = *((Export **) (export_val(obj) + 1)); + Atom* module = atom_tab(atom_val(ep->code[0])); + Atom* name = atom_tab(atom_val(ep->code[1])); + + PRINT_STRING(res, fn, arg, "#Fun<"); + PRINT_BUF(res, fn, arg, module->name, module->len); + PRINT_CHAR(res, fn, arg, '.'); + PRINT_BUF(res, fn, arg, name->name, name->len); + PRINT_CHAR(res, fn, arg, '.'); + PRINT_SLONG(res, fn, arg, 'd', 0, 1, + (signed long) ep->code[2]); + PRINT_CHAR(res, fn, arg, '>'); + } + break; + case FUN_DEF: + { + ErlFunThing *funp = (ErlFunThing *) fun_val(obj); + Atom *ap = atom_tab(atom_val(funp->fe->module)); + + PRINT_STRING(res, fn, arg, "#Fun<"); + PRINT_BUF(res, fn, arg, ap->name, ap->len); + PRINT_CHAR(res, fn, arg, '.'); + PRINT_SLONG(res, fn, arg, 'd', 0, 1, + (signed long) funp->fe->old_index); + PRINT_CHAR(res, fn, arg, '.'); + PRINT_SLONG(res, fn, arg, 'd', 0, 1, + (signed long) funp->fe->old_uniq); + PRINT_CHAR(res, fn, arg, '>'); + } + break; + default: + PRINT_STRING(res, fn, arg, "<unknown:"); + PRINT_POINTER(res, fn, arg, (UWord) obj); + PRINT_CHAR(res, fn, arg, '>'); + break; } - break; - default: - PRINT_STRING(res, fn, arg, "<unknown:"); - PRINT_POINTER(res, fn, arg, (UWord) obj); - PRINT_CHAR(res, fn, arg, '>'); - break; } + L_done: + + DESTROY_WSTACK(s); return res; } diff --git a/erts/emulator/beam/erl_process.c b/erts/emulator/beam/erl_process.c index 428ca12eb1..31f23d3978 100644 --- a/erts/emulator/beam/erl_process.c +++ b/erts/emulator/beam/erl_process.c @@ -1267,7 +1267,6 @@ ssi_flags_set_wake(ErtsSchedulerSleepInfo *ssi) static void wake_scheduler(ErtsRunQueue *rq, int incq, int one) { - int res; ErtsSchedulerSleepInfo *ssi; ErtsSchedulerSleepList *sl; @@ -1298,7 +1297,6 @@ wake_scheduler(ErtsRunQueue *rq, int incq, int one) if (ssi->next) ssi->next->prev = ssi->prev; - res = sl->list != NULL; erts_smp_spin_unlock(&sl->lock); ERTS_THR_MEMORY_BARRIER; @@ -2857,7 +2855,6 @@ resume_process(Process *p) return; switch(p->rstatus) { case P_RUNABLE: - *statusp = P_WAITING; /* make erts_add_to_runq work */ erts_add_to_runq(p); break; case P_WAITING: @@ -3668,7 +3665,7 @@ sched_thread_func(void *vesdp) #ifdef ERTS_ENABLE_LOCK_CHECK { char buf[31]; - erts_snprintf(&buf[0], 31, "scheduler %bpu", no); + erts_snprintf(&buf[0], 31, "scheduler %beu", no); erts_lc_set_thread_name(&buf[0]); } #endif @@ -3726,7 +3723,7 @@ sched_thread_func(void *vesdp) process_main(); /* No schedulers should *ever* terminate */ - erl_exit(ERTS_ABORT_EXIT, "Scheduler thread number %bpu terminated\n", + erl_exit(ERTS_ABORT_EXIT, "Scheduler thread number %beu terminated\n", ((ErtsSchedulerData *) vesdp)->no); return NULL; } @@ -3775,8 +3772,8 @@ erts_start_schedulers(void) erts_dsprintf_buf_t *dsbufp = erts_create_logger_dsbuf(); ASSERT(actual != wanted_no_schedulers); erts_dsprintf(dsbufp, - "Failed to create %bpu scheduler-threads (%s:%d); " - "only %bpu scheduler-thread%s created.\n", + "Failed to create %beu scheduler-threads (%s:%d); " + "only %beu scheduler-thread%s created.\n", wanted_no_schedulers, erl_errno_id(res), res, actual, actual == 1 ? " was" : "s were"); erts_send_error_to_logger_nogl(dsbufp); @@ -4653,7 +4650,7 @@ internal_add_to_runq(ErtsRunQueue *runq, Process *p) if (p->status_flags & ERTS_PROC_SFLG_INRUNQ) return NULL; else if (p->runq_flags & ERTS_PROC_RUNQ_FLG_RUNNING) { - ASSERT(p->status != P_SUSPENDED); + ASSERT(p->rcount == 0); ERTS_DBG_CHK_PROCS_RUNQ_NOPROC(runq, p); p->status_flags |= ERTS_PROC_SFLG_PENDADD2SCHEDQ; return NULL; @@ -4664,9 +4661,8 @@ internal_add_to_runq(ErtsRunQueue *runq, Process *p) ERTS_DBG_CHK_PROCS_RUNQ_NOPROC(runq, p); #ifndef ERTS_SMP /* Never schedule a suspended process (ok in smp case) */ - ASSERT(p->status != P_SUSPENDED); + ASSERT(p->rcount == 0); add_runq = runq; - #else ASSERT(!p->bound_runq || p->bound_runq == p->run_queue); if (p->bound_runq) { @@ -5166,7 +5162,7 @@ Process *schedule(Process *p, int calls) handle_pending_suspend(p, ERTS_PROC_LOCK_MAIN|ERTS_PROC_LOCK_STATUS); ASSERT(!(p->status_flags & ERTS_PROC_SFLG_PENDADD2SCHEDQ) - || p->status != P_SUSPENDED); + || p->rcount == 0); } #endif erts_smp_runq_lock(rq); @@ -7611,10 +7607,28 @@ timeout_proc(Process* p) p->flags |= F_TIMO; p->flags &= ~F_INSLPQUEUE; - if (p->status == P_WAITING) - erts_add_to_runq(p); - if (p->status == P_SUSPENDED) + switch (p->status) { + case P_GARBING: + switch (p->gcstatus) { + case P_SUSPENDED: + goto suspended; + case P_WAITING: + goto waiting; + default: + break; + } + break; + case P_WAITING: + waiting: + erts_add_to_runq(p); + break; + case P_SUSPENDED: + suspended: p->rstatus = P_RUNABLE; /* MUST set resume status to runnable */ + break; + default: + break; + } } @@ -7700,7 +7714,7 @@ erts_program_counter_info(int to, void *to_arg, Process *p) * only cause problems. */ for (i = 0; i < p->arity; i++) - erts_print(to, to_arg, " %T\n", p->arg_reg[i]); + erts_print(to, to_arg, " %.*T\n", INT_MAX, p->arg_reg[i]); } } } diff --git a/erts/emulator/beam/erl_process.h b/erts/emulator/beam/erl_process.h index 8f78a7d76e..334ae5573f 100644 --- a/erts/emulator/beam/erl_process.h +++ b/erts/emulator/beam/erl_process.h @@ -895,6 +895,7 @@ extern struct erts_system_profile_flags_t erts_system_profile_flags; #define F_HAVE_BLCKD_MSCHED (1 << 8) /* Process has blocked multi-scheduling */ #define F_P2PNR_RESCHED (1 << 9) /* Process has been rescheduled via erts_pid2proc_not_running() */ #define F_FORCE_GC (1 << 10) /* Force gc at process in-scheduling */ +#define F_HIBERNATE_SCHED (1 << 11) /* Schedule out after hibernate op */ /* process trace_flags */ #define F_SENSITIVE (1 << 0) diff --git a/erts/emulator/beam/erl_process_dump.c b/erts/emulator/beam/erl_process_dump.c index 68fda01597..5410bcd495 100644 --- a/erts/emulator/beam/erl_process_dump.c +++ b/erts/emulator/beam/erl_process_dump.c @@ -194,7 +194,7 @@ dump_element(int to, void *to_arg, Eterm x) } else if (is_pid(x)) { erts_print(to, to_arg, "P%T", x); } else if (is_port(x)) { - erts_print(to, to_arg, "p<%bpu.%bpu>", + erts_print(to, to_arg, "p<%beu.%beu>", port_channel_no(x), port_number(x)); } else if (is_nil(x)) { erts_putc(to, to_arg, 'N'); @@ -376,7 +376,7 @@ heap_dump(int to, void *to_arg, Eterm x) erts_print(to, to_arg, "P%T\n", x); *ptr = OUR_NIL; } else if (is_external_port_header(hdr)) { - erts_print(to, to_arg, "p<%bpu.%bpu>\n", + erts_print(to, to_arg, "p<%beu.%beu>\n", port_channel_no(x), port_number(x)); *ptr = OUR_NIL; } else { diff --git a/erts/emulator/beam/erl_unicode.c b/erts/emulator/beam/erl_unicode.c index 545b345a71..dacf228e92 100644 --- a/erts/emulator/beam/erl_unicode.c +++ b/erts/emulator/beam/erl_unicode.c @@ -902,7 +902,6 @@ static BIF_RETTYPE build_utf8_return(Process *p,Eterm bin,int pos, static BIF_RETTYPE characters_to_utf8_trap(BIF_ALIST_3) { Eterm *real_bin; - Sint need; byte* bytes; Eterm rest_term; int left, sleft; @@ -918,7 +917,6 @@ static BIF_RETTYPE characters_to_utf8_trap(BIF_ALIST_3) ASSERT(is_binary(BIF_ARG_1)); real_bin = binary_val(BIF_ARG_1); ASSERT(*real_bin == HEADER_PROC_BIN); - need = ((ProcBin *) real_bin)->val->orig_size; pos = (int) binary_size(BIF_ARG_1); bytes = binary_bytes(BIF_ARG_1); sleft = left = allowed_iterations(BIF_P); diff --git a/erts/emulator/beam/global.h b/erts/emulator/beam/global.h index 432bdd705b..96da894d90 100644 --- a/erts/emulator/beam/global.h +++ b/erts/emulator/beam/global.h @@ -1828,7 +1828,7 @@ erts_alloc_message_heap(Uint size, #endif if (size > (Uint) INT_MAX) - erl_exit(ERTS_ABORT_EXIT, "HUGE size (%bpu)\n", size); + erl_exit(ERTS_ABORT_EXIT, "HUGE size (%beu)\n", size); if ( #if defined(ERTS_SMP) diff --git a/erts/emulator/beam/io.c b/erts/emulator/beam/io.c index f21a96c754..f619c6f88b 100644 --- a/erts/emulator/beam/io.c +++ b/erts/emulator/beam/io.c @@ -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 @@ -1226,7 +1226,6 @@ void init_io(void) { int i; ErlDrvEntry** dp; - ErlDrvEntry* drv; char maxports[21]; /* enough for any 64-bit integer */ size_t maxportssize = sizeof(maxports); Uint ports_bits = ERTS_PORTS_BITS; @@ -1309,10 +1308,8 @@ void init_io(void) init_driver(&fd_driver, &fd_driver_entry, NULL); init_driver(&vanilla_driver, &vanilla_driver_entry, NULL); init_driver(&spawn_driver, &spawn_driver_entry, NULL); - for (dp = driver_tab; *dp != NULL; dp++) { - drv = *dp; + for (dp = driver_tab; *dp != NULL; dp++) erts_add_driver_entry(*dp, NULL, 1); - } erts_smp_tsd_set(driver_list_lock_status_key, NULL); erts_smp_mtx_unlock(&erts_driver_list_lock); @@ -2420,7 +2417,7 @@ void erts_raw_port_command(Port* p, byte* buf, Uint len) if (len > (Uint) INT_MAX) erl_exit(ERTS_ABORT_EXIT, - "Absurdly large data buffer (%bpu bytes) passed to" + "Absurdly large data buffer (%beu bytes) passed to" "output callback of %s driver.\n", len, p->drv_ptr->name ? p->drv_ptr->name : "unknown"); @@ -3670,7 +3667,7 @@ driver_pdl_inc_refc(ErlDrvPDL pdl) { ErlDrvSInt refc = pdl_inctest_refc(pdl); #ifdef HARDDEBUG - erts_fprintf(stderr, "driver_pdl_inc_refc(%p) -> %bpd\r\n", + erts_fprintf(stderr, "driver_pdl_inc_refc(%p) -> %bed\r\n", pdl, refc); #endif return refc; diff --git a/erts/emulator/beam/ops.tab b/erts/emulator/beam/ops.tab index e861f97e7a..6caa1e0b2d 100644 --- a/erts/emulator/beam/ops.tab +++ b/erts/emulator/beam/ops.tab @@ -1066,7 +1066,7 @@ is_function f y is_function f r is_function Fail=f c => jump Fail -func_info M=a F=a A=u | label L => gen_func_info(M, F, A, L) +func_info M F A => i_func_info u M F A # ================================================================ # New bit syntax matching (R11B). diff --git a/erts/emulator/beam/sys.h b/erts/emulator/beam/sys.h index ff828ae889..e64c43de6e 100644 --- a/erts/emulator/beam/sys.h +++ b/erts/emulator/beam/sys.h @@ -538,8 +538,8 @@ typedef struct preload { */ typedef struct _SysDriverOpts { - int ifd; /* Input file descriptor (fd driver). */ - int ofd; /* Outputfile descriptor (fd driver). */ + Uint ifd; /* Input file descriptor (fd driver). */ + Uint ofd; /* Outputfile descriptor (fd driver). */ int packet_bytes; /* Number of bytes in packet header. */ int read_write; /* Read and write bits. */ int use_stdio; /* Use standard I/O: TRUE or FALSE. */ diff --git a/erts/emulator/beam/utils.c b/erts/emulator/beam/utils.c index f531d1430b..6b4f3b3b36 100644 --- a/erts/emulator/beam/utils.c +++ b/erts/emulator/beam/utils.c @@ -2705,7 +2705,7 @@ term_array: /* arrays in 'aa' and 'bb', length in 'i' */ while (--i) { a = *aa++; b = *bb++; - if (a != b) { + if (!is_same(a,a_base, b,b_base)) { if (is_atom(a) && is_atom(b)) { if ((j = cmp_atoms(a, b)) != 0) { goto not_equal; diff --git a/erts/emulator/drivers/common/efile_drv.c b/erts/emulator/drivers/common/efile_drv.c index 4e9b5005c1..f0ff3f54c5 100644 --- a/erts/emulator/drivers/common/efile_drv.c +++ b/erts/emulator/drivers/common/efile_drv.c @@ -410,7 +410,7 @@ struct t_data static void *ef_safe_alloc(Uint s) { void *p = EF_ALLOC(s); - if (!p) erl_exit(1, "efile drv: Can't allocate %d bytes of memory\n", s); + if (!p) erl_exit(1, "efile drv: Can't allocate %lu bytes of memory\n", (unsigned long)s); return p; } diff --git a/erts/emulator/drivers/common/gzio.c b/erts/emulator/drivers/common/gzio.c index 5531a275ea..741cb6ae20 100644 --- a/erts/emulator/drivers/common/gzio.c +++ b/erts/emulator/drivers/common/gzio.c @@ -632,6 +632,7 @@ erts_gzseek(gzFile file, int offset, int whence) while (s->position < pos) { char buf[512]; int n; + int save_pos = s->position; n = pos - s->position; if (n > sizeof(buf)) @@ -643,6 +644,7 @@ erts_gzseek(gzFile file, int offset, int whence) memset(buf, '\0', n); erts_gzwrite(file, buf, n); } + if (save_pos == s->position) break; } return s->position; diff --git a/erts/emulator/drivers/common/inet_drv.c b/erts/emulator/drivers/common/inet_drv.c index b491242aea..aec456151c 100644 --- a/erts/emulator/drivers/common/inet_drv.c +++ b/erts/emulator/drivers/common/inet_drv.c @@ -490,7 +490,6 @@ static int my_strncasecmp(const char *s1, const char *s2, size_t n) #define TCP_REQ_RECV 42 #define TCP_REQ_UNRECV 43 #define TCP_REQ_SHUTDOWN 44 -#define TCP_REQ_MULTI_OP 45 /* UDP and SCTP requests */ #define PACKET_REQ_RECV 60 /* Common for UDP and SCTP */ #define SCTP_REQ_LISTEN 61 /* Different from TCP; not for UDP */ @@ -1763,7 +1762,6 @@ send_async_error(ErlDrvPort port, ErlDrvTermData Port, int Ref, LOAD_INT_CNT + 2*LOAD_TUPLE_CNT]; int i = 0; - i = 0; i = LOAD_ATOM(spec, i, am_inet_async); i = LOAD_PORT(spec, i, Port); i = LOAD_INT(spec, i, Ref); @@ -8550,7 +8548,9 @@ static int tcp_deliver(tcp_descriptor* desc, int len) len = 0; if (!desc->inet.active) { - driver_cancel_timer(desc->inet.port); + if (!desc->busy_on_send) { + driver_cancel_timer(desc->inet.port); + } sock_select(INETP(desc),(FD_READ|FD_CLOSE),0); if (desc->i_buf != NULL) tcp_restart_input(desc); diff --git a/erts/emulator/hipe/hipe_abi.txt b/erts/emulator/hipe/hipe_abi.txt index aea30d262d..d0ec162342 100644 --- a/erts/emulator/hipe/hipe_abi.txt +++ b/erts/emulator/hipe/hipe_abi.txt @@ -2,7 +2,7 @@ %CopyrightBegin% %CopyrightEnd% -$Id$ + HiPE ABI ======== diff --git a/erts/emulator/hipe/hipe_amd64.c b/erts/emulator/hipe/hipe_amd64.c index ff87492f4d..b5dff06987 100644 --- a/erts/emulator/hipe/hipe_amd64.c +++ b/erts/emulator/hipe/hipe_amd64.c @@ -1,23 +1,23 @@ /* * %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% */ -/* $Id$ - */ + + #include <stddef.h> /* offsetof() */ #ifdef HAVE_CONFIG_H #include "config.h" @@ -334,43 +334,3 @@ void hipe_arch_print_pcb(struct hipe_process_state *p) U("narity ", narity); #undef U } - -/* - * XXX: The following should really be moved to a generic hipe_bifs_64 file. - */ - -#if 0 /* unused */ -static int term_to_Sint64(Eterm term, Sint64 *sp) -{ - return term_to_Sint(term, sp); -} - -BIF_RETTYPE hipe_bifs_write_s64_2(BIF_ALIST_2) -{ - Sint64 *address; - Sint64 value; - - address = term_to_address(BIF_ARG_1); - if (!address || !hipe_word64_address_ok(address)) - BIF_ERROR(BIF_P, BADARG); - if (!term_to_Sint64(BIF_ARG_2, &value)) - BIF_ERROR(BIF_P, BADARG); - *address = value; - BIF_RET(NIL); -} -#endif - -BIF_RETTYPE hipe_bifs_write_u64_2(BIF_ALIST_2) -{ - Uint64 *address; - Uint64 value; - - address = term_to_address(BIF_ARG_1); - if (!address || !hipe_word64_address_ok(address)) - BIF_ERROR(BIF_P, BADARG); - if (!term_to_Uint(BIF_ARG_2, &value)) - BIF_ERROR(BIF_P, BADARG); - *address = value; - hipe_flush_icache_word(address); - BIF_RET(NIL); -} diff --git a/erts/emulator/hipe/hipe_amd64.h b/erts/emulator/hipe/hipe_amd64.h index 532d47c092..bf41d238dd 100644 --- a/erts/emulator/hipe/hipe_amd64.h +++ b/erts/emulator/hipe/hipe_amd64.h @@ -1,23 +1,23 @@ /* * %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% */ -/* $Id$ - */ + + #ifndef HIPE_AMD64_H #define HIPE_AMD64_H diff --git a/erts/emulator/hipe/hipe_amd64.tab b/erts/emulator/hipe/hipe_amd64.tab index 3787bbf23b..e039d74525 100644 --- a/erts/emulator/hipe/hipe_amd64.tab +++ b/erts/emulator/hipe/hipe_amd64.tab @@ -1,28 +1,24 @@ # # %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% # -# $Id$ # AMD64-specific atoms and bifs atom amd64 atom handle_fp_exception atom inc_stack_0 atom sse2_fnegate_mask - -# bif hipe_bifs:write_s64/2 -bif hipe_bifs:write_u64/2 diff --git a/erts/emulator/hipe/hipe_amd64_abi.txt b/erts/emulator/hipe/hipe_amd64_abi.txt index 27beff4ea2..8a34bfa67f 100644 --- a/erts/emulator/hipe/hipe_amd64_abi.txt +++ b/erts/emulator/hipe/hipe_amd64_abi.txt @@ -2,7 +2,7 @@ %CopyrightBegin% %CopyrightEnd% -$Id$ + HiPE AMD64 ABI ============== diff --git a/erts/emulator/hipe/hipe_amd64_asm.m4 b/erts/emulator/hipe/hipe_amd64_asm.m4 index 7f563c35d8..7c81040b8b 100644 --- a/erts/emulator/hipe/hipe_amd64_asm.m4 +++ b/erts/emulator/hipe/hipe_amd64_asm.m4 @@ -2,7 +2,7 @@ changecom(`/*', `*/')dnl /* * %CopyrightBegin% * - * Copyright Ericsson AB 2004-2010. 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 @@ -17,9 +17,8 @@ changecom(`/*', `*/')dnl * * %CopyrightEnd% */ -/* - * $Id$ - */ + + `#ifndef HIPE_AMD64_ASM_H #define HIPE_AMD64_ASM_H' diff --git a/erts/emulator/hipe/hipe_amd64_bifs.m4 b/erts/emulator/hipe/hipe_amd64_bifs.m4 index f7c9604e2b..0ba763cbea 100644 --- a/erts/emulator/hipe/hipe_amd64_bifs.m4 +++ b/erts/emulator/hipe/hipe_amd64_bifs.m4 @@ -2,7 +2,7 @@ changecom(`/*', `*/')dnl /* * %CopyrightBegin% * - * Copyright Ericsson AB 2004-2010. 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 @@ -17,9 +17,7 @@ changecom(`/*', `*/')dnl * * %CopyrightEnd% */ -/* - * $Id$ - */ + include(`hipe/hipe_amd64_asm.m4') #`include' "hipe_literals.h" diff --git a/erts/emulator/hipe/hipe_amd64_gc.h b/erts/emulator/hipe/hipe_amd64_gc.h index 56650901d6..c5a6fee6fe 100644 --- a/erts/emulator/hipe/hipe_amd64_gc.h +++ b/erts/emulator/hipe/hipe_amd64_gc.h @@ -1,22 +1,22 @@ /* * %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% */ -/* $Id$ +/* * Stack walking helpers for native stack GC procedures. */ #ifndef HIPE_AMD64_GC_H diff --git a/erts/emulator/hipe/hipe_amd64_glue.S b/erts/emulator/hipe/hipe_amd64_glue.S index 3376487292..8816906870 100644 --- a/erts/emulator/hipe/hipe_amd64_glue.S +++ b/erts/emulator/hipe/hipe_amd64_glue.S @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 2004-2010. 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 @@ -16,9 +16,7 @@ * * %CopyrightEnd% */ -/* - * $Id$ - */ + #include "hipe_amd64_asm.h" #include "hipe_literals.h" diff --git a/erts/emulator/hipe/hipe_amd64_glue.h b/erts/emulator/hipe/hipe_amd64_glue.h index c92eb842cb..36508467fa 100644 --- a/erts/emulator/hipe/hipe_amd64_glue.h +++ b/erts/emulator/hipe/hipe_amd64_glue.h @@ -1,24 +1,23 @@ /* * %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% */ -/* - * $Id$ - */ + + #ifndef HIPE_AMD64_GLUE_H #define HIPE_AMD64_GLUE_H diff --git a/erts/emulator/hipe/hipe_amd64_primops.h b/erts/emulator/hipe/hipe_amd64_primops.h index dcfa8be92a..e3c7111997 100644 --- a/erts/emulator/hipe/hipe_amd64_primops.h +++ b/erts/emulator/hipe/hipe_amd64_primops.h @@ -1,23 +1,23 @@ /* * %CopyrightBegin% - * - * Copyright Ericsson AB 2005-2009. All Rights Reserved. - * + * + * Copyright Ericsson AB 2005-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% */ -/* $Id$ - */ + + PRIMOP_LIST(am_inc_stack_0, &nbif_inc_stack_0) PRIMOP_LIST(am_handle_fp_exception, &nbif_handle_fp_exception) PRIMOP_LIST(am_sse2_fnegate_mask, &sse2_fnegate_mask) diff --git a/erts/emulator/hipe/hipe_arch.h b/erts/emulator/hipe/hipe_arch.h index 7803543ef1..04ed980126 100644 --- a/erts/emulator/hipe/hipe_arch.h +++ b/erts/emulator/hipe/hipe_arch.h @@ -1,23 +1,23 @@ /* * %CopyrightBegin% - * - * Copyright Ericsson AB 2003-2009. All Rights Reserved. - * + * + * Copyright Ericsson AB 2003-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% */ -/* $Id$ - */ + + #ifndef HIPE_ARCH_H #define HIPE_ARCH_H diff --git a/erts/emulator/hipe/hipe_arm.c b/erts/emulator/hipe/hipe_arm.c index b70b32947b..d52f429a9b 100644 --- a/erts/emulator/hipe/hipe_arm.c +++ b/erts/emulator/hipe/hipe_arm.c @@ -1,23 +1,23 @@ /* * %CopyrightBegin% - * - * Copyright Ericsson AB 2005-2009. All Rights Reserved. - * + * + * Copyright Ericsson AB 2005-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% */ -/* $Id$ - */ + + #include <stddef.h> /* offsetof() */ #ifdef HAVE_CONFIG_H #include "config.h" diff --git a/erts/emulator/hipe/hipe_arm.h b/erts/emulator/hipe/hipe_arm.h index 84f58a681f..19f2a986cf 100644 --- a/erts/emulator/hipe/hipe_arm.h +++ b/erts/emulator/hipe/hipe_arm.h @@ -1,23 +1,23 @@ /* * %CopyrightBegin% - * - * Copyright Ericsson AB 2005-2009. All Rights Reserved. - * + * + * Copyright Ericsson AB 2005-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% */ -/* $Id$ - */ + + #ifndef HIPE_ARM_H #define HIPE_ARM_H diff --git a/erts/emulator/hipe/hipe_arm.tab b/erts/emulator/hipe/hipe_arm.tab index 81626796a7..49b89d6748 100644 --- a/erts/emulator/hipe/hipe_arm.tab +++ b/erts/emulator/hipe/hipe_arm.tab @@ -1,22 +1,22 @@ # # %CopyrightBegin% -# -# Copyright Ericsson AB 2005-2009. All Rights Reserved. -# +# +# Copyright Ericsson AB 2005-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% # -# $Id$ + # ARM-specific atoms and bifs atom arm diff --git a/erts/emulator/hipe/hipe_arm_abi.txt b/erts/emulator/hipe/hipe_arm_abi.txt index 6868704d62..6778ff6663 100644 --- a/erts/emulator/hipe/hipe_arm_abi.txt +++ b/erts/emulator/hipe/hipe_arm_abi.txt @@ -2,7 +2,7 @@ %CopyrightBegin% %CopyrightEnd% -$Id$ + HiPE ARM ABI ================ diff --git a/erts/emulator/hipe/hipe_arm_asm.m4 b/erts/emulator/hipe/hipe_arm_asm.m4 index b9a696ffff..85dc84973d 100644 --- a/erts/emulator/hipe/hipe_arm_asm.m4 +++ b/erts/emulator/hipe/hipe_arm_asm.m4 @@ -1,25 +1,24 @@ changecom(`/*', `*/')dnl /* * %CopyrightBegin% - * - * Copyright Ericsson AB 2005-2009. All Rights Reserved. - * + * + * Copyright Ericsson AB 2005-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% */ -/* - * $Id$ - */ + + `#ifndef HIPE_ARM_ASM_H #define HIPE_ARM_ASM_H' diff --git a/erts/emulator/hipe/hipe_arm_bifs.m4 b/erts/emulator/hipe/hipe_arm_bifs.m4 index 4d8636e711..3664fb6502 100644 --- a/erts/emulator/hipe/hipe_arm_bifs.m4 +++ b/erts/emulator/hipe/hipe_arm_bifs.m4 @@ -1,25 +1,23 @@ changecom(`/*', `*/')dnl /* * %CopyrightBegin% - * - * Copyright Ericsson AB 2005-2009. All Rights Reserved. - * + * + * Copyright Ericsson AB 2005-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% */ -/* - * $Id$ - */ + include(`hipe/hipe_arm_asm.m4') #`include' "hipe_literals.h" diff --git a/erts/emulator/hipe/hipe_arm_gc.h b/erts/emulator/hipe/hipe_arm_gc.h index a2a919e3d7..787c6fef3e 100644 --- a/erts/emulator/hipe/hipe_arm_gc.h +++ b/erts/emulator/hipe/hipe_arm_gc.h @@ -1,22 +1,22 @@ /* * %CopyrightBegin% - * - * Copyright Ericsson AB 2005-2009. All Rights Reserved. - * + * + * Copyright Ericsson AB 2005-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% */ -/* $Id$ +/* * Stack walking helpers for native stack GC procedures. * ARM version. */ diff --git a/erts/emulator/hipe/hipe_arm_glue.S b/erts/emulator/hipe/hipe_arm_glue.S index 8c1c55b216..2e2b8604a6 100644 --- a/erts/emulator/hipe/hipe_arm_glue.S +++ b/erts/emulator/hipe/hipe_arm_glue.S @@ -1,23 +1,23 @@ /* * %CopyrightBegin% - * + * * Copyright Ericsson AB 2005-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% */ -/* $Id$ - */ + + #include "hipe_arm_asm.h" #include "hipe_literals.h" #define ASM diff --git a/erts/emulator/hipe/hipe_arm_glue.h b/erts/emulator/hipe/hipe_arm_glue.h index e840c3dc0f..165f73320d 100644 --- a/erts/emulator/hipe/hipe_arm_glue.h +++ b/erts/emulator/hipe/hipe_arm_glue.h @@ -1,23 +1,23 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 2005-2009. All Rights Reserved. - * + * Copyright Ericsson AB 2005-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% */ -/* $Id$ - */ + + #ifndef HIPE_ARM_GLUE_H #define HIPE_ARM_GLUE_H diff --git a/erts/emulator/hipe/hipe_arm_primops.h b/erts/emulator/hipe/hipe_arm_primops.h index a28b509eee..2a1a87b862 100644 --- a/erts/emulator/hipe/hipe_arm_primops.h +++ b/erts/emulator/hipe/hipe_arm_primops.h @@ -1,21 +1,21 @@ /* * %CopyrightBegin% - * - * Copyright Ericsson AB 2005-2009. All Rights Reserved. - * + * + * Copyright Ericsson AB 2005-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% */ -/* $Id$ - */ + + PRIMOP_LIST(am_inc_stack_0, &hipe_arm_inc_stack) diff --git a/erts/emulator/hipe/hipe_bif0.h b/erts/emulator/hipe/hipe_bif0.h index c5c1c30619..f02e8862dc 100644 --- a/erts/emulator/hipe/hipe_bif0.h +++ b/erts/emulator/hipe/hipe_bif0.h @@ -1,22 +1,23 @@ /* * %CopyrightBegin% - * + + * * 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% */ -/* $Id$ +/* * hipe_bif0.h * * Compiler and linker support. diff --git a/erts/emulator/hipe/hipe_bif0.tab b/erts/emulator/hipe/hipe_bif0.tab index 46c0a3d67d..b6c6bede23 100644 --- a/erts/emulator/hipe/hipe_bif0.tab +++ b/erts/emulator/hipe/hipe_bif0.tab @@ -1,22 +1,22 @@ # # %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% # -# $Id$ +# # HiPE level 0 bifs: compiler and linker support # # bif hipe_bifs:name/arity diff --git a/erts/emulator/hipe/hipe_bif1.c b/erts/emulator/hipe/hipe_bif1.c index 2369ad4fa8..87cdfb8c7a 100644 --- a/erts/emulator/hipe/hipe_bif1.c +++ b/erts/emulator/hipe/hipe_bif1.c @@ -1,22 +1,23 @@ /* * %CopyrightBegin% - * + + * * 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% */ -/* $Id$ +/* * hipe_bif1.c * * Performance analysis support. diff --git a/erts/emulator/hipe/hipe_bif1.h b/erts/emulator/hipe/hipe_bif1.h index c3b607565d..89241fb835 100644 --- a/erts/emulator/hipe/hipe_bif1.h +++ b/erts/emulator/hipe/hipe_bif1.h @@ -1,22 +1,22 @@ /* * %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% */ -/* $Id$ +/* * hipe_bif1.h * * Performance analysis support. diff --git a/erts/emulator/hipe/hipe_bif2.c b/erts/emulator/hipe/hipe_bif2.c index 6bcd5046e9..19cd32c68f 100644 --- a/erts/emulator/hipe/hipe_bif2.c +++ b/erts/emulator/hipe/hipe_bif2.c @@ -1,22 +1,23 @@ /* * %CopyrightBegin% - * + + * * 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% */ -/* $Id$ +/* * hipe_bif2.c * * Miscellaneous add-ons. diff --git a/erts/emulator/hipe/hipe_bif64.c b/erts/emulator/hipe/hipe_bif64.c new file mode 100644 index 0000000000..73784fc1e8 --- /dev/null +++ b/erts/emulator/hipe/hipe_bif64.c @@ -0,0 +1,68 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 2001-2010. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + */ +/* hipe_bif_64.c + * + * Compiler and linker support. 64-bit specific. + */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#include "global.h" +#include "error.h" +#include "bif.h" +#include "big.h" /* term_to_Sint() */ +#include "hipe_arch.h" +#include "hipe_bif0.h" +#include "hipe_bif64.h" + +#if 0 /* unused */ +static int term_to_Sint64(Eterm term, Sint64 *sp) +{ + return term_to_Sint(term, sp); +} + +BIF_RETTYPE hipe_bifs_write_s64_2(BIF_ALIST_2) +{ + Sint64 *address; + Sint64 value; + + address = term_to_address(BIF_ARG_1); + if (!address || !hipe_word64_address_ok(address)) + BIF_ERROR(BIF_P, BADARG); + if (!term_to_Sint64(BIF_ARG_2, &value)) + BIF_ERROR(BIF_P, BADARG); + *address = value; + BIF_RET(NIL); +} +#endif + +BIF_RETTYPE hipe_bifs_write_u64_2(BIF_ALIST_2) +{ + Uint64 *address; + Uint64 value; + + address = term_to_address(BIF_ARG_1); + if (!address || !hipe_word64_address_ok(address)) + BIF_ERROR(BIF_P, BADARG); + if (!term_to_Uint(BIF_ARG_2, &value)) + BIF_ERROR(BIF_P, BADARG); + *address = value; + hipe_flush_icache_word(address); + BIF_RET(NIL); +} diff --git a/erts/emulator/hipe/hipe_bif64.h b/erts/emulator/hipe/hipe_bif64.h new file mode 100644 index 0000000000..9fd6b79605 --- /dev/null +++ b/erts/emulator/hipe/hipe_bif64.h @@ -0,0 +1,26 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 2001-2009. 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% + */ +/* hipe_bif64.c + * + * Compiler and linker support. 64-bit specific. + */ +#ifndef HIPE_BIF64_H +#define HIPE_BIF64_H + +#endif /* HIPE_BIF64_H */ diff --git a/erts/emulator/hipe/hipe_bif64.tab b/erts/emulator/hipe/hipe_bif64.tab new file mode 100644 index 0000000000..6e663cfd35 --- /dev/null +++ b/erts/emulator/hipe/hipe_bif64.tab @@ -0,0 +1,22 @@ +# +# %CopyrightBegin% +# +# Copyright Ericsson AB 2004-2009. 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% +# +# HiPE 64-bit specific bifs + +# bif hipe_bifs:write_s64/2 +bif hipe_bifs:write_u64/2 diff --git a/erts/emulator/hipe/hipe_bif_list.m4 b/erts/emulator/hipe/hipe_bif_list.m4 index c92d94ed9d..083788997b 100644 --- a/erts/emulator/hipe/hipe_bif_list.m4 +++ b/erts/emulator/hipe/hipe_bif_list.m4 @@ -1,22 +1,22 @@ /* * %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% */ -/* $Id$ +/* * * List all non architecture-specific BIFs and primops, and * classify each as belonging to one of the classes below. diff --git a/erts/emulator/hipe/hipe_debug.c b/erts/emulator/hipe/hipe_debug.c index 548998b7b7..7ca11f8c6c 100644 --- a/erts/emulator/hipe/hipe_debug.c +++ b/erts/emulator/hipe/hipe_debug.c @@ -1,22 +1,22 @@ /* * %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% */ -/* $Id$ +/* * hipe_debug.c * * TODO: @@ -51,7 +51,7 @@ static const char stars[2*sizeof(long)+5] = { extern Uint beam_apply[]; -static void print_beam_pc(Uint *pc) +static void print_beam_pc(BeamInstr *pc) { if (pc == hipe_beam_pc_return) { printf("return-to-native"); @@ -60,7 +60,7 @@ static void print_beam_pc(Uint *pc) } else if (pc == &beam_apply[1]) { printf("normal-process-exit"); } else { - Eterm *mfa = find_function_from_pc(pc); + BeamInstr *mfa = find_function_from_pc(pc); if (mfa) erts_printf("%T:%T/%bpu + 0x%bpx", mfa[0], mfa[1], mfa[2], pc - &mfa[3]); @@ -71,7 +71,7 @@ static void print_beam_pc(Uint *pc) static void catch_slot(Eterm *pos, Eterm val) { - Uint *pc = catch_pc(val); + BeamInstr *pc = catch_pc(val); printf(" | 0x%0*lx | 0x%0*lx | CATCH 0x%0*lx (BEAM ", 2*(int)sizeof(long), (unsigned long)pos, 2*(int)sizeof(long), (unsigned long)val, diff --git a/erts/emulator/hipe/hipe_debug.h b/erts/emulator/hipe/hipe_debug.h index 3980bc8230..a28597000a 100644 --- a/erts/emulator/hipe/hipe_debug.h +++ b/erts/emulator/hipe/hipe_debug.h @@ -1,22 +1,22 @@ /* * %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% */ -/* $Id$ +/* * hipe_debug.h */ #ifndef HIPE_DEBUG_H diff --git a/erts/emulator/hipe/hipe_gbif_list.h b/erts/emulator/hipe/hipe_gbif_list.h index 659f74b5e5..69dbab7ab9 100644 --- a/erts/emulator/hipe/hipe_gbif_list.h +++ b/erts/emulator/hipe/hipe_gbif_list.h @@ -1,22 +1,22 @@ /* * %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% */ -/* $Id$ +/* * GBIF_LIST(FunctionAtom,Arity,CFun) * manually maintained for now -- expand when necessary */ diff --git a/erts/emulator/hipe/hipe_gc.c b/erts/emulator/hipe/hipe_gc.c index a8b6c20dd0..0199dea99e 100644 --- a/erts/emulator/hipe/hipe_gc.c +++ b/erts/emulator/hipe/hipe_gc.c @@ -16,7 +16,7 @@ * * %CopyrightEnd% */ -/* $Id$ +/* * GC support procedures */ #ifdef HAVE_CONFIG_H diff --git a/erts/emulator/hipe/hipe_gc.h b/erts/emulator/hipe/hipe_gc.h index 712d0ffa78..0d5614c9cf 100644 --- a/erts/emulator/hipe/hipe_gc.h +++ b/erts/emulator/hipe/hipe_gc.h @@ -1,23 +1,23 @@ /* * %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% */ -/* $Id$ - */ + + #ifndef HIPE_GC_H #define HIPE_GC_H diff --git a/erts/emulator/hipe/hipe_mkliterals.c b/erts/emulator/hipe/hipe_mkliterals.c index 25e21ed79e..650861b54b 100644 --- a/erts/emulator/hipe/hipe_mkliterals.c +++ b/erts/emulator/hipe/hipe_mkliterals.c @@ -1,24 +1,24 @@ /* * %CopyrightBegin% - * + + * * 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% */ -/* - * $Id$ - */ + + #ifdef HAVE_CONFIG_H #include "config.h" #endif diff --git a/erts/emulator/hipe/hipe_mode_switch.c b/erts/emulator/hipe/hipe_mode_switch.c index 53ebcd4008..16f8fb1347 100644 --- a/erts/emulator/hipe/hipe_mode_switch.c +++ b/erts/emulator/hipe/hipe_mode_switch.c @@ -1,22 +1,23 @@ /* * %CopyrightBegin% - * + + * * 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% */ -/* $Id$ +/* * hipe_mode_switch.c */ #ifdef HAVE_CONFIG_H diff --git a/erts/emulator/hipe/hipe_mode_switch.h b/erts/emulator/hipe/hipe_mode_switch.h index e0c6c1b5f5..dbc2386e14 100644 --- a/erts/emulator/hipe/hipe_mode_switch.h +++ b/erts/emulator/hipe/hipe_mode_switch.h @@ -1,22 +1,23 @@ /* * %CopyrightBegin% - * + + * * 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% */ -/* $Id$ +/* * hipe_mode_switch.h */ #ifndef HIPE_MODE_SWITCH_H diff --git a/erts/emulator/hipe/hipe_native_bif.c b/erts/emulator/hipe/hipe_native_bif.c index f8c2502522..8d31348496 100644 --- a/erts/emulator/hipe/hipe_native_bif.c +++ b/erts/emulator/hipe/hipe_native_bif.c @@ -1,22 +1,22 @@ /* * %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% */ -/* $Id$ +/* * hipe_native_bif.c */ #ifdef HAVE_CONFIG_H diff --git a/erts/emulator/hipe/hipe_native_bif.h b/erts/emulator/hipe/hipe_native_bif.h index 3b55b64a41..13a02b84a2 100644 --- a/erts/emulator/hipe/hipe_native_bif.h +++ b/erts/emulator/hipe/hipe_native_bif.h @@ -1,22 +1,22 @@ /* * %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% */ -/* $Id$ +/* * hipe_native_bif.h */ diff --git a/erts/emulator/hipe/hipe_ops.tab b/erts/emulator/hipe/hipe_ops.tab index eb6f824d1c..50c3a4ae2f 100644 --- a/erts/emulator/hipe/hipe_ops.tab +++ b/erts/emulator/hipe/hipe_ops.tab @@ -1,19 +1,19 @@ # # %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% # diff --git a/erts/emulator/hipe/hipe_perfctr.c b/erts/emulator/hipe/hipe_perfctr.c index 69bb648854..371b3fb097 100644 --- a/erts/emulator/hipe/hipe_perfctr.c +++ b/erts/emulator/hipe/hipe_perfctr.c @@ -1,23 +1,23 @@ /* * %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% */ -/* $Id$ - */ + + #ifdef HAVE_CONFIG_H #include "config.h" #endif diff --git a/erts/emulator/hipe/hipe_perfctr.h b/erts/emulator/hipe/hipe_perfctr.h index 7b20c68cac..8fbf9ecf35 100644 --- a/erts/emulator/hipe/hipe_perfctr.h +++ b/erts/emulator/hipe/hipe_perfctr.h @@ -1,23 +1,22 @@ /* * %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% */ -/* $Id$ - */ + extern int hipe_perfctr_hrvtime_open(void); extern void hipe_perfctr_hrvtime_close(void); diff --git a/erts/emulator/hipe/hipe_perfctr.tab b/erts/emulator/hipe/hipe_perfctr.tab index 663522f85e..eaecea4651 100644 --- a/erts/emulator/hipe/hipe_perfctr.tab +++ b/erts/emulator/hipe/hipe_perfctr.tab @@ -1,22 +1,21 @@ # # %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% # -# $Id$ bif hipe_bifs:vperfctr_open/0 bif hipe_bifs:vperfctr_close/0 diff --git a/erts/emulator/hipe/hipe_ppc.c b/erts/emulator/hipe/hipe_ppc.c index 3a0beedb68..bc25061a16 100644 --- a/erts/emulator/hipe/hipe_ppc.c +++ b/erts/emulator/hipe/hipe_ppc.c @@ -1,23 +1,23 @@ /* * %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% */ -/* $Id$ - */ + + #include <stddef.h> /* offsetof() */ #ifdef HAVE_CONFIG_H #include "config.h" @@ -87,48 +87,6 @@ static struct segment { #define MAP_ANONYMOUS MAP_ANON #endif -#if defined(__powerpc64__) -static void *new_code_mapping(void) -{ - char *map_hint, *map_start; - - /* - * Allocate a new 32MB code segment in the low 2GB of the address space. - * - * This is problematic for several reasons: - * - Linux/ppc64 lacks the MAP_32BIT flag that Linux/x86-64 has. - * - The address space hint to mmap is only respected if that - * area is available. If it isn't, then mmap falls back to its - * defaults, which (according to testing) results in very high - * (and thus useless for us) addresses being returned. - * - Another mapping, presumably the brk, also occupies low addresses. - * - * As initial implementation, simply start allocating at the 0.5GB - * boundary. This leaves plenty of space for the brk before malloc - * needs to switch to mmap, while allowing for 1.5GB of code. - * - * A more robust implementation would be to parse /proc/self/maps, - * reserve all available space between (say) 0.5GB and 2GB with - * PROT_NONE MAP_NORESERVE mappings, and then allocate by releasing - * 32MB segments and re-mapping them properly. This would work on - * Linux/ppc64, I have no idea how things should be done on Darwin64. - */ - if (curseg.base) - map_hint = (char*)curseg.base + SEGMENT_NRBYTES; - else - map_hint = (char*)(512*1024*1024); /* 0.5GB */ - map_start = mmap(map_hint, SEGMENT_NRBYTES, - PROT_EXEC|PROT_READ|PROT_WRITE, - MAP_PRIVATE|MAP_ANONYMOUS, - -1, 0); - if (map_start != MAP_FAILED && - (((unsigned long)map_start + (SEGMENT_NRBYTES-1)) & ~0x7FFFFFFFUL)) { - fprintf(stderr, "mmap with hint %p returned code memory %p\r\n", map_hint, map_start); - abort(); - } - return map_start; -} -#else static void *new_code_mapping(void) { return mmap(0, SEGMENT_NRBYTES, @@ -136,7 +94,6 @@ static void *new_code_mapping(void) MAP_PRIVATE|MAP_ANONYMOUS, -1, 0); } -#endif static int check_callees(Eterm callees) { @@ -182,20 +139,30 @@ static unsigned int *try_alloc(Uint nrwords, int nrcallees, Eterm callees, unsig unsigned int a = unsigned_val(tuple_val(mfa)[3]); unsigned int *trampoline = hipe_mfa_get_trampoline(m, f, a); if (!in_area(trampoline, base, SEGMENT_NRBYTES)) { +#if defined(__powerpc64__) + if (nrfreewords < 7) + return NULL; + nrfreewords -= 7; + tramp_pos = trampoline = tramp_pos - 7; + trampoline[0] = 0x3D600000; /* addis r11,r0,0 */ + trampoline[1] = 0x616B0000; /* ori r11,r11,0 */ + trampoline[2] = 0x796B07C6; /* rldicr r11,r11,32,31 */ + trampoline[3] = 0x656B0000; /* oris r11,r11,0 */ + trampoline[4] = 0x616B0000; /* ori r11,r11,0 */ + trampoline[5] = 0x7D6903A6; /* mtctr r11 */ + trampoline[6] = 0x4E800420; /* bctr */ + hipe_flush_icache_range(trampoline, 7*sizeof(int)); +#else if (nrfreewords < 4) return NULL; nrfreewords -= 4; tramp_pos = trampoline = tramp_pos - 4; -#if defined(__powerpc64__) - trampoline[0] = 0x3D600000; /* addis r11,0,0 */ - trampoline[1] = 0x616B0000; /* ori r11,r11,0 */ -#else trampoline[0] = 0x39600000; /* addi r11,r0,0 */ trampoline[1] = 0x3D6B0000; /* addis r11,r11,0 */ -#endif trampoline[2] = 0x7D6903A6; /* mtctr r11 */ trampoline[3] = 0x4E800420; /* bctr */ hipe_flush_icache_range(trampoline, 4*sizeof(int)); +#endif hipe_mfa_set_trampoline(m, f, a, trampoline); } trampvec[trampnr-1] = trampoline; @@ -281,21 +248,22 @@ static void patch_imm16(Uint32 *address, unsigned int imm16) } #if defined(__powerpc64__) +/* + * To load a 64-bit immediate value 'val' into Rd (Rd != R0): + * + * addis Rd, 0, val@highest // (val >> 48) & 0xFFFF + * ori Rd, Rd, val@higher // (val >> 32) & 0xFFFF + * rldicr Rd, Rd, 32, 31 + * oris Rd, Rd, val@h // (val >> 16) & 0xFFFF + * ori Rd, Rd, val@l // val & 0xFFFF + */ static void patch_li64(Uint32 *address, Uint64 value) { - patch_imm16(address+0, value >> 48);/* addis r,0,value@highest */ - patch_imm16(address+1, value >> 32);/* ori r,r,value@higher */ - /* sldi r,r,32 */ - patch_imm16(address+3, value >> 16);/* oris r,r,value@h */ - patch_imm16(address+4, value); /* ori r,r,value@l */ -} - -static int patch_li31(Uint32 *address, Uint32 value) -{ - if ((value >> 31) != 0) - return -1; - patch_imm16(address, value >> 16); /* addis r,0,value@h */ - patch_imm16(address+1, value); /* ori r,r,value@l */ + patch_imm16(address+0, value >> 48); + patch_imm16(address+1, value >> 32); + /* rldicr Rd, Rd, 32, 31 */ + patch_imm16(address+3, value >> 16); + patch_imm16(address+4, value); } void hipe_patch_load_fe(Uint *address, Uint value) @@ -308,11 +276,10 @@ int hipe_patch_insn(void *address, Uint64 value, Eterm type) switch (type) { case am_closure: case am_constant: - patch_li64((Uint32*)address, value); - return 0; case am_atom: case am_c_const: - return patch_li31((Uint32*)address, value); + patch_li64((Uint32*)address, value); + return 0; default: return -1; } @@ -442,34 +409,33 @@ static void patch_b(Uint32 *address, Sint32 offset, Uint32 AA) int hipe_patch_call(void *callAddress, void *destAddress, void *trampoline) { - if ((Uint32)destAddress == ((Uint32)destAddress & 0x01FFFFFC)) { + if ((UWord)destAddress == ((UWord)destAddress & 0x01FFFFFC)) { /* The destination is in the [0,32MB[ range. We can reach it with a ba/bla instruction. This is the typical case for BIFs and primops. It's also common for trap-to-BEAM stubs (on ppc32). */ - patch_b((Uint32*)callAddress, (Uint32)destAddress >> 2, 2); + patch_b((Uint32*)callAddress, (Sint32)destAddress >> 2, 2); } else { - Sint32 destOffset = ((Sint32)destAddress - (Sint32)callAddress) >> 2; + SWord destOffset = ((SWord)destAddress - (SWord)callAddress) >> 2; if (destOffset >= -0x800000 && destOffset <= 0x7FFFFF) { /* The destination is within a [-32MB,+32MB[ range from us. We can reach it with a b/bl instruction. This is typical for nearby Erlang code. */ - patch_b((Uint32*)callAddress, destOffset, 0); + patch_b((Uint32*)callAddress, (Sint32)destOffset, 0); } else { /* The destination is too distant for b/bl/ba/bla. Must do a b/bl to the trampoline. */ - Sint32 trampOffset = ((Sint32)trampoline - (Sint32)callAddress) >> 2; + SWord trampOffset = ((SWord)trampoline - (SWord)callAddress) >> 2; if (trampOffset >= -0x800000 && trampOffset <= 0x7FFFFF) { /* Update the trampoline's address computation. (May be redundant, but we can't tell.) */ #if defined(__powerpc64__) - /* This relies on the fact that we allocate code below 2GB. */ - patch_li31((Uint32*)trampoline, (Uint32)destAddress); + patch_li64((Uint32*)trampoline, (Uint64)destAddress); #else patch_li((Uint32*)trampoline, (Uint32)destAddress); #endif /* Update this call site. */ - patch_b((Uint32*)callAddress, trampOffset, 0); + patch_b((Uint32*)callAddress, (Sint32)trampOffset, 0); } else return -1; } diff --git a/erts/emulator/hipe/hipe_ppc.h b/erts/emulator/hipe/hipe_ppc.h index e30ce30ed2..66000c1846 100644 --- a/erts/emulator/hipe/hipe_ppc.h +++ b/erts/emulator/hipe/hipe_ppc.h @@ -1,23 +1,23 @@ /* * %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% */ -/* $Id$ - */ + + #ifndef HIPE_PPC_H #define HIPE_PPC_H @@ -44,12 +44,20 @@ static __inline__ int hipe_word32_address_ok(void *address) return ((unsigned long)address & 0x3) == 0; } +#if defined(__powerpc64__) +/* for hipe_bifs_{read,write}_{s,u}64 */ +static __inline__ int hipe_word64_address_ok(void *address) +{ + return ((unsigned long)address & 0x7) == 0; +} +#endif + /* Native stack growth direction. */ #define HIPE_NSTACK_GROWS_DOWN #if defined(__powerpc64__) #define hipe_arch_name am_ppc64 -#define AEXTERN(RET,NAME,PROTO) extern const int NAME +#define AEXTERN(RET,NAME,PROTO) extern const int NAME[] AEXTERN(void,hipe_ppc_inc_stack,(void)); #else #define hipe_arch_name am_powerpc diff --git a/erts/emulator/hipe/hipe_ppc.tab b/erts/emulator/hipe/hipe_ppc.tab index a32dd820e7..38b7f46d3a 100644 --- a/erts/emulator/hipe/hipe_ppc.tab +++ b/erts/emulator/hipe/hipe_ppc.tab @@ -1,22 +1,22 @@ # # %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% # -# $Id$ + # PowerPC-specific atoms atom fconv_constant diff --git a/erts/emulator/hipe/hipe_ppc64.tab b/erts/emulator/hipe/hipe_ppc64.tab index 513182721c..0a390a3bb8 100644 --- a/erts/emulator/hipe/hipe_ppc64.tab +++ b/erts/emulator/hipe/hipe_ppc64.tab @@ -1,7 +1,7 @@ # # %CopyrightBegin% # -# Copyright Ericsson AB 2005-2009. All Rights Reserved. +# Copyright Ericsson AB 2005-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 @@ -16,7 +16,7 @@ # # %CopyrightEnd% # -# $Id$ + # PPC64-specific atoms atom inc_stack_0 diff --git a/erts/emulator/hipe/hipe_ppc_abi.txt b/erts/emulator/hipe/hipe_ppc_abi.txt index 4bf41e02b2..be0ef98b0d 100644 --- a/erts/emulator/hipe/hipe_ppc_abi.txt +++ b/erts/emulator/hipe/hipe_ppc_abi.txt @@ -2,7 +2,7 @@ %CopyrightBegin% %CopyrightEnd% -$Id$ + HiPE PowerPC ABI ================ diff --git a/erts/emulator/hipe/hipe_ppc_asm.m4 b/erts/emulator/hipe/hipe_ppc_asm.m4 index a0f8b78679..0eb5c441e6 100644 --- a/erts/emulator/hipe/hipe_ppc_asm.m4 +++ b/erts/emulator/hipe/hipe_ppc_asm.m4 @@ -1,25 +1,24 @@ changecom(`/*', `*/')dnl /* * %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% */ -/* - * $Id$ - */ + + `#ifndef HIPE_PPC_ASM_H #define HIPE_PPC_ASM_H' @@ -63,15 +62,31 @@ ifelse(OPSYS,darwin,`` #define SEMI @ #define SET_SIZE(NAME) /*empty*/ #define TYPE_FUNCTION(NAME) /*empty*/ +#define OPD(NAME) /*empty*/ '',`` /* Not Darwin */'' `ifelse(ARCH,ppc64,`` /* 64-bit */ +/* + * The 64-bit PowerPC ABI requires us to setup Official Procedure Descriptors + * for functions called from C. These are exported as "func", while the entry + * point should is exported as ".func". A function pointer in C points to the + * function descriptor in the opd rather than to the function entry point. + */ #define JOIN(X,Y) X##Y #define CSYM(NAME) JOIN(.,NAME) +#define OPD(NAME) \ + .pushsection .opd, "aw"; \ + .align 3; \ + .global NAME; \ +NAME: \ + .quad CSYM(NAME), .TOC.@tocbase, 0; \ + .type NAME, @function; \ + .popsection '',`` /* 32-bit */ #define CSYM(NAME) NAME +#define OPD(NAME) /*empty*/ '')' ``#define ASYM(NAME) NAME #define GLOBAL(NAME) .global NAME diff --git a/erts/emulator/hipe/hipe_ppc_bifs.m4 b/erts/emulator/hipe/hipe_ppc_bifs.m4 index 3849d9113a..203fefe1a1 100644 --- a/erts/emulator/hipe/hipe_ppc_bifs.m4 +++ b/erts/emulator/hipe/hipe_ppc_bifs.m4 @@ -1,25 +1,23 @@ changecom(`/*', `*/')dnl /* * %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% */ -/* - * $Id$ - */ + include(`hipe/hipe_ppc_asm.m4') #`include' "hipe_literals.h" diff --git a/erts/emulator/hipe/hipe_ppc_gc.h b/erts/emulator/hipe/hipe_ppc_gc.h index 796ebeb20a..823ba0ad06 100644 --- a/erts/emulator/hipe/hipe_ppc_gc.h +++ b/erts/emulator/hipe/hipe_ppc_gc.h @@ -1,22 +1,22 @@ /* * %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% */ -/* $Id$ +/* * Stack walking helpers for native stack GC procedures. * PowerPC version. */ diff --git a/erts/emulator/hipe/hipe_ppc_glue.S b/erts/emulator/hipe/hipe_ppc_glue.S index c766099102..6f0217c738 100644 --- a/erts/emulator/hipe/hipe_ppc_glue.S +++ b/erts/emulator/hipe/hipe_ppc_glue.S @@ -1,23 +1,23 @@ /* * %CopyrightBegin% - * + * * 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% */ -/* $Id$ - */ + + #include "hipe_ppc_asm.h" #include "hipe_literals.h" #define ASM @@ -198,6 +198,7 @@ * int hipe_ppc_call_to_native(Process *p); * Emulated code recursively calls native code. */ + OPD(hipe_ppc_call_to_native) GLOBAL(CSYM(hipe_ppc_call_to_native)) CSYM(hipe_ppc_call_to_native): /* save C context */ @@ -229,6 +230,7 @@ ASYM(nbif_return): * int hipe_ppc_return_to_native(Process *p); * Emulated code returns to its native code caller. */ + OPD(hipe_ppc_return_to_native) GLOBAL(CSYM(hipe_ppc_return_to_native)) CSYM(hipe_ppc_return_to_native): /* save C context */ @@ -252,6 +254,7 @@ CSYM(hipe_ppc_return_to_native): * int hipe_ppc_tailcall_to_native(Process *p); * Emulated code tailcalls native code. */ + OPD(hipe_ppc_tailcall_to_native) GLOBAL(CSYM(hipe_ppc_tailcall_to_native)) CSYM(hipe_ppc_tailcall_to_native): /* save C context */ @@ -274,6 +277,7 @@ CSYM(hipe_ppc_tailcall_to_native): * int hipe_ppc_throw_to_native(Process *p); * Emulated code throws an exception to its native code caller. */ + OPD(hipe_ppc_throw_to_native) GLOBAL(CSYM(hipe_ppc_throw_to_native)) CSYM(hipe_ppc_throw_to_native): /* save C context */ @@ -455,6 +459,10 @@ ASYM(nbif_fail): li r3, HIPE_MODE_SWITCH_RES_THROW b .flush_exit /* no need to save RA */ + OPD(nbif_0_gc_after_bif) + OPD(nbif_1_gc_after_bif) + OPD(nbif_2_gc_after_bif) + OPD(nbif_3_gc_after_bif) GLOBAL(CSYM(nbif_0_gc_after_bif)) GLOBAL(CSYM(nbif_1_gc_after_bif)) GLOBAL(CSYM(nbif_2_gc_after_bif)) @@ -493,18 +501,22 @@ CSYM(nbif_3_gc_after_bif): * The heap pointer was just read from P. * TEMP_LR contains a copy of LR */ + OPD(nbif_0_simple_exception) GLOBAL(CSYM(nbif_0_simple_exception)) CSYM(nbif_0_simple_exception): li r4, 0 b .nbif_simple_exception + OPD(nbif_1_simple_exception) GLOBAL(CSYM(nbif_1_simple_exception)) CSYM(nbif_1_simple_exception): li r4, 1 b .nbif_simple_exception + OPD(nbif_2_simple_exception) GLOBAL(CSYM(nbif_2_simple_exception)) CSYM(nbif_2_simple_exception): li r4, 2 b .nbif_simple_exception + OPD(nbif_3_simple_exception) GLOBAL(CSYM(nbif_3_simple_exception)) CSYM(nbif_3_simple_exception): li r4, 3 diff --git a/erts/emulator/hipe/hipe_ppc_glue.h b/erts/emulator/hipe/hipe_ppc_glue.h index dcf5ec7644..f9c4460e60 100644 --- a/erts/emulator/hipe/hipe_ppc_glue.h +++ b/erts/emulator/hipe/hipe_ppc_glue.h @@ -1,23 +1,23 @@ /* * %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% */ -/* $Id$ - */ + + #ifndef HIPE_PPC_GLUE_H #define HIPE_PPC_GLUE_H diff --git a/erts/emulator/hipe/hipe_ppc_primops.h b/erts/emulator/hipe/hipe_ppc_primops.h index 67205fe1d1..7dba0afc88 100644 --- a/erts/emulator/hipe/hipe_ppc_primops.h +++ b/erts/emulator/hipe/hipe_ppc_primops.h @@ -1,23 +1,23 @@ /* * %CopyrightBegin% - * - * Copyright Ericsson AB 2005-2009. All Rights Reserved. - * + * + * Copyright Ericsson AB 2005-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% */ -/* $Id$ - */ + + #if !defined(__powerpc64__) PRIMOP_LIST(am_fconv_constant, &fconv_constant) #endif diff --git a/erts/emulator/hipe/hipe_primops.h b/erts/emulator/hipe/hipe_primops.h index cc2fc425d5..94113ffcd8 100644 --- a/erts/emulator/hipe/hipe_primops.h +++ b/erts/emulator/hipe/hipe_primops.h @@ -1,23 +1,23 @@ /* * %CopyrightBegin% - * - * Copyright Ericsson AB 2005-2009. All Rights Reserved. - * + * + * Copyright Ericsson AB 2005-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% */ -/* $Id$ - */ + + #ifndef HIPE_PRIMOPS_H #define HIPE_PRIMOPS_H diff --git a/erts/emulator/hipe/hipe_process.h b/erts/emulator/hipe/hipe_process.h index 5528e68826..5effacb398 100644 --- a/erts/emulator/hipe/hipe_process.h +++ b/erts/emulator/hipe/hipe_process.h @@ -1,22 +1,22 @@ /* * %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% */ -/* $Id$ +/* * HiPE-specific process fields */ #ifndef HIPE_PROCESS_H diff --git a/erts/emulator/hipe/hipe_risc_gc.h b/erts/emulator/hipe/hipe_risc_gc.h index 4a9a7878f0..947eb5956b 100644 --- a/erts/emulator/hipe/hipe_risc_gc.h +++ b/erts/emulator/hipe/hipe_risc_gc.h @@ -1,22 +1,22 @@ /* * %CopyrightBegin% - * - * Copyright Ericsson AB 2008-2009. All Rights Reserved. - * + * + * Copyright Ericsson AB 2008-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% */ -/* $Id$ +/* * Stack walking helpers for native stack GC procedures. * Generic RISC version. */ diff --git a/erts/emulator/hipe/hipe_risc_glue.h b/erts/emulator/hipe/hipe_risc_glue.h index 3b2d6498d3..e74023e3e9 100644 --- a/erts/emulator/hipe/hipe_risc_glue.h +++ b/erts/emulator/hipe/hipe_risc_glue.h @@ -1,23 +1,23 @@ /* * %CopyrightBegin% - * - * Copyright Ericsson AB 2008-2009. All Rights Reserved. - * + * + * Copyright Ericsson AB 2008-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% */ -/* $Id$ - */ + + #ifndef HIPE_RISC_GLUE_H #define HIPE_RISC_GLUE_H diff --git a/erts/emulator/hipe/hipe_risc_stack.c b/erts/emulator/hipe/hipe_risc_stack.c index 976ca0b85d..1183856c7e 100644 --- a/erts/emulator/hipe/hipe_risc_stack.c +++ b/erts/emulator/hipe/hipe_risc_stack.c @@ -1,23 +1,23 @@ /* * %CopyrightBegin% - * - * Copyright Ericsson AB 2008-2009. All Rights Reserved. - * + * + * Copyright Ericsson AB 2008-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% */ -/* $Id$ - */ + + #ifdef HAVE_CONFIG_H #include "config.h" #endif diff --git a/erts/emulator/hipe/hipe_signal.h b/erts/emulator/hipe/hipe_signal.h index 3c3c844d52..4eacf52b5d 100644 --- a/erts/emulator/hipe/hipe_signal.h +++ b/erts/emulator/hipe/hipe_signal.h @@ -1,22 +1,22 @@ /* * %CopyrightBegin% - * - * Copyright Ericsson AB 2002-2009. All Rights Reserved. - * + * + * Copyright Ericsson AB 2002-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% */ -/* $Id$ +/* * hipe_signal.h * * Architecture-specific initialisation of Unix signals. diff --git a/erts/emulator/hipe/hipe_sparc.c b/erts/emulator/hipe/hipe_sparc.c index 661b42130a..49d4da7bab 100644 --- a/erts/emulator/hipe/hipe_sparc.c +++ b/erts/emulator/hipe/hipe_sparc.c @@ -1,23 +1,23 @@ /* * %CopyrightBegin% - * - * Copyright Ericsson AB 2003-2009. All Rights Reserved. - * + * + * Copyright Ericsson AB 2003-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% */ -/* $Id$ - */ + + #include <stddef.h> /* offsetof() */ #ifdef HAVE_CONFIG_H #include "config.h" diff --git a/erts/emulator/hipe/hipe_sparc.h b/erts/emulator/hipe/hipe_sparc.h index 53cb18ee45..1134b86004 100644 --- a/erts/emulator/hipe/hipe_sparc.h +++ b/erts/emulator/hipe/hipe_sparc.h @@ -1,23 +1,23 @@ /* * %CopyrightBegin% - * - * Copyright Ericsson AB 2003-2009. All Rights Reserved. - * + * + * Copyright Ericsson AB 2003-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% */ -/* $Id$ - */ + + #ifndef HIPE_SPARC_H #define HIPE_SPARC_H diff --git a/erts/emulator/hipe/hipe_sparc.tab b/erts/emulator/hipe/hipe_sparc.tab index f192e1f81c..c620c73c67 100644 --- a/erts/emulator/hipe/hipe_sparc.tab +++ b/erts/emulator/hipe/hipe_sparc.tab @@ -1,22 +1,22 @@ # # %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% # -# $Id$ + # SPARC-specific atoms atom inc_stack_0 diff --git a/erts/emulator/hipe/hipe_sparc_abi.txt b/erts/emulator/hipe/hipe_sparc_abi.txt index d016a96c1c..cb5cda310b 100644 --- a/erts/emulator/hipe/hipe_sparc_abi.txt +++ b/erts/emulator/hipe/hipe_sparc_abi.txt @@ -2,7 +2,7 @@ %CopyrightBegin% %CopyrightEnd% -$Id$ + HiPE SPARC ABI ============== diff --git a/erts/emulator/hipe/hipe_sparc_asm.m4 b/erts/emulator/hipe/hipe_sparc_asm.m4 index 7a4403ac09..227d10ed80 100644 --- a/erts/emulator/hipe/hipe_sparc_asm.m4 +++ b/erts/emulator/hipe/hipe_sparc_asm.m4 @@ -1,25 +1,24 @@ changecom(`/*', `*/')dnl /* * %CopyrightBegin% - * - * Copyright Ericsson AB 2007-2009. All Rights Reserved. - * + * + * Copyright Ericsson AB 2007-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% */ -/* - * $Id$ - */ + + `#ifndef HIPE_SPARC_ASM_H #define HIPE_SPARC_ASM_H' diff --git a/erts/emulator/hipe/hipe_sparc_bifs.m4 b/erts/emulator/hipe/hipe_sparc_bifs.m4 index f3753b3847..03db7f3413 100644 --- a/erts/emulator/hipe/hipe_sparc_bifs.m4 +++ b/erts/emulator/hipe/hipe_sparc_bifs.m4 @@ -1,25 +1,23 @@ changecom(`/*', `*/')dnl /* * %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% */ -/* - * $Id$ - */ + include(`hipe/hipe_sparc_asm.m4') #`include' "hipe_literals.h" diff --git a/erts/emulator/hipe/hipe_sparc_gc.h b/erts/emulator/hipe/hipe_sparc_gc.h index 9035f5baee..b870ddd59e 100644 --- a/erts/emulator/hipe/hipe_sparc_gc.h +++ b/erts/emulator/hipe/hipe_sparc_gc.h @@ -1,22 +1,22 @@ /* * %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% */ -/* $Id$ +/* * Stack walking helpers for native stack GC procedures. * SPARC version. */ diff --git a/erts/emulator/hipe/hipe_sparc_glue.S b/erts/emulator/hipe/hipe_sparc_glue.S index aa07137116..44bdf1bc7e 100644 --- a/erts/emulator/hipe/hipe_sparc_glue.S +++ b/erts/emulator/hipe/hipe_sparc_glue.S @@ -1,23 +1,24 @@ /* * %CopyrightBegin% - * + + * * 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% */ -/* $Id$ - */ + + #include "hipe_sparc_asm.h" #include "hipe_literals.h" #define ASM diff --git a/erts/emulator/hipe/hipe_sparc_glue.h b/erts/emulator/hipe/hipe_sparc_glue.h index 3f881d2140..1404c0d4c0 100644 --- a/erts/emulator/hipe/hipe_sparc_glue.h +++ b/erts/emulator/hipe/hipe_sparc_glue.h @@ -1,23 +1,23 @@ /* * %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% */ -/* $Id$ - */ + + #ifndef HIPE_SPARC_GLUE_H #define HIPE_SPARC_GLUE_H diff --git a/erts/emulator/hipe/hipe_sparc_primops.h b/erts/emulator/hipe/hipe_sparc_primops.h index 1fbb261c67..413371e5f0 100644 --- a/erts/emulator/hipe/hipe_sparc_primops.h +++ b/erts/emulator/hipe/hipe_sparc_primops.h @@ -1,21 +1,21 @@ /* * %CopyrightBegin% - * - * Copyright Ericsson AB 2005-2009. All Rights Reserved. - * + * + * Copyright Ericsson AB 2005-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% */ -/* $Id$ - */ + + PRIMOP_LIST(am_inc_stack_0, &hipe_sparc_inc_stack) diff --git a/erts/emulator/hipe/hipe_stack.c b/erts/emulator/hipe/hipe_stack.c index 82f7f022b6..da462a64e1 100644 --- a/erts/emulator/hipe/hipe_stack.c +++ b/erts/emulator/hipe/hipe_stack.c @@ -1,23 +1,23 @@ /* * %CopyrightBegin% - * - * Copyright Ericsson AB 2003-2009. All Rights Reserved. - * + * + * Copyright Ericsson AB 2003-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% */ -/* $Id$ - */ + + #ifdef HAVE_CONFIG_H #include "config.h" #endif diff --git a/erts/emulator/hipe/hipe_stack.h b/erts/emulator/hipe/hipe_stack.h index 354ac81b4c..4c14b4a519 100644 --- a/erts/emulator/hipe/hipe_stack.h +++ b/erts/emulator/hipe/hipe_stack.h @@ -1,23 +1,23 @@ /* * %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% */ -/* $Id$ - */ + + #ifndef HIPE_STACK_H #define HIPE_STACK_H diff --git a/erts/emulator/hipe/hipe_x86.c b/erts/emulator/hipe/hipe_x86.c index f79a2d53f4..24d232c968 100644 --- a/erts/emulator/hipe/hipe_x86.c +++ b/erts/emulator/hipe/hipe_x86.c @@ -1,23 +1,23 @@ /* * %CopyrightBegin% - * - * Copyright Ericsson AB 2003-2009. All Rights Reserved. - * + * + * Copyright Ericsson AB 2003-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% */ -/* $Id$ - */ + + #include <stddef.h> /* offsetof() */ #ifdef HAVE_CONFIG_H #include "config.h" diff --git a/erts/emulator/hipe/hipe_x86.h b/erts/emulator/hipe/hipe_x86.h index 94ca39fc4f..f0f3c158af 100644 --- a/erts/emulator/hipe/hipe_x86.h +++ b/erts/emulator/hipe/hipe_x86.h @@ -1,23 +1,23 @@ /* * %CopyrightBegin% - * - * Copyright Ericsson AB 2003-2009. All Rights Reserved. - * + * + * Copyright Ericsson AB 2003-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% */ -/* $Id$ - */ + + #ifndef HIPE_X86_H #define HIPE_X86_H diff --git a/erts/emulator/hipe/hipe_x86.tab b/erts/emulator/hipe/hipe_x86.tab index a38fe49156..fb33d0a6b9 100644 --- a/erts/emulator/hipe/hipe_x86.tab +++ b/erts/emulator/hipe/hipe_x86.tab @@ -1,22 +1,22 @@ # # %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% # -# $Id$ + # x86-specific atoms atom handle_fp_exception diff --git a/erts/emulator/hipe/hipe_x86_abi.txt b/erts/emulator/hipe/hipe_x86_abi.txt index 62a704eef3..aa04a12611 100644 --- a/erts/emulator/hipe/hipe_x86_abi.txt +++ b/erts/emulator/hipe/hipe_x86_abi.txt @@ -1,7 +1,7 @@ %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 @@ -16,7 +16,7 @@ %CopyrightEnd% -$Id$ + HiPE x86 ABI ============ diff --git a/erts/emulator/hipe/hipe_x86_asm.m4 b/erts/emulator/hipe/hipe_x86_asm.m4 index 4c1d612ccd..020ccf8d4b 100644 --- a/erts/emulator/hipe/hipe_x86_asm.m4 +++ b/erts/emulator/hipe/hipe_x86_asm.m4 @@ -1,25 +1,24 @@ changecom(`/*', `*/')dnl /* * %CopyrightBegin% - * - * Copyright Ericsson AB 2002-2009. All Rights Reserved. - * + * + * Copyright Ericsson AB 2002-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% */ -/* - * $Id$ - */ + + `#ifndef HIPE_X86_ASM_H #define HIPE_X86_ASM_H' diff --git a/erts/emulator/hipe/hipe_x86_bifs.m4 b/erts/emulator/hipe/hipe_x86_bifs.m4 index 80be74f7b2..1bb6488b00 100644 --- a/erts/emulator/hipe/hipe_x86_bifs.m4 +++ b/erts/emulator/hipe/hipe_x86_bifs.m4 @@ -1,25 +1,23 @@ changecom(`/*', `*/')dnl /* * %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% */ -/* - * $Id$ - */ + include(`hipe/hipe_x86_asm.m4') #`include' "hipe_literals.h" diff --git a/erts/emulator/hipe/hipe_x86_gc.h b/erts/emulator/hipe/hipe_x86_gc.h index 4f17f767df..e4607ad27d 100644 --- a/erts/emulator/hipe/hipe_x86_gc.h +++ b/erts/emulator/hipe/hipe_x86_gc.h @@ -1,22 +1,22 @@ /* * %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% */ -/* $Id$ +/* * Stack walking helpers for native stack GC procedures. */ #ifndef HIPE_X86_GC_H diff --git a/erts/emulator/hipe/hipe_x86_glue.S b/erts/emulator/hipe/hipe_x86_glue.S index af2d0cb970..88b86f4de7 100644 --- a/erts/emulator/hipe/hipe_x86_glue.S +++ b/erts/emulator/hipe/hipe_x86_glue.S @@ -1,24 +1,23 @@ /* * %CopyrightBegin% - * + + * * 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% */ -/* - * $Id$ - */ + #include "hipe_x86_asm.h" #include "hipe_literals.h" diff --git a/erts/emulator/hipe/hipe_x86_glue.h b/erts/emulator/hipe/hipe_x86_glue.h index 4c9c92c52f..a7b0f164be 100644 --- a/erts/emulator/hipe/hipe_x86_glue.h +++ b/erts/emulator/hipe/hipe_x86_glue.h @@ -1,24 +1,23 @@ /* * %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% */ -/* - * $Id$ - */ + + #ifndef HIPE_X86_GLUE_H #define HIPE_X86_GLUE_H diff --git a/erts/emulator/hipe/hipe_x86_primops.h b/erts/emulator/hipe/hipe_x86_primops.h index 757da484ad..96d2336bc5 100644 --- a/erts/emulator/hipe/hipe_x86_primops.h +++ b/erts/emulator/hipe/hipe_x86_primops.h @@ -1,22 +1,22 @@ /* * %CopyrightBegin% - * - * Copyright Ericsson AB 2005-2009. All Rights Reserved. - * + * + * Copyright Ericsson AB 2005-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% */ -/* $Id$ - */ + + PRIMOP_LIST(am_inc_stack_0, &nbif_inc_stack_0) PRIMOP_LIST(am_handle_fp_exception, &nbif_handle_fp_exception) diff --git a/erts/emulator/hipe/hipe_x86_signal.c b/erts/emulator/hipe/hipe_x86_signal.c index e515f1cd60..64c0e0da3e 100644 --- a/erts/emulator/hipe/hipe_x86_signal.c +++ b/erts/emulator/hipe/hipe_x86_signal.c @@ -1,22 +1,23 @@ /* * %CopyrightBegin% - * + + * * 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% */ -/* $Id$ +/* * hipe_x86_signal.c * * Erlang code compiled to x86 native code uses the x86 %esp as its diff --git a/erts/emulator/hipe/hipe_x86_stack.c b/erts/emulator/hipe/hipe_x86_stack.c index b459593883..9ad3fa9d31 100644 --- a/erts/emulator/hipe/hipe_x86_stack.c +++ b/erts/emulator/hipe/hipe_x86_stack.c @@ -1,23 +1,23 @@ /* * %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% */ -/* $Id$ - */ + + #ifdef HAVE_CONFIG_H #include "config.h" #endif diff --git a/erts/emulator/sys/common/erl_mseg.c b/erts/emulator/sys/common/erl_mseg.c index ceb290b644..ffa3a6328c 100644 --- a/erts/emulator/sys/common/erl_mseg.c +++ b/erts/emulator/sys/common/erl_mseg.c @@ -1092,10 +1092,10 @@ info_options(char *prefix, if (print_to_p) { int to = *print_to_p; void *arg = print_to_arg; - erts_print(to, arg, "%samcbf: %bpu\n", prefix, abs_max_cache_bad_fit); - erts_print(to, arg, "%srmcbf: %bpu\n", prefix, rel_max_cache_bad_fit); - erts_print(to, arg, "%smcs: %bpu\n", prefix, max_cache_size); - erts_print(to, arg, "%scci: %bpu\n", prefix, cache_check_interval); + erts_print(to, arg, "%samcbf: %beu\n", prefix, abs_max_cache_bad_fit); + erts_print(to, arg, "%srmcbf: %beu\n", prefix, rel_max_cache_bad_fit); + erts_print(to, arg, "%smcs: %beu\n", prefix, max_cache_size); + erts_print(to, arg, "%scci: %beu\n", prefix, cache_check_interval); } if (hpp || szp) { @@ -1131,9 +1131,9 @@ info_calls(int *print_to_p, void *print_to_arg, Uint **hpp, Uint *szp) #define PRINT_CC(TO, TOA, CC) \ if (calls.CC.giga_no == 0) \ - erts_print(TO, TOA, "mseg_%s calls: %bpu\n", #CC, calls.CC.no); \ + erts_print(TO, TOA, "mseg_%s calls: %b32u\n", #CC, calls.CC.no); \ else \ - erts_print(TO, TOA, "mseg_%s calls: %bpu%09bpu\n", #CC, \ + erts_print(TO, TOA, "mseg_%s calls: %b32u%09b32u\n", #CC, \ calls.CC.giga_no, calls.CC.no) int to = *print_to_p; @@ -1215,13 +1215,13 @@ info_status(MemKind* mk, int *print_to_p, void *print_to_arg, int to = *print_to_p; void *arg = print_to_arg; - erts_print(to, arg, "cached_segments: %bpu\n", mk->cache_size); - erts_print(to, arg, "cache_hits: %bpu\n", mk->cache_hits); - erts_print(to, arg, "segments: %bpu %bpu %bpu\n", + erts_print(to, arg, "cached_segments: %beu\n", mk->cache_size); + erts_print(to, arg, "cache_hits: %beu\n", mk->cache_hits); + erts_print(to, arg, "segments: %beu %beu %beu\n", mk->segments.current.no, mk->segments.max.no, mk->segments.max_ever.no); - erts_print(to, arg, "segments_size: %bpu %bpu %bpu\n", + erts_print(to, arg, "segments_size: %beu %beu %beu\n", mk->segments.current.sz, mk->segments.max.sz, mk->segments.max_ever.sz); - erts_print(to, arg, "segments_watermark: %bpu\n", + erts_print(to, arg, "segments_watermark: %beu\n", mk->segments.current.watermark); } @@ -1507,7 +1507,7 @@ erts_mseg_init(ErtsMsegInit_t *init) while ((page_size >> page_shift) != 1) { if ((page_size & (1 << (page_shift - 1))) != 0) erl_exit(ERTS_ABORT_EXIT, - "erts_mseg: Unexpected page_size %bpu\n", page_size); + "erts_mseg: Unexpected page_size %beu\n", page_size); page_shift++; } diff --git a/erts/emulator/sys/win32/sys.c b/erts/emulator/sys/win32/sys.c index 37041ed987..a2159d063c 100644 --- a/erts/emulator/sys/win32/sys.c +++ b/erts/emulator/sys/win32/sys.c @@ -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 @@ -75,7 +75,7 @@ static int create_pipe(LPHANDLE, LPHANDLE, BOOL, BOOL); static int application_type(const char* originalName, char fullPath[MAX_PATH], BOOL search_in_path, BOOL handle_quotes, int *error_return); -static int application_type_w(const char* originalName, WCHAR fullPath[MAX_PATH], +static int application_type_w(const WCHAR *originalName, WCHAR fullPath[MAX_PATH], BOOL search_in_path, BOOL handle_quotes, int *error_return); @@ -260,7 +260,7 @@ erts_sys_prepare_crash_dump(void) } static void -init_console() +init_console(void) { char* mode = erts_read_env("ERL_CONSOLE_MODE"); @@ -280,7 +280,7 @@ init_console() erts_free_read_env(mode); } -int sys_max_files() +int sys_max_files(void) { return max_files; } @@ -296,10 +296,7 @@ int sys_max_files() */ static int -get_and_remove_option(argc, argv, option) - int* argc; /* Number of arguments. */ - char* argv[]; /* The argument vector. */ - const char* option; /* Option to search for and remove. */ +get_and_remove_option(int* argc, char* argv[], const char *option) { int i; @@ -349,9 +346,7 @@ static char *get_and_remove_option2(int *argc, char **argv, char os_type[] = "win32"; void -os_flavor(namebuf, size) -char* namebuf; /* Where to return the name. */ -unsigned size; /* Size of name buffer. */ +os_flavor(char *namebuf, unsigned size) { switch (int_os_version.dwPlatformId) { case VER_PLATFORM_WIN32_WINDOWS: @@ -624,12 +619,7 @@ struct erl_drv_entry async_driver_entry = { */ static DriverData* -new_driver_data(port_num, packet_bytes, wait_objs_required, use_threads) - int port_num; /* The port number. */ - int packet_bytes; /* Number of bytes in header. */ - int wait_objs_required; /* The number objects this port is going - /* wait for (typically 1 or 2). */ - int use_threads; /* TRUE if threads are intended to be used. */ +new_driver_data(int port_num, int packet_bytes, int wait_objs_required, int use_threads) { DriverData* dp; @@ -867,12 +857,7 @@ threaded_handle_closer(LPVOID param) */ static ErlDrvData -set_driver_data(dp, ifd, ofd, read_write, report_exit) - DriverData* dp; - HANDLE ifd; - HANDLE ofd; - int read_write; - int report_exit; +set_driver_data(DriverData* dp, HANDLE ifd, HANDLE ofd, int read_write, int report_exit) { int index = dp - driver_data; int result; @@ -896,6 +881,31 @@ set_driver_data(dp, ifd, ofd, read_write, report_exit) return (ErlDrvData)index; } +static ErlDrvData +reuse_driver_data(DriverData *dp, HANDLE ifd, HANDLE ofd, int read_write, ErlDrvPort port_num) +{ + int index = dp - driver_data; + int result; + + dp->port_num = port_num; + dp->in.fd = ifd; + dp->out.fd = ofd; + dp->report_exit = 0; + + if (read_write & DO_READ) { + result = driver_select(dp->port_num, (ErlDrvEvent)dp->in.ov.hEvent, + ERL_DRV_READ|ERL_DRV_USE, 1); + ASSERT(result != -1); + } + + if (read_write & DO_WRITE) { + result = driver_select(dp->port_num, (ErlDrvEvent)dp->out.ov.hEvent, + ERL_DRV_WRITE|ERL_DRV_USE, 1); + ASSERT(result != -1); + } + return (ErlDrvData)index; +} + /* * Initialises an AsyncIo structure. */ @@ -969,10 +979,7 @@ release_async_io(AsyncIo* aio, ErlDrvPort port_num) */ static void -async_read_file(aio, buf, numToRead) - AsyncIo* aio; /* Pointer to driver data. */ - LPVOID buf; /* Pointer to buffer to receive data. */ - DWORD numToRead; /* Number of bytes to read. */ +async_read_file(AsyncIo* aio, LPVOID buf, DWORD numToRead) { aio->pendingError = NO_ERROR; #ifdef HARD_POLL_DEBUG @@ -1023,10 +1030,9 @@ async_read_file(aio, buf, numToRead) * ---------------------------------------------------------------------- */ static int -async_write_file(aio, buf, numToWrite) - AsyncIo* aio; /* Pointer to async control block. */ - LPVOID buf; /* Pointer to buffer with data to write. */ - DWORD numToWrite; /* Number of bytes to write. */ +async_write_file(AsyncIo* aio, /* Pointer to async control block. */ + LPVOID buf, /* Pointer to buffer with data to write. */ + DWORD numToWrite) /* Number of bytes to write. */ { aio->pendingError = NO_ERROR; if (aio->thread != (HANDLE) -1) { @@ -1070,12 +1076,12 @@ async_write_file(aio, buf, numToWrite) * ---------------------------------------------------------------------- */ static int -get_overlapped_result(aio, pBytesRead, wait) - AsyncIo* aio; /* Pointer to async control block. */ - LPDWORD pBytesRead; /* Where to place the number of bytes - * transferred. - */ - BOOL wait; /* If true, wait until result is ready. */ +get_overlapped_result(AsyncIo* aio, /* Pointer to async control block. */ + LPDWORD pBytesRead, /* Where to place the number of bytes + * transferred. + */ + BOOL wait /* If true, wait until result is ready. */ + ) { DWORD error = NO_ERROR; /* Error status from last function. */ @@ -1145,7 +1151,7 @@ fd_init(void) return 0; } static int -spawn_init() +spawn_init(void) { int i; #if defined(ERTS_SMP) && defined(USE_CANCELIOEX) @@ -1532,7 +1538,7 @@ create_child_process siStartInfo.hStdOutput = hStdout; siStartInfo.hStdError = hStderr; - applType = application_type_w(origcmd, (char *) execPath, FALSE, FALSE, + applType = application_type_w((WCHAR *) origcmd, execPath, FALSE, FALSE, errno_return); if (applType == APPL_NONE) { return FALSE; @@ -1555,7 +1561,7 @@ create_child_process if (run_cmd) { WCHAR cmdPath[MAX_PATH]; int cmdType; - cmdType = application_type_w((char *) L"cmd.exe", (char *) cmdPath, TRUE, FALSE, errno_return); + cmdType = application_type_w(L"cmd.exe", cmdPath, TRUE, FALSE, errno_return); if (cmdType == APPL_NONE || cmdType == APPL_DOS) { return FALSE; } @@ -1921,7 +1927,7 @@ static int application_type return applType; } -static int application_type_w (const char *originalName, /* Name of the application to find. */ +static int application_type_w (const WCHAR *originalName, /* Name of the application to find. */ WCHAR wfullpath[MAX_PATH],/* Filled with complete path to * application. */ BOOL search_in_path, /* If we should search the system wide path */ @@ -1937,25 +1943,24 @@ static int application_type_w (const char *originalName, /* Name of the applicat static WCHAR extensions[][5] = {L"", L".com", L".exe", L".bat"}; int is_quoted; int len; - WCHAR *wname = (WCHAR *) originalName; WCHAR xfullpath[MAX_PATH]; - len = wcslen(wname); - is_quoted = handle_quotes && len > 0 && wname[0] == L'"' && - wname[len-1] == L'"'; + len = wcslen(originalName); + is_quoted = handle_quotes && len > 0 && originalName[0] == L'"' && + originalName[len-1] == L'"'; applType = APPL_NONE; *error_return = ENOENT; for (i = 0; i < (int) (sizeof(extensions) / sizeof(extensions[0])); i++) { if(is_quoted) { - lstrcpynW(xfullpath, wname+1, MAX_PATH - 7); /* Cannot start using StringCchCopy yet, we support + lstrcpynW(xfullpath, originalName+1, MAX_PATH - 7); /* Cannot start using StringCchCopy yet, we support older platforms */ len = wcslen(xfullpath); if(len > 0) { xfullpath[len-1] = L'\0'; } } else { - lstrcpynW(xfullpath, wname, MAX_PATH - 5); + lstrcpynW(xfullpath, originalName, MAX_PATH - 5); } wcscat(xfullpath, extensions[i]); /* It seems that the Unicode version does not allow in and out parameter to overlap. */ @@ -2080,9 +2085,10 @@ threaded_reader(LPVOID param) buf = OV_BUFFER_PTR(aio); numToRead = OV_NUM_TO_READ(aio); aio->pendingError = 0; - if (!ReadFile(aio->fd, buf, numToRead, &aio->bytesTransferred, NULL)) - aio->pendingError = GetLastError(); - else if (aio->flags & DF_XLAT_CR) { + if (!ReadFile(aio->fd, buf, numToRead, &aio->bytesTransferred, NULL)) { + int error = GetLastError(); + aio->pendingError = error; + } else if (aio->flags & DF_XLAT_CR) { char *s; int n; @@ -2209,56 +2215,79 @@ translate_fd(int fd) return handle; } +/* Driver level locking, start function is serialized */ +static DriverData *save_01_port = NULL; +static DriverData *save_22_port = NULL; + static ErlDrvData fd_start(ErlDrvPort port_num, char* name, SysDriverOpts* opts) { DriverData* dp; int is_std_error = (opts->ofd == 2); - - opts->ifd = (int) translate_fd(opts->ifd); - opts->ofd = (int) translate_fd(opts->ofd); - if ((dp = new_driver_data(port_num, opts->packet_bytes, 2, TRUE)) == NULL) - return ERL_DRV_ERROR_GENERAL; - - if (!create_file_thread(&dp->in, DO_READ)) { - dp->port_num = PORT_FREE; - return ERL_DRV_ERROR_GENERAL; - } - - if (!create_file_thread(&dp->out, DO_WRITE)) { - dp->port_num = PORT_FREE; - return ERL_DRV_ERROR_GENERAL; - } - - fd_driver_input = &(dp->in); - dp->in.flags = DF_XLAT_CR; - if (is_std_error) { - dp->out.flags |= DF_DROP_IF_INVH; /* Just drop messages if stderror - is an invalid handle */ + int in = opts->ifd, out = opts->ofd; + + opts->ifd = (Uint) translate_fd(in); + opts->ofd = (Uint) translate_fd(out); + if ( in == 0 && out == 1 && save_01_port != NULL) { + dp = save_01_port; + return reuse_driver_data(dp, (HANDLE) opts->ifd, (HANDLE) opts->ofd, opts->read_write, port_num); + } else if (in == 2 && out == 2 && save_22_port != NULL) { + dp = save_22_port; + return reuse_driver_data(dp, (HANDLE) opts->ifd, (HANDLE) opts->ofd, opts->read_write, port_num); + } else { + if ((dp = new_driver_data(port_num, opts->packet_bytes, 2, TRUE)) == NULL) + return ERL_DRV_ERROR_GENERAL; + + if (!create_file_thread(&dp->in, DO_READ)) { + dp->port_num = PORT_FREE; + return ERL_DRV_ERROR_GENERAL; + } + + if (!create_file_thread(&dp->out, DO_WRITE)) { + dp->port_num = PORT_FREE; + return ERL_DRV_ERROR_GENERAL; + } + + fd_driver_input = &(dp->in); + dp->in.flags = DF_XLAT_CR; + if (is_std_error) { + dp->out.flags |= DF_DROP_IF_INVH; /* Just drop messages if stderror + is an invalid handle */ + } + + if ( in == 0 && out == 1) { + save_01_port = dp; + } else if (in == 2 && out == 2) { + save_22_port = dp; + } + return set_driver_data(dp, (HANDLE) opts->ifd, (HANDLE) opts->ofd, opts->read_write, 0); } - return set_driver_data(dp, opts->ifd, opts->ofd, opts->read_write, 0); } static void fd_stop(ErlDrvData d) { int fd = (int)d; + DriverData* dp = driver_data+fd; /* - * I don't know a clean way to terminate the threads - * (TerminateThread() doesn't release the stack), - * so will we'll let the threads live. Normally, the fd - * driver is only used to support the -oldshell option, - * so this shouldn't be a problem in practice. - * - * Since we will not attempt to terminate the threads, - * better not close the input or output files either. + * There's no way we can terminate an fd port in a consistent way. + * Instead we let it live until it's opened again (which it is, + * as the only FD-drivers are for 0,1 and 2 adn the only time they + * get closed is by init:reboot). + * So - just deselect them and let everything be as is. + * They get woken up in fd_start again, where the DriverData is + * remembered. /PaN */ + if (dp->in.ov.hEvent != NULL) { + (void) driver_select(dp->port_num, + (ErlDrvEvent)dp->in.ov.hEvent, + ERL_DRV_READ, 0); + } + if (dp->out.ov.hEvent != NULL) { + (void) driver_select(dp->port_num, + (ErlDrvEvent)dp->out.ov.hEvent, + ERL_DRV_WRITE, 0); + } - driver_data[fd].in.thread = (HANDLE) -1; - driver_data[fd].out.thread = (HANDLE) -1; - driver_data[fd].in.fd = INVALID_HANDLE_VALUE; - driver_data[fd].out.fd = INVALID_HANDLE_VALUE; - - /*return */ common_stop(fd); } static ErlDrvData @@ -2350,7 +2379,6 @@ threaded_exiter(LPVOID param) * because it is an auto reset event. Therefore, always set the * exit flag and signal the event. */ - i = 0; if (dp->out.thread != (HANDLE) -1) { dp->out.flags = DF_EXIT_THREAD; @@ -2718,6 +2746,7 @@ ready_input(ErlDrvData drv_data, ErlDrvEvent ready_event) driver_failure_eof(dp->port_num); } else { /* Report real errors. */ int error = GetLastError(); + (void) driver_select(dp->port_num, ready_event, ERL_DRV_READ, 0); _dosmaperr(error); driver_failure_posix(dp->port_num, errno); diff --git a/erts/emulator/test/Makefile b/erts/emulator/test/Makefile index 3afcae494d..4d0c87bf12 100644 --- a/erts/emulator/test/Makefile +++ b/erts/emulator/test/Makefile @@ -200,7 +200,7 @@ release_tests_spec: make_emakefile $(ERL_FILES) $(RELSYSDIR) $(INSTALL_DATA) $(NO_OPT_ERL_FILES) $(RELSYSDIR) $(INSTALL_DATA) $(NATIVE_ERL_FILES) $(RELSYSDIR) - chmod -f -R u+w $(RELSYSDIR) + chmod -R u+w $(RELSYSDIR) tar cf - *_SUITE_data | (cd $(RELSYSDIR); tar xf -) release_docs_spec: diff --git a/erts/emulator/test/bif_SUITE.erl b/erts/emulator/test/bif_SUITE.erl index 509586826b..c7617d3b90 100644 --- a/erts/emulator/test/bif_SUITE.erl +++ b/erts/emulator/test/bif_SUITE.erl @@ -24,6 +24,7 @@ -export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1, init_per_group/2,end_per_group/2, init_per_testcase/2,end_per_testcase/2, + display/1, display_huge/0, types/1, t_list_to_existing_atom/1,os_env/1,otp_7526/1, binary_to_atom/1,binary_to_existing_atom/1, @@ -33,6 +34,7 @@ suite() -> [{ct_hooks,[ts_install_cth]}]. all() -> [types, t_list_to_existing_atom, os_env, otp_7526, + display, atom_to_binary, binary_to_atom, binary_to_existing_atom, min_max]. @@ -60,6 +62,31 @@ end_per_testcase(_Func, Config) -> Dog=?config(watchdog, Config), ?t:timetrap_cancel(Dog). + +display(suite) -> + []; +display(doc) -> + ["Uses erlang:display to test that erts_printf does not do deep recursion"]; +display(Config) when is_list(Config) -> + Pa = filename:dirname(code:which(?MODULE)), + {ok, Node} = test_server:start_node(display_huge_term,peer, + [{args, "-pa "++Pa}]), + true = rpc:call(Node,?MODULE,display_huge,[]), + test_server:stop_node(Node), + ok. + +display_huge() -> + erlang:display(deeep(100000)). + +deeep(0,Acc) -> + Acc; +deeep(N,Acc) -> + deeep(N-1,[Acc|[]]). + +deeep(N) -> + deeep(N,[hello]). + + types(Config) when is_list(Config) -> c:l(erl_bif_types), case erlang:function_exported(erl_bif_types, module_info, 0) of diff --git a/erts/emulator/test/code_SUITE.erl b/erts/emulator/test/code_SUITE.erl index 703a00a598..c1a048be75 100644 --- a/erts/emulator/test/code_SUITE.erl +++ b/erts/emulator/test/code_SUITE.erl @@ -483,7 +483,7 @@ do_false_dependency(Init, Code) -> %% Spawn process. Make sure it has the appropriate init function %% and returned. CP should not contain garbage after the return. Parent = self(), - ?line Pid = spawn_link(fun() -> false_dependency_loop(Parent, Init) end), + ?line Pid = spawn_link(fun() -> false_dependency_loop(Parent, Init, true) end), ?line receive initialized -> ok end, %% Reload the module. Make sure the process is still alive. @@ -501,11 +501,18 @@ do_false_dependency(Init, Code) -> ?line true = erlang:purge_module(cpbugx), ok. -false_dependency_loop(Parent, Init) -> +false_dependency_loop(Parent, Init, SendInitAck) -> Init(), - Parent ! initialized, + case SendInitAck of + true -> Parent ! initialized; + false -> void + %% Just send one init-ack. I guess the point of this test + %% wasn't to fill parents msg-queue (?). Seen to cause + %% out-of-mem (on halfword-vm for some reason) by + %% 91 million msg in queue. /sverker + end, receive - _ -> false_dependency_loop(Parent, Init) + _ -> false_dependency_loop(Parent, Init, false) end. coverage(Config) when is_list(Config) -> diff --git a/erts/emulator/test/estone_SUITE.erl b/erts/emulator/test/estone_SUITE.erl index 2ba9375a41..2417d4bcfe 100644 --- a/erts/emulator/test/estone_SUITE.erl +++ b/erts/emulator/test/estone_SUITE.erl @@ -31,7 +31,7 @@ trav/1, port_io/1, large_dataset_work/1, - large_local_dataset_work/1,mk_big_procs/1,big_proc/0, + large_local_dataset_work/1,mk_big_procs/1,big_proc/0, very_big/1, alloc/1, bif_dispatch/1, binary_h/1,echo/1, diff --git a/erts/emulator/test/exception_SUITE.erl b/erts/emulator/test/exception_SUITE.erl index d44dc117d2..9d6fc9521d 100644 --- a/erts/emulator/test/exception_SUITE.erl +++ b/erts/emulator/test/exception_SUITE.erl @@ -275,7 +275,16 @@ stacktrace(Conf) when is_list(Conf) -> ?line [{?MODULE,stacktrace_1,3}|_] = erase(stacktrace1), ?line St4 = erase(stacktrace2), ?line St4 = erlang:get_stacktrace(), - ok. + + try + ?line stacktrace_2() + catch + error:{badmatch,_} -> + [{?MODULE,stacktrace_2,0}, + {?MODULE,stacktrace,1}|_] = + erlang:get_stacktrace(), + ok + end. stacktrace_1(X, C1, Y) -> erase(stacktrace1), @@ -295,6 +304,9 @@ stacktrace_1(X, C1, Y) -> put(stacktrace2, erlang:get_stacktrace()) end. +stacktrace_2() -> + ok = erlang:process_info(self(), current_function), + ok. nested_stacktrace(Conf) when is_list(Conf) -> diff --git a/erts/emulator/test/nif_SUITE.erl b/erts/emulator/test/nif_SUITE.erl index b79c30d8d9..91d695d979 100644 --- a/erts/emulator/test/nif_SUITE.erl +++ b/erts/emulator/test/nif_SUITE.erl @@ -1121,7 +1121,14 @@ is_checks(Config) when is_list(Config) -> ?line ensure_lib_loaded(Config, 1), ?line ok = check_is(hejsan, <<19,98>>, make_ref(), ok, fun() -> ok end, self(), hd(erlang:ports()), [], [1,9,9,8], - {hejsan, "hejsan", [$h,"ejs",<<"an">>]}). + {hejsan, "hejsan", [$h,"ejs",<<"an">>]}), + try + ?line error = check_is_exception(), + ?line throw(expected_badarg) + catch + error:badarg -> + ?line ok + end. get_length(doc) -> ["Test all enif_get_length functions"]; get_length(Config) when is_list(Config) -> @@ -1245,6 +1252,7 @@ release_resource(_) -> ?nif_stub. last_resource_dtor_call() -> ?nif_stub. make_new_resource(_,_) -> ?nif_stub. check_is(_,_,_,_,_,_,_,_,_,_) -> ?nif_stub. +check_is_exception() -> ?nif_stub. length_test(_,_,_,_,_) -> ?nif_stub. make_atoms() -> ?nif_stub. make_strings() -> ?nif_stub. diff --git a/erts/emulator/test/nif_SUITE_data/nif_SUITE.c b/erts/emulator/test/nif_SUITE_data/nif_SUITE.c index 8489124966..dc047394b5 100644 --- a/erts/emulator/test/nif_SUITE_data/nif_SUITE.c +++ b/erts/emulator/test/nif_SUITE_data/nif_SUITE.c @@ -802,6 +802,23 @@ static ERL_NIF_TERM check_is(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[] } /* + * no arguments + * + * This function is separate from check_is because it calls enif_make_badarg + * and so it must return the badarg exception as its return value. Thus, the + * badarg exception indicates success. Failure is indicated by returning an + * error atom. + */ +static ERL_NIF_TERM check_is_exception(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) +{ + ERL_NIF_TERM error_atom = enif_make_atom(env, "error"); + ERL_NIF_TERM badarg = enif_make_badarg(env); + if (enif_is_exception(env, error_atom)) return error_atom; + if (!enif_is_exception(env, badarg)) return error_atom; + return badarg; +} + +/* * argv[0] atom with length of 6 * argv[1] list with length of 6 * argv[2] empty list @@ -1383,6 +1400,7 @@ static ErlNifFunc nif_funcs[] = {"last_resource_dtor_call", 0, last_resource_dtor_call}, {"make_new_resource", 2, make_new_resource}, {"check_is", 10, check_is}, + {"check_is_exception", 0, check_is_exception}, {"length_test", 5, length_test}, {"make_atoms", 0, make_atoms}, {"make_strings", 0, make_strings}, diff --git a/erts/emulator/test/process_SUITE.erl b/erts/emulator/test/process_SUITE.erl index a731f09e4c..36bae908aa 100644 --- a/erts/emulator/test/process_SUITE.erl +++ b/erts/emulator/test/process_SUITE.erl @@ -39,6 +39,7 @@ process_info_other_dist_msg/1, process_info_2_list/1, process_info_lock_reschedule/1, process_info_lock_reschedule2/1, + process_info_lock_reschedule3/1, bump_reductions/1, low_prio/1, binary_owner/1, yield/1, yield2/1, process_status_exiting/1, otp_4725/1, bad_register/1, garbage_collect/1, otp_6237/1, @@ -65,7 +66,8 @@ all() -> t_process_info, process_info_other_msg, process_info_other_dist_msg, process_info_2_list, process_info_lock_reschedule, - process_info_lock_reschedule2, process_status_exiting, + process_info_lock_reschedule2, + process_info_lock_reschedule3, process_status_exiting, bump_reductions, low_prio, yield, yield2, otp_4725, bad_register, garbage_collect, process_info_messages, process_flag_badarg, process_flag_heap_size, @@ -702,6 +704,52 @@ process_info_lock_reschedule2(Config) when is_list(Config) -> ?line unlink(P6), exit(P6, bang), ?line ok. +many_args(0,_B,_C,_D,_E,_F,_G,_H,_I,_J) -> + ok; +many_args(A,B,C,D,E,F,G,H,I,J) -> + many_args(A-1,B,C,D,E,F,G,H,I,J). + +do_pi_msg_len(PT, AT) -> + lists:map(fun (_) -> ok end, [a,b,c,d]), + {message_queue_len, _} = process_info(element(2,PT), element(2,AT)). + +process_info_lock_reschedule3(doc) -> + []; +process_info_lock_reschedule3(suite) -> + []; +process_info_lock_reschedule3(Config) when is_list(Config) -> + %% We need a process that is running and an item that requires + %% process_info to take the main process lock. + ?line Target1 = spawn_link(fun tok_loop/0), + ?line Name1 = process_info_lock_reschedule_running, + ?line register(Name1, Target1), + ?line Target2 = spawn_link(fun () -> receive after infinity -> ok end end), + ?line Name2 = process_info_lock_reschedule_waiting, + ?line register(Name2, Target2), + ?line PI = fun(N) -> + case N rem 10 of + 0 -> erlang:yield(); + _ -> ok + end, + ?line do_pi_msg_len({proc, Target1}, + {arg, message_queue_len}) + end, + ?line many_args(100000,1,2,3,4,5,6,7,8,9), + ?line lists:foreach(PI, lists:seq(1,1000000)), + %% Make sure Target1 still is willing to "tok loop" + ?line case process_info(Target1, status) of + {status, OkStatus} when OkStatus == runnable; + OkStatus == running; + OkStatus == garbage_collecting -> + ?line unlink(Target1), + ?line unlink(Target2), + ?line exit(Target1, bang), + ?line exit(Target2, bang), + ?line OkStatus; + {status, BadStatus} -> + ?line ?t:fail(BadStatus) + end. + process_status_exiting(Config) when is_list(Config) -> %% Make sure that erts_debug:get_internal_state({process_status,P}) %% returns exiting if it is in status P_EXITING. diff --git a/erts/epmd/src/epmd.c b/erts/epmd/src/epmd.c index 65ff0cd6b2..a1f202251c 100644 --- a/erts/epmd/src/epmd.c +++ b/erts/epmd/src/epmd.c @@ -33,6 +33,7 @@ static void usage(EpmdVars *); static void run_daemon(EpmdVars*); +static char* get_addresses(void); static int get_port_no(void); static int check_relaxed(void); #ifdef __WIN32__ @@ -133,6 +134,7 @@ int main(int argc, char** argv) { EpmdVars g_empd_vars; EpmdVars *g = &g_empd_vars; + int i; #ifdef __WIN32__ WORD wVersionRequested; WSADATA wsaData; @@ -158,8 +160,9 @@ int main(int argc, char** argv) g->argv = NULL; #endif - g->port = get_port_no(); - g->debug = 0; + g->addresses = get_addresses(); + g->port = get_port_no(); + g->debug = 0; g->silent = 0; g->is_daemon = 0; @@ -168,12 +171,14 @@ int main(int argc, char** argv) g->delay_accept = 0; g->delay_write = 0; g->progname = argv[0]; - g->listenfd = -1; g->conn = NULL; g->nodes.reg = g->nodes.unreg = g->nodes.unreg_tail = NULL; g->nodes.unreg_count = 0; g->active_conn = 0; + for (i = 0; i < MAX_LISTEN_SOCKETS; i++) + g->listenfd[i] = -1; + argc--; argv++; while (argc > 0) { @@ -208,6 +213,11 @@ int main(int argc, char** argv) else usage(g); epmd_cleanup_exit(g,0); + } else if (strcmp(argv[0], "-address") == 0) { + if (argc == 1) + usage(g); + g->addresses = argv[1]; + argv += 2; argc -= 2; } else if (strcmp(argv[0], "-port") == 0) { if ((argc == 1) || ((g->port = atoi(argv[1])) == 0)) @@ -252,13 +262,10 @@ int main(int argc, char** argv) /* * max_conn must not be greater than FD_SETSIZE. * (at least QNX crashes) - * - * More correctly, it must be FD_SETSIZE - 1, beacuse the - * listen FD is stored outside the connection array. */ if (g->max_conn > FD_SETSIZE) { - g->max_conn = FD_SETSIZE - 1; + g->max_conn = FD_SETSIZE; } if (g->is_daemon) { @@ -393,11 +400,14 @@ static void run_daemon(EpmdVars *g) static void usage(EpmdVars *g) { - fprintf(stderr, "usage: epmd [-d|-debug] [DbgExtra...] [-port No] [-daemon]\n"); - fprintf(stderr, " [-relaxed_command_check]\n"); + fprintf(stderr, "usage: epmd [-d|-debug] [DbgExtra...] [-address List]\n"); + fprintf(stderr, " [-port No] [-daemon] [-relaxed_command_check]\n"); fprintf(stderr, " epmd [-d|-debug] [-port No] [-names|-kill|-stop name]\n\n"); fprintf(stderr, "See the Erlang epmd manual page for info about the usage.\n\n"); fprintf(stderr, "Regular options\n"); + fprintf(stderr, " -address List\n"); + fprintf(stderr, " Let epmd listen only on the comma-separated list of IP\n"); + fprintf(stderr, " addresses (and on the loopback interface).\n"); fprintf(stderr, " -port No\n"); fprintf(stderr, " Let epmd listen to another port than default %d\n", EPMD_PORT_NO); @@ -433,7 +443,7 @@ static void usage(EpmdVars *g) fprintf(stderr, " List names registered with the currently " "running epmd\n"); fprintf(stderr, " -kill\n"); - fprintf(stderr, " Kill the currently runniing epmd\n"); + fprintf(stderr, " Kill the currently running epmd\n"); fprintf(stderr, " (only allowed if -names show empty database or\n"); fprintf(stderr, " -relaxed_command_check was given when epmd was started).\n"); fprintf(stderr, " -stop Name\n"); @@ -487,8 +497,8 @@ static void dbg_gen_printf(int onsyslog,int perr,int from_level, (int) strlen(timestr)-1, timestr); len = strlen(buf); erts_vsnprintf(buf + len, DEBUG_BUFFER_SIZE - len, format, args); - if (perr == 1) - perror(buf); + if (perr != 0) + fprintf(stderr,"%s: %s\r\n",buf,strerror(perr)); else fprintf(stderr,"%s\r\n",buf); } @@ -499,7 +509,7 @@ void dbg_perror(EpmdVars *g,const char *format,...) { va_list args; va_start(args, format); - dbg_gen_printf(1,1,0,g,format,args); + dbg_gen_printf(1,errno,0,g,format,args); va_end(args); } @@ -555,8 +565,9 @@ void epmd_cleanup_exit(EpmdVars *g, int exitval) epmd_conn_close(g,&g->conn[i]); free(g->conn); } - if(g->listenfd >= 0) - close(g->listenfd); + for(i=0; i < MAX_LISTEN_SOCKETS; i++) + if(g->listenfd[i] >= 0) + close(g->listenfd[i]); free_all_nodes(g); if(g->argv){ for(i=0; g->argv[i] != NULL; ++i) @@ -568,6 +579,10 @@ void epmd_cleanup_exit(EpmdVars *g, int exitval) exit(exitval); } +static char* get_addresses(void) +{ + return getenv("ERL_EPMD_ADDRESS"); +} static int get_port_no(void) { char* port_str = getenv("ERL_EPMD_PORT"); diff --git a/erts/epmd/src/epmd_cli.c b/erts/epmd/src/epmd_cli.c index 7c60ba0420..ac55ba6bb6 100644 --- a/erts/epmd/src/epmd_cli.c +++ b/erts/epmd/src/epmd_cli.c @@ -137,7 +137,7 @@ static int conn_to_epmd(EpmdVars *g) { /* store port number in unsigned short */ unsigned short sport = g->port; - SET_ADDR_LOOPBACK(address, FAMILY, sport); + SET_ADDR(address, EPMD_ADDR_LOOPBACK, sport); } if (connect(connect_sock, (struct sockaddr*)&address, sizeof address) < 0) diff --git a/erts/epmd/src/epmd_int.h b/erts/epmd/src/epmd_int.h index c2558d52a1..2a0de4df9c 100644 --- a/erts/epmd/src/epmd_int.h +++ b/erts/epmd/src/epmd_int.h @@ -168,42 +168,40 @@ #if defined(HAVE_IN6) && defined(AF_INET6) && defined(EPMD6) #define EPMD_SOCKADDR_IN sockaddr_in6 -#define FAMILY AF_INET6 - -#define SET_ADDR_LOOPBACK(addr, af, port) do { \ - memset((char*)&(addr), 0, sizeof(addr)); \ - (addr).sin6_family = (af); \ - (addr).sin6_flowinfo = 0; \ - (addr).sin6_addr = in6addr_loopback; \ - (addr).sin6_port = htons(port); \ +#define EPMD_IN_ADDR in6_addr +#define EPMD_S_ADDR s6_addr +#define EPMD_ADDR_LOOPBACK in6addr_loopback.s6_addr +#define EPMD_ADDR_ANY in6addr_any.s6_addr +#define FAMILY AF_INET6 + +#define SET_ADDR(dst, addr, port) do { \ + memset((char*)&(dst), 0, sizeof(dst)); \ + memcpy((char*)&(dst).sin6_addr.s6_addr, (char*)&(addr), 16); \ + (dst).sin6_family = AF_INET6; \ + (dst).sin6_flowinfo = 0; \ + (dst).sin6_port = htons(port); \ } while(0) -#define SET_ADDR_ANY(addr, af, port) do { \ - memset((char*)&(addr), 0, sizeof(addr)); \ - (addr).sin6_family = (af); \ - (addr).sin6_flowinfo = 0; \ - (addr).sin6_addr = in6addr_any; \ - (addr).sin6_port = htons(port); \ - } while(0) +#define IS_ADDR_LOOPBACK(addr) \ + (memcmp((addr).s6_addr, in6addr_loopback.s6_addr, 16) == 0) #else /* Not IP v6 */ #define EPMD_SOCKADDR_IN sockaddr_in -#define FAMILY AF_INET - -#define SET_ADDR_LOOPBACK(addr, af, port) do { \ - memset((char*)&(addr), 0, sizeof(addr)); \ - (addr).sin_family = (af); \ - (addr).sin_addr.s_addr = htonl(INADDR_LOOPBACK); \ - (addr).sin_port = htons(port); \ +#define EPMD_IN_ADDR in_addr +#define EPMD_S_ADDR s_addr +#define EPMD_ADDR_LOOPBACK htonl(INADDR_LOOPBACK) +#define EPMD_ADDR_ANY htonl(INADDR_ANY) +#define FAMILY AF_INET + +#define SET_ADDR(dst, addr, port) do { \ + memset((char*)&(dst), 0, sizeof(dst)); \ + (dst).sin_family = AF_INET; \ + (dst).sin_addr.s_addr = (addr); \ + (dst).sin_port = htons(port); \ } while(0) -#define SET_ADDR_ANY(addr, af, port) do { \ - memset((char*)&(addr), 0, sizeof(addr)); \ - (addr).sin_family = (af); \ - (addr).sin_addr.s_addr = htonl(INADDR_ANY); \ - (addr).sin_port = htons(port); \ - } while(0) +#define IS_ADDR_LOOPBACK(addr) ((addr).s_addr == htonl(INADDR_LOOPBACK)) #endif /* Not IP v6 */ @@ -231,6 +229,8 @@ /* Maximum length of a node name == atom name */ #define MAXSYMLEN 255 +#define MAX_LISTEN_SOCKETS 16 + #define INBUF_SIZE 1024 #define OUTBUF_SIZE 1024 @@ -299,7 +299,8 @@ typedef struct { Connection *conn; Nodes nodes; fd_set orig_read_mask; - int listenfd; + int listenfd[MAX_LISTEN_SOCKETS]; + char *addresses; char **argv; } EpmdVars; diff --git a/erts/epmd/src/epmd_srv.c b/erts/epmd/src/epmd_srv.c index 3499ab2934..4d9b454f97 100644 --- a/erts/epmd/src/epmd_srv.c +++ b/erts/epmd/src/epmd_srv.c @@ -24,6 +24,10 @@ #include "epmd.h" /* Renamed from 'epmd_r4.h' */ #include "epmd_int.h" +#ifndef INADDR_NONE +# define INADDR_NONE 0xffffffff +#endif + /* * * This server is a local name server for Erlang nodes. Erlang nodes can @@ -79,91 +83,157 @@ static void print_names(EpmdVars*); void run(EpmdVars *g) { - int listensock; + struct EPMD_SOCKADDR_IN iserv_addr[MAX_LISTEN_SOCKETS]; + int listensock[MAX_LISTEN_SOCKETS]; + int num_sockets; int i; int opt; - struct EPMD_SOCKADDR_IN iserv_addr; + unsigned short sport = g->port; node_init(g); g->conn = conn_init(g); dbg_printf(g,2,"try to initiate listening port %d", g->port); - - if ((listensock = socket(FAMILY,SOCK_STREAM,0)) < 0) { - dbg_perror(g,"error opening stream socket"); - epmd_cleanup_exit(g,1); - } - g->listenfd = listensock; + + if (g->addresses != NULL) + { + char *tmp; + char *token; + int loopback_ok = 0; + + if ((tmp = (char *)malloc(strlen(g->addresses) + 1)) == NULL) + { + dbg_perror(g,"cannot allocate memory"); + epmd_cleanup_exit(g,1); + } + strcpy(tmp,g->addresses); + + for(token = strtok(tmp,", "), num_sockets = 0; + token != NULL; + token = strtok(NULL,", "), num_sockets++) + { + struct EPMD_IN_ADDR addr; +#ifdef HAVE_INET_PTON + int ret; + + if ((ret = inet_pton(FAMILY,token,&addr)) == -1) + { + dbg_perror(g,"cannot convert IP address to network format"); + epmd_cleanup_exit(g,1); + } + else if (ret == 0) +#elif !defined(EPMD6) + if ((addr.EPMD_S_ADDR = inet_addr(token)) == INADDR_NONE) +#endif + { + dbg_tty_printf(g,0,"cannot parse IP address \"%s\"",token); + epmd_cleanup_exit(g,1); + } + + if (IS_ADDR_LOOPBACK(addr)) + loopback_ok = 1; + + if (num_sockets - loopback_ok == MAX_LISTEN_SOCKETS - 1) + { + dbg_tty_printf(g,0,"cannot listen on more than %d IP addresses", + MAX_LISTEN_SOCKETS); + epmd_cleanup_exit(g,1); + } + + SET_ADDR(iserv_addr[num_sockets],addr.EPMD_S_ADDR,sport); + } + + free(tmp); + + if (!loopback_ok) + { + SET_ADDR(iserv_addr[num_sockets],EPMD_ADDR_LOOPBACK,sport); + num_sockets++; + } + } + else + { + SET_ADDR(iserv_addr[0],EPMD_ADDR_ANY,sport); + num_sockets = 1; + } + +#if !defined(__WIN32__) + /* We ignore the SIGPIPE signal that is raised when we call write + twice on a socket closed by the other end. */ + signal(SIGPIPE, SIG_IGN); +#endif /* * Initialize number of active file descriptors. * Stdin, stdout, and stderr are still open. - * One for the listen socket. */ - g->active_conn = 3+1; + g->active_conn = 3 + num_sockets; + g->max_conn -= num_sockets; + + FD_ZERO(&g->orig_read_mask); + + for (i = 0; i < num_sockets; i++) + { + if ((listensock[i] = socket(FAMILY,SOCK_STREAM,0)) < 0) + { + dbg_perror(g,"error opening stream socket"); + epmd_cleanup_exit(g,1); + } + g->listenfd[i] = listensock[i]; - /* - * Note that we must not enable the SO_REUSEADDR on Windows, - * because addresses will be reused even if they are still in use. - */ + /* + * Note that we must not enable the SO_REUSEADDR on Windows, + * because addresses will be reused even if they are still in use. + */ #if !defined(__WIN32__) - /* We ignore the SIGPIPE signal that is raised when we call write - twice on a socket closed by the other end. */ - signal(SIGPIPE, SIG_IGN); - - opt = 1; /* Set this option */ - if (setsockopt(listensock,SOL_SOCKET,SO_REUSEADDR,(char* ) &opt, - sizeof(opt)) <0) { - dbg_perror(g,"can't set sockopt"); - epmd_cleanup_exit(g,1); - } + opt = 1; + if (setsockopt(listensock[i],SOL_SOCKET,SO_REUSEADDR,(char* ) &opt, + sizeof(opt)) <0) + { + dbg_perror(g,"can't set sockopt"); + epmd_cleanup_exit(g,1); + } #endif - /* In rare cases select returns because there is someone - to accept but the request is withdrawn before the - accept function is called. We set the listen socket - to be non blocking to prevent us from being hanging - in accept() waiting for the next request. */ + /* In rare cases select returns because there is someone + to accept but the request is withdrawn before the + accept function is called. We set the listen socket + to be non blocking to prevent us from being hanging + in accept() waiting for the next request. */ #if (defined(__WIN32__) || defined(NO_FCNTL)) - opt = 1; - if (ioctl(listensock, FIONBIO, &opt) != 0) /* Gives warning in VxWorks */ + opt = 1; + /* Gives warning in VxWorks */ + if (ioctl(listensock[i], FIONBIO, &opt) != 0) #else - opt = fcntl(listensock, F_GETFL, 0); - if (fcntl(listensock, F_SETFL, opt | O_NONBLOCK) == -1) + opt = fcntl(listensock[i], F_GETFL, 0); + if (fcntl(listensock[i], F_SETFL, opt | O_NONBLOCK) == -1) #endif /* __WIN32__ || VXWORKS */ - dbg_perror(g,"failed to set non-blocking mode of listening socket %d", - listensock); + dbg_perror(g,"failed to set non-blocking mode of listening socket %d", + listensock[i]); - { /* store port number in unsigned short */ - unsigned short sport = g->port; - SET_ADDR_ANY(iserv_addr, FAMILY, sport); - } - - if(bind(listensock,(struct sockaddr*) &iserv_addr, sizeof(iserv_addr)) < 0 ) - { - if (errno == EADDRINUSE) + if (bind(listensock[i], (struct sockaddr*) &iserv_addr[i], + sizeof(iserv_addr[i])) < 0) { - dbg_tty_printf(g,1,"there is already a epmd running at port %d", - g->port); - epmd_cleanup_exit(g,0); - } - else - { - dbg_perror(g,"failed to bind socket"); - epmd_cleanup_exit(g,1); + if (errno == EADDRINUSE) + { + dbg_tty_printf(g,1,"there is already a epmd running at port %d", + g->port); + epmd_cleanup_exit(g,0); + } + else + { + dbg_perror(g,"failed to bind socket"); + epmd_cleanup_exit(g,1); + } } - } - - dbg_printf(g,2,"starting"); - if(listen(listensock, SOMAXCONN) < 0) { - dbg_perror(g,"failed to listen on socket"); - epmd_cleanup_exit(g,1); - } - - FD_ZERO(&g->orig_read_mask); - FD_SET(listensock,&g->orig_read_mask); + if(listen(listensock[i], SOMAXCONN) < 0) { + dbg_perror(g,"failed to listen on socket"); + epmd_cleanup_exit(g,1); + } + FD_SET(listensock[i],&g->orig_read_mask); + } dbg_tty_printf(g,2,"entering the main select() loop"); @@ -200,17 +270,18 @@ void run(EpmdVars *g) sleep(g->delay_accept); } - if (FD_ISSET(listensock,&read_mask)) { - if (do_accept(g, listensock) && g->active_conn < g->max_conn) { - /* - * The accept() succeeded, and we have at least one file - * descriptor still free, which means that another accept() - * could succeed. Go do do another select(), in case there - * are more incoming connections waiting to be accepted. - */ - goto select_again; + for (i = 0; i < num_sockets; i++) + if (FD_ISSET(listensock[i],&read_mask)) { + if (do_accept(g, listensock[i]) && g->active_conn < g->max_conn) { + /* + * The accept() succeeded, and we have at least one file + * descriptor still free, which means that another accept() + * could succeed. Go do do another select(), in case there + * are more incoming connections waiting to be accepted. + */ + goto select_again; + } } - } /* Check all open streams marked by select for data or a close. We also close all open sockets except ALIVE @@ -738,6 +809,7 @@ static int conn_open(EpmdVars *g,int fd) for (i = 0; i < g->max_conn; i++) { if (g->conn[i].open == EPMD_FALSE) { struct sockaddr_in si; + struct sockaddr_in di; #ifdef HAVE_SOCKLEN_T socklen_t st; #else @@ -758,12 +830,16 @@ static int conn_open(EpmdVars *g,int fd) /* Determine if connection is from localhost */ if (getpeername(s->fd,(struct sockaddr*) &si,&st) || st < sizeof(si)) { - /* Failure to get peername is regarder as non local host */ + /* Failure to get peername is regarded as non local host */ s->local_peer = EPMD_FALSE; } else { + /* Only 127.x.x.x and connections from the host's IP address + allowed, no false positives */ s->local_peer = - ((((unsigned) ntohl(si.sin_addr.s_addr)) & 0xFF000000U) == - 0x7F000000U); /* Only 127.x.x.x allowed, no false positives */ + (((((unsigned) ntohl(si.sin_addr.s_addr)) & 0xFF000000U) == + 0x7F000000U) || + (getsockname(s->fd,(struct sockaddr*) &di,&st) ? + EPMD_FALSE : si.sin_addr.s_addr == di.sin_addr.s_addr)); } dbg_tty_printf(g,2,(s->local_peer) ? "Local peer connected" : "Non-local peer connected"); diff --git a/erts/epmd/test/Makefile b/erts/epmd/test/Makefile index 13dad09ae3..54688fd90b 100644 --- a/erts/epmd/test/Makefile +++ b/erts/epmd/test/Makefile @@ -74,7 +74,7 @@ release_tests_spec: opt $(INSTALL_DIR) $(RELEPMDDIR) $(INSTALL_DATA) epmd.spec epmd.spec.vxworks $(ERL_FILES) \ $(EMAKEFILE) $(RELEPMDDIR) - chmod -f -R u+w $(RELEPMDDIR) + chmod -R u+w $(RELEPMDDIR) release_docs_spec: diff --git a/erts/etc/common/heart.c b/erts/etc/common/heart.c index 778b3569c7..7a5746e630 100644 --- a/erts/etc/common/heart.c +++ b/erts/etc/common/heart.c @@ -727,16 +727,16 @@ static int heart_cmd_reply(int fd, char *s) { struct msg m; - int len = strlen(s) + 1; /* Include \0 */ + int len = strlen(s); /* if s >= MSG_BODY_SIZE, return a write * failure immediately. */ - if (len > sizeof(m.fill)) + if (len >= sizeof(m.fill)) return -1; m.op = HEART_CMD; - m.len = htons(len + 2); /* Include Op */ + m.len = htons(len + 1); /* Include Op */ strcpy((char*)m.fill, s); return write_message(fd, &m); diff --git a/erts/etc/common/inet_gethost.c b/erts/etc/common/inet_gethost.c index 8bd9368aa1..18ccf974aa 100644 --- a/erts/etc/common/inet_gethost.c +++ b/erts/etc/common/inet_gethost.c @@ -1297,7 +1297,7 @@ static int read_request(AddrByte **buff, size_t *buff_size) } if (siz > *buff_size) { - if (buff_size == 0) { + if (*buff_size == 0) { *buff = ALLOC((*buff_size = siz)); } else { *buff = REALLOC(*buff, (*buff_size = siz)); diff --git a/erts/etc/unix/run_erl.c b/erts/etc/unix/run_erl.c index cadff12c6f..e97cc14fab 100644 --- a/erts/etc/unix/run_erl.c +++ b/erts/etc/unix/run_erl.c @@ -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 @@ -221,6 +221,8 @@ int main(int argc, char **argv) char *p, *ptyslave=NULL; int i = 1; int off_argv; + int calculated_pipename = 0; + int highest_pipe_num = 0; program_name = argv[0]; @@ -298,10 +300,10 @@ int main(int argc, char **argv) if(*pipename && pipename[strlen(pipename)-1] == '/') { /* The user wishes us to find a unique pipe name in the specified */ /* directory */ - int highest_pipe_num = 0; DIR *dirp; struct dirent *direntp; + calculated_pipename = 1; dirp = opendir(pipename); if(!dirp) { ERRNO_ERR1(LOG_ERR,"Can't access pipe directory '%s'.", pipename); @@ -322,28 +324,37 @@ int main(int argc, char **argv) PIPE_STUBNAME, highest_pipe_num+1); } /* if */ - /* write FIFO - is read FIFO for `to_erl' program */ - strn_cpy(fifo1, sizeof(fifo1), pipename); - strn_cat(fifo1, sizeof(fifo1), ".r"); - if (create_fifo(fifo1, PERM) < 0) { - ERRNO_ERR1(LOG_ERR,"Cannot create FIFO %s for writing.", fifo1); - exit(1); - } - - /* read FIFO - is write FIFO for `to_erl' program */ - strn_cpy(fifo2, sizeof(fifo2), pipename); - strn_cat(fifo2, sizeof(fifo2), ".w"); - - /* Check that nobody is running run_erl already */ - if ((fd = open (fifo2, O_WRONLY|DONT_BLOCK_PLEASE, 0)) >= 0) { - /* Open as client succeeded -- run_erl is already running! */ - fprintf(stderr, "Erlang already running on pipe %s.\n", pipename); - close(fd); - exit(1); - } - if (create_fifo(fifo2, PERM) < 0) { - ERRNO_ERR1(LOG_ERR,"Cannot create FIFO %s for reading.", fifo2); - exit(1); + for(;;) { + /* write FIFO - is read FIFO for `to_erl' program */ + strn_cpy(fifo1, sizeof(fifo1), pipename); + strn_cat(fifo1, sizeof(fifo1), ".r"); + if (create_fifo(fifo1, PERM) < 0) { + ERRNO_ERR1(LOG_ERR,"Cannot create FIFO %s for writing.", fifo1); + exit(1); + } + + /* read FIFO - is write FIFO for `to_erl' program */ + strn_cpy(fifo2, sizeof(fifo2), pipename); + strn_cat(fifo2, sizeof(fifo2), ".w"); + + /* Check that nobody is running run_erl already */ + if ((fd = open (fifo2, O_WRONLY|DONT_BLOCK_PLEASE, 0)) >= 0) { + /* Open as client succeeded -- run_erl is already running! */ + close(fd); + if (calculated_pipename) { + ++highest_pipe_num; + strn_catf(pipename, sizeof(pipename), "%s.%d", + PIPE_STUBNAME, highest_pipe_num+1); + continue; + } + fprintf(stderr, "Erlang already running on pipe %s.\n", pipename); + exit(1); + } + if (create_fifo(fifo2, PERM) < 0) { + ERRNO_ERR1(LOG_ERR,"Cannot create FIFO %s for reading.", fifo2); + exit(1); + } + break; } /* diff --git a/erts/etc/unix/to_erl.c b/erts/etc/unix/to_erl.c index 886b301997..b7c3c956c6 100644 --- a/erts/etc/unix/to_erl.c +++ b/erts/etc/unix/to_erl.c @@ -125,7 +125,7 @@ static void usage(char *pname) int main(int argc, char **argv) { char FIFO1[FILENAME_MAX], FIFO2[FILENAME_MAX]; - int i, len, wfd, rfd, result = 0; + int i, len, wfd, rfd; fd_set readfds; char buf[BUFSIZ]; char pipename[FILENAME_MAX]; @@ -367,7 +367,6 @@ int main(int argc, char **argv) } else { fprintf(stderr, "Error in select.\n"); - result = -1; break; } } @@ -398,7 +397,6 @@ int main(int argc, char **argv) close(wfd); if (len < 0) { fprintf(stderr, "Error in reading from stdin.\n"); - result = -1; } else { fprintf(stderr, "[EOF]\n\r"); } @@ -420,7 +418,6 @@ int main(int argc, char **argv) fprintf(stderr, "Error in writing to FIFO.\n"); close(rfd); close(wfd); - result = -1; break; } STATUS("\" OK\r\n"); @@ -447,7 +444,6 @@ int main(int argc, char **argv) close(wfd); if (len < 0) { fprintf(stderr, "Error in reading from FIFO.\n"); - result = -1; } else fprintf(stderr, "[End]\n\r"); break; @@ -456,7 +452,6 @@ int main(int argc, char **argv) if ((len=version_handshake(buf,len,wfd)) < 0) { close(rfd); close(wfd); - result = -1; break; } if (protocol_ver >= 1) { @@ -475,7 +470,6 @@ int main(int argc, char **argv) fprintf(stderr, "Error in writing to terminal.\n"); close(rfd); close(wfd); - result = -1; break; } STATUS("\" OK\r\n"); diff --git a/erts/etc/win32/erlsrv/erlsrv_service.c b/erts/etc/win32/erlsrv/erlsrv_service.c index a58ee862c5..8891379643 100644 --- a/erts/etc/win32/erlsrv/erlsrv_service.c +++ b/erts/etc/win32/erlsrv/erlsrv_service.c @@ -523,7 +523,7 @@ static BOOL start_a_service(ServerInfo *srvi){ srvi->keys[WorkDir].data.bytes : NULL, &start, &(srvi->info))){ - sprintf(errbuff,"Could not start erlang service" + sprintf(errbuff,"Could not start erlang service " "with commandline \"%s\".", service_name, execbuff @@ -924,7 +924,7 @@ static VOID WINAPI service_main_loop(DWORD argc, char **argv){ } else { DWORD ecode = NO_ERROR; if(success_wait == NO_SUCCESS_WAIT){ - log_warning("Erlang machine volountarily stopped. " + log_warning("Erlang machine voluntarily stopped. " "The service is not restarted as OnFail " "is set to ignore."); } else { diff --git a/erts/etc/win32/nsis/dll_version_helper.sh b/erts/etc/win32/nsis/dll_version_helper.sh index 571ee3e39e..eecd4a72b5 100755 --- a/erts/etc/win32/nsis/dll_version_helper.sh +++ b/erts/etc/win32/nsis/dll_version_helper.sh @@ -2,7 +2,7 @@ # # %CopyrightBegin% # -# Copyright Ericsson AB 2007-2010. All Rights Reserved. +# Copyright Ericsson AB 2007-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 @@ -26,6 +26,7 @@ # exit 0 cat > hello.c <<EOF +#include <windows.h> #include <stdio.h> int main(void) @@ -35,14 +36,74 @@ int main(void) } EOF -cl /MD hello.c > /dev/null 2>&1 +cl /MD hello.c > /dev/null 2>&1 if [ '!' -f hello.exe.manifest ]; then - echo "This compiler does not generate manifest files - OK if using mingw" >&2 - exit 0 + # Gah - VC 2010 changes the way it handles DLL's and manifests... Again... + # need another way of getting the version + DLLNAME=`dumpbin.exe /imports hello.exe | egrep MSVCR.*dll` + DLLNAME=`echo $DLLNAME` + cat > helper.c <<EOF +#include <windows.h> +#include <stdio.h> + +#define REQ_MODULE "$DLLNAME" + +int main(void) +{ + DWORD dummy; + DWORD versize; + int i,n; + unsigned char *versinfo; + char buff[100]; + + char *vs_verinfo; + unsigned int vs_ver_size; + + struct LANGANDCODEPAGE { + WORD language; + WORD codepage; + } *translate; + + unsigned int tr_size; + + if (!(versize = GetFileVersionInfoSize(REQ_MODULE,&dummy))) { + fprintf(stderr,"No version info size in %s!\n",REQ_MODULE); + exit(1); + } + versinfo=malloc(versize); + if (!GetFileVersionInfo(REQ_MODULE,dummy,versize,versinfo)) { + fprintf(stderr,"No version info in %s!\n",REQ_MODULE); + exit(2); + } + if (!VerQueryValue(versinfo,"\\\\VarFileInfo\\\\Translation",&translate,&tr_size)) { + fprintf(stderr,"No translation info in %s!\n",REQ_MODULE); + exit(3); + } + n = tr_size/sizeof(translate); + for(i=0; i < n; ++i) { + sprintf(buff,"\\\\StringFileInfo\\\\%04x%04x\\\\FileVersion", + translate[i].language,translate[i].codepage); + if (VerQueryValue(versinfo,buff,&vs_verinfo,&vs_ver_size)) { + printf("%s\n",(char *) vs_verinfo); + return 0; + } + } + fprintf(stderr,"Failed to find file version of %s\n",REQ_MODULE); + return 0; +} +EOF + cl /MD helper.c version.lib > /dev/null 2>&1 + if [ '!' -f helper.exe ]; then + echo "Failed to build helper program." >&2 + exit 1 + fi + NAME=$DLLNAME + VERSION=`./helper` +else + VERSION=`grep '<assemblyIdentity' hello.exe.manifest | sed 's,.*version=.\([0-9\.]*\).*,\1,g' | grep -v '<'` + NAME=`grep '<assemblyIdentity' hello.exe.manifest | sed 's,.*name=.[A-Za-z\.]*\([0-9]*\).*,msvcr\1.dll,g' | grep -v '<'` fi -VERSION=`grep '<assemblyIdentity' hello.exe.manifest | sed 's,.*version=.\([0-9\.]*\).*,\1,g' | grep -v '<'` -NAME=`grep '<assemblyIdentity' hello.exe.manifest | sed 's,.*name=.[A-Za-z\.]*\([0-9]*\).*,msvcr\1.dll,g' | grep -v '<'` -rm -f hello.c hello.obj hello.exe hello.exe.manifest +#rm -f hello.c hello.obj hello.exe hello.exe.manifest helper.c helper.obj helper.exe helper.exe.manifest if [ "$1" = "-n" ]; then ASKEDFOR=$NAME else diff --git a/erts/etc/win32/nsis/find_redist.sh b/erts/etc/win32/nsis/find_redist.sh index 153977ded5..328811a0d7 100755 --- a/erts/etc/win32/nsis/find_redist.sh +++ b/erts/etc/win32/nsis/find_redist.sh @@ -2,7 +2,7 @@ # # %CopyrightBegin% # -# Copyright Ericsson AB 2007-2010. All Rights Reserved. +# Copyright Ericsson AB 2007-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 @@ -114,13 +114,18 @@ RCPATH=`lookup_prog_in_path rc` fail=false if [ '!' -z "$RCPATH" ]; then BPATH=$RCPATH - for x in rc bin v6.0A ; do - NBPATH=`remove_path_element $x "$BPATH"` - if [ "$NBPATH" = "$BPATH" ]; then - fail=true - break; + allow_fail=false + for x in rc bin @ANY v6.0A v7.0A v7.1; do + if [ $x = @ANY ]; then + allow_fail=true + else + NBPATH=`remove_path_element $x "$BPATH"` + if [ $allow_fail = false -a "$NBPATH" = "$BPATH" ]; then + fail=true + break; + fi + BPATH="$NBPATH" fi - BPATH="$NBPATH" done if [ $fail = false ]; then BPATH_LIST="$BPATH_LIST $BPATH" @@ -129,23 +134,32 @@ fi # Frantic search through two roots with different # version directories. We want to be very specific about the -# directory structures as we woildnt want to find the wrong +# directory structures as we wouldnt want to find the wrong # redistributables... -#echo $BPATH +#echo $BPATH_LIST for BP in $BPATH_LIST; do - for verdir in "sdk v2.0" "sdk v3.5" "v6.0A"; do + #echo "BP=$BP" + for verdir in "sdk v2.0" "sdk v3.5" "v6.0A" "v7.0A" "v7.1"; do BPATH=$BP fail=false - for x in $verdir bootstrapper packages vcredist_x86 vcredist_x86.exe; do + allow_fail=false + for x in $verdir @ANY bootstrapper packages vcredist_x86 Redist VC @ALL vcredist_x86.exe; do #echo "x=$x" #echo "BPATH=$BPATH" - NBPATH=`add_path_element $x "$BPATH"` - if [ "$NBPATH" = "$BPATH" ]; then - fail=true - break; + #echo "allow_fail=$allow_fail" + if [ $x = @ANY ]; then + allow_fail=true + elif [ $x = @ALL ]; then + allow_fail=false + else + NBPATH=`add_path_element $x "$BPATH"` + if [ $allow_fail = false -a "$NBPATH" = "$BPATH" ]; then + fail=true + break; + fi + BPATH="$NBPATH" fi - BPATH="$NBPATH" done if [ $fail = false ]; then break; diff --git a/erts/example/next_perm.cc b/erts/example/next_perm.cc index ee81cb0404..1427cd3979 100644 --- a/erts/example/next_perm.cc +++ b/erts/example/next_perm.cc @@ -120,7 +120,7 @@ static void ready_async(ErlDrvData drv_data, ErlDrvThreadData async_data) ErlDrvPort port = reinterpret_cast<ErlDrvPort>(drv_data); our_async_data* d = reinterpret_cast<our_async_data*>(async_data); int n = d->data.size(), result_n = n*2 + 5; - ErlDrvTermData* result = new ErlDrvTermData[result_n], * rp = result; + ErlDrvTermData *result = new ErlDrvTermData[result_n], *rp = result; *rp++ = ERL_DRV_PORT; *rp++ = driver_mk_port(port); for (vector<int>::iterator i = d->data.begin(); diff --git a/erts/lib_src/common/erl_misc_utils.c b/erts/lib_src/common/erl_misc_utils.c index 4c881993a5..ec729407bb 100644 --- a/erts/lib_src/common/erl_misc_utils.c +++ b/erts/lib_src/common/erl_misc_utils.c @@ -813,7 +813,7 @@ read_topology(erts_cpu_info_t *cpuinfo) cpuinfo->topology = malloc(sizeof(erts_cpu_topology_t) * cpuinfo->configured); - if (!cpuinfo) + if (!cpuinfo->topology) goto error; for (ix = 0; ix < cpuinfo->configured; ix++) { @@ -1023,7 +1023,7 @@ read_topology(erts_cpu_info_t *cpuinfo) cpuinfo->topology = malloc(sizeof(erts_cpu_topology_t) * cpuinfo->configured); - if (!cpuinfo) + if (!cpuinfo->topology) goto error; for (ix = 0; ix < cpuinfo->configured; ix++) { diff --git a/erts/lib_src/common/erl_printf_format.c b/erts/lib_src/common/erl_printf_format.c index bd3d38e649..968d563325 100644 --- a/erts/lib_src/common/erl_printf_format.c +++ b/erts/lib_src/common/erl_printf_format.c @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 2005-2009. All Rights Reserved. + * Copyright Ericsson AB 2005-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 @@ -27,7 +27,7 @@ * length: hh | h | l | ll | L | j | t | b<sz> * conversion: d,i | o,u,x,X | e,E | f,F | g,G | a,A | c | s | T | * p | n | % - * sz: 8 | 16 | 32 | 64 | p + * sz: 8 | 16 | 32 | 64 | p | e */ /* Without this, variable argument lists break on VxWorks */ @@ -76,6 +76,18 @@ #endif #endif +#ifndef ERTS_SIZEOF_ETERM +# ifdef HALFWORD_HEAP_EMULATOR +# if SIZEOF_VOID_P == 8 +# define ERTS_SIZEOF_ETERM 4 +# else +# error "HALFWORD_HEAP_EMULATOR only allowed on 64-bit architecture" +# endif +# else +# define ERTS_SIZEOF_ETERM SIZEOF_VOID_P +# endif +#endif + #if defined(__GNUC__) # undef inline # define inline __inline__ @@ -520,6 +532,17 @@ int erts_printf_format(fmtfn_t fn, void* arg, char* fmt, va_list ap) #error No integer datatype with the same size as 'void *' found #endif } + else if (*ptr == 'e') { + ptr++; +#if SIZEOF_INT == ERTS_SIZEOF_ETERM +#elif SIZEOF_LONG == ERTS_SIZEOF_ETERM + fmt |= FMTL_l; +#elif SIZEOF_LONG_LONG == ERTS_SIZEOF_ETERM + fmt |= FMTL_ll; +#else +#error No integer datatype with the same size as Eterm found +#endif + } else { int bits = 0; while(isdigit((int) *ptr)) diff --git a/erts/preloaded/ebin/prim_file.beam b/erts/preloaded/ebin/prim_file.beam Binary files differindex 4a75e43e73..c2ae01d0d5 100644 --- a/erts/preloaded/ebin/prim_file.beam +++ b/erts/preloaded/ebin/prim_file.beam diff --git a/erts/preloaded/src/prim_file.erl b/erts/preloaded/src/prim_file.erl index 10be852e92..fb0aef8947 100644 --- a/erts/preloaded/src/prim_file.erl +++ b/erts/preloaded/src/prim_file.erl @@ -64,7 +64,7 @@ -include("file.hrl"). -define(DRV, efile). --define(FD_DRV, efile). +-define(FD_DRV, "efile"). -define(LARGEFILESIZE, (1 bsl 63)). @@ -506,7 +506,7 @@ read_file(_) -> %% Takes a Port opened with open/1. read_file(Port, File) when is_port(Port), - (is_list(File) orelse is_binary(File))-> + (is_list(File) orelse is_binary(File)) -> Cmd = [?FILE_READ_FILE | pathname(File)], case drv_command(Port, Cmd) of {error, enomem} -> @@ -832,7 +832,7 @@ drv_open(Driver, Portopts) -> {ok, Port} catch error:Reason -> - {error,Reason} + {error, Reason} end. @@ -1041,8 +1041,8 @@ translate_response(?FILE_RESP_NUMBER, List) -> {N, []} = get_uint64(List), {ok, N}; translate_response(?FILE_RESP_DATA, List) -> - {N, Data} = get_uint64(List), - {ok, {N, Data}}; + {_N, _Data} = ND = get_uint64(List), + {ok, ND}; translate_response(?FILE_RESP_INFO, List) when is_list(List) -> {ok, transform_info_ints(get_uint32s(List))}; translate_response(?FILE_RESP_NUMERR, L0) -> @@ -1087,10 +1087,8 @@ translate_response(?FILE_RESP_FNAME, Data) when is_binary(Data) -> {ok, prim_file:internal_native2name(Data)}; translate_response(?FILE_RESP_FNAME, Data) -> {ok, Data}; - translate_response(?FILE_RESP_ALL_DATA, Data) -> {ok, Data}; - translate_response(X, Data) -> {error, {bad_response_from_port, [X | Data]}}. @@ -1137,14 +1135,14 @@ date_to_bytes(undefined) -> date_to_bytes({{Y, Mon, D}, {H, Min, S}}) -> <<Y:32, Mon:32, D:32, H:32, Min:32, S:32>>. -% uint64([[X1, X2, X3, X4] = Y1 | [X5, X6, X7, X8] = Y2]) -> -% (uint32(Y1) bsl 32) bor uint32(Y2). +%% uint64([[X1, X2, X3, X4] = Y1 | [X5, X6, X7, X8] = Y2]) -> +%% (uint32(Y1) bsl 32) bor uint32(Y2). -% uint64(X1, X2, X3, X4, X5, X6, X7, X8) -> -% (uint32(X1, X2, X3, X4) bsl 32) bor uint32(X5, X6, X7, X8). +%% uint64(X1, X2, X3, X4, X5, X6, X7, X8) -> +%% (uint32(X1, X2, X3, X4) bsl 32) bor uint32(X5, X6, X7, X8). -% uint32([X1,X2,X3,X4]) -> -% (X1 bsl 24) bor (X2 bsl 16) bor (X3 bsl 8) bor X4. +%% uint32([X1,X2,X3,X4]) -> +%% (X1 bsl 24) bor (X2 bsl 16) bor (X3 bsl 8) bor X4. uint32(X1,X2,X3,X4) -> (X1 bsl 24) bor (X2 bsl 16) bor (X3 bsl 8) bor X4. diff --git a/erts/test/Makefile b/erts/test/Makefile index 94458da019..68be3f2178 100644 --- a/erts/test/Makefile +++ b/erts/test/Makefile @@ -89,7 +89,7 @@ release_tests_spec: opt $(INSTALL_DIR) $(RELSYSDIR) $(INSTALL_DATA) system.spec system.dynspec system.spec.vxworks \ $(ERL_FILES) $(TARGET_FILES) $(RELSYSDIR) - chmod -f -R u+w $(RELSYSDIR) + chmod -R u+w $(RELSYSDIR) tar cf - *_SUITE_data utils | (cd $(RELSYSDIR); tar xf -) release_docs_spec: diff --git a/lib/asn1/test/Makefile b/lib/asn1/test/Makefile index 4f3776e478..7ecd544d4b 100644 --- a/lib/asn1/test/Makefile +++ b/lib/asn1/test/Makefile @@ -194,7 +194,7 @@ release_tests_spec: opt $(INSTALL_DIR) $(RELSYSDIR)/asn1_bin_v2_SUITE_data $(INSTALL_DATA) $(ERL_FILES) $(HRL_FILES) $(RELSYSDIR) $(INSTALL_DATA) asn1.spec asn1.cover $(INSTALL_PROGS) $(RELSYSDIR) - chmod -f -R u+w $(RELSYSDIR) + chmod -R u+w $(RELSYSDIR) cd asn1_SUITE_data; tar cfh $(RELSYSDIR)/asn1_SUITE_data.tar * cd $(RELSYSDIR)/asn1_SUITE_data; tar xf $(RELSYSDIR)/asn1_SUITE_data.tar cd $(RELSYSDIR)/asn1_bin_SUITE_data; tar xf $(RELSYSDIR)/asn1_SUITE_data.tar diff --git a/lib/common_test/doc/src/common_test_app.xml b/lib/common_test/doc/src/common_test_app.xml index 1ee73b890b..c92566de37 100644 --- a/lib/common_test/doc/src/common_test_app.xml +++ b/lib/common_test/doc/src/common_test_app.xml @@ -296,7 +296,7 @@ </func> <func> - <name>Module:init_per_testcase(TestCase, Config) -> NewConfig | {skip,Reason}</name> + <name>Module:init_per_testcase(TestCase, Config) -> NewConfig | {fail,Reason} | {skip,Reason}</name> <fsummary>Test case initialization.</fsummary> <type> <v> TestCase = atom()</v> @@ -311,10 +311,12 @@ <p>This function is called before each test case. The <c>TestCase</c> argument is the name of the test case, and - <c>Config</c> is the configuration which can be modified - here. Whatever is returned from this function is given as - <c>Config</c> to the test case. If <c>{skip,Reason}</c> is returned, - the test case will be skipped and <c>Reason</c> printed + <c>Config</c> (list of key-value tuples) is the configuration + data that can be modified here. The <c>NewConfig</c> list returned + from this function is given as <c>Config</c> to the test case. + If <c>{fail,Reason}</c> is returned, the test case is + marked as failed without being executed. If <c>{skip,Reason}</c> is + returned, the test case will be skipped and <c>Reason</c> printed in the overview log for the suite.</p> </desc> </func> diff --git a/lib/common_test/doc/src/write_test_chapter.xml b/lib/common_test/doc/src/write_test_chapter.xml index 723492d8f3..3f9fdb7121 100644 --- a/lib/common_test/doc/src/write_test_chapter.xml +++ b/lib/common_test/doc/src/write_test_chapter.xml @@ -167,12 +167,16 @@ returning <c>{fail,Reason}</c>, nor will it be able to save data with <c>{save_config,Data}</c>.</p> - <p>If <c>init_per_testcase</c> crashes, the test case itself is skipped + <p>If <c>init_per_testcase</c> crashes, the test case itself gets skipped automatically (so called <em>auto skipped</em>). If <c>init_per_testcase</c> - returns a <c>skip</c> tuple, also then will the test case be skipped (so - called <em>user skipped</em>). In either event, the <c>end_per_testcase</c> is - never called. + returns a tuple <c>{skip,Reason}</c>, also then the test case gets skipped + (so called <em>user skipped</em>). It is also possible, by returning a tuple + <c>{fail,Reason}</c> from <c>init_per_testcase</c>, to mark the test case + as failed without actually executing it. </p> + <note><p>If <c>init_per_testcase</c> crashes, or returns <c>{skip,Reason}</c> + or <c>{fail,Reason}</c>, the <c>end_per_testcase</c> function is not called. + </p></note> <p>If it is determined during execution of <c>end_per_testcase</c> that the status of a successful test case should be changed to failed, diff --git a/lib/common_test/src/ct.erl b/lib/common_test/src/ct.erl index dfec2b7a67..66da3ef742 100644 --- a/lib/common_test/src/ct.erl +++ b/lib/common_test/src/ct.erl @@ -861,6 +861,7 @@ remove_config(Callback, Config) -> %%% %%% @doc <p>Use this function to set a new timetrap for the running test case.</p> timetrap(Time) -> + test_server:timetrap_cancel(), test_server:timetrap(Time). %%%----------------------------------------------------------------- diff --git a/lib/common_test/src/ct_framework.erl b/lib/common_test/src/ct_framework.erl index 38a2aa53ac..c016b9c66b 100644 --- a/lib/common_test/src/ct_framework.erl +++ b/lib/common_test/src/ct_framework.erl @@ -24,7 +24,7 @@ -module(ct_framework). --export([init_tc/3, end_tc/4, get_suite/2, report/2, warn/1]). +-export([init_tc/3, end_tc/3, end_tc/4, get_suite/2, report/2, warn/1]). -export([error_notification/4]). -export([overview_html_header/1]). @@ -434,6 +434,9 @@ try_set_default(Name,Key,Info,Where) -> %%% %%% @doc Test server framework callback, called by the test_server %%% when a test case is finished. +end_tc(Mod, Fun, Args) -> + %% Have to keep end_tc/3 for backwards compatabilty issues + end_tc(Mod, Fun, Args, '$end_tc_dummy'). end_tc(?MODULE,error_in_suite,_, _) -> % bad start! ok; end_tc(Mod,Func,{TCPid,Result,[Args]}, Return) when is_pid(TCPid) -> @@ -490,9 +493,9 @@ end_tc(Mod,Func,TCPid,Result,Args,Return) -> case ct_hooks:end_tc( Mod, FuncSpec, Args, Result, Return) of '$ct_no_change' -> - {FinalResult = ok,Result}; - FinalResult -> - {FinalResult,FinalResult} + {ok,Result}; + FinalResult1 -> + {FinalResult1,FinalResult1} end, % send sync notification so that event handlers may print % in the log file before it gets closed @@ -734,7 +737,7 @@ get_suite(Mod, Group={conf,Props,_Init,TCs,_End}) -> %% (and only) test case so we can report Error properly [{?MODULE,error_in_suite,[[Error]]}]; [] -> - {error,{invalid_group_spec,Name}}; + []; ConfTests -> case lists:member(skipped, Props) of true -> @@ -764,23 +767,7 @@ get_suite(Mod, Name) -> find_groups(Mod, Name, TCs, GroupDefs) -> Found = find(Mod, Name, TCs, GroupDefs, [], GroupDefs, false), - Trimmed = trim(Found), - %% I cannot find a reason to why this function is called, - %% It deletes any group which is referenced in any other - %% group. i.e. - %% groups() -> - %% [{test, [], [testcase1]}, - %% {testcases, [], [{group, test}]}]. - %% Would be changed to - %% groups() -> - %% [{testcases, [], [testcase1]}]. - %% instead of what I believe is correct: - %% groups() -> - %% [{test, [], [testcase1]}, - %% {testcases, [], [testcase1]}]. - %% Have to double check with peppe - delete_subs(Trimmed, Trimmed), - Trimmed. + trim(Found). find(Mod, all, _TCs, [{Name,Props,Tests} | Gs], Known, Defs, _) when is_atom(Name), is_list(Props), is_list(Tests) -> @@ -1170,12 +1157,14 @@ error_in_suite(Config) -> %% if the group config functions are missing in the suite, %% use these instead ct_init_per_group(GroupName, Config) -> - ct_logs:log("WARNING", "init_per_group/2 for ~w missing in suite, using default.", + ct_logs:log("WARNING", "init_per_group/2 for ~w missing " + "in suite, using default.", [GroupName]), Config. ct_end_per_group(GroupName, _) -> - ct_logs:log("WARNING", "end_per_group/2 for ~w missing in suite, using default.", + ct_logs:log("WARNING", "end_per_group/2 for ~w missing " + "in suite, using default.", [GroupName]), ok. @@ -1184,6 +1173,13 @@ ct_end_per_group(GroupName, _) -> %%% @spec report(What,Data) -> ok report(What,Data) -> case What of + loginfo -> + %% logfiles and direcories have been created for a test and the + %% top level test index page needs to be refreshed + TestName = filename:basename(proplists:get_value(topdir, Data), ".logs"), + RunDir = proplists:get_value(rundir, Data), + ct_logs:make_all_suites_index({TestName,RunDir}), + ok; tests_start -> case ct_util:get_testdata(cover) of undefined -> diff --git a/lib/common_test/src/ct_logs.erl b/lib/common_test/src/ct_logs.erl index f8ace73cbf..ba4adb8683 100644 --- a/lib/common_test/src/ct_logs.erl +++ b/lib/common_test/src/ct_logs.erl @@ -97,11 +97,11 @@ logdir_node_prefix() -> logdir_prefix()++"."++atom_to_list(node()). %%%----------------------------------------------------------------- -%%% @spec close(How) -> ok +%%% @spec close(Info) -> ok %%% %%% @doc Create index pages with test results and close the CT Log %%% (tool-internal use only). -close(How) -> +close(Info) -> make_last_run_index(), ct_event:notify(#event{name=stop_logging,node=node(),data=[]}), @@ -118,7 +118,7 @@ close(How) -> ok end, - if How == clean -> + if Info == clean -> case cleanup() of ok -> ok; @@ -427,8 +427,8 @@ logger(Parent,Mode) -> file:make_dir(Dir), ct_event:notify(#event{name=start_logging,node=node(), data=?abs(Dir)}), - make_all_suites_index(start), make_all_runs_index(start), + make_all_suites_index(start), case Mode of interactive -> interactive_link(); _ -> ok @@ -796,24 +796,29 @@ make_one_index_entry(SuiteName, LogDir, Label, All, Missing) -> {Succ,Fail,UserSkip,AutoSkip} -> NotBuilt = not_built(SuiteName, LogDir, All, Missing), NewResult = make_one_index_entry1(SuiteName, LogDir, Label, Succ, Fail, - UserSkip, AutoSkip, NotBuilt, All), + UserSkip, AutoSkip, NotBuilt, All, + normal), {NewResult,Succ,Fail,UserSkip,AutoSkip,NotBuilt}; error -> error end. make_one_index_entry1(SuiteName, Link, Label, Success, Fail, UserSkip, AutoSkip, - NotBuilt, All) -> + NotBuilt, All, Mode) -> LogFile = filename:join(Link, ?suitelog_name ++ ".html"), - CrashDumpName = SuiteName ++ "_erl_crash.dump", - CrashDumpLink = - case filelib:is_file(CrashDumpName) of - true -> - [" <A HREF=\"", CrashDumpName, - "\">(CrashDump)</A>"]; - false -> - "" - end, + CrashDumpLink = case Mode of + cached -> + ""; + normal -> + CrashDumpName = SuiteName ++ "_erl_crash.dump", + case filelib:is_file(CrashDumpName) of + true -> + [" <A HREF=\"", CrashDumpName, + "\">(CrashDump)</A>"]; + false -> + "" + end + end, {Lbl,Timestamp,Node,AllInfo} = case All of {true,OldRuns} -> @@ -975,9 +980,13 @@ index_header(Label, StartTime) -> "<th>Missing<br>Suites</th>\n" "\n"]]. + all_suites_index_header() -> {ok,Cwd} = file:get_cwd(), - LogDir = filename:basename(Cwd), + all_suites_index_header(Cwd). + +all_suites_index_header(IndexDir) -> + LogDir = filename:basename(IndexDir), AllRuns = "All test runs in \"" ++ LogDir ++ "\"", [header("Test Results") | ["<CENTER>\n", @@ -1414,15 +1423,72 @@ timestamp(Dir) -> [S,Min,H,D,M,Y] = [list_to_integer(N) || N <- lists:sublist(TsR,6)], format_time({{Y,M,D},{H,Min,S}}). -make_all_suites_index(When) -> +%% ----------------------------- NOTE -------------------------------------- +%% The top level index file is generated based on the file contents under +%% logdir. This takes place initially when the test run starts (When = start) +%% and an update takes place at the end of the test run, or when the user +%% requests an explicit refresh (When = refresh). +%% The index file needs to be updated also at the start of each individual +%% test (in order for the user to be able to track test progress by refreshing +%% the browser). Since it would be too expensive to generate a new file from +%% scratch every time (by reading the data from disk), a copy of the dir tree +%% is cached as a result of the first index file creation. This copy is then +%% used for all top level index page updates that occur during the test run. +%% This means that any changes to the dir tree under logdir during the test +%% run will not show until after the final refresh. +%% ------------------------------------------------------------------------- + +%% Creates the top level index file. When == start | refresh. +%% A copy of the dir tree under logdir is cached as a result. +make_all_suites_index(When) when is_atom(When) -> AbsIndexName = ?abs(?index_name), notify_and_lock_file(AbsIndexName), LogDirs = filelib:wildcard(logdir_prefix()++".*/*"++?logdir_ext), - Sorted = sort_logdirs(LogDirs,[]), - Result = make_all_suites_index1(When,Sorted), + Sorted = sort_logdirs(LogDirs, []), + Result = make_all_suites_index1(When, AbsIndexName, Sorted), notify_and_unlock_file(AbsIndexName), - Result. - + Result; + +%% This updates the top level index file using cached data from +%% the initial index file creation. +make_all_suites_index(NewTestData = {_TestName,DirName}) -> + %% AllLogDirs = [{TestName,Label,Missing,{LastLogDir,Summary},OldDirs}|...] + {AbsIndexName,LogDirData} = ct_util:get_testdata(test_index), + + CtRunDirPos = length(filename:split(AbsIndexName)), + CtRunDir = filename:join(lists:sublist(filename:split(DirName), + CtRunDirPos)), + + Label = case read_totals_file(filename:join(CtRunDir, ?totals_name)) of + {_,"-",_,_} -> "..."; + {_,Lbl,_,_} -> Lbl; + _ -> "..." + end, + notify_and_lock_file(AbsIndexName), + Result = + case catch make_all_suites_ix_cached(AbsIndexName, + NewTestData, + Label, + LogDirData) of + {'EXIT',Reason} -> + io:put_chars("CRASHED while updating " ++ AbsIndexName ++ "!\n"), + io:format("~p~n", [Reason]), + {error,Reason}; + {error,Reason} -> + io:put_chars("FAILED while updating " ++ AbsIndexName ++ "\n"), + io:format("~p~n", [Reason]), + {error,Reason}; + ok -> + ok; + Err -> + io:format("Unknown internal error while updating ~s. " + "Please report.\n(Err: ~p, ID: 1)", + [AbsIndexName,Err]), + {error, Err} + end, + notify_and_unlock_file(AbsIndexName), + Result. + sort_logdirs([Dir|Dirs],Groups) -> TestName = filename:rootname(filename:basename(Dir)), case filelib:wildcard(filename:join(Dir,"run.*")) of @@ -1448,13 +1514,12 @@ sort_each_group([{Test,IxDirs}|Groups]) -> sort_each_group([]) -> []. -make_all_suites_index1(When,AllSuitesLogDirs) -> +make_all_suites_index1(When, AbsIndexName, AllLogDirs) -> IndexName = ?index_name, - AbsIndexName = ?abs(IndexName), if When == start -> ok; true -> io:put_chars("Updating " ++ AbsIndexName ++ "... ") end, - case catch make_all_suites_index2(IndexName,AllSuitesLogDirs) of + case catch make_all_suites_index2(IndexName, AllLogDirs) of {'EXIT', Reason} -> io:put_chars("CRASHED while updating " ++ AbsIndexName ++ "!\n"), io:format("~p~n", [Reason]), @@ -1463,11 +1528,16 @@ make_all_suites_index1(When,AllSuitesLogDirs) -> io:put_chars("FAILED while updating " ++ AbsIndexName ++ "\n"), io:format("~p~n", [Reason]), {error, Reason}; - ok -> - if When == start -> ok; - true -> io:put_chars("done\n") - end, - ok; + {ok,CacheData} -> + case When of + start -> + ct_util:set_testdata_async({test_index,{AbsIndexName, + CacheData}}), + ok; + _ -> + io:put_chars("done\n"), + ok + end; Err -> io:format("Unknown internal error while updating ~s. " "Please report.\n(Err: ~p, ID: 1)", @@ -1475,56 +1545,124 @@ make_all_suites_index1(When,AllSuitesLogDirs) -> {error, Err} end. -make_all_suites_index2(IndexName,AllSuitesLogDirs) -> - {ok,Index0,_Totals} = make_all_suites_index3(AllSuitesLogDirs, - all_suites_index_header(), - 0, 0, 0, 0, 0, []), +make_all_suites_index2(IndexName, AllTestLogDirs) -> + {ok,Index0,_Totals,CacheData} = + make_all_suites_index3(AllTestLogDirs, + all_suites_index_header(), + 0, 0, 0, 0, 0, [], []), Index = [Index0|index_footer()], case force_write_file(IndexName, Index) of ok -> - ok; + {ok,CacheData}; {error, Reason} -> {error,{index_write_error, Reason}} end. -make_all_suites_index3([{SuiteName,[LastLogDir|OldDirs]}|Rest], +make_all_suites_index3([{TestName,[LastLogDir|OldDirs]}|Rest], Result, TotSucc, TotFail, UserSkip, AutoSkip, TotNotBuilt, - Labels) -> + Labels, CacheData) -> [EntryDir|_] = filename:split(LastLogDir), Missing = - case file:read_file(filename:join(EntryDir,?missing_suites_info)) of + case file:read_file(filename:join(EntryDir, ?missing_suites_info)) of {ok,Bin} -> binary_to_term(Bin); _ -> [] end, {Label,Labels1} = case proplists:get_value(EntryDir, Labels) of undefined -> - case read_totals_file(filename:join(EntryDir,?totals_name)) of + case read_totals_file(filename:join(EntryDir, ?totals_name)) of {_,Lbl,_,_} -> {Lbl,[{EntryDir,Lbl}|Labels]}; _ -> {"-",[{EntryDir,"-"}|Labels]} end; Lbl -> {Lbl,Labels} end, - case make_one_index_entry(SuiteName, LastLogDir, Label, {true,OldDirs}, Missing) of + case make_one_index_entry(TestName, LastLogDir, Label, {true,OldDirs}, Missing) of {Result1,Succ,Fail,USkip,ASkip,NotBuilt} -> %% for backwards compatibility AutoSkip1 = case catch AutoSkip+ASkip of {'EXIT',_} -> undefined; Res -> Res end, + IxEntry = {TestName,Label,Missing, + {LastLogDir,{Succ,Fail,USkip,ASkip}},OldDirs}, make_all_suites_index3(Rest, [Result|Result1], TotSucc+Succ, TotFail+Fail, UserSkip+USkip, AutoSkip1, - TotNotBuilt+NotBuilt,Labels1); + TotNotBuilt+NotBuilt, Labels1, + [IxEntry|CacheData]); error -> + IxEntry = {TestName,Label,Missing,{LastLogDir,error},OldDirs}, make_all_suites_index3(Rest, Result, TotSucc, TotFail, - UserSkip, AutoSkip, TotNotBuilt,Labels1) + UserSkip, AutoSkip, TotNotBuilt, Labels1, + [IxEntry|CacheData]) end; make_all_suites_index3([], Result, TotSucc, TotFail, UserSkip, AutoSkip, - TotNotBuilt,_) -> + TotNotBuilt, _, CacheData) -> {ok, [Result|total_row(TotSucc, TotFail, UserSkip, AutoSkip, TotNotBuilt,true)], - {TotSucc,TotFail,UserSkip,AutoSkip,TotNotBuilt}}. + {TotSucc,TotFail,UserSkip,AutoSkip,TotNotBuilt}, lists:reverse(CacheData)}. + + +make_all_suites_ix_cached(AbsIndexName, NewTestData, Label, AllTestLogDirs) -> + AllTestLogDirs1 = insert_new_test_data(NewTestData, Label, AllTestLogDirs), + IndexDir = filename:dirname(AbsIndexName), + Index0 = make_all_suites_ix_cached1(AllTestLogDirs1, + all_suites_index_header(IndexDir), + 0, 0, 0, 0, 0), + Index = [Index0|index_footer()], + case force_write_file(AbsIndexName, Index) of + ok -> + ok; + {error, Reason} -> + {error,{index_write_error, Reason}} + end. + +insert_new_test_data({NewTestName,NewTestDir}, NewLabel, AllTestLogDirs) -> + AllTestLogDirs1 = + case lists:keysearch(NewTestName, 1, AllTestLogDirs) of + {value,{_,_,_,{LastLogDir,_},OldDirs}} -> + [{NewTestName,NewLabel,[],{NewTestDir,{0,0,0,0}}, + [LastLogDir|OldDirs]} | + lists:keydelete(NewTestName, 1, AllTestLogDirs)]; + false -> + [{NewTestName,NewLabel,[],{NewTestDir,{0,0,0,0}},[]} | + AllTestLogDirs] + end, + lists:keysort(1, AllTestLogDirs1). + +make_all_suites_ix_cached1([{TestName,Label,Missing,LastLogDirData,OldDirs}|Rest], + Result, TotSucc, TotFail, UserSkip, AutoSkip, + TotNotBuilt) -> + case make_one_ix_entry_cached(TestName, LastLogDirData, + Label, {true,OldDirs}, Missing) of + {Result1,Succ,Fail,USkip,ASkip,NotBuilt} -> + %% for backwards compatibility + AutoSkip1 = case catch AutoSkip+ASkip of + {'EXIT',_} -> undefined; + Res -> Res + end, + make_all_suites_ix_cached1(Rest, [Result|Result1], TotSucc+Succ, + TotFail+Fail, UserSkip+USkip, AutoSkip1, + TotNotBuilt+NotBuilt); + error -> + make_all_suites_ix_cached1(Rest, Result, TotSucc, TotFail, + UserSkip, AutoSkip, TotNotBuilt) + end; +make_all_suites_ix_cached1([], Result, TotSucc, TotFail, UserSkip, AutoSkip, + TotNotBuilt) -> + [Result|total_row(TotSucc, TotFail, UserSkip, AutoSkip, TotNotBuilt, true)]. + +make_one_ix_entry_cached(TestName, {LogDir,Summary}, Label, All, Missing) -> + case Summary of + {Succ,Fail,UserSkip,AutoSkip} -> + NotBuilt = not_built(TestName, LogDir, All, Missing), + NewResult = make_one_index_entry1(TestName, LogDir, Label, + Succ, Fail, UserSkip, AutoSkip, + NotBuilt, All, cached), + {NewResult,Succ,Fail,UserSkip,AutoSkip,NotBuilt}; + error -> + error + end. %%----------------------------------------------------------------- %% Remove log files. diff --git a/lib/common_test/src/ct_run.erl b/lib/common_test/src/ct_run.erl index 7bd7dc7d66..c01e97b358 100644 --- a/lib/common_test/src/ct_run.erl +++ b/lib/common_test/src/ct_run.erl @@ -262,15 +262,15 @@ run_or_refresh(StartOpts = #opts{logdir = LogDir}, Args) -> %% give the shell time to print version etc timer:sleep(500), io:nl(), - case catch ct_logs:make_all_suites_index(refresh) of - {'EXIT',ASReason} -> + case catch ct_logs:make_all_runs_index(refresh) of + {'EXIT',ARReason} -> file:set_cwd(Cwd), - {error,{all_suites_index,ASReason}}; + {error,{all_runs_index,ARReason}}; _ -> - case catch ct_logs:make_all_runs_index(refresh) of - {'EXIT',ARReason} -> + case catch ct_logs:make_all_suites_index(refresh) of + {'EXIT',ASReason} -> file:set_cwd(Cwd), - {error,{all_runs_index,ARReason}}; + {error,{all_suites_index,ASReason}}; _ -> file:set_cwd(Cwd), io:format("Logs in ~s refreshed!~n~n", [LogDir1]), @@ -1111,6 +1111,8 @@ run(TestDirs) -> install([]), reformat_result(catch do_run(tests(TestDirs), [])). +reformat_result({'EXIT',{user_error,Reason}}) -> + {error,Reason}; reformat_result({user_error,Reason}) -> {error,Reason}; reformat_result(Result) -> diff --git a/lib/common_test/src/ct_util.erl b/lib/common_test/src/ct_util.erl index 115207beed..b3e345b4e5 100644 --- a/lib/common_test/src/ct_util.erl +++ b/lib/common_test/src/ct_util.erl @@ -37,7 +37,7 @@ read_suite_data/1, delete_suite_data/0, delete_suite_data/1, match_delete_suite_data/1, delete_testdata/0, delete_testdata/1, set_testdata/1, get_testdata/1, - update_testdata/2]). + set_testdata_async/1, update_testdata/2]). -export([override_silence_all_connections/0, override_silence_connections/1, get_overridden_silenced_connections/0, @@ -96,7 +96,8 @@ start(Mode,LogDir) -> Pid = spawn_link(fun() -> do_start(S,Mode,LogDir) end), receive {Pid,started} -> Pid; - {Pid,Error} -> exit(Error) + {Pid,Error} -> exit(Error); + {_Ref,{Pid,Error}} -> exit(Error) end; Pid -> case get_mode() of @@ -162,21 +163,19 @@ do_start(Parent,Mode,LogDir) -> end, {StartTime,TestLogDir} = ct_logs:init(Mode), - %% Initiate ct_hooks + ct_event:notify(#event{name=test_start, + node=node(), + data={StartTime, + lists:flatten(TestLogDir)}}), + %% Initialize ct_hooks case catch ct_hooks:init(Opts) of ok -> - ok; + Parent ! {self(),started}; {_,CTHReason} -> ct_logs:tc_print('Suite Callback',CTHReason,[]), - Parent ! {self(), CTHReason}, - self() ! {{stop,normal},{self(),make_ref()}} + self() ! {{stop,{self(),{user_error,CTHReason}}}, + {Parent,make_ref()}} end, - - ct_event:notify(#event{name=test_start, - node=node(), - data={StartTime, - lists:flatten(TestLogDir)}}), - Parent ! {self(),started}, loop(Mode,[],StartDir). create_table(TableName,KeyPos) -> @@ -232,6 +231,9 @@ update_testdata(Key, Fun) -> set_testdata(TestData) -> call({set_testdata, TestData}). +set_testdata_async(TestData) -> + cast({set_testdata, TestData}). + get_testdata(Key) -> call({get_testdata, Key}). @@ -317,7 +319,7 @@ loop(Mode,TestData,StartDir) -> {reset_cwd,From} -> return(From,file:set_cwd(StartDir)), loop(From,TestData,StartDir); - {{stop,How},From} -> + {{stop,Info},From} -> Time = calendar:local_time(), ct_event:sync_notify(#event{name=test_done, node=node(), @@ -330,11 +332,11 @@ loop(Mode,TestData,StartDir) -> ets:delete(?conn_table), ets:delete(?board_table), ets:delete(?suite_table), - ct_logs:close(How), + ct_logs:close(Info), ct_event:stop(), ct_config:stop(), file:set_cwd(StartDir), - return(From,ok); + return(From, Info); {Ref, _Msg} when is_reference(Ref) -> %% This clause is used when doing cast operations. loop(Mode,TestData,StartDir); @@ -537,16 +539,16 @@ reset_silent_connections() -> %%%----------------------------------------------------------------- -%%% @spec stop(How) -> ok +%%% @spec stop(Info) -> ok %%% %%% @doc Stop the ct_util_server and close all existing connections %%% (tool-internal use only). %%% %%% @see ct -stop(How) -> +stop(Info) -> case whereis(ct_util_server) of undefined -> ok; - _ -> call({stop,How}) + _ -> call({stop,Info}) end. %%%----------------------------------------------------------------- diff --git a/lib/common_test/src/vts.erl b/lib/common_test/src/vts.erl index 2ee982d726..081f98e889 100644 --- a/lib/common_test/src/vts.erl +++ b/lib/common_test/src/vts.erl @@ -281,9 +281,7 @@ run_test1(State=#state{tests=Tests,current_log_dir=LogDir}) -> end, unlink(Self) end, - Pid = spawn_link(RunTest), - Total = receive {{test_info,start_info,{_,_,Cases}},From} -> @@ -480,7 +478,7 @@ create_testdir_entries([],_N) -> []. testdir_entry(Dir,Suite,Case,N) -> - NStr = integer_to_list(N), + NStr = vts_integer_to_list(N), tr([td(delete_button(NStr)), td(Dir), td(suite_select(Dir,Suite,NStr)), @@ -691,11 +689,11 @@ result_summary_frame1(State) -> result_summary_body(State) -> N = State#state.ok + State#state.fail + State#state.skip, [h2("Result Summary"), - p([b(integer_to_list(N))," cases executed (of ", - b(integer_to_list(State#state.total)),")"]), - p([green([b(integer_to_list(State#state.ok))," successful"]),br(), - red([b(integer_to_list(State#state.fail))," failed"]),br(), - orange([b(integer_to_list(State#state.skip))," skipped"])]), + p([b(vts_integer_to_list(N))," cases executed (of ", + b(vts_integer_to_list(State#state.total)),")"]), + p([green([b(vts_integer_to_list(State#state.ok))," successful"]),br(), + red([b(vts_integer_to_list(State#state.fail))," failed"]),br(), + orange([b(vts_integer_to_list(State#state.skip))," skipped"])]), executed_test_list(State)]. executed_test_list(#state{testruns=[]}) -> @@ -735,6 +733,14 @@ report1(tc_done,{_Suite,init_per_suite,_},State) -> State; report1(tc_done,{_Suite,end_per_suite,_},State) -> State; +report1(tc_done,{_Suite,init_per_group,_},State) -> + State; +report1(tc_done,{_Suite,end_per_group,_},State) -> + State; +report1(tc_done,{_Suite,ct_init_per_group,_},State) -> + State; +report1(tc_done,{_Suite,ct_end_per_group,_},State) -> + State; report1(tc_done,{_Suite,_Case,ok},State) -> State#state{ok=State#state.ok+1}; report1(tc_done,{_Suite,_Case,{failed,_Reason}},State) -> @@ -742,7 +748,9 @@ report1(tc_done,{_Suite,_Case,{failed,_Reason}},State) -> report1(tc_done,{_Suite,_Case,{skipped,_Reason}},State) -> State#state{skip=State#state.skip+1}; report1(tc_user_skip,{_Suite,_Case,_Reason},State) -> - State#state{skip=State#state.skip+1}. + State#state{skip=State#state.skip+1}; +report1(loginfo,_,State) -> + State. get_test_log(TestName,LogDir) -> [Log] = @@ -882,3 +890,7 @@ get_input_data(Input,Key)-> parse(Input) -> httpd:parse_query(Input). +vts_integer_to_list(X) when is_atom(X) -> + atom_to_list(X); +vts_integer_to_list(X) when is_integer(X) -> + integer_to_list(X). diff --git a/lib/common_test/test/Makefile b/lib/common_test/test/Makefile index 115565aaa0..b7b099069c 100644 --- a/lib/common_test/test/Makefile +++ b/lib/common_test/test/Makefile @@ -96,7 +96,7 @@ release_tests_spec: $(INSTALL_DIR) $(RELSYSDIR) $(INSTALL_DATA) $(ERL_FILES) $(COVERFILE) $(RELSYSDIR) $(INSTALL_DATA) common_test.spec $(RELSYSDIR) - chmod -f -R u+w $(RELSYSDIR) + chmod -R u+w $(RELSYSDIR) @tar cf - *_SUITE_data | (cd $(RELSYSDIR); tar xf -) release_docs_spec: diff --git a/lib/common_test/test/ct_config_SUITE.erl b/lib/common_test/test/ct_config_SUITE.erl index b6b50f33e0..8ce75f582a 100644 --- a/lib/common_test/test/ct_config_SUITE.erl +++ b/lib/common_test/test/ct_config_SUITE.erl @@ -174,7 +174,8 @@ run_test(Name, Config, CTConfig, SuiteNames)-> TestEvents = ct_test_support:get_events(ERPid, Config), ct_test_support:log_events(Name, reformat_events(TestEvents, ?eh), - ?config(config_dir, Config)), + ?config(config_dir, Config), + Opts), ExpEvents = events_to_check(Name), ok = ct_test_support:verify_events(ExpEvents, TestEvents, Config). diff --git a/lib/common_test/test/ct_error_SUITE.erl b/lib/common_test/test/ct_error_SUITE.erl index ad6cf1ba8f..6867e59b60 100644 --- a/lib/common_test/test/ct_error_SUITE.erl +++ b/lib/common_test/test/ct_error_SUITE.erl @@ -102,8 +102,9 @@ cfg_error(Config) when is_list(Config) -> Events = ct_test_support:get_events(ERPid, Config), ct_test_support:log_events(cfg_error, - reformat(Events, ?eh), - ?config(priv_dir, Config)), + reformat(Events, ?eh), + ?config(priv_dir, Config), + Opts), TestEvents = events_to_check(cfg_error), ok = ct_test_support:verify_events(TestEvents, Events, Config). @@ -120,8 +121,9 @@ lib_error(Config) when is_list(Config) -> Events = ct_test_support:get_events(ERPid, Config), ct_test_support:log_events(lib_error, - reformat(Events, ?eh), - ?config(priv_dir, Config)), + reformat(Events, ?eh), + ?config(priv_dir, Config), + Opts), TestEvents = events_to_check(lib_error), ok = ct_test_support:verify_events(TestEvents, Events, Config). @@ -138,8 +140,9 @@ no_compile(Config) when is_list(Config) -> Events = ct_test_support:get_events(ERPid, Config), ct_test_support:log_events(no_compile, - reformat(Events, ?eh), - ?config(priv_dir, Config)), + reformat(Events, ?eh), + ?config(priv_dir, Config), + Opts), TestEvents = events_to_check(no_compile), ok = ct_test_support:verify_events(TestEvents, Events, Config). @@ -156,7 +159,8 @@ timetrap_end_conf(Config) when is_list(Config) -> ct_test_support:log_events(timetrap_end_conf, reformat(Events, ?eh), - ?config(priv_dir, Config)), + ?config(priv_dir, Config), + Opts), TestEvents = events_to_check(timetrap_end_conf), ok = ct_test_support:verify_events(TestEvents, Events, Config). @@ -176,7 +180,8 @@ timetrap_normal(Config) when is_list(Config) -> ct_test_support:log_events(timetrap_normal, reformat(Events, ?eh), - ?config(priv_dir, Config)), + ?config(priv_dir, Config), + Opts), TestEvents = events_to_check(timetrap_normal), ok = ct_test_support:verify_events(TestEvents, Events, Config). @@ -198,12 +203,31 @@ timetrap_extended(Config) when is_list(Config) -> ct_test_support:log_events(timetrap_extended, reformat(Events, ?eh), - ?config(priv_dir, Config)), + ?config(priv_dir, Config), + Opts), TestEvents = events_to_check(timetrap_extended), ok = ct_test_support:verify_events(TestEvents, Events, Config). %%%----------------------------------------------------------------- +%%% +timetrap_parallel(Config) when is_list(Config) -> + DataDir = ?config(data_dir, Config), + Join = fun(D, S) -> filename:join(D, "error/test/"++S) end, + Suite = Join(DataDir, "timetrap_3_SUITE"), + {Opts,ERPid} = setup([{suite,Suite}], Config), + ok = ct_test_support:run(Opts, Config), + Events = ct_test_support:get_events(ERPid, Config), + + ct_test_support:log_events(timetrap_parallel, + reformat(Events, ?eh), + ?config(priv_dir, Config), + Opts), + + TestEvents = events_to_check(timetrap_parallel), + ok = ct_test_support:verify_events(TestEvents, Events, Config). + +%%%----------------------------------------------------------------- %%% HELP FUNCTIONS %%%----------------------------------------------------------------- @@ -236,7 +260,7 @@ test_events(cfg_error) -> [ {?eh,start_logging,{'DEF','RUNDIR'}}, {?eh,test_start,{'DEF',{'START_TIME','LOGDIR'}}}, - {?eh,start_info,{14,14,42}}, + {?eh,start_info,{14,14,43}}, {?eh,tc_start,{cfg_error_1_SUITE,init_per_suite}}, {?eh,tc_done, @@ -405,7 +429,6 @@ test_events(cfg_error) -> {cfg_error_8_SUITE,{init_per_group,g3,[]}, {failed,{error,{{badmatch,42}, [{cfg_error_8_SUITE,init_per_group,2}, - {cfg_error_8_SUITE,init_per_group,2}, {test_server,my_apply,3}, {test_server,ts_tc,3}, {test_server,run_test_case_eval1,6}, @@ -415,7 +438,6 @@ test_events(cfg_error) -> {failed,{cfg_error_8_SUITE,init_per_group, {'EXIT',{{badmatch,42}, [{cfg_error_8_SUITE,init_per_group,2}, - {cfg_error_8_SUITE,init_per_group,2}, {test_server,my_apply,3}, {test_server,ts_tc,3}, {test_server,run_test_case_eval1,6}, @@ -426,7 +448,6 @@ test_events(cfg_error) -> {failed,{cfg_error_8_SUITE,init_per_group, {'EXIT',{{badmatch,42}, [{cfg_error_8_SUITE,init_per_group,2}, - {cfg_error_8_SUITE,init_per_group,2}, {test_server,my_apply,3}, {test_server,ts_tc,3}, {test_server,run_test_case_eval1,6}, @@ -520,16 +541,19 @@ test_events(cfg_error) -> %%! end_tc failes the testcase {?eh,tc_done,{cfg_error_9_SUITE,tc6,ok}}, {?eh,test_stats,{9,2,{0,18}}}, + {?eh,tc_start,{cfg_error_9_SUITE,tc7}}, + {?eh,tc_done,{cfg_error_9_SUITE,tc7,{failed,{error,tc7_should_be_failed}}}}, + {ct_test_support_eh,test_stats,{9,3,{0,18}}}, {?eh,tc_start,{cfg_error_9_SUITE,tc11}}, {?eh,tc_done,{cfg_error_9_SUITE,tc11, {failed,{cfg_error_9_SUITE,end_per_testcase, {'EXIT',warning_should_be_printed}}}}}, - {?eh,test_stats,{10,2,{0,18}}}, + {?eh,test_stats,{10,3,{0,18}}}, {?eh,tc_start,{cfg_error_9_SUITE,tc12}}, {?eh,tc_done,{cfg_error_9_SUITE,tc12, {failed,{cfg_error_9_SUITE,end_per_testcase, {timetrap_timeout,2000}}}}}, - {?eh,test_stats,{11,2,{0,18}}}, + {?eh,test_stats,{11,3,{0,18}}}, {?eh,tc_start,{cfg_error_9_SUITE,tc13}}, {?eh,tc_done,{cfg_error_9_SUITE,tc13, {failed,{cfg_error_9_SUITE,end_per_testcase, @@ -539,11 +563,11 @@ test_events(cfg_error) -> {test_server,do_end_per_testcase,4}, {test_server,run_test_case_eval1,6}, {test_server,run_test_case_eval,8}]}}}}}}, - {?eh,test_stats,{12,2,{0,18}}}, + {?eh,test_stats,{12,3,{0,18}}}, {?eh,tc_start,{cfg_error_9_SUITE,tc14}}, {?eh,tc_done, {cfg_error_9_SUITE,tc14,{failed,{error,tc14_should_be_failed}}}}, - {?eh,test_stats,{12,3,{0,18}}}, + {?eh,test_stats,{12,4,{0,18}}}, {?eh,tc_start,{cfg_error_9_SUITE,end_per_suite}}, {?eh,tc_done,{cfg_error_9_SUITE,end_per_suite,ok}}, @@ -554,7 +578,7 @@ test_events(cfg_error) -> {?eh,tc_auto_skip,{cfg_error_10_SUITE,tc1, {failed,{cfg_error_10_SUITE,init_per_suite, {failed,fail_init_per_suite}}}}}, - {?eh,test_stats,{12,3,{0,19}}}, + {?eh,test_stats,{12,4,{0,19}}}, {?eh,tc_auto_skip,{cfg_error_10_SUITE,end_per_suite, {failed,{cfg_error_10_SUITE,init_per_suite, {failed,fail_init_per_suite}}}}}, @@ -563,40 +587,40 @@ test_events(cfg_error) -> {?eh,tc_start,{cfg_error_11_SUITE,tc1}}, {?eh,tc_done,{cfg_error_11_SUITE,tc1, {skipped,{config_name_already_in_use,[dummy0]}}}}, - {?eh,test_stats,{12,3,{1,19}}}, + {?eh,test_stats,{12,4,{1,19}}}, {?eh,tc_start,{cfg_error_11_SUITE,tc2}}, {?eh,tc_done,{cfg_error_11_SUITE,tc2,ok}}, - {?eh,test_stats,{13,3,{1,19}}}, + {?eh,test_stats,{13,4,{1,19}}}, {?eh,tc_start,{cfg_error_11_SUITE,end_per_suite}}, {?eh,tc_done,{cfg_error_11_SUITE,end_per_suite,ok}}, {?eh,tc_start,{cfg_error_12_SUITE,tc1}}, {?eh,tc_done,{cfg_error_12_SUITE,tc1,{failed,{timetrap_timeout,500}}}}, - {?eh,test_stats,{13,4,{1,19}}}, + {?eh,test_stats,{13,5,{1,19}}}, {?eh,tc_start,{cfg_error_12_SUITE,tc2}}, {?eh,tc_done,{cfg_error_12_SUITE,tc2,{failed, {cfg_error_12_SUITE,end_per_testcase, {timetrap_timeout,500}}}}}, - {?eh,test_stats,{14,4,{1,19}}}, + {?eh,test_stats,{14,5,{1,19}}}, {?eh,tc_start,{cfg_error_12_SUITE,tc3}}, {?eh,tc_done,{cfg_error_12_SUITE,tc3,ok}}, - {?eh,test_stats,{15,4,{1,19}}}, + {?eh,test_stats,{15,5,{1,19}}}, {?eh,tc_start,{cfg_error_12_SUITE,tc4}}, {?eh,tc_done,{cfg_error_12_SUITE,tc4,{failed, {cfg_error_12_SUITE,end_per_testcase, {timetrap_timeout,500}}}}}, - {?eh,test_stats,{16,4,{1,19}}}, + {?eh,test_stats,{16,5,{1,19}}}, {?eh,tc_start,{cfg_error_13_SUITE,init_per_suite}}, {?eh,tc_done,{cfg_error_13_SUITE,init_per_suite,ok}}, {?eh,tc_start,{cfg_error_13_SUITE,tc1}}, {?eh,tc_done,{cfg_error_13_SUITE,tc1,ok}}, - {?eh,test_stats,{17,4,{1,19}}}, + {?eh,test_stats,{17,5,{1,19}}}, {?eh,tc_start,{cfg_error_13_SUITE,end_per_suite}}, {?eh,tc_done,{cfg_error_13_SUITE,end_per_suite,ok}}, {?eh,tc_start,{cfg_error_14_SUITE,init_per_suite}}, {?eh,tc_done,{cfg_error_14_SUITE,init_per_suite,ok}}, {?eh,tc_start,{cfg_error_14_SUITE,tc1}}, {?eh,tc_done,{cfg_error_14_SUITE,tc1,ok}}, - {?eh,test_stats,{18,4,{1,19}}}, + {?eh,test_stats,{18,5,{1,19}}}, {?eh,tc_start,{cfg_error_14_SUITE,end_per_suite}}, {?eh,tc_done,{cfg_error_14_SUITE,end_per_suite, {comment, @@ -729,7 +753,7 @@ test_events(timetrap_normal) -> [ {?eh,start_logging,{'DEF','RUNDIR'}}, {?eh,test_start,{'DEF',{'START_TIME','LOGDIR'}}}, - {?eh,start_info,{1,1,3}}, + {?eh,start_info,{1,1,4}}, {?eh,tc_start,{timetrap_2_SUITE,init_per_suite}}, {?eh,tc_done,{timetrap_2_SUITE,init_per_suite,ok}}, {?eh,tc_start,{timetrap_2_SUITE,tc0}}, @@ -744,6 +768,9 @@ test_events(timetrap_normal) -> {?eh,tc_done, {timetrap_2_SUITE,tc2,{failed,{timetrap_timeout,500}}}}, {?eh,test_stats,{0,3,{0,0}}}, + {?eh,tc_start,{timetrap_2_SUITE,tc3}}, + {?eh,tc_done,{timetrap_2_SUITE,tc3,ok}}, + {?eh,test_stats,{1,3,{0,0}}}, {?eh,tc_start,{timetrap_2_SUITE,end_per_suite}}, {?eh,tc_done,{timetrap_2_SUITE,end_per_suite,ok}}, {?eh,test_done,{'DEF','STOP_TIME'}}, @@ -754,7 +781,7 @@ test_events(timetrap_extended) -> [ {?eh,start_logging,{'DEF','RUNDIR'}}, {?eh,test_start,{'DEF',{'START_TIME','LOGDIR'}}}, - {?eh,start_info,{1,1,3}}, + {?eh,start_info,{1,1,4}}, {?eh,tc_start,{timetrap_2_SUITE,init_per_suite}}, {?eh,tc_done,{timetrap_2_SUITE,init_per_suite,ok}}, {?eh,tc_start,{timetrap_2_SUITE,tc0}}, @@ -769,8 +796,52 @@ test_events(timetrap_extended) -> {?eh,tc_done, {timetrap_2_SUITE,tc2,{failed,{timetrap_timeout,1000}}}}, {?eh,test_stats,{0,3,{0,0}}}, + {?eh,tc_start,{timetrap_2_SUITE,tc3}}, + {?eh,tc_done,{timetrap_2_SUITE,tc3,ok}}, + {?eh,test_stats,{1,3,{0,0}}}, {?eh,tc_start,{timetrap_2_SUITE,end_per_suite}}, {?eh,tc_done,{timetrap_2_SUITE,end_per_suite,ok}}, {?eh,test_done,{'DEF','STOP_TIME'}}, {?eh,stop_logging,[]} - ]. + ]; + +test_events(timetrap_parallel) -> + [ + {?eh,start_logging,{'DEF','RUNDIR'}}, + {?eh,test_start,{'DEF',{'START_TIME','LOGDIR'}}}, + {?eh,start_info,{1,1,7}}, + {?eh,tc_done,{timetrap_3_SUITE,init_per_suite,ok}}, + {parallel, + [{?eh,tc_start, + {timetrap_3_SUITE,{init_per_group,g1,[parallel]}}}, + {?eh,tc_done, + {timetrap_3_SUITE,{init_per_group,g1,[parallel]},ok}}, + {?eh,tc_start,{timetrap_3_SUITE,tc0}}, + {?eh,tc_start,{timetrap_3_SUITE,tc1}}, + {?eh,tc_start,{timetrap_3_SUITE,tc2}}, + {?eh,tc_start,{timetrap_3_SUITE,tc3}}, + {?eh,tc_start,{timetrap_3_SUITE,tc4}}, + {?eh,tc_start,{timetrap_3_SUITE,tc6}}, + {?eh,tc_start,{timetrap_3_SUITE,tc7}}, + {?eh,tc_done, + {timetrap_3_SUITE,tc1,{failed,{timetrap_timeout,500}}}}, + {?eh,tc_done, + {timetrap_3_SUITE,tc2,{failed,{timetrap_timeout,1000}}}}, + {?eh,tc_done, + {timetrap_3_SUITE,tc6,{failed,{timetrap_timeout,1000}}}}, + {?eh,tc_done, + {timetrap_3_SUITE,tc7,{failed,{timetrap_timeout,1500}}}}, + {?eh,tc_done, + {timetrap_3_SUITE,tc0,{failed,{timetrap_timeout,2000}}}}, + {?eh,tc_done, + {timetrap_3_SUITE,tc4,{failed,{timetrap_timeout,2000}}}}, + {?eh,tc_done, + {timetrap_3_SUITE,tc3,{failed,{timetrap_timeout,3000}}}}, + {?eh,test_stats,{0,7,{0,0}}}, + {?eh,tc_start, + {timetrap_3_SUITE,{end_per_group,g1,[parallel]}}}, + {?eh,tc_done, + {timetrap_3_SUITE,{end_per_group,g1,[parallel]},ok}}]}, + {?eh,tc_done,{timetrap_3_SUITE,end_per_suite,ok}}, + {?eh,test_done,{'DEF','STOP_TIME'}}, + {?eh,stop_logging,[]}]. diff --git a/lib/common_test/test/ct_error_SUITE_data/error/test/cfg_error_9_SUITE.erl b/lib/common_test/test/ct_error_SUITE_data/error/test/cfg_error_9_SUITE.erl index d73287ad62..40b7d2da47 100644 --- a/lib/common_test/test/ct_error_SUITE_data/error/test/cfg_error_9_SUITE.erl +++ b/lib/common_test/test/ct_error_SUITE_data/error/test/cfg_error_9_SUITE.erl @@ -83,6 +83,8 @@ init_per_testcase(tc3, Config) -> Config; init_per_testcase(tc4, _) -> ok; +init_per_testcase(tc7, _) -> + {fail,tc7_should_be_failed}; init_per_testcase(_, Config) -> Config. @@ -136,7 +138,7 @@ groups() -> %% Reason = term() %%-------------------------------------------------------------------- all() -> - [tc1,tc2,tc3,tc4,tc5,tc6, + [tc1,tc2,tc3,tc4,tc5,tc6,tc7, tc11,tc12,tc13,tc14]. tc1(_) -> @@ -171,6 +173,11 @@ tc6(_) -> ct:comment("This one should succeed but then get failed by end_tc!"), fini. +tc7(_) -> + ct:comment("This one should get failed by iptc!"), + fini. + + tc11(_) -> fini. tc12(_) -> diff --git a/lib/common_test/test/ct_error_SUITE_data/error/test/timetrap_2_SUITE.erl b/lib/common_test/test/ct_error_SUITE_data/error/test/timetrap_2_SUITE.erl index 99bb400137..7fcb631d06 100644 --- a/lib/common_test/test/ct_error_SUITE_data/error/test/timetrap_2_SUITE.erl +++ b/lib/common_test/test/ct_error_SUITE_data/error/test/timetrap_2_SUITE.erl @@ -77,8 +77,8 @@ init_per_testcase(tc1, Config) -> ct:timetrap({seconds,1}), Config; -init_per_testcase(tc3, Config) -> - ct:timetrap({seconds,1}), +init_per_testcase(tc2, Config) -> + ct:timetrap(250), Config; init_per_testcase(_TestCase, Config) -> @@ -90,7 +90,7 @@ init_per_testcase(_TestCase, Config) -> %% TestCase = atom() %% Config0 = Config1 = [tuple()] %%-------------------------------------------------------------------- -end_per_testcase(_, Config) -> +end_per_testcase(_, _Config) -> ok. %%-------------------------------------------------------------------- @@ -116,7 +116,7 @@ groups() -> %% Reason = term() %%-------------------------------------------------------------------- all() -> - [tc0,tc1,tc2]. + [tc0,tc1,tc2,tc3]. tc0(_) -> N = list_to_integer(ct:get_config(multiply)), @@ -131,8 +131,24 @@ tc1(_) -> ok. tc2(_) -> + ct:timetrap(500), N = list_to_integer(ct:get_config(multiply)), ct:comment(io_lib:format("TO after ~w sec", [0.5*N])), - ct:timetrap(500), ct:sleep(2000), ok. + +tc3() -> + [{timetrap,{seconds,2}}]. + +tc3(_) -> + T0 = now(), + ct:timetrap(infinity), + N = list_to_integer(ct:get_config(multiply)), + ct:comment(io_lib:format("Sleeping for ~w sec...", [4*N])), + ct:sleep(4000), + Diff = timer:now_diff(now(), T0), + if ((Diff < (N*4000000)) or (Diff > (N*4500000))) -> + exit(not_expected); + true -> + ok + end. diff --git a/lib/common_test/test/ct_event_handler_SUITE.erl b/lib/common_test/test/ct_event_handler_SUITE.erl index 5ef04c0e75..b534a7141d 100644 --- a/lib/common_test/test/ct_event_handler_SUITE.erl +++ b/lib/common_test/test/ct_event_handler_SUITE.erl @@ -102,8 +102,9 @@ start_stop(Config) when is_list(Config) -> Events = ct_test_support:get_events(ERPid, Config), ct_test_support:log_events(start_stop, - ct_test_support:reformat(Events, eh_A), - ?config(priv_dir, Config)), + ct_test_support:reformat(Events, eh_A), + ?config(priv_dir, Config), + Opts), TestEvents = [{eh_A,start_logging,{'DEF','RUNDIR'}}, @@ -148,8 +149,9 @@ results(Config) when is_list(Config) -> Events = ct_test_support:get_events(ERPid, Config), ct_test_support:log_events(results, - ct_test_support:reformat(Events, eh_A), - ?config(priv_dir, Config)), + ct_test_support:reformat(Events, eh_A), + ?config(priv_dir, Config), + Opts), TestEvents = [{eh_A,start_logging,{'DEF','RUNDIR'}}, diff --git a/lib/common_test/test/ct_groups_test_1_SUITE.erl b/lib/common_test/test/ct_groups_test_1_SUITE.erl index 7775d8a55d..e520a72227 100644 --- a/lib/common_test/test/ct_groups_test_1_SUITE.erl +++ b/lib/common_test/test/ct_groups_test_1_SUITE.erl @@ -89,8 +89,9 @@ groups_suite_1(Config) when is_list(Config) -> Events = ct_test_support:get_events(ERPid, Config), ct_test_support:log_events(groups_suite_1, - reformat(Events, ?eh), - ?config(priv_dir, Config)), + reformat(Events, ?eh), + ?config(priv_dir, Config), + Opts), TestEvents = events_to_check(groups_suite_1), ok = ct_test_support:verify_events(TestEvents, Events, Config). @@ -109,8 +110,9 @@ groups_suite_2(Config) when is_list(Config) -> Events = ct_test_support:get_events(ERPid, Config), ct_test_support:log_events(groups_suite_2, - reformat(Events, ?eh), - ?config(priv_dir, Config)), + reformat(Events, ?eh), + ?config(priv_dir, Config), + Opts), TestEvents = events_to_check(groups_suite_2), ok = ct_test_support:verify_events(TestEvents, Events, Config). @@ -130,8 +132,9 @@ groups_suites_1(Config) when is_list(Config) -> Events = ct_test_support:get_events(ERPid, Config), ct_test_support:log_events(groups_suites_1, - reformat(Events, ?eh), - ?config(priv_dir, Config)), + reformat(Events, ?eh), + ?config(priv_dir, Config), + Opts), TestEvents = events_to_check(groups_suites_1), ok = ct_test_support:verify_events(TestEvents, Events, Config). @@ -150,8 +153,9 @@ groups_dir_1(Config) when is_list(Config) -> Events = ct_test_support:get_events(ERPid, Config), ct_test_support:log_events(groups_dir_1, - reformat(Events, ?eh), - ?config(priv_dir, Config)), + reformat(Events, ?eh), + ?config(priv_dir, Config), + Opts), TestEvents = events_to_check(groups_dir_1), ok = ct_test_support:verify_events(TestEvents, Events, Config). @@ -170,8 +174,9 @@ groups_dirs_1(Config) when is_list(Config) -> Events = ct_test_support:get_events(ERPid, Config), ct_test_support:log_events(groups_dirs_1, - reformat(Events, ?eh), - ?config(priv_dir, Config)), + reformat(Events, ?eh), + ?config(priv_dir, Config), + Opts), TestEvents = events_to_check(groups_dirs_1), ok = ct_test_support:verify_events(TestEvents, Events, Config). diff --git a/lib/common_test/test/ct_groups_test_2_SUITE.erl b/lib/common_test/test/ct_groups_test_2_SUITE.erl index 2ae63f4f99..f33be8a9d4 100644 --- a/lib/common_test/test/ct_groups_test_2_SUITE.erl +++ b/lib/common_test/test/ct_groups_test_2_SUITE.erl @@ -59,7 +59,7 @@ end_per_testcase(TestCase, Config) -> suite() -> [{ct_hooks,[ts_install_cth]}]. all() -> - [missing_conf, repeat_1]. + [missing_conf, repeat_1, empty_group]. groups() -> []. @@ -83,13 +83,14 @@ missing_conf(Config) when is_list(Config) -> Suite = filename:join(DataDir, "groups_1/missing_conf_SUITE"), - {Opts,ERPid} = setup({suite,Suite}, Config), + {Opts,ERPid} = setup([{suite,Suite}], Config), ok = ct_test_support:run(Opts, Config), Events = ct_test_support:get_events(ERPid, Config), ct_test_support:log_events(missing_conf_SUITE, - reformat(Events, ?eh), - ?config(priv_dir, Config)), + reformat(Events, ?eh), + ?config(priv_dir, Config), + Opts), TestEvents = events_to_check(missing_conf), ok = ct_test_support:verify_events(TestEvents, Events, Config). @@ -102,18 +103,41 @@ repeat_1(Config) when is_list(Config) -> Suite = filename:join(DataDir, "groups_1/repeat_1_SUITE"), - {Opts,ERPid} = setup({suite,Suite}, Config), + {Opts,ERPid} = setup([{suite,Suite}], Config), ok = ct_test_support:run(Opts, Config), Events = ct_test_support:get_events(ERPid, Config), ct_test_support:log_events(repeat_1, reformat(Events, ?eh), - ?config(priv_dir, Config)), + ?config(priv_dir, Config), + Opts), TestEvents = events_to_check(repeat_1), ok = ct_test_support:verify_events(TestEvents, Events, Config). %%%----------------------------------------------------------------- +%%% + +empty_group(Config) when is_list(Config) -> + DataDir = ?config(data_dir, Config), + + Suite = filename:join(DataDir, "groups_2/groups_22_SUITE"), + + {Opts,ERPid} = setup([{suite,Suite}, + {group,[test_group_8,test_group_9,test_group_10]}], + Config), + ok = ct_test_support:run(Opts, Config), + Events = ct_test_support:get_events(ERPid, Config), + + ct_test_support:log_events(empty_group, + reformat(Events, ?eh), + ?config(priv_dir, Config), + Opts), + + TestEvents = events_to_check(empty_group), + ok = ct_test_support:verify_events(TestEvents, Events, Config). + +%%%----------------------------------------------------------------- %%% HELP FUNCTIONS %%%----------------------------------------------------------------- @@ -121,7 +145,7 @@ setup(Test, Config) -> Opts0 = ct_test_support:get_opts(Config), Level = ?config(trace_level, Config), EvHArgs = [{cbm,ct_test_support},{trace_level,Level}], - Opts = Opts0 ++ [Test,{event_handler,{?eh,EvHArgs}}], + Opts = Opts0 ++ [{event_handler,{?eh,EvHArgs}} | Test], ERPid = ct_test_support:start_event_receiver(Config), {Opts,ERPid}. @@ -256,4 +280,27 @@ test_events(repeat_1) -> {?eh,tc_done,{repeat_1_SUITE,end_per_suite,ok}}, {?eh,test_done,{'DEF','STOP_TIME'}}, {?eh,stop_logging,[]} + ]; + +test_events(empty_group) -> + [{?eh,start_logging,{'DEF','RUNDIR'}}, + {?eh,test_start,{'DEF',{'START_TIME','LOGDIR'}}}, + {?eh,start_info,{1,1,1}}, + {?eh,tc_start,{groups_22_SUITE,init_per_suite}}, + {?eh,tc_done,{groups_22_SUITE,init_per_suite,ok}}, + [{?eh,tc_start, + {groups_22_SUITE,{init_per_group,test_group_8,[]}}}, + {?eh,tc_done, + {groups_22_SUITE,{init_per_group,test_group_8,[]},ok}}, + {?eh,tc_start,{groups_22_SUITE,testcase_8}}, + {?eh,tc_done,{groups_22_SUITE,testcase_8,ok}}, + {?eh,test_stats,{1,0,{0,0}}}, + {?eh,tc_start, + {groups_22_SUITE,{end_per_group,test_group_8,[]}}}, + {?eh,tc_done, + {groups_22_SUITE,{end_per_group,test_group_8,[]},ok}}], + {?eh,tc_start,{groups_22_SUITE,end_per_suite}}, + {?eh,tc_done,{groups_22_SUITE,end_per_suite,init}}, + {?eh,test_done,{'DEF','STOP_TIME'}}, + {?eh,stop_logging,[]} ]. diff --git a/lib/common_test/test/ct_groups_test_2_SUITE_data/groups_2/groups_22_SUITE.erl b/lib/common_test/test/ct_groups_test_2_SUITE_data/groups_2/groups_22_SUITE.erl index cd517876df..14eb8769ad 100644 --- a/lib/common_test/test/ct_groups_test_2_SUITE_data/groups_2/groups_22_SUITE.erl +++ b/lib/common_test/test/ct_groups_test_2_SUITE_data/groups_2/groups_22_SUITE.erl @@ -31,27 +31,33 @@ suite() -> groups() -> [ - {test_group_1a, [shuffle], [testcase_1a,testcase_1b,testcase_1c]}, + {test_group_1a, [shuffle], [testcase_1a,testcase_1b,testcase_1c]}, - {test_group_1b, [parallel], [testcase_1a,testcase_1b]}, + {test_group_1b, [parallel], [testcase_1a,testcase_1b]}, - {test_group_2, [parallel], [testcase_2a, + {test_group_2, [parallel], [testcase_2a, - {test_group_3, [{repeat,1}], - [testcase_3a, testcase_3b]}, + {test_group_3, [{repeat,1}], + [testcase_3a, testcase_3b]}, - testcase_2b]}, + testcase_2b]}, - {test_group_4, [{test_group_5, [parallel], [testcase_5a, + {test_group_4, [{test_group_5, [parallel], [testcase_5a, - {group, test_group_6}, + {group, test_group_6}, - testcase_5b]}]}, + testcase_5b]}]}, - {test_group_6, [parallel], [{group, test_group_7}]}, + {test_group_6, [parallel], [{group, test_group_7}]}, - {test_group_7, [sequence], [testcase_7a,testcase_7b]} - ]. + {test_group_7, [sequence], [testcase_7a,testcase_7b]}, + + {test_group_8, [], [{group, test_group_9}, testcase_8]}, + + {test_group_9, [], []}, + + {test_group_10, [], [{group, test_group_9}]} + ]. all() -> [{group, test_group_1a}, @@ -60,7 +66,10 @@ all() -> testcase_2, {group, test_group_2}, testcase_3, - {group, test_group_4}]. + {group, test_group_4}, + {group, test_group_8}, + {group, test_group_9}, + {group, test_group_10}]. %% this func only for internal test purposes grs_and_tcs() -> @@ -68,7 +77,9 @@ grs_and_tcs() -> test_group_1a, test_group_1b, test_group_2, test_group_3, test_group_4, test_group_5, - test_group_6, test_group_7 + test_group_6, test_group_7, + test_group_8, test_group_9, + test_group_10 ], [ testcase_1a, testcase_1b, testcase_1c, @@ -78,7 +89,8 @@ grs_and_tcs() -> testcase_3a, testcase_3b, testcase_3, testcase_5a, testcase_5b, - testcase_7a, testcase_7b + testcase_7a, testcase_7b, + testcase_8 ]}. %%-------------------------------------------------------------------- @@ -107,7 +119,10 @@ init_per_group(Group, Config) -> {test_group_4,[{name,test_group_4}]} -> ok; {test_group_5,[{name,test_group_5},parallel]} -> "parallel"; {test_group_6,[{name,test_group_6},parallel]} -> "parallel"; - {test_group_7,[{name,test_group_7},sequence]} -> "sequence" + {test_group_7,[{name,test_group_7},sequence]} -> "sequence"; + {test_group_8,[{name,test_group_8}]} -> ok; + {test_group_9,[{name,test_group_9}]} -> ok; + {test_group_10,[{name,test_group_10}]} -> ok end, {Grs,_} = grs_and_tcs(), case lists:member(Group, Grs) of @@ -312,3 +327,7 @@ testcase_7b(Config) -> undefined = ?config(testcase_7a,Config), testcase_7b = ?config(testcase_7b,Config), ok. +testcase_8() -> + []. +testcase_8(_Config) -> + ok. diff --git a/lib/common_test/test/ct_hooks_SUITE.erl b/lib/common_test/test/ct_hooks_SUITE.erl index 5479e6943d..8574d7aabc 100644 --- a/lib/common_test/test/ct_hooks_SUITE.erl +++ b/lib/common_test/test/ct_hooks_SUITE.erl @@ -231,8 +231,9 @@ do_test(Tag, SuiteWildCard, CTHs, Config, Res, EC) -> Events = ct_test_support:get_events(ERPid, Config), ct_test_support:log_events(Tag, - reformat(Events, ?eh), - ?config(priv_dir, Config)), + reformat(Events, ?eh), + ?config(priv_dir, Config), + Opts), TestEvents = events_to_check(Tag, EC), ok = ct_test_support:verify_events(TestEvents, Events, Config). @@ -265,9 +266,9 @@ events_to_check(Test, N) -> test_events(one_empty_cth) -> [ {?eh,start_logging,{'DEF','RUNDIR'}}, + {?eh,test_start,{'DEF',{'START_TIME','LOGDIR'}}}, {?eh,cth,{empty_cth,id,[[]]}}, {?eh,cth,{empty_cth,init,[{'_','_','_'},[]]}}, - {?eh,test_start,{'DEF',{'START_TIME','LOGDIR'}}}, {?eh,tc_start,{ct_cth_empty_SUITE,init_per_suite}}, {?eh,cth,{empty_cth,pre_init_per_suite, [ct_cth_empty_SUITE,'$proplist',[]]}}, @@ -293,11 +294,11 @@ test_events(one_empty_cth) -> test_events(two_empty_cth) -> [ {?eh,start_logging,{'DEF','RUNDIR'}}, + {?eh,test_start,{'DEF',{'START_TIME','LOGDIR'}}}, {?eh,cth,{'_',id,[[]]}}, {?eh,cth,{'_',init,['_',[]]}}, {?eh,cth,{'_',id,[[]]}}, {?eh,cth,{'_',init,['_',[]]}}, - {?eh,test_start,{'DEF',{'START_TIME','LOGDIR'}}}, {?eh,tc_start,{ct_cth_empty_SUITE,init_per_suite}}, {?eh,cth,{'_',pre_init_per_suite,[ct_cth_empty_SUITE,'$proplist',[]]}}, {?eh,cth,{'_',pre_init_per_suite,[ct_cth_empty_SUITE,'$proplist',[]]}}, @@ -335,8 +336,8 @@ test_events(faulty_cth_no_init) -> test_events(faulty_cth_id_no_init) -> [ {?eh,start_logging,{'DEF','RUNDIR'}}, - {?eh,cth,{'_',id,[[]]}}, {?eh,test_start,{'DEF',{'START_TIME','LOGDIR'}}}, + {?eh,cth,{'_',id,[[]]}}, {negative,{?eh,tc_start,'_'}, {?eh,test_done,{'DEF','STOP_TIME'}}}, {?eh,stop_logging,[]} @@ -345,9 +346,9 @@ test_events(faulty_cth_id_no_init) -> test_events(minimal_cth) -> [ {?eh,start_logging,{'DEF','RUNDIR'}}, + {?eh,test_start,{'DEF',{'START_TIME','LOGDIR'}}}, {negative,{?eh,cth,{'_',id,['_',[]]}}, {?eh,cth,{'_',init,['_',[]]}}}, - {?eh,test_start,{'DEF',{'START_TIME','LOGDIR'}}}, {?eh,tc_start,{ct_cth_empty_SUITE,init_per_suite}}, {?eh,tc_done,{ct_cth_empty_SUITE,init_per_suite,ok}}, @@ -363,11 +364,11 @@ test_events(minimal_cth) -> test_events(minimal_and_maximal_cth) -> [ {?eh,start_logging,{'DEF','RUNDIR'}}, + {?eh,test_start,{'DEF',{'START_TIME','LOGDIR'}}}, {negative,{?eh,cth,{'_',id,['_',[]]}}, {?eh,cth,{'_',init,['_',[]]}}}, {?eh,cth,{'_',id,[[]]}}, {?eh,cth,{'_',init,['_',[]]}}, - {?eh,test_start,{'DEF',{'START_TIME','LOGDIR'}}}, {?eh,tc_start,{ct_cth_empty_SUITE,init_per_suite}}, {?eh,cth,{'_',pre_init_per_suite,[ct_cth_empty_SUITE,'$proplist',[]]}}, {?eh,cth,{'_',post_init_per_suite,[ct_cth_empty_SUITE,'$proplist','$proplist',[]]}}, @@ -393,8 +394,8 @@ test_events(faulty_cth_undef) -> {failed,FailReasonStr}}, [ {?eh,start_logging,{'DEF','RUNDIR'}}, - {?eh,cth,{'_',init,['_',[]]}}, {?eh,test_start,{'DEF',{'START_TIME','LOGDIR'}}}, + {?eh,cth,{'_',init,['_',[]]}}, {?eh,tc_start,{ct_cth_empty_SUITE,init_per_suite}}, {?eh,tc_done,{ct_cth_empty_SUITE,init_per_suite, {failed, {error,FailReasonStr}}}}, @@ -439,15 +440,15 @@ test_events(faulty_cth_exit_in_init_scope_suite) -> test_events(faulty_cth_exit_in_init) -> [{?eh,start_logging,{'DEF','RUNDIR'}}, - {?eh,cth,{empty_cth,init,['_',[]]}}, {?eh,test_start,{'DEF',{'START_TIME','LOGDIR'}}}, + {?eh,cth,{empty_cth,init,['_',[]]}}, {?eh,test_done,{'DEF','STOP_TIME'}}, {?eh,stop_logging,[]}]; test_events(faulty_cth_exit_in_id) -> [{?eh,start_logging,{'DEF','RUNDIR'}}, - {?eh,cth,{empty_cth,id,[[]]}}, {?eh,test_start,{'DEF',{'START_TIME','LOGDIR'}}}, + {?eh,cth,{empty_cth,id,[[]]}}, {negative, {?eh,tc_start,'_'}, {?eh,test_done,{'DEF','STOP_TIME'}}}, {?eh,stop_logging,[]}]; @@ -615,9 +616,8 @@ test_events(scope_per_group_state_cth) -> test_events(fail_pre_suite_cth) -> [ {?eh,start_logging,{'DEF','RUNDIR'}}, - {?eh,cth,{'_',init,['_',[]]}}, {?eh,test_start,{'DEF',{'START_TIME','LOGDIR'}}}, - + {?eh,cth,{'_',init,['_',[]]}}, {?eh,tc_start,{ct_cth_empty_SUITE,init_per_suite}}, {?eh,cth,{'_',pre_init_per_suite,[ct_cth_empty_SUITE,'$proplist',[]]}}, @@ -672,8 +672,8 @@ test_events(double_fail_pre_suite_cth) -> test_events(fail_post_suite_cth) -> [ {?eh,start_logging,{'DEF','RUNDIR'}}, - {?eh,cth,{'_',init,['_',[]]}}, {?eh,test_start,{'DEF',{'START_TIME','LOGDIR'}}}, + {?eh,cth,{'_',init,['_',[]]}}, {?eh,tc_start,{ct_cth_empty_SUITE,init_per_suite}}, {?eh,cth,{'_',pre_init_per_suite,[ct_cth_empty_SUITE,'$proplist',[]]}}, {?eh,cth,{'_',post_init_per_suite,[ct_cth_empty_SUITE,'$proplist','$proplist',[]]}}, @@ -699,8 +699,8 @@ test_events(fail_post_suite_cth) -> test_events(skip_pre_suite_cth) -> [ {?eh,start_logging,{'DEF','RUNDIR'}}, - {?eh,cth,{'_',init,['_',[]]}}, {?eh,test_start,{'DEF',{'START_TIME','LOGDIR'}}}, + {?eh,cth,{'_',init,['_',[]]}}, {?eh,tc_start,{ct_cth_empty_SUITE,init_per_suite}}, {?eh,cth,{'_',pre_init_per_suite,[ct_cth_empty_SUITE,'$proplist',[]]}}, {?eh,cth,{'_',post_init_per_suite,[ct_cth_empty_SUITE,'$proplist',{skip,"Test skip"},[]]}}, @@ -722,8 +722,8 @@ test_events(skip_pre_suite_cth) -> test_events(skip_post_suite_cth) -> [ {?eh,start_logging,{'DEF','RUNDIR'}}, - {?eh,cth,{'_',init,['_',[]]}}, {?eh,test_start,{'DEF',{'START_TIME','LOGDIR'}}}, + {?eh,cth,{'_',init,['_',[]]}}, {?eh,tc_start,{ct_cth_empty_SUITE,init_per_suite}}, {?eh,cth,{'_',pre_init_per_suite,[ct_cth_empty_SUITE,'$proplist',[]]}}, @@ -747,8 +747,8 @@ test_events(recover_post_suite_cth) -> Suite = ct_cth_fail_per_suite_SUITE, [ {?eh,start_logging,'_'}, - {?eh,cth,{'_',init,['_',[]]}}, {?eh,test_start,{'DEF',{'START_TIME','LOGDIR'}}}, + {?eh,cth,{'_',init,['_',[]]}}, {?eh,tc_start,{Suite,init_per_suite}}, {?eh,cth,{'_',pre_init_per_suite,[Suite,'$proplist','$proplist']}}, {?eh,cth,{'_',post_init_per_suite,[Suite,contains([tc_status]), @@ -776,8 +776,8 @@ test_events(recover_post_suite_cth) -> test_events(update_config_cth) -> [ {?eh,start_logging,{'DEF','RUNDIR'}}, - {?eh,cth,{'_',init,['_',[]]}}, {?eh,test_start,{'DEF',{'START_TIME','LOGDIR'}}}, + {?eh,cth,{'_',init,['_',[]]}}, {?eh,tc_start,{ct_update_config_SUITE,init_per_suite}}, {?eh,cth,{'_',pre_init_per_suite, @@ -887,9 +887,9 @@ test_events(update_config_cth) -> test_events(state_update_cth) -> [ {?eh,start_logging,{'DEF','RUNDIR'}}, + {?eh,test_start,{'DEF',{'START_TIME','LOGDIR'}}}, {?eh,cth,{'_',init,['_',[]]}}, {?eh,cth,{'_',init,['_',[]]}}, - {?eh,test_start,{'DEF',{'START_TIME','LOGDIR'}}}, {?eh,tc_start,{'_',init_per_suite}}, {?eh,tc_done,{'_',end_per_suite,ok}}, @@ -925,8 +925,8 @@ test_events(state_update_cth) -> test_events(options_cth) -> [ {?eh,start_logging,{'DEF','RUNDIR'}}, - {?eh,cth,{empty_cth,init,['_',[test]]}}, {?eh,test_start,{'DEF',{'START_TIME','LOGDIR'}}}, + {?eh,cth,{empty_cth,init,['_',[test]]}}, {?eh,tc_start,{ct_cth_empty_SUITE,init_per_suite}}, {?eh,cth,{empty_cth,pre_init_per_suite, [ct_cth_empty_SUITE,'$proplist',[test]]}}, @@ -952,10 +952,10 @@ test_events(options_cth) -> test_events(same_id_cth) -> [ {?eh,start_logging,{'DEF','RUNDIR'}}, + {?eh,test_start,{'DEF',{'START_TIME','LOGDIR'}}}, {?eh,cth,{'_',id,[[]]}}, {?eh,cth,{'_',init,[same_id_cth,[]]}}, {?eh,cth,{'_',id,[[]]}}, - {?eh,test_start,{'DEF',{'START_TIME','LOGDIR'}}}, {?eh,tc_start,{ct_cth_empty_SUITE,init_per_suite}}, {?eh,cth,{'_',pre_init_per_suite,[ct_cth_empty_SUITE,'$proplist',[]]}}, {negative, @@ -992,8 +992,8 @@ test_events(same_id_cth) -> test_events(fail_n_skip_with_minimal_cth) -> [{?eh,start_logging,{'DEF','RUNDIR'}}, - {?eh,cth,{'_',init,['_',[]]}}, {?eh,test_start,{'DEF',{'START_TIME','LOGDIR'}}}, + {?eh,cth,{'_',init,['_',[]]}}, {?eh,tc_start,{'_',init_per_suite}}, {?eh,tc_done,{'_',end_per_suite,ok}}, diff --git a/lib/common_test/test/ct_master_SUITE.erl b/lib/common_test/test/ct_master_SUITE.erl index e89b6f7de6..1471cc1e0c 100644 --- a/lib/common_test/test/ct_master_SUITE.erl +++ b/lib/common_test/test/ct_master_SUITE.erl @@ -119,8 +119,9 @@ ct_master_test(Config) when is_list(Config)-> Events = ct_test_support:get_events(ERPid, Config), ct_test_support:log_events(groups_suite_1, - reformat(Events, ?eh), - ?config(priv_dir, Config)), + reformat(Events, ?eh), + PrivDir, []), + find_events(NodeNames, [{tc_start,{master_SUITE,init_per_suite}}, {tc_start,{master_SUITE,first_testcase}}, {tc_start,{master_SUITE,second_testcase}}, @@ -174,7 +175,7 @@ make_spec(DataDir, FileName, NodeNames, Suites, Config)-> ct_test_support:write_testspec(N++Include++EH++C++S++LD++NS, FileName). -get_log_dir({win32,_},PrivDir, NodeName)-> +get_log_dir({win32,_}, _PrivDir, NodeName)-> case filelib:is_dir(?TEMP_DIR) of false -> file:make_dir(?TEMP_DIR); diff --git a/lib/common_test/test/ct_misc_1_SUITE.erl b/lib/common_test/test/ct_misc_1_SUITE.erl index a8bd2c2189..cb17af9ab5 100644 --- a/lib/common_test/test/ct_misc_1_SUITE.erl +++ b/lib/common_test/test/ct_misc_1_SUITE.erl @@ -111,7 +111,8 @@ beam_me_up(Config) when is_list(Config) -> ct_test_support:log_events(beam_me_up, reformat(Events, ?eh), - ?config(priv_dir, Config)), + ?config(priv_dir, Config), + Opts), TestEvents = events_to_check(beam_me_up, 1), ok = ct_test_support:verify_events(TestEvents, Events, Config). diff --git a/lib/common_test/test/ct_repeat_1_SUITE.erl b/lib/common_test/test/ct_repeat_1_SUITE.erl index e674315526..4e842bd6d6 100644 --- a/lib/common_test/test/ct_repeat_1_SUITE.erl +++ b/lib/common_test/test/ct_repeat_1_SUITE.erl @@ -159,7 +159,8 @@ execute(TestCase, SuiteName, Group, Config) -> ct_test_support:log_events(TestCase, reformat(Events, ?eh), - ?config(priv_dir, Config)), + ?config(priv_dir, Config), + Opts), TestEvents = events_to_check(TestCase), ok = ct_test_support:verify_events(TestEvents, Events, Config). @@ -561,7 +562,6 @@ test_events(repeat_cs_until_any_fail) -> {error, {{badmatch,2}, [{repeat_1_SUITE,tc_fail_1,1}, - {repeat_1_SUITE,tc_fail_1,1}, {test_server,my_apply,3}, {test_server,ts_tc,3}, {test_server,run_test_case_eval1,6}, diff --git a/lib/common_test/test/ct_sequence_1_SUITE.erl b/lib/common_test/test/ct_sequence_1_SUITE.erl index c7650b169c..5facf90656 100644 --- a/lib/common_test/test/ct_sequence_1_SUITE.erl +++ b/lib/common_test/test/ct_sequence_1_SUITE.erl @@ -132,7 +132,8 @@ execute(TestCase, SuiteName, Group, Config) -> ct_test_support:log_events(TestCase, reformat(Events, ?eh), - ?config(priv_dir, Config)), + ?config(priv_dir, Config), + Opts), TestEvents = events_to_check(TestCase), ok = ct_test_support:verify_events(TestEvents, Events, Config). diff --git a/lib/common_test/test/ct_skip_SUITE.erl b/lib/common_test/test/ct_skip_SUITE.erl index 62c5f10b7c..4ba4479208 100644 --- a/lib/common_test/test/ct_skip_SUITE.erl +++ b/lib/common_test/test/ct_skip_SUITE.erl @@ -99,8 +99,9 @@ auto_skip(Config) when is_list(Config) -> Events = ct_test_support:get_events(ERPid, Config), ct_test_support:log_events(auto_skip, - reformat(Events, ?eh), - ?config(priv_dir, Config)), + reformat(Events, ?eh), + ?config(priv_dir, Config), + Opts), TestEvents = events_to_check(auto_skip), ok = ct_test_support:verify_events(TestEvents, Events, Config). @@ -122,8 +123,9 @@ user_skip(Config) when is_list(Config) -> Events = ct_test_support:get_events(ERPid, Config), ct_test_support:log_events(user_skip, - reformat(Events, ?eh), - ?config(priv_dir, Config)), + reformat(Events, ?eh), + ?config(priv_dir, Config), + Opts), TestEvents = events_to_check(user_skip), ok = ct_test_support:verify_events(TestEvents, Events, Config). diff --git a/lib/common_test/test/ct_smoke_test_SUITE.erl b/lib/common_test/test/ct_smoke_test_SUITE.erl index c3d49a5afa..49b38361e2 100644 --- a/lib/common_test/test/ct_smoke_test_SUITE.erl +++ b/lib/common_test/test/ct_smoke_test_SUITE.erl @@ -175,8 +175,9 @@ dir1(Config) when is_list(Config) -> Events = ct_test_support:get_events(ERPid, Config), ct_test_support:log_events(dir1, - ct_test_support:reformat(Events, ?eh), - ?config(priv_dir, Config)), + ct_test_support:reformat(Events, ?eh), + ?config(priv_dir, Config), + Opts), TestEvents = events_to_check(dir1), ok = ct_test_support:verify_events(TestEvents, Events, Config). @@ -204,8 +205,9 @@ dir2(Config) when is_list(Config) -> Events = ct_test_support:get_events(ERPid, Config), ct_test_support:log_events(dir2, - ct_test_support:reformat(Events, ?eh), - ?config(priv_dir, Config)), + ct_test_support:reformat(Events, ?eh), + ?config(priv_dir, Config), + Opts), TestEvents = events_to_check(dir2), ok = ct_test_support:verify_events(TestEvents, Events, Config). @@ -234,8 +236,9 @@ dir1_2(Config) when is_list(Config) -> Events = ct_test_support:get_events(ERPid, Config), ct_test_support:log_events(dir1_2, - ct_test_support:reformat(Events, ?eh), - ?config(priv_dir, Config)), + ct_test_support:reformat(Events, ?eh), + ?config(priv_dir, Config), + Opts), TestEvents = events_to_check(dir1_2), ok = ct_test_support:verify_events(TestEvents, Events, Config). @@ -264,8 +267,8 @@ suite11(Config) when is_list(Config) -> Events = ct_test_support:get_events(ERPid, Config), ct_test_support:log_events(suite11, - ct_test_support:reformat(Events, ?eh), - ?config(priv_dir, Config)), + ct_test_support:reformat(Events, ?eh), + ?config(priv_dir, Config), Opts), TestEvents = events_to_check(suite11), ok = ct_test_support:verify_events(TestEvents, Events, Config). @@ -293,8 +296,8 @@ suite21(Config) when is_list(Config) -> Events = ct_test_support:get_events(ERPid, Config), ct_test_support:log_events(suite21, - ct_test_support:reformat(Events, ?eh), - ?config(priv_dir, Config)), + ct_test_support:reformat(Events, ?eh), + ?config(priv_dir, Config), Opts), TestEvents = events_to_check(suite21), ok = ct_test_support:verify_events(TestEvents, Events, Config). @@ -324,8 +327,8 @@ suite11_21(Config) when is_list(Config) -> Events = ct_test_support:get_events(ERPid, Config), ct_test_support:log_events(suite11_21, - ct_test_support:reformat(Events, ?eh), - ?config(priv_dir, Config)), + ct_test_support:reformat(Events, ?eh), + ?config(priv_dir, Config), Opts), TestEvents = events_to_check(suite11_21), ok = ct_test_support:verify_events(TestEvents, Events, Config). @@ -355,8 +358,8 @@ tc111(Config) when is_list(Config) -> Events = ct_test_support:get_events(ERPid, Config), ct_test_support:log_events(tc111, - ct_test_support:reformat(Events, ?eh), - ?config(priv_dir, Config)), + ct_test_support:reformat(Events, ?eh), + ?config(priv_dir, Config), Opts), TestEvents = events_to_check(tc111), ok = ct_test_support:verify_events(TestEvents, Events, Config). @@ -385,8 +388,8 @@ tc211(Config) when is_list(Config) -> Events = ct_test_support:get_events(ERPid, Config), ct_test_support:log_events(tc211, - ct_test_support:reformat(Events, ?eh), - ?config(priv_dir, Config)), + ct_test_support:reformat(Events, ?eh), + ?config(priv_dir, Config), Opts), TestEvents = events_to_check(tc211), ok = ct_test_support:verify_events(TestEvents, Events, Config). @@ -416,8 +419,8 @@ tc111_112(Config) when is_list(Config) -> Events = ct_test_support:get_events(ERPid, Config), ct_test_support:log_events(tc111_112, - ct_test_support:reformat(Events, ?eh), - ?config(priv_dir, Config)), + ct_test_support:reformat(Events, ?eh), + ?config(priv_dir, Config), Opts), TestEvents = events_to_check(tc111_112), ok = ct_test_support:verify_events(TestEvents, Events, Config). diff --git a/lib/common_test/test/ct_test_server_if_1_SUITE.erl b/lib/common_test/test/ct_test_server_if_1_SUITE.erl index 9d3e6a9e59..4471915e69 100644 --- a/lib/common_test/test/ct_test_server_if_1_SUITE.erl +++ b/lib/common_test/test/ct_test_server_if_1_SUITE.erl @@ -98,8 +98,9 @@ ts_if_1(Config) when is_list(Config) -> Events = ct_test_support:get_events(ERPid, Config), ct_test_support:log_events(ts_if_1, - reformat(Events, ?eh), - PrivDir), + reformat(Events, ?eh), + PrivDir, + Opts), TestEvents = events_to_check(ts_if_1), ok = ct_test_support:verify_events(TestEvents, Events, Config). diff --git a/lib/common_test/test/ct_test_support.erl b/lib/common_test/test/ct_test_support.erl index b4f1a0e71f..601d5315ce 100644 --- a/lib/common_test/test/ct_test_support.erl +++ b/lib/common_test/test/ct_test_support.erl @@ -32,7 +32,8 @@ run/2, run/4, get_opts/1, wait_for_ct_stop/1]). -export([handle_event/2, start_event_receiver/1, get_events/2, - verify_events/3, reformat/2, log_events/3]). + verify_events/3, reformat/2, log_events/4, + join_abs_dirs/2]). -include_lib("kernel/include/file.hrl"). @@ -63,7 +64,6 @@ init_per_suite(Config, Level) -> start_slave(Config,Level) -> [_,Host] = string:tokens(atom_to_list(node()), "@"), - test_server:format(0, "Trying to start ~s~n", ["ct@"++Host]), case slave:start(Host, ct, []) of {error,Reason} -> @@ -72,18 +72,19 @@ start_slave(Config,Level) -> test_server:format(0, "Node ~p started~n", [CTNode]), IsCover = test_server:is_cover(), if IsCover -> - cover:start(CTNode); - true-> - ok + cover:start(CTNode); + true-> + ok end, - DataDir = ?config(data_dir, Config), - PrivDir = ?config(priv_dir, Config), + + DataDir = proplists:get_value(data_dir, Config), + PrivDir = proplists:get_value(priv_dir, Config), %% PrivDir as well as directory of Test Server suites %% have to be in code path on Common Test node. [_ | Parts] = lists:reverse(filename:split(DataDir)), TSDir = filename:join(lists:reverse(Parts)), - AddPathDirs = case ?config(path_dirs, Config) of + AddPathDirs = case proplists:get_value(path_dirs, Config) of undefined -> []; Ds -> Ds end, @@ -110,8 +111,8 @@ start_slave(Config,Level) -> %%% end_per_suite/1 end_per_suite(Config) -> - CTNode = ?config(ct_node, Config), - PrivDir = ?config(priv_dir, Config), + CTNode = proplists:get_value(ct_node, Config), + PrivDir = proplists:get_value(priv_dir, Config), true = rpc:call(CTNode, code, del_path, [filename:join(PrivDir,"")]), cover:stop(CTNode), slave:stop(CTNode), @@ -121,7 +122,9 @@ end_per_suite(Config) -> %%% init_per_testcase/2 init_per_testcase(_TestCase, Config) -> - {_,{_,LogDir}} = lists:keysearch(logdir, 1, get_opts(Config)), + Opts = get_opts(Config), + NetDir = proplists:get_value(net_dir, Opts), + LogDir = join_abs_dirs(NetDir, proplists:get_value(logdir, Opts)), case lists:keysearch(master, 1, Config) of false-> test_server:format("See Common Test logs here:\n\n" @@ -139,7 +142,7 @@ init_per_testcase(_TestCase, Config) -> %%% end_per_testcase/2 end_per_testcase(_TestCase, Config) -> - CTNode = ?config(ct_node, Config), + CTNode = proplists:get_value(ct_node, Config), case wait_for_ct_stop(CTNode) of %% Common test was not stopped to we restart node. false -> @@ -169,7 +172,7 @@ write_testspec(TestSpec, TSFile) -> %%% get_opts(Config) -> - PrivDir = ?config(priv_dir, Config), + PrivDir = proplists:get_value(priv_dir, Config), TempDir = case os:getenv("TMP") of false -> case os:getenv("TEMP") of @@ -195,20 +198,48 @@ get_opts(Config) -> _ -> TempDir end, - InitOpts = ?config(ct_opts, Config), - [{logdir,LogDir} | InitOpts]. + + %% Copy test variables to app environment on new node + CtTestVars = + case init:get_argument(ct_test_vars) of + {ok,[Vars]} -> + [begin {ok,Ts,_} = erl_scan:string(Str++"."), + {ok,Expr} = erl_parse:parse_term(Ts), + Expr + end || Str <- Vars]; + _ -> + [] + end, + %% test_server:format("Test variables added to Config: ~p\n\n", + %% [CtTestVars]), + InitOpts = + case proplists:get_value(ct_opts, Config) of + undefined -> []; + CtOpts -> CtOpts + end, + [{logdir,LogDir} | InitOpts ++ CtTestVars]. %%%----------------------------------------------------------------- %%% run(Opts, Config) -> - CTNode = ?config(ct_node, Config), - Level = ?config(trace_level, Config), + CTNode = proplists:get_value(ct_node, Config), + Level = proplists:get_value(trace_level, Config), %% use ct interface test_server:format(Level, "~n[RUN #1] Calling ct:run_test(~p) on ~p~n", [Opts, CTNode]), Result1 = rpc:call(CTNode, ct, run_test, [Opts]), + case rpc:call(CTNode, erlang, whereis, [ct_util_server]) of + undefined -> + ok; + _ -> + test_server:format(Level, + "ct_util_server not stopped on ~p yet, waiting 5 s...~n", + [CTNode]), + timer:sleep(5000), + undefined = rpc:call(CTNode, erlang, whereis, [ct_util_server]) + end, %% use run_test interface (simulated) test_server:format(Level, "Saving start opts on ~p: ~p~n", [CTNode,Opts]), rpc:call(CTNode, application, set_env, [common_test, run_test_start_opts, Opts]), @@ -224,8 +255,8 @@ run(Opts, Config) -> end. run(M, F, A, Config) -> - CTNode = ?config(ct_node, Config), - Level = ?config(trace_level, Config), + CTNode = proplists:get_value(ct_node, Config), + Level = proplists:get_value(trace_level, Config), test_server:format(Level, "~nCalling ~w:~w(~p) on ~p~n", [M, F, A, CTNode]), rpc:call(CTNode, M, F, A). @@ -261,11 +292,11 @@ handle_event(EH, Event) -> ok. start_event_receiver(Config) -> - CTNode = ?config(ct_node, Config), + CTNode = proplists:get_value(ct_node, Config), spawn_link(CTNode, fun() -> er() end). get_events(_, Config) -> - CTNode = ?config(ct_node, Config), + CTNode = proplists:get_value(ct_node, Config), {event_receiver,CTNode} ! {self(),get_events}, Events = receive {event_receiver,Evs} -> Evs end, {event_receiver,CTNode} ! stop, @@ -288,7 +319,7 @@ er_loop(Evs) -> end. verify_events(TEvs, Evs, Config) -> - Node = ?config(ct_node, Config), + Node = proplists:get_value(ct_node, Config), case catch verify_events1(TEvs, Evs, Node, Config) of {'EXIT',Reason} -> Reason; @@ -349,10 +380,15 @@ locate(TEvs, Node, Evs, Config) when is_list(TEvs) -> data={M,{init_per_group,GroupName,Props}}}}, {TEH,#event{name=tc_done, node=Node, - data={M,{init_per_group,GroupName,Props},R}}} | Evs1] -> - test_server:format("Found ~p!", [InitStart]), - test_server:format("Found ~p!", [InitDone]), - verify_events1(TEvs1, Evs1, Node, Config); + data={M,{init_per_group,GroupName,Props},Res}}} | Evs1] -> + case result_match(R, Res) of + false -> + nomatch; + true -> + test_server:format("Found ~p!", [InitStart]), + test_server:format("Found ~p!", [InitDone]), + verify_events1(TEvs1, Evs1, Node, Config) + end; _ -> nomatch end; @@ -384,9 +420,11 @@ locate({parallel,TEvs}, Node, Evs, Config) -> EvProps},EvR}}}) when TEH == EH, EvNode == Node, EvM == M, EvGroupName == GroupName, - EvProps == Props, - EvR == R -> - false; + EvProps == Props -> + case result_match(R, EvR) of + true -> false; + false -> true + end; ({EH,#event{name=stop_logging, node=EvNode,data=_}}) when EH == TEH, EvNode == Node -> @@ -466,7 +504,7 @@ locate({parallel,TEvs}, Node, Evs, Config) -> node=EvNode, data={Mod,Func,Result}}} <- Done, EH == TEH, EvNode == Node, Mod == M, - Func == F, Result == R] of + Func == F, result_match(R, Result)] of [TcDone|_] -> test_server:format("Found ~p!", [TEv]), {lists:delete(TcDone, Done),RemEvs,RemSize}; @@ -509,8 +547,13 @@ locate({parallel,TEvs}, Node, Evs, Config) -> data={Mod,{end_per_group, EvGName,EvProps},Res}}}) when EH == TEH, EvNode == Node, Mod == M, - EvGName == GroupName, EvProps == Props, Res == R -> - false; + EvGName == GroupName, EvProps == Props -> + case result_match(R, Res) of + true -> + false; + false -> + true + end; ({EH,#event{name=stop_logging, node=EvNode,data=_}}) when EH == TEH, EvNode == Node -> @@ -603,23 +646,29 @@ locate({shuffle,TEvs}, Node, Evs, Config) -> data={M,{init_per_group,GroupName,EvProps}}}}, {TEH,#event{name=tc_done, node=Node, - data={M,{init_per_group,GroupName,EvProps},R}}} | Es] -> - case proplists:get_value(shuffle, Props) of - '_' -> - case proplists:get_value(shuffle, EvProps) of - false -> - exit({no_shuffle_prop_found,{M,init_per_group, - GroupName,EvProps}}); + data={M,{init_per_group,GroupName,EvProps},Res}}} | Es] -> + case result_match(R, Res) of + true -> + case proplists:get_value(shuffle, Props) of + '_' -> + case proplists:get_value(shuffle, EvProps) of + false -> + exit({no_shuffle_prop_found, + {M,init_per_group, + GroupName,EvProps}}); + _ -> + PropsCmp = proplists:delete(shuffle, EvProps), + PropsCmp = proplists:delete(shuffle, Props) + end; _ -> - PropsCmp = proplists:delete(shuffle, EvProps), - PropsCmp = proplists:delete(shuffle, Props) - end; - _ -> - Props = EvProps - end, - test_server:format("Found ~p!", [InitStart]), - test_server:format("Found ~p!", [InitDone]), - {TEs,Es}; + Props = EvProps + end, + test_server:format("Found ~p!", [InitStart]), + test_server:format("Found ~p!", [InitDone]), + {TEs,Es}; + false -> + nomatch + end; _ -> nomatch end; @@ -670,7 +719,7 @@ locate({shuffle,TEvs}, Node, Evs, Config) -> node=EvNode, data={Mod,Func,Result}}} <- Done, EH == TEH, EvNode == Node, Mod == M, - Func == F, Result == R] of + Func == F, result_match(R, Result)] of [TcDone|_] -> test_server:format("Found ~p!", [TEv]), {lists:delete(TcDone, Done),RemEvs,RemSize}; @@ -726,8 +775,13 @@ locate({shuffle,TEvs}, Node, Evs, Config) -> data={Mod,{end_per_group, EvGName,_},Res}}}) when EH == TEH, EvNode == Node, Mod == M, - EvGName == GroupName, Res == R -> - false; + EvGName == GroupName -> + case result_match(R, Res) of + true -> + false; + false -> + true + end; ({EH,#event{name=stop_logging, node=EvNode,data=_}}) when EH == TEH, EvNode == Node -> @@ -864,25 +918,34 @@ locate({TEH,Name,{'DEF','STOP_TIME'}}, Node, [Ev|Evs], Config) -> nomatch end; -%% to match variable data as a result of a failed test case -locate({TEH,tc_done,{Mod,Func,{failed,{error,{Slogan,'_'}}}}}, Node, [Ev|Evs], Config) -> +%% to match variable data as a result of an aborted test case +locate({TEH,tc_done,{undefined,undefined,{testcase_aborted, + {abort_current_testcase,Func},'_'}}}, + Node, [Ev|Evs], Config) -> case Ev of - {TEH,#event{name=tc_done, node=Node, - data={Mod,Func,{failed,{error,{Slogan,_}}}}}} -> + {TEH,#event{name=tc_done, node=Node, + data={undefined,undefined, + {testcase_aborted,{abort_current_testcase,Func},_}}}} -> {Config,Evs}; _ -> nomatch end; -%% to match variable data as a result of an aborted test case -locate({TEH,tc_done,{undefined,undefined,{testcase_aborted, - {abort_current_testcase,Func},'_'}}}, - Node, [Ev|Evs], Config) -> +%% to match variable data as a result of a failed test case +locate({TEH,tc_done,{Mod,Func,R={SkipOrFail,{_ErrInd,ErrInfo}}}}, + Node, [Ev|Evs], Config) when ((SkipOrFail == skipped) or + (SkipOrFail == failed)) and + ((size(ErrInfo) == 2) or + (size(ErrInfo) == 3)) -> case Ev of {TEH,#event{name=tc_done, node=Node, - data={undefined,undefined, - {testcase_aborted,{abort_current_testcase,Func},_}}}} -> - {Config,Evs}; + data={Mod,Func,Result}}} -> + case result_match(R, Result) of + true -> + {Config,Evs}; + false -> + nomatch + end; _ -> nomatch end; @@ -931,14 +994,27 @@ match_data(Tuple1,Tuple2) when is_tuple(Tuple1),is_tuple(Tuple2) -> match_data([],[]) -> match. -log_events(TC, Events, PrivDir) -> - LogFile = filename:join(PrivDir, atom_to_list(TC)++".events"), +result_match({SkipOrFail,{ErrorInd,{Why,'_'}}}, + {SkipOrFail,{ErrorInd,{Why,_Stack}}}) -> + true; +result_match({SkipOrFail,{ErrorInd,{EMod,EFunc,{Why,'_'}}}}, + {SkipOrFail,{ErrorInd,{EMod,EFunc,{Why,_Stack}}}}) -> + true; +result_match(Result, Result) -> + true; +result_match(_, _) -> + false. + +log_events(TC, Events, EvLogDir, Opts) -> + LogFile = filename:join(EvLogDir, atom_to_list(TC)++".events"), {ok,Dev} = file:open(LogFile, [write]), io:format(Dev, "[~n", []), log_events1(Events, Dev, " "), file:close(Dev), + FullLogFile = join_abs_dirs(proplists:get_value(net_dir, Opts), + LogFile), io:format("Events written to logfile: <a href=\"file://~s\">~s</a>~n", - [LogFile,LogFile]), + [FullLogFile,FullLogFile]), io:format(user, "Events written to logfile: ~p~n", [LogFile]). log_events1(Evs, Dev, "") -> @@ -1024,13 +1100,25 @@ reformat([], _EH) -> %%%----------------------------------------------------------------- %%% MISC HELP FUNCTIONS +join_abs_dirs(undefined, Dir2) -> + Dir2; +join_abs_dirs(Dir1, Dir2) -> + case filename:pathtype(Dir2) of + relative -> + filename:join(Dir1, Dir2); + _ -> + [_Abs|Parts] = filename:split(Dir2), + filename:join(Dir1, filename:join(Parts)) + end. + create_tmp_logdir(Tmp) -> LogDir = filename:join(Tmp,"ct"), file:make_dir(LogDir), LogDir. delete_old_logs({win32,_}, Config) -> - case {?config(priv_dir, Config),?config(logdir, get_opts(Config))} of + case {proplists:get_value(priv_dir, Config), + proplists:get_value(logdir, get_opts(Config))} of {LogDir,LogDir} -> ignore; {_,LogDir} -> % using tmp for logs @@ -1042,7 +1130,8 @@ delete_old_logs(_, Config) -> false -> ignore; _ -> - catch delete_dirs(?config(logdir, get_opts(Config))) + catch delete_dirs(proplists:get_value(logdir, + get_opts(Config))) end. delete_dirs(LogDir) -> diff --git a/lib/common_test/test/ct_testspec_1_SUITE.erl b/lib/common_test/test/ct_testspec_1_SUITE.erl index 616c2db869..b6dcf63fdf 100644 --- a/lib/common_test/test/ct_testspec_1_SUITE.erl +++ b/lib/common_test/test/ct_testspec_1_SUITE.erl @@ -612,6 +612,12 @@ setup_and_execute(TCName, TestSpec, Config) -> false -> [{spec,SpecFile},{label,TCName}] end, {Opts,ERPid} = setup(TestTerms, Config), + + FullSpecFile = ct_test_support:join_abs_dirs(?config(net_dir, Opts), + SpecFile), + io:format("~nTest spec created here~n~n<a href=\"file://~s\">~s</a>~n", + [FullSpecFile,FullSpecFile]), + ok = ct_test_support:run(Opts, Config), TestSpec1 = [{logdir,proplists:get_value(logdir,Opts)}, {label,proplists:get_value(label,TestTerms)} | TestSpec], @@ -620,7 +626,8 @@ setup_and_execute(TCName, TestSpec, Config) -> ct_test_support:log_events(TCName, reformat(Events, ?eh), - ?config(priv_dir, Config)), + ?config(priv_dir, Config), + Opts), TestEvents = events_to_check(TCName), ok = ct_test_support:verify_events(TestEvents, Events, Config). @@ -631,8 +638,6 @@ create_spec_file(SpecDir, TCName, TestSpec) -> {ok,Dev} = file:open(FileName, [write]), [io:format(Dev, "~p.~n", [Term]) || Term <- TestSpec], file:close(Dev), - io:format("~nTest spec created here~n~n<a href=\"file://~s\">~s</a>~n", - [FileName,FileName]), FileName. setup(Test, Config) when is_tuple(Test) -> @@ -791,7 +796,9 @@ test_events(skip_group) -> {?eh,tc_done,{groups_11_SUITE,{end_per_group,test_group_1a,[]},'_'}}, {?eh,tc_user_skip, {groups_11_SUITE,{group,test_group_1b},"SKIPPED!"}}, - {?eh,test_stats,{2,0,{1,0}}}, + {?eh,tc_user_skip, {groups_11_SUITE,{group,test_group_2},"SKIPPED!"}}, + %%! But not test_group_7 since it's a sub-group! + {?eh,test_stats,{2,0,{2,0}}}, {negative,{?eh,tc_user_skip,'_'},{?eh,stop_logging,'_'}} ]; @@ -1188,10 +1195,9 @@ test_events(sub_skipped_by_top) -> {?eh,tc_start,{groups_12_SUITE,init_per_suite}}, {?eh,tc_user_skip,{groups_12_SUITE,{group,test_group_4},"SKIPPED!"}}, + {?eh,tc_user_skip,{groups_12_SUITE,{group,test_group_4},"SKIPPED!"}}, - {negative, - {?eh,tc_user_skip,{groups_12_SUITE,{group,test_group_4},"SKIPPED!"}}, - {?eh,tc_done,{groups_12_SUITE,end_per_suite,'_'}}}, + {?eh,tc_done,{groups_12_SUITE,end_per_suite,'_'}}, {negative,{?eh,tc_start,'_'},{?eh,stop_logging,'_'}} ]; diff --git a/lib/compiler/src/beam_bsm.erl b/lib/compiler/src/beam_bsm.erl index 2a36fda1ea..5cc8252b99 100644 --- a/lib/compiler/src/beam_bsm.erl +++ b/lib/compiler/src/beam_bsm.erl @@ -651,10 +651,8 @@ add_warning(Term, Anno, Ws) -> warning_translate_label(Term, D) when is_tuple(Term) -> case element(1, Term) of {label,F} -> - case gb_trees:lookup(F, D) of - none -> Term; - {value,FA} -> setelement(1, Term, FA) - end; + FA = gb_trees:get(F, D), + setelement(1, Term, FA); _ -> Term end; warning_translate_label(Term, _) -> Term. diff --git a/lib/compiler/src/beam_dead.erl b/lib/compiler/src/beam_dead.erl index bb93110176..8e96569414 100644 --- a/lib/compiler/src/beam_dead.erl +++ b/lib/compiler/src/beam_dead.erl @@ -162,14 +162,11 @@ function({function,Name,Arity,CLabel,Is0}, Lc0) -> %% We must split the basic block when we encounter instructions with labels, %% such as catches and BIFs. All labels must be visible outside the blocks. -%% Also remove empty blocks. split_blocks({function,Name,Arity,CLabel,Is0}) -> Is = split_blocks(Is0, []), {function,Name,Arity,CLabel,Is}. -split_blocks([{block,[]}|Is], Acc) -> - split_blocks(Is, Acc); split_blocks([{block,Bl}|Is], Acc0) -> Acc = split_block(Bl, [], Acc0), split_blocks(Is, Acc); @@ -246,30 +243,24 @@ forward([{select_val,Reg,_,{list,List}}=I|Is], D0, Lc, Acc) -> D = update_value_dict(List, Reg, D0), forward(Is, D, Lc, [I|Acc]); forward([{label,Lbl}=LblI,{block,[{set,[Dst],[Lit],move}|BlkIs]}=Blk|Is], D, Lc, Acc) -> + %% Assumption: The target labels in a select_val/3 instruction + %% cannot be reached in any other way than through the select_val/3 + %% instruction (i.e. there can be no fallthrough to such label and + %% it cannot be referenced by, for example, a jump/1 instruction). Block = case gb_trees:lookup({Lbl,Dst}, D) of - {value,Lit} -> - %% The move instruction seems to be redundant, but also make - %% sure that the instruction preceeding the label - %% cannot fall through to the move instruction. - case is_unreachable_after(Acc) of - false -> Blk; %Must keep move instruction. - true -> {block,BlkIs} %Safe to remove move instruction. - end; - _ -> Blk %Keep move instruction. + {value,Lit} -> {block,BlkIs}; %Safe to remove move instruction. + _ -> Blk %Must keep move instruction. end, forward([Block|Is], D, Lc, [LblI|Acc]); forward([{label,Lbl}=LblI|[{move,Lit,Dst}|Is1]=Is0], D, Lc, Acc) -> + %% Assumption: The target labels in a select_val/3 instruction + %% cannot be reached in any other way than through the select_val/3 + %% instruction (i.e. there can be no fallthrough to such label and + %% it cannot be referenced by, for example, a jump/1 instruction). Is = case gb_trees:lookup({Lbl,Dst}, D) of - {value,Lit} -> - %% The move instruction seems to be redundant, but also make - %% sure that the instruction preceeding the label - %% cannot fall through to the move instruction. - case is_unreachable_after(Acc) of - false -> Is0; %Must keep move instruction. - true -> Is1 %Safe to remove move instruction. - end; - _ -> Is0 %Keep move instruction. - end, + {value,Lit} -> Is1; %Safe to remove move instruction. + _ -> Is0 %Keep move instruction. + end, forward(Is, D, Lc, [LblI|Acc]); forward([{test,is_eq_exact,_,[Dst,Src]}=I, {block,[{set,[Dst],[Src],move}|Bl]}|Is], D, Lc, Acc) -> @@ -299,16 +290,12 @@ update_value_dict([Lit,{f,Lbl}|T], Reg, D0) -> Key = {Lbl,Reg}, D = case gb_trees:lookup(Key, D0) of none -> gb_trees:insert(Key, Lit, D0); %New. - {value,Lit} -> D0; %Already correct. {value,inconsistent} -> D0; %Inconsistent. {value,_} -> gb_trees:update(Key, inconsistent, D0) end, update_value_dict(T, Reg, D); update_value_dict([], _, D) -> D. -is_unreachable_after([I|_]) -> - beam_jump:is_unreachable_after(I). - %%% %%% Scan instructions in reverse execution order and remove dead code. %%% @@ -602,16 +589,11 @@ count_bits_matched([{test,_,_,_}|Is], SavePoint, Bits) -> count_bits_matched([{bs_save2,Reg,SavePoint}|_], {Reg,SavePoint}, Bits) -> %% The save point we are looking for - we are done. Bits; -count_bits_matched([{bs_save2,_,_}|Is], SavePoint, Bits) -> - %% Another save point - keep counting. - count_bits_matched(Is, SavePoint, Bits); count_bits_matched([_|_], _, Bits) -> Bits. shortcut_bs_pos_used(To, Reg, D) -> shortcut_bs_pos_used_1(beam_utils:code_at(To, D), Reg, D). -shortcut_bs_pos_used_1([{bs_restore2,Reg,_}|_], Reg, _) -> - false; shortcut_bs_pos_used_1([{bs_context_to_binary,Reg}|_], Reg, _) -> false; shortcut_bs_pos_used_1(Is, Reg, D) -> diff --git a/lib/compiler/src/beam_dict.erl b/lib/compiler/src/beam_dict.erl index a503fcab38..c50ed28aa9 100644 --- a/lib/compiler/src/beam_dict.erl +++ b/lib/compiler/src/beam_dict.erl @@ -36,7 +36,6 @@ strings = <<>> :: binary(), %String pool lambdas = [], %[{...}] literals = dict:new() :: dict(), %Format: {Literal,Number} - next_atom = 1 :: pos_integer(), next_import = 0 :: non_neg_integer(), string_offset = 0 :: non_neg_integer(), next_literal = 0 :: non_neg_integer(), @@ -66,13 +65,14 @@ highest_opcode(#asm{highest_opcode=Op}) -> Op. %% atom(Atom, Dict) -> {Index,Dict'} -spec atom(atom(), bdict()) -> {pos_integer(), bdict()}. -atom(Atom, #asm{atoms=Atoms0,next_atom=NextIndex}=Dict) when is_atom(Atom) -> +atom(Atom, #asm{atoms=Atoms0}=Dict) when is_atom(Atom) -> case gb_trees:lookup(Atom, Atoms0) of {value,Index} -> {Index,Dict}; none -> + NextIndex = gb_trees:size(Atoms0) + 1, Atoms = gb_trees:insert(Atom, NextIndex, Atoms0), - {NextIndex,Dict#asm{atoms=Atoms,next_atom=NextIndex+1}} + {NextIndex,Dict#asm{atoms=Atoms}} end. %% Remembers an exported function. @@ -139,7 +139,7 @@ lambda(Lbl, Index, OldUniq, NumFree, #asm{lambdas=Lambdas0}=Dict) -> Lambdas = [{Lbl,{OldIndex,Lbl,Index,NumFree,OldUniq}}|Lambdas0], {OldIndex,Dict#asm{lambdas=Lambdas}}. -%% Returns the index for a literal (adding it to the atom table if necessary). +%% Returns the index for a literal (adding it to the literal table if necessary). %% literal(Literal, Dict) -> {Index,Dict'} -spec literal(term(), bdict()) -> {non_neg_integer(), bdict()}. @@ -156,14 +156,15 @@ literal(Lit, #asm{literals=Tab0,next_literal=NextIndex}=Dict) -> %% atom_table(Dict) -> {LastIndex,[Length,AtomString...]} -spec atom_table(bdict()) -> {non_neg_integer(), [[non_neg_integer(),...]]}. -atom_table(#asm{atoms=Atoms,next_atom=NumAtoms}) -> +atom_table(#asm{atoms=Atoms}) -> + NumAtoms = gb_trees:size(Atoms), Sorted = lists:keysort(2, gb_trees:to_list(Atoms)), Fun = fun({A,_}) -> L = atom_to_list(A), [length(L)|L] end, AtomTab = lists:map(Fun, Sorted), - {NumAtoms-1,AtomTab}. + {NumAtoms,AtomTab}. %% Returns the table of local functions. %% local_table(Dict) -> {NumLocals, [{Function, Arity, Label}...]} diff --git a/lib/compiler/src/sys_core_fold.erl b/lib/compiler/src/sys_core_fold.erl index 96015fbe58..9360556e00 100644 --- a/lib/compiler/src/sys_core_fold.erl +++ b/lib/compiler/src/sys_core_fold.erl @@ -460,7 +460,8 @@ eval_binary(#c_binary{anno=Anno,segments=Ss}=Bin) -> Bin; throw:{badarg,Warning} -> add_warning(Bin, Warning), - #c_call{module=#c_literal{val=erlang}, + #c_call{anno=Anno, + module=#c_literal{val=erlang}, name=#c_literal{val=error}, args=[#c_literal{val=badarg}]} end. @@ -658,36 +659,34 @@ call_0(Call, M, N, As0, Sub) -> %% We inline some very common higher order list operations. %% We use the same evaluation order as the library function. -call_1(_Call, lists, all, [Arg1,Arg2], Sub) -> +call_1(#c_call{anno=Anno}, lists, all, [Arg1,Arg2], Sub) -> Loop = #c_var{name={'lists^all',1}}, F = #c_var{name='F'}, Xs = #c_var{name='Xs'}, X = #c_var{name='X'}, Err1 = #c_tuple{es=[#c_literal{val='case_clause'}, X]}, CC1 = #c_clause{pats=[#c_literal{val=true}], guard=#c_literal{val=true}, - body=#c_apply{op=Loop, args=[Xs]}}, + body=#c_apply{anno=Anno, op=Loop, args=[Xs]}}, CC2 = #c_clause{pats=[#c_literal{val=false}], guard=#c_literal{val=true}, body=#c_literal{val=false}}, CC3 = #c_clause{pats=[X], guard=#c_literal{val=true}, - body=#c_primop{name=#c_literal{val='match_fail'}, - args=[Err1]}}, + body=match_fail(Anno, Err1)}, C1 = #c_clause{pats=[#c_cons{hd=X, tl=Xs}], guard=#c_literal{val=true}, - body=#c_case{arg=#c_apply{op=F, args=[X]}, + body=#c_case{arg=#c_apply{anno=Anno, op=F, args=[X]}, clauses = [CC1, CC2, CC3]}}, C2 = #c_clause{pats=[#c_literal{val=[]}], guard=#c_literal{val=true}, body=#c_literal{val=true}}, Err2 = #c_tuple{es=[#c_literal{val='function_clause'}, Xs]}, C3 = #c_clause{pats=[Xs], guard=#c_literal{val=true}, - body=#c_primop{name=#c_literal{val='match_fail'}, - args=[Err2]}}, + body=match_fail(Anno, Err2)}, Fun = #c_fun{vars=[Xs], body=#c_case{arg=Xs, clauses=[C1, C2, C3]}}, L = #c_var{name='L'}, expr(#c_let{vars=[F, L], arg=#c_values{es=[Arg1, Arg2]}, body=#c_letrec{defs=[{Loop,Fun}], - body=#c_apply{op=Loop, args=[L]}}}, + body=#c_apply{anno=Anno, op=Loop, args=[L]}}}, Sub); -call_1(_Call, lists, any, [Arg1,Arg2], Sub) -> +call_1(#c_call{anno=Anno}, lists, any, [Arg1,Arg2], Sub) -> Loop = #c_var{name={'lists^any',1}}, F = #c_var{name='F'}, Xs = #c_var{name='Xs'}, @@ -696,72 +695,71 @@ call_1(_Call, lists, any, [Arg1,Arg2], Sub) -> CC1 = #c_clause{pats=[#c_literal{val=true}], guard=#c_literal{val=true}, body=#c_literal{val=true}}, CC2 = #c_clause{pats=[#c_literal{val=false}], guard=#c_literal{val=true}, - body=#c_apply{op=Loop, args=[Xs]}}, + body=#c_apply{anno=Anno, op=Loop, args=[Xs]}}, CC3 = #c_clause{pats=[X], guard=#c_literal{val=true}, - body=#c_primop{name=#c_literal{val='match_fail'}, - args=[Err1]}}, + body=match_fail(Anno, Err1)}, C1 = #c_clause{pats=[#c_cons{hd=X, tl=Xs}], guard=#c_literal{val=true}, - body=#c_case{arg=#c_apply{op=F, args=[X]}, + body=#c_case{arg=#c_apply{anno=Anno, op=F, args=[X]}, clauses = [CC1, CC2, CC3]}}, C2 = #c_clause{pats=[#c_literal{val=[]}], guard=#c_literal{val=true}, body=#c_literal{val=false}}, Err2 = #c_tuple{es=[#c_literal{val='function_clause'}, Xs]}, C3 = #c_clause{pats=[Xs], guard=#c_literal{val=true}, - body=#c_primop{name=#c_literal{val='match_fail'}, - args=[Err2]}}, + body=match_fail(Anno, Err2)}, Fun = #c_fun{vars=[Xs], body=#c_case{arg=Xs, clauses=[C1, C2, C3]}}, L = #c_var{name='L'}, expr(#c_let{vars=[F, L], arg=#c_values{es=[Arg1, Arg2]}, body=#c_letrec{defs=[{Loop,Fun}], - body=#c_apply{op=Loop, args=[L]}}}, + body=#c_apply{anno=Anno, op=Loop, args=[L]}}}, Sub); -call_1(_Call, lists, foreach, [Arg1,Arg2], Sub) -> +call_1(#c_call{anno=Anno}, lists, foreach, [Arg1,Arg2], Sub) -> Loop = #c_var{name={'lists^foreach',1}}, F = #c_var{name='F'}, Xs = #c_var{name='Xs'}, X = #c_var{name='X'}, C1 = #c_clause{pats=[#c_cons{hd=X, tl=Xs}], guard=#c_literal{val=true}, - body=#c_seq{arg=#c_apply{op=F, args=[X]}, - body=#c_apply{op=Loop, args=[Xs]}}}, + body=#c_seq{arg=#c_apply{anno=Anno, op=F, args=[X]}, + body=#c_apply{anno=Anno, op=Loop, args=[Xs]}}}, C2 = #c_clause{pats=[#c_literal{val=[]}], guard=#c_literal{val=true}, body=#c_literal{val=ok}}, Err = #c_tuple{es=[#c_literal{val='function_clause'}, Xs]}, C3 = #c_clause{pats=[Xs], guard=#c_literal{val=true}, - body=#c_primop{name=#c_literal{val='match_fail'}, - args=[Err]}}, + body=match_fail(Anno, Err)}, Fun = #c_fun{vars=[Xs], body=#c_case{arg=Xs, clauses=[C1, C2, C3]}}, L = #c_var{name='L'}, expr(#c_let{vars=[F, L], arg=#c_values{es=[Arg1, Arg2]}, body=#c_letrec{defs=[{Loop,Fun}], - body=#c_apply{op=Loop, args=[L]}}}, + body=#c_apply{anno=Anno, op=Loop, args=[L]}}}, Sub); -call_1(_Call, lists, map, [Arg1,Arg2], Sub) -> +call_1(#c_call{anno=Anno}, lists, map, [Arg1,Arg2], Sub) -> Loop = #c_var{name={'lists^map',1}}, F = #c_var{name='F'}, Xs = #c_var{name='Xs'}, X = #c_var{name='X'}, H = #c_var{name='H'}, C1 = #c_clause{pats=[#c_cons{hd=X, tl=Xs}], guard=#c_literal{val=true}, - body=#c_let{vars=[H], arg=#c_apply{op=F, args=[X]}, + body=#c_let{vars=[H], arg=#c_apply{anno=Anno, + op=F, + args=[X]}, body=#c_cons{hd=H, - tl=#c_apply{op=Loop, + tl=#c_apply{anno=Anno, + op=Loop, args=[Xs]}}}}, C2 = #c_clause{pats=[#c_literal{val=[]}], guard=#c_literal{val=true}, body=#c_literal{val=[]}}, Err = #c_tuple{es=[#c_literal{val='function_clause'}, Xs]}, C3 = #c_clause{pats=[Xs], guard=#c_literal{val=true}, - body=#c_primop{name=#c_literal{val='match_fail'}, - args=[Err]}}, + body=match_fail(Anno, Err)}, Fun = #c_fun{vars=[Xs], body=#c_case{arg=Xs, clauses=[C1, C2, C3]}}, L = #c_var{name='L'}, expr(#c_let{vars=[F, L], arg=#c_values{es=[Arg1, Arg2]}, body=#c_letrec{defs=[{Loop,Fun}], - body=#c_apply{op=Loop, args=[L]}}}, + body=#c_apply{anno=Anno, op=Loop, args=[L]}}}, Sub); -call_1(_Call, lists, flatmap, [Arg1,Arg2], Sub) -> +call_1(#c_call{anno=Anno}, lists, flatmap, [Arg1,Arg2], Sub) -> Loop = #c_var{name={'lists^flatmap',1}}, F = #c_var{name='F'}, Xs = #c_var{name='Xs'}, @@ -769,26 +767,27 @@ call_1(_Call, lists, flatmap, [Arg1,Arg2], Sub) -> H = #c_var{name='H'}, C1 = #c_clause{pats=[#c_cons{hd=X, tl=Xs}], guard=#c_literal{val=true}, body=#c_let{vars=[H], - arg=#c_apply{op=F, args=[X]}, - body=#c_call{module=#c_literal{val=erlang}, + arg=#c_apply{anno=Anno, op=F, args=[X]}, + body=#c_call{anno=Anno, + module=#c_literal{val=erlang}, name=#c_literal{val='++'}, args=[H, - #c_apply{op=Loop, + #c_apply{anno=Anno, + op=Loop, args=[Xs]}]}}}, C2 = #c_clause{pats=[#c_literal{val=[]}], guard=#c_literal{val=true}, body=#c_literal{val=[]}}, Err = #c_tuple{es=[#c_literal{val='function_clause'}, Xs]}, C3 = #c_clause{pats=[Xs], guard=#c_literal{val=true}, - body=#c_primop{name=#c_literal{val='match_fail'}, - args=[Err]}}, + body=match_fail(Anno, Err)}, Fun = #c_fun{vars=[Xs], body=#c_case{arg=Xs, clauses=[C1, C2, C3]}}, L = #c_var{name='L'}, expr(#c_let{vars=[F, L], arg=#c_values{es=[Arg1, Arg2]}, body=#c_letrec{defs=[{Loop,Fun}], - body=#c_apply{op=Loop, args=[L]}}}, + body=#c_apply{anno=Anno, op=Loop, args=[L]}}}, Sub); -call_1(_Call, lists, filter, [Arg1,Arg2], Sub) -> +call_1(#c_call{anno=Anno}, lists, filter, [Arg1,Arg2], Sub) -> Loop = #c_var{name={'lists^filter',1}}, F = #c_var{name='F'}, Xs = #c_var{name='Xs'}, @@ -800,72 +799,75 @@ call_1(_Call, lists, filter, [Arg1,Arg2], Sub) -> CC2 = #c_clause{pats=[#c_literal{val=false}], guard=#c_literal{val=true}, body=Xs}, CC3 = #c_clause{pats=[X], guard=#c_literal{val=true}, - body=#c_primop{name=#c_literal{val='match_fail'}, - args=[Err1]}}, + body=match_fail(Anno, Err1)}, Case = #c_case{arg=B, clauses = [CC1, CC2, CC3]}, C1 = #c_clause{pats=[#c_cons{hd=X, tl=Xs}], guard=#c_literal{val=true}, body=#c_let{vars=[B], - arg=#c_apply{op=F, args=[X]}, + arg=#c_apply{anno=Anno, op=F, args=[X]}, body=#c_let{vars=[Xs], - arg=#c_apply{op=Loop, + arg=#c_apply{anno=Anno, + op=Loop, args=[Xs]}, body=Case}}}, C2 = #c_clause{pats=[#c_literal{val=[]}], guard=#c_literal{val=true}, body=#c_literal{val=[]}}, Err2 = #c_tuple{es=[#c_literal{val='function_clause'}, Xs]}, C3 = #c_clause{pats=[Xs], guard=#c_literal{val=true}, - body=#c_primop{name=#c_literal{val='match_fail'}, - args=[Err2]}}, + body=match_fail(Anno, Err2)}, Fun = #c_fun{vars=[Xs], body=#c_case{arg=Xs, clauses=[C1, C2, C3]}}, L = #c_var{name='L'}, expr(#c_let{vars=[F, L], arg=#c_values{es=[Arg1, Arg2]}, body=#c_letrec{defs=[{Loop,Fun}], - body=#c_apply{op=Loop, args=[L]}}}, + body=#c_apply{anno=Anno, op=Loop, args=[L]}}}, Sub); -call_1(_Call, lists, foldl, [Arg1,Arg2,Arg3], Sub) -> +call_1(#c_call{anno=Anno}, lists, foldl, [Arg1,Arg2,Arg3], Sub) -> Loop = #c_var{name={'lists^foldl',2}}, F = #c_var{name='F'}, Xs = #c_var{name='Xs'}, X = #c_var{name='X'}, A = #c_var{name='A'}, C1 = #c_clause{pats=[#c_cons{hd=X, tl=Xs}], guard=#c_literal{val=true}, - body=#c_apply{op=Loop, - args=[Xs, #c_apply{op=F, args=[X, A]}]}}, + body=#c_apply{anno=Anno, + op=Loop, + args=[Xs, #c_apply{anno=Anno, + op=F, + args=[X, A]}]}}, C2 = #c_clause{pats=[#c_literal{val=[]}], guard=#c_literal{val=true}, body=A}, Err = #c_tuple{es=[#c_literal{val='function_clause'}, Xs]}, C3 = #c_clause{pats=[Xs], guard=#c_literal{val=true}, - body=#c_primop{name=#c_literal{val='match_fail'}, - args=[Err]}}, + body=match_fail(Anno, Err)}, Fun = #c_fun{vars=[Xs, A], body=#c_case{arg=Xs, clauses=[C1, C2, C3]}}, L = #c_var{name='L'}, expr(#c_let{vars=[F, A, L], arg=#c_values{es=[Arg1, Arg2, Arg3]}, body=#c_letrec{defs=[{Loop,Fun}], - body=#c_apply{op=Loop, args=[L, A]}}}, + body=#c_apply{anno=Anno, op=Loop, args=[L, A]}}}, Sub); -call_1(_Call, lists, foldr, [Arg1,Arg2,Arg3], Sub) -> +call_1(#c_call{anno=Anno}, lists, foldr, [Arg1,Arg2,Arg3], Sub) -> Loop = #c_var{name={'lists^foldr',2}}, F = #c_var{name='F'}, Xs = #c_var{name='Xs'}, X = #c_var{name='X'}, A = #c_var{name='A'}, C1 = #c_clause{pats=[#c_cons{hd=X, tl=Xs}], guard=#c_literal{val=true}, - body=#c_apply{op=F, args=[X, #c_apply{op=Loop, - args=[Xs, A]}]}}, + body=#c_apply{anno=Anno, + op=F, + args=[X, #c_apply{anno=Anno, + op=Loop, + args=[Xs, A]}]}}, C2 = #c_clause{pats=[#c_literal{val=[]}], guard=#c_literal{val=true}, body=A}, Err = #c_tuple{es=[#c_literal{val='function_clause'}, Xs]}, C3 = #c_clause{pats=[Xs], guard=#c_literal{val=true}, - body=#c_primop{name=#c_literal{val='match_fail'}, - args=[Err]}}, + body=match_fail(Anno, Err)}, Fun = #c_fun{vars=[Xs, A], body=#c_case{arg=Xs, clauses=[C1, C2, C3]}}, L = #c_var{name='L'}, expr(#c_let{vars=[F, A, L], arg=#c_values{es=[Arg1, Arg2, Arg3]}, body=#c_letrec{defs=[{Loop,Fun}], - body=#c_apply{op=Loop, args=[L, A]}}}, + body=#c_apply{anno=Anno, op=Loop, args=[L, A]}}}, Sub); -call_1(_Call, lists, mapfoldl, [Arg1,Arg2,Arg3], Sub) -> +call_1(#c_call{anno=Anno}, lists, mapfoldl, [Arg1,Arg2,Arg3], Sub) -> Loop = #c_var{name={'lists^mapfoldl',2}}, F = #c_var{name='F'}, Xs = #c_var{name='Xs'}, @@ -876,15 +878,16 @@ call_1(_Call, lists, mapfoldl, [Arg1,Arg2,Arg3], Sub) -> C1 = #c_clause{pats=[P], guard=#c_literal{val=true}, body=E}, Err = #c_tuple{es=[#c_literal{val='badmatch'}, X]}, C2 = #c_clause{pats=[X], guard=#c_literal{val=true}, - body=#c_primop{name=#c_literal{val='match_fail'}, - args=[Err]}}, + body=match_fail(Anno, Err)}, #c_case{arg=A, clauses=[C1, C2]} end, C1 = #c_clause{pats=[#c_cons{hd=X, tl=Xs}], guard=#c_literal{val=true}, - body=Match(#c_apply{op=F, args=[X, Avar]}, + body=Match(#c_apply{anno=Anno, op=F, args=[X, Avar]}, #c_tuple{es=[X, Avar]}, %%% Tuple passing version - Match(#c_apply{op=Loop, args=[Xs, Avar]}, + Match(#c_apply{anno=Anno, + op=Loop, + args=[Xs, Avar]}, #c_tuple{es=[Xs, Avar]}, #c_tuple{es=[#c_cons{hd=X, tl=Xs}, Avar]}) %%% Multiple-value version @@ -902,22 +905,23 @@ call_1(_Call, lists, mapfoldl, [Arg1,Arg2,Arg3], Sub) -> %%% body=#c_values{es=[#c_literal{val=[]}, A]}}, Err = #c_tuple{es=[#c_literal{val='function_clause'}, Xs]}, C3 = #c_clause{pats=[Xs], guard=#c_literal{val=true}, - body=#c_primop{name=#c_literal{val='match_fail'}, - args=[Err]}}, + body=match_fail(Anno, Err)}, Fun = #c_fun{vars=[Xs, Avar], body=#c_case{arg=Xs, clauses=[C1, C2, C3]}}, L = #c_var{name='L'}, expr(#c_let{vars=[F, Avar, L], arg=#c_values{es=[Arg1, Arg2, Arg3]}, body=#c_letrec{defs=[{Loop,Fun}], %%% Tuple passing version - body=#c_apply{op=Loop, args=[L, Avar]}}}, + body=#c_apply{anno=Anno, + op=Loop, + args=[L, Avar]}}}, %%% Multiple-value version %%% body=#c_let{vars=[Xs, A], %%% arg=#c_apply{op=Loop, %%% args=[L, A]}, %%% body=#c_tuple{es=[Xs, A]}}}}, Sub); -call_1(_Call, lists, mapfoldr, [Arg1,Arg2,Arg3], Sub) -> +call_1(#c_call{anno=Anno}, lists, mapfoldr, [Arg1,Arg2,Arg3], Sub) -> Loop = #c_var{name={'lists^mapfoldr',2}}, F = #c_var{name='F'}, Xs = #c_var{name='Xs'}, @@ -928,15 +932,16 @@ call_1(_Call, lists, mapfoldr, [Arg1,Arg2,Arg3], Sub) -> C1 = #c_clause{pats=[P], guard=#c_literal{val=true}, body=E}, Err = #c_tuple{es=[#c_literal{val='badmatch'}, X]}, C2 = #c_clause{pats=[X], guard=#c_literal{val=true}, - body=#c_primop{name=#c_literal{val='match_fail'}, - args=[Err]}}, + body=match_fail(Anno, Err)}, #c_case{arg=A, clauses=[C1, C2]} end, C1 = #c_clause{pats=[#c_cons{hd=X, tl=Xs}], guard=#c_literal{val=true}, %%% Tuple passing version - body=Match(#c_apply{op=Loop, args=[Xs, Avar]}, + body=Match(#c_apply{anno=Anno, + op=Loop, + args=[Xs, Avar]}, #c_tuple{es=[Xs, Avar]}, - Match(#c_apply{op=F, args=[X, Avar]}, + Match(#c_apply{anno=Anno, op=F, args=[X, Avar]}, #c_tuple{es=[X, Avar]}, #c_tuple{es=[#c_cons{hd=X, tl=Xs}, Avar]})) %%% Multiple-value version @@ -955,15 +960,16 @@ call_1(_Call, lists, mapfoldr, [Arg1,Arg2,Arg3], Sub) -> %%% body=#c_values{es=[#c_literal{val=[]}, A]}}, Err = #c_tuple{es=[#c_literal{val='function_clause'}, Xs]}, C3 = #c_clause{pats=[Xs], guard=#c_literal{val=true}, - body=#c_primop{name=#c_literal{val='match_fail'}, - args=[Err]}}, + body=match_fail(Anno, Err)}, Fun = #c_fun{vars=[Xs, Avar], body=#c_case{arg=Xs, clauses=[C1, C2, C3]}}, L = #c_var{name='L'}, expr(#c_let{vars=[F, Avar, L], arg=#c_values{es=[Arg1, Arg2, Arg3]}, body=#c_letrec{defs=[{Loop,Fun}], %%% Tuple passing version - body=#c_apply{op=Loop, args=[L, Avar]}}}, + body=#c_apply{anno=Anno, + op=Loop, + args=[L, Avar]}}}, %%% Multiple-value version %%% body=#c_let{vars=[Xs, A], %%% arg=#c_apply{op=Loop, @@ -973,6 +979,11 @@ call_1(_Call, lists, mapfoldr, [Arg1,Arg2,Arg3], Sub) -> call_1(#c_call{module=M, name=N}=Call, _, _, As, Sub) -> call_0(Call, M, N, As, Sub). +match_fail(Anno, Arg) -> + #c_primop{anno=Anno, + name=#c_literal{val='match_fail'}, + args=[Arg]}. + %% fold_call(Call, Mod, Name, Args, Sub) -> Expr. %% Try to safely evaluate the call. Just try to evaluate arguments, %% do the call and convert return values to literals. If this @@ -1280,9 +1291,9 @@ eval_setelement_2(Pos, [H|T], NewVal) when Pos > 1 -> %% eval_failure(Call, Reason) -> add_warning(Call, {eval_failure,Reason}), - #c_call{module=#c_literal{val=erlang}, - name=#c_literal{val=error}, - args=[#c_literal{val=Reason}]}. + Call#c_call{module=#c_literal{val=erlang}, + name=#c_literal{val=error}, + args=[#c_literal{val=Reason}]}. %% simplify_apply(Call0, Mod, Func, Args) -> Call %% Simplify an apply/3 to a call if the number of arguments @@ -1742,23 +1753,24 @@ opt_bool_clauses([_|_], _, _) -> opt_bool_not(#c_case{arg=Arg,clauses=Cs0}=Case0) -> case Arg of - #c_call{module=#c_literal{val=erlang}, + #c_call{anno=Anno,module=#c_literal{val=erlang}, name=#c_literal{val='not'}, args=[Expr]} -> - Cs = opt_bool_not(Expr, Cs0), + Cs = opt_bool_not(Anno, Expr, Cs0), Case = Case0#c_case{arg=Expr,clauses=Cs}, opt_bool_not(Case); _ -> opt_bool_case_redundant(Case0) end. -opt_bool_not(Expr, Cs) -> +opt_bool_not(Anno, Expr, Cs) -> Tail = case is_bool_expr(Expr) of false -> [#c_clause{anno=[compiler_generated], pats=[#c_var{name=cor_variable}], guard=#c_literal{val=true}, - body=#c_call{module=#c_literal{val=erlang}, + body=#c_call{anno=Anno, + module=#c_literal{val=erlang}, name=#c_literal{val=error}, args=[#c_literal{val=badarg}]}}]; true -> [] @@ -1957,13 +1969,25 @@ case_tuple_pat([#c_tuple{es=Ps}], Arity) when length(Ps) =:= Arity -> case_tuple_pat([#c_literal{val=T}], Arity) when tuple_size(T) =:= Arity -> Ps = [#c_literal{val=E} || E <- tuple_to_list(T)], {ok,Ps,[]}; -case_tuple_pat([#c_var{anno=A}=V], Arity) -> - Vars = make_vars(A, 1, Arity), - {ok,Vars,[{V,#c_tuple{es=Vars}}]}; +case_tuple_pat([#c_var{anno=Anno0}=V], Arity) -> + Vars = make_vars(Anno0, 1, Arity), + + %% If the entire case statement is evaluated in an effect + %% context (e.g. "case {A,B} of ... end, ok"), there will + %% be a warning that a term is constructed but never used. + %% To avoid that warning, we must annotate the tuple as + %% compiler generated. + + Anno = [compiler_generated|Anno0], + {ok,Vars,[{V,#c_tuple{anno=Anno,es=Vars}}]}; case_tuple_pat([#c_alias{var=V,pat=P}], Arity) -> case case_tuple_pat([P], Arity) of - {ok,Ps,Avs} -> {ok,Ps,[{V,#c_tuple{es=unalias_pat_list(Ps)}}|Avs]}; - error -> error + {ok,Ps,Avs} -> + Anno0 = core_lib:get_anno(P), + Anno = [compiler_generated|Anno0], + {ok,Ps,[{V,#c_tuple{anno=Anno,es=unalias_pat_list(Ps)}}|Avs]}; + error -> + error end; case_tuple_pat(_, _) -> error. diff --git a/lib/compiler/src/v3_core.erl b/lib/compiler/src/v3_core.erl index 2da24b2908..e1a593fffa 100644 --- a/lib/compiler/src/v3_core.erl +++ b/lib/compiler/src/v3_core.erl @@ -1820,7 +1820,21 @@ upattern_list([], _, St) -> {[],[],[],[],St}. %% upat_bin([Pat], [KnownVar], State) -> %% {[Pat],[GuardTest],[NewVar],[UsedVar],State}. upat_bin(Es0, Ks, St0) -> - upat_bin(Es0, Ks, [], St0). + {Es1,Pg,Pv,Pu0,St1} = upat_bin(Es0, Ks, [], St0), + + %% In a clause such as <<Sz:8,V:Sz>> in a function head, Sz will both + %% be new and used; a situation that is not handled properly by + %% uclause/4. (Basically, since Sz occurs in two sets that are + %% subtracted from each other, Sz will not be added to the list of + %% known variables and will seem to be new the next time it is + %% used in a match.) + %% Since the variable Sz really is new (it does not use a + %% value bound prior to the binary matching), Sz should only be + %% included in the set of new variables. Thus we should take it + %% out of the set of used variables. + + Pu1 = subtract(Pu0, intersection(Pv, Pu0)), + {Es1,Pg,Pv,Pu1,St1}. %% upat_bin([Pat], [KnownVar], [LocalVar], State) -> %% {[Pat],[GuardTest],[NewVar],[UsedVar],State}. @@ -1832,35 +1846,36 @@ upat_bin([], _, _, St) -> {[],[],[],[],St}. %% upat_element(Segment, [KnownVar], [LocalVar], State) -> -%% {Segment,[GuardTest],[NewVar],[UsedVar],[LocalVar],State} -upat_element(#c_bitstr{val=H0,size=Sz}=Seg, Ks, Bs, St0) -> - {H1,Hg,Hv,[],St1} = upattern(H0, Ks, St0), - Bs1 = case H0 of - #c_var{name=Hname} -> - case H1 of +%% {Segment,[GuardTest],[NewVar],[UsedVar],[LocalVar],State} +upat_element(#c_bitstr{val=H0,size=Sz0}=Seg, Ks, Bs0, St0) -> + {H1,Hg,Hv,[],St1} = upattern(H0, Ks, St0), + Bs1 = case H0 of #c_var{name=Hname} -> - Bs; - #c_var{name=Other} -> - [{Hname, Other}|Bs] - end; - _ -> - Bs - end, - {Sz1, Us} = case Sz of - #c_var{name=Vname} -> - rename_bitstr_size(Vname, Bs); - _Other -> {Sz, []} - end, - {Seg#c_bitstr{val=H1, size=Sz1},Hg,Hv,Us,Bs1,St1}. - -rename_bitstr_size(V, [{V, N}|_]) -> - New = #c_var{name=N}, - {New, [N]}; + case H1 of + #c_var{name=Hname} -> + Bs0; + #c_var{name=Other} -> + [{Hname,Other}|Bs0] + end; + _ -> + Bs0 + end, + {Sz1,Us} = case Sz0 of + #c_var{name=Vname} -> + rename_bitstr_size(Vname, Bs0); + _Other -> + {Sz0,[]} + end, + {Seg#c_bitstr{val=H1,size=Sz1},Hg,Hv,Us,Bs1,St1}. + +rename_bitstr_size(V, [{V,N}|_]) -> + New = #c_var{name=N}, + {New,[N]}; rename_bitstr_size(V, [_|Rest]) -> - rename_bitstr_size(V, Rest); + rename_bitstr_size(V, Rest); rename_bitstr_size(V, []) -> - Old = #c_var{name=V}, - {Old, [V]}. + Old = #c_var{name=V}, + {Old,[V]}. used_in_any(Les) -> foldl(fun (Le, Ns) -> union((get_anno(Le))#a.us, Ns) end, diff --git a/lib/compiler/test/Makefile b/lib/compiler/test/Makefile index 934bf39393..fe713fd019 100644 --- a/lib/compiler/test/Makefile +++ b/lib/compiler/test/Makefile @@ -157,7 +157,7 @@ release_tests_spec: make_emakefile $(EMAKEFILE) $(ERL_FILES) $(CORE_FILES) $(RELSYSDIR) $(INSTALL_DATA) $(NO_OPT_ERL_FILES) $(POST_OPT_ERL_FILES) \ $(INLINE_ERL_FILES) $(RELSYSDIR) - chmod -f -R u+w $(RELSYSDIR) + chmod -R u+w $(RELSYSDIR) @tar cf - *_SUITE_data | (cd $(RELSYSDIR); tar xf -) release_docs_spec: diff --git a/lib/compiler/test/andor_SUITE.erl b/lib/compiler/test/andor_SUITE.erl index cab22e03d0..f7388f1614 100644 --- a/lib/compiler/test/andor_SUITE.erl +++ b/lib/compiler/test/andor_SUITE.erl @@ -28,7 +28,7 @@ suite() -> [{ct_hooks,[ts_install_cth]}]. all() -> - test_lib:recompile(andor_SUITE), + test_lib:recompile(?MODULE), [t_case, t_and_or, t_andalso, t_orelse, inside, overlap, combined, in_case, before_and_inside_if]. diff --git a/lib/compiler/test/apply_SUITE.erl b/lib/compiler/test/apply_SUITE.erl index c517c4465e..25f8a8dfb5 100644 --- a/lib/compiler/test/apply_SUITE.erl +++ b/lib/compiler/test/apply_SUITE.erl @@ -28,7 +28,7 @@ suite() -> [{ct_hooks,[ts_install_cth]}]. all() -> - test_lib:recompile(apply_SUITE), + test_lib:recompile(?MODULE), [mfa, fun_apply]. groups() -> diff --git a/lib/compiler/test/beam_validator_SUITE.erl b/lib/compiler/test/beam_validator_SUITE.erl index fc88ebeb41..556dc54a8f 100644 --- a/lib/compiler/test/beam_validator_SUITE.erl +++ b/lib/compiler/test/beam_validator_SUITE.erl @@ -46,7 +46,7 @@ end_per_testcase(Case, Config) when is_atom(Case), is_list(Config) -> suite() -> [{ct_hooks,[ts_install_cth]}]. all() -> - test_lib:recompile(beam_validator_SUITE), + test_lib:recompile(?MODULE), [beam_files, compiler_bug, stupid_but_valid, xrange, yrange, stack, call_last, merge_undefined, uninit, unsafe_catch, dead_code, mult_labels, diff --git a/lib/compiler/test/bs_bincomp_SUITE.erl b/lib/compiler/test/bs_bincomp_SUITE.erl index 30c04f80cf..d39e340429 100644 --- a/lib/compiler/test/bs_bincomp_SUITE.erl +++ b/lib/compiler/test/bs_bincomp_SUITE.erl @@ -32,7 +32,7 @@ suite() -> [{ct_hooks,[ts_install_cth]}]. all() -> - test_lib:recompile(bs_bincomp_SUITE), + test_lib:recompile(?MODULE), [byte_aligned, bit_aligned, extended_byte_aligned, extended_bit_aligned, mixed, filters, trim_coverage, nomatch, sizes, tail]. diff --git a/lib/compiler/test/bs_bit_binaries_SUITE.erl b/lib/compiler/test/bs_bit_binaries_SUITE.erl index 8be0c4196a..30276f1259 100644 --- a/lib/compiler/test/bs_bit_binaries_SUITE.erl +++ b/lib/compiler/test/bs_bit_binaries_SUITE.erl @@ -33,7 +33,7 @@ suite() -> [{ct_hooks,[ts_install_cth]}]. all() -> - test_lib:recompile(bs_bit_binaries_SUITE), + test_lib:recompile(?MODULE), [misc, horrid_match, test_bitstr, test_bit_size, asymmetric_tests, big_asymmetric_tests, binary_to_and_from_list, big_binary_to_and_from_list, diff --git a/lib/compiler/test/bs_construct_SUITE.erl b/lib/compiler/test/bs_construct_SUITE.erl index c430b12b70..31c7890f26 100644 --- a/lib/compiler/test/bs_construct_SUITE.erl +++ b/lib/compiler/test/bs_construct_SUITE.erl @@ -35,7 +35,7 @@ suite() -> [{ct_hooks,[ts_install_cth]}]. all() -> - test_lib:recompile(bs_construct_SUITE), + test_lib:recompile(?MODULE), [two, test1, fail, float_bin, in_guard, in_catch, nasty_literals, side_effect, opt, otp_7556, float_arith, otp_8054]. diff --git a/lib/compiler/test/bs_match_SUITE.erl b/lib/compiler/test/bs_match_SUITE.erl index 1e3c670fb8..6a795f6634 100644 --- a/lib/compiler/test/bs_match_SUITE.erl +++ b/lib/compiler/test/bs_match_SUITE.erl @@ -35,7 +35,7 @@ match_string/1,zero_width/1,bad_size/1,haystack/1, cover_beam_bool/1]). --export([coverage_id/1]). +-export([coverage_id/1,coverage_external_ignore/2]). -include_lib("test_server/include/test_server.hrl"). @@ -43,7 +43,7 @@ suite() -> [{ct_hooks,[ts_install_cth]}]. all() -> - test_lib:recompile(bs_match_SUITE), + test_lib:recompile(?MODULE), [fun_shadow, int_float, otp_5269, null_fields, wiger, bin_tail, save_restore, shadowed_size_var, partitioned_bs_match, function_clause, unit, @@ -142,7 +142,14 @@ otp_5269(Config) when is_list(Config) -> [X || <<X:X>> <- [<<1:32>>,<<2:32>>,<<3:8>>]] end, %% "binsize variable" ^ [1,2]), - + ?line check(fun() -> + (fun (<<A:1/binary, B:8/integer, _C:B/binary>>) -> + case A of + B -> wrong; + _ -> ok + end + end)(<<1,2,3,4>>) end, + ok), ok. null_fields(Config) when is_list(Config) -> @@ -578,13 +585,17 @@ coverage(Config) when is_list(Config) -> A+B end, 0, [a,b,c])), + ?line {<<42.0:64/float>>,float} = coverage_build(<<>>, <<42>>, float), ?line {<<>>,not_a_tuple} = coverage_build(<<>>, <<>>, not_a_tuple), ?line {<<16#76,"abc",16#A9,"abc">>,{x,42,43}} = coverage_build(<<>>, <<16#7,16#A>>, {x,y,z}), + ?line [<<2>>,<<1>>] = coverage_bc(<<1,2>>, []), + ?line {x,<<"abc">>,z} = coverage_setelement(<<2,"abc">>, {x,y,z}), ?line [42] = coverage_apply(<<42>>, [coverage_id]), + ?line 42 = coverage_external(<<42>>), ?line do_coverage_bin_to_term_list([]), ?line do_coverage_bin_to_term_list([lists:seq(0, 10),{a,b,c},<<23:42>>]), @@ -601,6 +612,10 @@ coverage_fold(Fun, Acc, <<H,T/binary>>) -> coverage_fold(Fun, Fun(IdFun(H), IdFun(Acc)), T); coverage_fold(Fun, Acc, <<>>) when is_function(Fun, 2) -> Acc. +coverage_build(Acc0, <<H,T/binary>>, float) -> + Float = id(<<H:64/float>>), + Acc = <<Acc0/binary,Float/binary>>, + coverage_build(Acc, T, float); coverage_build(Acc0, <<H,T/binary>>, Tuple0) -> Str = id(<<H:(id(4)),(H-1):4,"abc">>), Acc = id(<<Acc0/bitstring,Str/bitstring>>), @@ -611,6 +626,11 @@ coverage_build(Acc0, <<H,T/binary>>, Tuple0) -> end; coverage_build(Acc, <<>>, Tuple) -> {Acc,Tuple}. +coverage_bc(<<H,T/binary>>, Acc) -> + B = << <<C:8>> || C <- [H] >>, + coverage_bc(T, [B|Acc]); +coverage_bc(<<>>, Acc) -> Acc. + coverage_setelement(<<H,T1/binary>>, Tuple) when element(1, Tuple) =:= x -> setelement(H, Tuple, T1). @@ -618,6 +638,13 @@ coverage_apply(<<H,T/binary>>, [F|Fs]) -> [?MODULE:F(H)|coverage_apply(T, Fs)]; coverage_apply(<<>>, []) -> []. +coverage_external(<<H,T/binary>>) -> + ?MODULE:coverage_external_ignore(T, T), + H. + +coverage_external_ignore(_, _) -> + ok. + coverage_id(I) -> id(I). do_coverage_bin_to_term_list(L) -> diff --git a/lib/compiler/test/bs_utf_SUITE.erl b/lib/compiler/test/bs_utf_SUITE.erl index d37943ce3a..f30a4d3fef 100644 --- a/lib/compiler/test/bs_utf_SUITE.erl +++ b/lib/compiler/test/bs_utf_SUITE.erl @@ -30,7 +30,7 @@ suite() -> [{ct_hooks,[ts_install_cth]}]. all() -> - test_lib:recompile(bs_utf_SUITE), + test_lib:recompile(?MODULE), [utf8_roundtrip, unused_utf_char, utf16_roundtrip, utf32_roundtrip, guard, extreme_tripping, literals, coverage]. diff --git a/lib/compiler/test/compilation_SUITE.erl b/lib/compiler/test/compilation_SUITE.erl index ba225b66d0..1343fbd1c9 100644 --- a/lib/compiler/test/compilation_SUITE.erl +++ b/lib/compiler/test/compilation_SUITE.erl @@ -27,7 +27,7 @@ suite() -> [{ct_hooks,[ts_install_cth]}]. all() -> - test_lib:recompile(compilation_SUITE), + test_lib:recompile(?MODULE), [self_compile_old_inliner, self_compile, compiler_1, compiler_3, compiler_5, beam_compiler_1, beam_compiler_2, beam_compiler_3, beam_compiler_4, diff --git a/lib/compiler/test/compile_SUITE.erl b/lib/compiler/test/compile_SUITE.erl index 037c078fd0..b3e5376ffd 100644 --- a/lib/compiler/test/compile_SUITE.erl +++ b/lib/compiler/test/compile_SUITE.erl @@ -40,7 +40,7 @@ suite() -> [{ct_hooks,[ts_install_cth]}]. -spec all() -> all_return_type(). all() -> - test_lib:recompile(compile_SUITE), + test_lib:recompile(?MODULE), [app_test, file_1, module_mismatch, big_file, outdir, binary, makedep, cond_and_ifdef, listings, listings_big, other_output, package_forms, encrypted_abstr, diff --git a/lib/compiler/test/core_SUITE.erl b/lib/compiler/test/core_SUITE.erl index 21a5f65dee..26173c62b8 100644 --- a/lib/compiler/test/core_SUITE.erl +++ b/lib/compiler/test/core_SUITE.erl @@ -40,7 +40,7 @@ end_per_testcase(Case, Config) when is_atom(Case), is_list(Config) -> suite() -> [{ct_hooks,[ts_install_cth]}]. all() -> - test_lib:recompile(core_SUITE), + test_lib:recompile(?MODULE), [dehydrated_itracer, nested_tries]. groups() -> diff --git a/lib/compiler/test/core_fold_SUITE.erl b/lib/compiler/test/core_fold_SUITE.erl index 710751b09d..ac14d36e82 100644 --- a/lib/compiler/test/core_fold_SUITE.erl +++ b/lib/compiler/test/core_fold_SUITE.erl @@ -30,7 +30,7 @@ suite() -> [{ct_hooks,[ts_install_cth]}]. all() -> - test_lib:recompile(core_fold_SUITE), + test_lib:recompile(?MODULE), [t_element, setelement, t_length, append, t_apply, bifs, eq, nested_call_in_case, coverage]. diff --git a/lib/compiler/test/error_SUITE.erl b/lib/compiler/test/error_SUITE.erl index c9823665b4..6e0aadf007 100644 --- a/lib/compiler/test/error_SUITE.erl +++ b/lib/compiler/test/error_SUITE.erl @@ -27,7 +27,7 @@ suite() -> [{ct_hooks,[ts_install_cth]}]. all() -> - test_lib:recompile(error_SUITE), + test_lib:recompile(?MODULE), [head_mismatch_line, warnings_as_errors, bif_clashes]. groups() -> diff --git a/lib/compiler/test/float_SUITE.erl b/lib/compiler/test/float_SUITE.erl index 6738265776..afc04fd440 100644 --- a/lib/compiler/test/float_SUITE.erl +++ b/lib/compiler/test/float_SUITE.erl @@ -26,7 +26,7 @@ suite() -> [{ct_hooks,[ts_install_cth]}]. all() -> - test_lib:recompile(float_SUITE), + test_lib:recompile(?MODULE), [pending, bif_calls, math_functions, mixed_float_and_int]. diff --git a/lib/compiler/test/fun_SUITE.erl b/lib/compiler/test/fun_SUITE.erl index aa9be83c82..368a5815bf 100644 --- a/lib/compiler/test/fun_SUITE.erl +++ b/lib/compiler/test/fun_SUITE.erl @@ -27,7 +27,7 @@ suite() -> [{ct_hooks,[ts_install_cth]}]. all() -> - test_lib:recompile(fun_SUITE), + test_lib:recompile(?MODULE), [test1, overwritten_fun, otp_7202, bif_fun]. groups() -> diff --git a/lib/compiler/test/guard_SUITE.erl b/lib/compiler/test/guard_SUITE.erl index 482564a32b..0e69efba6b 100644 --- a/lib/compiler/test/guard_SUITE.erl +++ b/lib/compiler/test/guard_SUITE.erl @@ -37,7 +37,7 @@ suite() -> [{ct_hooks,[ts_install_cth]}]. all() -> - test_lib:recompile(guard_SUITE), + test_lib:recompile(?MODULE), [misc, const_cond, basic_not, complex_not, nested_nots, semicolon, complex_semicolon, comma, or_guard, more_or_guards, complex_or_guards, and_guard, xor_guard, diff --git a/lib/compiler/test/inline_SUITE.erl b/lib/compiler/test/inline_SUITE.erl index 7b9600c2f6..af2b8ec92a 100644 --- a/lib/compiler/test/inline_SUITE.erl +++ b/lib/compiler/test/inline_SUITE.erl @@ -31,7 +31,7 @@ suite() -> [{ct_hooks,[ts_install_cth]}]. all() -> - test_lib:recompile(inline_SUITE), + test_lib:recompile(?MODULE), [attribute, bsdecode, bsdes, barnes2, decode1, smith, itracer, pseudoknot, lists, really_inlined, otp_7223, coverage]. diff --git a/lib/compiler/test/lc_SUITE.erl b/lib/compiler/test/lc_SUITE.erl index bcdcf2fd9f..c8908858ba 100644 --- a/lib/compiler/test/lc_SUITE.erl +++ b/lib/compiler/test/lc_SUITE.erl @@ -30,7 +30,7 @@ suite() -> [{ct_hooks,[ts_install_cth]}]. all() -> - test_lib:recompile(lc_SUITE), + test_lib:recompile(?MODULE), [basic, deeply_nested, no_generator, empty_generator]. groups() -> diff --git a/lib/compiler/test/match_SUITE.erl b/lib/compiler/test/match_SUITE.erl index 04879300d1..9406d7de8f 100644 --- a/lib/compiler/test/match_SUITE.erl +++ b/lib/compiler/test/match_SUITE.erl @@ -22,16 +22,16 @@ init_per_group/2,end_per_group/2, pmatch/1,mixed/1,aliases/1,match_in_call/1, untuplify/1,shortcut_boolean/1,letify_guard/1, - selectify/1,underscore/1]). + selectify/1,underscore/1,coverage/1]). -include_lib("test_server/include/test_server.hrl"). suite() -> [{ct_hooks,[ts_install_cth]}]. all() -> - test_lib:recompile(match_SUITE), + test_lib:recompile(?MODULE), [pmatch, mixed, aliases, match_in_call, untuplify, - shortcut_boolean, letify_guard, selectify, underscore]. + shortcut_boolean, letify_guard, selectify, underscore, coverage]. groups() -> []. @@ -398,4 +398,18 @@ underscore(Config) when is_list(Config) -> _ = is_list(Config), ok. +coverage(Config) when is_list(Config) -> + %% Cover beam_dead. + ok = coverage_1(x, a), + ok = coverage_1(x, b). + +coverage_1(B, Tag) -> + case Tag of + a -> coverage_2(1, a, B); + b -> coverage_2(2, b, B) + end. + +coverage_2(1, a, x) -> ok; +coverage_2(2, b, x) -> ok. + id(I) -> I. diff --git a/lib/compiler/test/misc_SUITE.erl b/lib/compiler/test/misc_SUITE.erl index f1f9b17084..c941a80e61 100644 --- a/lib/compiler/test/misc_SUITE.erl +++ b/lib/compiler/test/misc_SUITE.erl @@ -56,7 +56,7 @@ suite() -> [{ct_hooks,[ts_install_cth]}]. -spec all() -> misc_SUITE_test_cases(). all() -> - test_lib:recompile(misc_SUITE), + test_lib:recompile(?MODULE), [tobias, empty_string, md5, silly_coverage, confused_literals, integer_encoding, override_bif]. diff --git a/lib/compiler/test/num_bif_SUITE.erl b/lib/compiler/test/num_bif_SUITE.erl index 0a4750dc08..3479cf5425 100644 --- a/lib/compiler/test/num_bif_SUITE.erl +++ b/lib/compiler/test/num_bif_SUITE.erl @@ -40,7 +40,7 @@ suite() -> [{ct_hooks,[ts_install_cth]}]. all() -> - test_lib:recompile(num_bif_SUITE), + test_lib:recompile(?MODULE), [t_abs, t_float, t_float_to_list, t_integer_to_list, {group, t_list_to_float}, t_list_to_integer, t_round, t_trunc]. diff --git a/lib/compiler/test/pmod_SUITE.erl b/lib/compiler/test/pmod_SUITE.erl index 4c68d777ca..9a317b5762 100644 --- a/lib/compiler/test/pmod_SUITE.erl +++ b/lib/compiler/test/pmod_SUITE.erl @@ -28,7 +28,7 @@ suite() -> [{ct_hooks,[ts_install_cth]}]. all() -> - test_lib:recompile(pmod_SUITE), + test_lib:recompile(?MODULE), [basic, otp_8447]. groups() -> diff --git a/lib/compiler/test/receive_SUITE.erl b/lib/compiler/test/receive_SUITE.erl index 75e8045693..2a67615e5e 100644 --- a/lib/compiler/test/receive_SUITE.erl +++ b/lib/compiler/test/receive_SUITE.erl @@ -39,7 +39,7 @@ end_per_testcase(_Case, Config) -> suite() -> [{ct_hooks,[ts_install_cth]}]. all() -> - test_lib:recompile(receive_SUITE), + test_lib:recompile(?MODULE), [recv, coverage, otp_7980, ref_opt, export]. groups() -> diff --git a/lib/compiler/test/record_SUITE.erl b/lib/compiler/test/record_SUITE.erl index 65b96590ed..363422ec7e 100644 --- a/lib/compiler/test/record_SUITE.erl +++ b/lib/compiler/test/record_SUITE.erl @@ -26,7 +26,8 @@ init_per_group/2,end_per_group/2, init_per_testcase/2,end_per_testcase/2, errors/1,record_test_2/1,record_test_3/1,record_access_in_guards/1, - guard_opt/1,eval_once/1,foobar/1,missing_test_heap/1, nested_access/1]). + guard_opt/1,eval_once/1,foobar/1,missing_test_heap/1, + nested_access/1,coverage/1]). init_per_testcase(_Case, Config) -> ?line Dog = test_server:timetrap(test_server:minutes(2)), @@ -40,10 +41,10 @@ end_per_testcase(_Case, Config) -> suite() -> [{ct_hooks,[ts_install_cth]}]. all() -> - test_lib:recompile(record_SUITE), + test_lib:recompile(?MODULE), [errors, record_test_2, record_test_3, record_access_in_guards, guard_opt, eval_once, foobar, - missing_test_heap, nested_access]. + missing_test_heap, nested_access, coverage]. groups() -> []. @@ -568,4 +569,18 @@ nested_access(Config) when is_list(Config) -> ?line N2a = N2b, ok. +-record(rr, {a,b,c}). + +coverage(Config) when is_list(Config) -> + %% There should only remain one record test in the code below. + R0 = id(#rr{a=1,b=2,c=3}), + B = R0#rr.b, %Test the record here. + R = R0#rr{c=42}, %No need to test here. + if + B > R#rr.a -> %No need to test here. + ok + end, + #rr{a=1,b=2,c=42} = id(R), %Test for correctness. + ok. + id(I) -> I. diff --git a/lib/compiler/test/trycatch_SUITE.erl b/lib/compiler/test/trycatch_SUITE.erl index 92a79d3cba..c6e0f8d85d 100644 --- a/lib/compiler/test/trycatch_SUITE.erl +++ b/lib/compiler/test/trycatch_SUITE.erl @@ -31,7 +31,7 @@ suite() -> [{ct_hooks,[ts_install_cth]}]. all() -> - test_lib:recompile(trycatch_SUITE), + test_lib:recompile(?MODULE), [basic, lean_throw, try_of, try_after, catch_oops, after_oops, eclectic, rethrow, nested_of, nested_catch, nested_after, nested_horrid, last_call_optimization, diff --git a/lib/compiler/test/warnings_SUITE.erl b/lib/compiler/test/warnings_SUITE.erl index 8cc3ca4199..f6a572abfa 100644 --- a/lib/compiler/test/warnings_SUITE.erl +++ b/lib/compiler/test/warnings_SUITE.erl @@ -54,7 +54,7 @@ end_per_testcase(_Case, Config) -> suite() -> [{ct_hooks,[ts_install_cth]}]. all() -> - test_lib:recompile(warnings_SUITE), + test_lib:recompile(?MODULE), [pattern, pattern2, pattern3, pattern4, guard, bad_arith, bool_cases, bad_apply, files, effect, bin_opt_info, bin_construction]. @@ -453,6 +453,16 @@ effect(Config) when is_list(Config) -> true -> ok end, ok. + + m8(A, B) -> + case {A,B} of + V -> V + end, + ok. + + m9(Bs) -> + [{B,ok} = {B,foo:bar(B)} || B <- Bs], + ok. ">>, [], {warnings,[{5,sys_core_fold,{no_effect,{erlang,is_integer,1}}}, diff --git a/lib/cosFileTransfer/test/Makefile b/lib/cosFileTransfer/test/Makefile index ec7ebcafca..b46fb35356 100644 --- a/lib/cosFileTransfer/test/Makefile +++ b/lib/cosFileTransfer/test/Makefile @@ -130,4 +130,4 @@ release_tests_spec: tests $(INSTALL_DATA) $(IDL_FILES) $(TEST_SPEC_FILE) \ $(COVER_FILE) $(ERL_FILES) $(RELSYSDIR) $(INSTALL_DATA) $(SUITE_TARGET_FILES) $(RELSYSDIR) - chmod -f -R u+w $(RELSYSDIR) + chmod -R u+w $(RELSYSDIR) diff --git a/lib/crypto/c_src/crypto.c b/lib/crypto/c_src/crypto.c index b8786f6f94..3ebf62d87c 100644 --- a/lib/crypto/c_src/crypto.c +++ b/lib/crypto/c_src/crypto.c @@ -134,7 +134,9 @@ static ERL_NIF_TERM des_ede3_cbc_crypt(ErlNifEnv* env, int argc, const ERL_NIF_T static ERL_NIF_TERM aes_cfb_128_crypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); static ERL_NIF_TERM aes_ctr_encrypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); static ERL_NIF_TERM rand_bytes_1(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); +static ERL_NIF_TERM strong_rand_bytes_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); static ERL_NIF_TERM rand_bytes_3(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); +static ERL_NIF_TERM strong_rand_mpint_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); static ERL_NIF_TERM rand_uniform_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); static ERL_NIF_TERM mod_exp_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); static ERL_NIF_TERM dss_verify(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); @@ -204,7 +206,9 @@ static ErlNifFunc nif_funcs[] = { {"aes_ctr_encrypt", 3, aes_ctr_encrypt}, {"aes_ctr_decrypt", 3, aes_ctr_encrypt}, {"rand_bytes", 1, rand_bytes_1}, + {"strong_rand_bytes_nif", 1, strong_rand_bytes_nif}, {"rand_bytes", 3, rand_bytes_3}, + {"strong_rand_mpint_nif", 3, strong_rand_mpint_nif}, {"rand_uniform_nif", 2, rand_uniform_nif}, {"mod_exp_nif", 3, mod_exp_nif}, {"dss_verify", 4, dss_verify}, @@ -704,6 +708,22 @@ static ERL_NIF_TERM rand_bytes_1(ErlNifEnv* env, int argc, const ERL_NIF_TERM ar ERL_VALGRIND_MAKE_MEM_DEFINED(data, bytes); return ret; } +static ERL_NIF_TERM strong_rand_bytes_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) +{/* (Bytes) */ + unsigned bytes; + unsigned char* data; + ERL_NIF_TERM ret; + if (!enif_get_uint(env, argv[0], &bytes)) { + return enif_make_badarg(env); + } + data = enif_make_new_binary(env, bytes, &ret); + if ( RAND_bytes(data, bytes) != 1) { + return atom_false; + } + ERL_VALGRIND_MAKE_MEM_DEFINED(data, bytes); + return ret; +} + static ERL_NIF_TERM rand_bytes_3(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) {/* (Bytes, TopMask, BottomMask) */ unsigned bytes; @@ -724,6 +744,47 @@ static ERL_NIF_TERM rand_bytes_3(ErlNifEnv* env, int argc, const ERL_NIF_TERM ar } return ret; } +static ERL_NIF_TERM strong_rand_mpint_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) +{/* (Bytes, TopMask, BottomMask) */ + unsigned bits; + BIGNUM *bn_rand; + int top, bottom; + unsigned char* data; + unsigned dlen; + ERL_NIF_TERM ret; + if (!enif_get_uint(env, argv[0], &bits) + || !enif_get_int(env, argv[1], &top) + || !enif_get_int(env, argv[2], &bottom)) { + return enif_make_badarg(env); + } + if (! (top == -1 || top == 0 || top == 1) ) { + return enif_make_badarg(env); + } + if (! (bottom == 0 || bottom == 1) ) { + return enif_make_badarg(env); + } + + bn_rand = BN_new(); + if (! bn_rand ) { + return enif_make_badarg(env); + } + + /* Get a (bits) bit random number */ + if (!BN_rand(bn_rand, bits, top, bottom)) { + ret = atom_false; + } + else { + /* Copy the bignum into an erlang mpint binary. */ + dlen = BN_num_bytes(bn_rand); + data = enif_make_new_binary(env, dlen+4, &ret); + put_int32(data, dlen); + BN_bn2bin(bn_rand, data+4); + ERL_VALGRIND_MAKE_MEM_DEFINED(data+4, dlen); + } + BN_free(bn_rand); + + return ret; +} static int get_bn_from_mpint(ErlNifEnv* env, ERL_NIF_TERM term, BIGNUM** bnp) { diff --git a/lib/crypto/doc/src/crypto.xml b/lib/crypto/doc/src/crypto.xml index c407350c47..1ccea6df79 100644 --- a/lib/crypto/doc/src/crypto.xml +++ b/lib/crypto/doc/src/crypto.xml @@ -4,7 +4,7 @@ <erlref> <header> <copyright> - <year>1999</year><year>2010</year> + <year>1999</year><year>2011</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> @@ -419,16 +419,18 @@ Mpint() = <![CDATA[<<ByteLen:32/integer-big, Bytes:ByteLen/binary>>]]> <fsummary>Encrypt the first 64 bits of <c>Text</c> using Blowfish in ECB mode</fsummary> <type> <v>Key = Text = iolist() | binary()</v> - <v>IVec = Cipher = binary()</v> + <v>Cipher = binary()</v> </type> <desc> <p>Encrypts the first 64 bits of <c>Text</c> using Blowfish in ECB mode. <c>Key</c> is the Blowfish key. The length of <c>Text</c> must be at least 64 bits (8 bytes).</p> </desc> + </func> + <func> <name>blowfish_ecb_decrypt(Key, Text) -> Cipher</name> <fsummary>Decrypt the first 64 bits of <c>Text</c> using Blowfish in ECB mode</fsummary> <type> <v>Key = Text = iolist() | binary()</v> - <v>IVec = Cipher = binary()</v> + <v>Cipher = binary()</v> </type> <desc> <p>Decrypts the first 64 bits of <c>Text</c> using Blowfish in ECB mode. <c>Key</c> is the Blowfish key. The length of <c>Text</c> must be at least 64 bits (8 bytes).</p> @@ -436,7 +438,7 @@ Mpint() = <![CDATA[<<ByteLen:32/integer-big, Bytes:ByteLen/binary>>]]> </func> <func> - <name>blowfish_cbc_encrypt(Key, Text) -> Cipher</name> + <name>blowfish_cbc_encrypt(Key, IVec, Text) -> Cipher</name> <fsummary>Encrypt <c>Text</c> using Blowfish in CBC mode</fsummary> <type> <v>Key = Text = iolist() | binary()</v> @@ -447,7 +449,9 @@ Mpint() = <![CDATA[<<ByteLen:32/integer-big, Bytes:ByteLen/binary>>]]> arbitrary initializing vector. The length of <c>IVec</c> must be 64 bits (8 bytes). The length of <c>Text</c> must be a multiple of 64 bits (8 bytes).</p> </desc> - <name>blowfish_cbc_decrypt(Key, Text) -> Cipher</name> + </func> + <func> + <name>blowfish_cbc_decrypt(Key, IVec, Text) -> Cipher</name> <fsummary>Decrypt <c>Text</c> using Blowfish in CBC mode</fsummary> <type> <v>Key = Text = iolist() | binary()</v> @@ -615,6 +619,21 @@ Mpint() = <![CDATA[<<ByteLen:32/integer-big, Bytes:ByteLen/binary>>]]> </desc> </func> <func> + <name>strong_rand_bytes(N) -> binary()</name> + <fsummary>Generate a binary of random bytes</fsummary> + <type> + <v>N = integer()</v> + </type> + <desc> + <p>Generates N bytes randomly uniform 0..255, and returns the + result in a binary. Uses a cryptographically secure prng seeded and + periodically mixed with operating system provided entropy. By default + this is the <c>RAND_bytes</c> method from OpenSSL.</p> + <p>May throw exception <c>low_entropy</c> in case the random generator + failed due to lack of secure "randomness".</p> + </desc> + </func> + <func> <name>rand_uniform(Lo, Hi) -> N</name> <fsummary>Generate a random number</fsummary> <type> @@ -629,6 +648,31 @@ Mpint() = <![CDATA[<<ByteLen:32/integer-big, Bytes:ByteLen/binary>>]]> </desc> </func> <func> + <name>strong_rand_mpint(N, Top, Bottom) -> Mpint</name> + <fsummary>Generate an N bit random number</fsummary> + <type> + <v>N = non_neg_integer()</v> + <v>Top = -1 | 0 | 1</v> + <v>Bottom = 0 | 1</v> + <v>Mpint = binary()</v> + </type> + <desc> + <p>Generate an N bit random number using OpenSSL's + cryptographically strong pseudo random number generator + <c>BN_rand</c>.</p> + <p>The parameter <c>Top</c> places constraints on the most + significant bits of the generated number. If <c>Top</c> is 1, then the + two most significant bits will be set to 1, if <c>Top</c> is 0, the + most significant bit will be 1, and if <c>Top</c> is -1 then no + constraints are applied and thus the generated number may be less than + N bits long.</p> + <p>If <c>Bottom</c> is 1, then the generated number is + constrained to be odd.</p> + <p>May throw exception <c>low_entropy</c> in case the random generator + failed due to lack of secure "randomness".</p> + </desc> + </func> + <func> <name>mod_exp(N, P, M) -> Result</name> <fsummary>Perform N ^ P mod M</fsummary> <type> diff --git a/lib/crypto/doc/src/notes.xml b/lib/crypto/doc/src/notes.xml index 5e9bda3920..ab1ffa9e5c 100644 --- a/lib/crypto/doc/src/notes.xml +++ b/lib/crypto/doc/src/notes.xml @@ -4,7 +4,7 @@ <chapter> <header> <copyright> - <year>1999</year><year>2010</year> + <year>1999</year><year>2011</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> @@ -30,6 +30,21 @@ </header> <p>This document describes the changes made to the Crypto application.</p> +<section><title>Crypto 2.0.2.2</title> + + <section><title>Improvements and New Features</title> + <list> + <item> + <p> + Strengthened random number generation. (Thanks to Geoff Cant)</p> + <p> + Own Id: OTP-9225</p> + </item> + </list> + </section> + +</section> + <section><title>Crypto 2.0.2.1</title> <section><title>Improvements and New Features</title> diff --git a/lib/crypto/src/crypto.erl b/lib/crypto/src/crypto.erl index d6e2e033c0..cc7b3acc9c 100644 --- a/lib/crypto/src/crypto.erl +++ b/lib/crypto/src/crypto.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1999-2010. All Rights Reserved. +%% Copyright Ericsson AB 1999-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 @@ -46,6 +46,7 @@ -export([rsa_private_encrypt/3, rsa_public_decrypt/3]). -export([dh_generate_key/1, dh_generate_key/2, dh_compute_key/3]). -export([rand_bytes/1, rand_bytes/3, rand_uniform/2]). +-export([strong_rand_bytes/1, strong_rand_mpint/3]). -export([mod_exp/3, mpint/1, erlint/1]). %% -export([idea_cbc_encrypt/3, idea_cbc_decrypt/3]). -export([aes_cbc_128_encrypt/3, aes_cbc_128_decrypt/3]). @@ -68,6 +69,8 @@ des_ede3_cbc_encrypt, des_ede3_cbc_decrypt, aes_cfb_128_encrypt, aes_cfb_128_decrypt, rand_bytes, + strong_rand_bytes, + strong_rand_mpint, rand_uniform, mod_exp, dss_verify,dss_sign, @@ -361,12 +364,32 @@ aes_cfb_128_crypt(_Key, _IVec, _Data, _IsEncrypt) -> ?nif_stub. %% RAND - pseudo random numbers using RN_ functions in crypto lib %% -spec rand_bytes(non_neg_integer()) -> binary(). +-spec strong_rand_bytes(non_neg_integer()) -> binary(). -spec rand_uniform(crypto_integer(), crypto_integer()) -> crypto_integer(). +-spec strong_rand_mpint(Bits::non_neg_integer(), + Top::-1..1, + Bottom::0..1) -> binary(). rand_bytes(_Bytes) -> ?nif_stub. + +strong_rand_bytes(Bytes) -> + case strong_rand_bytes_nif(Bytes) of + false -> erlang:error(low_entropy); + Bin -> Bin + end. +strong_rand_bytes_nif(_Bytes) -> ?nif_stub. + rand_bytes(_Bytes, _Topmask, _Bottommask) -> ?nif_stub. +strong_rand_mpint(Bits, Top, Bottom) -> + case strong_rand_mpint_nif(Bits,Top,Bottom) of + false -> erlang:error(low_entropy); + Bin -> Bin + end. +strong_rand_mpint_nif(_Bits, _Top, _Bottom) -> ?nif_stub. + + rand_uniform(From,To) when is_binary(From), is_binary(To) -> case rand_uniform_nif(From,To) of <<Len:32/integer, MSB, Rest/binary>> when MSB > 127 -> diff --git a/lib/crypto/test/Makefile b/lib/crypto/test/Makefile index f4689a23df..3150bd472d 100644 --- a/lib/crypto/test/Makefile +++ b/lib/crypto/test/Makefile @@ -77,7 +77,7 @@ release_spec: release_tests_spec: $(TEST_TARGET) $(INSTALL_DIR) $(RELSYSDIR) $(INSTALL_DATA) crypto.spec crypto.cover $(RELTEST_FILES) $(RELSYSDIR) - chmod -f -R u+w $(RELSYSDIR) + chmod -R u+w $(RELSYSDIR) release_docs_spec: diff --git a/lib/crypto/test/crypto_SUITE.erl b/lib/crypto/test/crypto_SUITE.erl index fe8f8e69a0..854a8b4485 100644 --- a/lib/crypto/test/crypto_SUITE.erl +++ b/lib/crypto/test/crypto_SUITE.erl @@ -46,6 +46,7 @@ aes_ctr/1, mod_exp_test/1, rand_uniform_test/1, + strong_rand_test/1, rsa_verify_test/1, dsa_verify_test/1, rsa_sign_test/1, @@ -68,7 +69,8 @@ all() -> md5_mac_io, sha, sha_update, %% sha256, sha256_update, sha512,sha512_update, des_cbc, aes_cfb, aes_cbc, - aes_cbc_iter, aes_ctr, des_cbc_iter, des_ecb, rand_uniform_test, + aes_cbc_iter, aes_ctr, des_cbc_iter, des_ecb, + rand_uniform_test, strong_rand_test, rsa_verify_test, dsa_verify_test, rsa_sign_test, dsa_sign_test, rsa_encrypt_decrypt, dh, exor_test, rc4_test, rc4_stream_test, mod_exp_test, blowfish_cfb64, @@ -710,6 +712,33 @@ rand_uniform_aux_test(N) -> %% %% +strong_rand_test(doc) -> + "strong_rand_mpint and strong_random_bytes testing"; +strong_rand_test(suite) -> + []; +strong_rand_test(Config) when is_list(Config) -> + strong_rand_aux_test(180), + ?line 10 = byte_size(crypto:strong_rand_bytes(10)). + +strong_rand_aux_test(0) -> + ?line t(crypto:strong_rand_mpint(0,0,0) =:= <<0,0,0,0>>), + ok; +strong_rand_aux_test(1) -> + ?line t(crypto:erlint(crypto:strong_rand_mpint(1,0,1)) =:= 1), + ?line strong_rand_aux_test(0); +strong_rand_aux_test(N) -> + ?line t(sru_length(crypto:strong_rand_mpint(N,-1,0)) =< N), + ?line t(sru_length(crypto:strong_rand_mpint(N,0,0)) =:= N), + ?line t(crypto:erlint(crypto:strong_rand_mpint(N,0,1)) band 1 =:= 1), + ?line t(crypto:erlint(crypto:strong_rand_mpint(N,1,0)) bsr (N - 2) =:= 2#11), + ?line strong_rand_aux_test(N-1). + +sru_length(Mpint) -> + I = crypto:erlint(Mpint), + length(erlang:integer_to_list(I, 2)). + +%% +%% %% %% rsa_verify_test(doc) -> @@ -1097,7 +1126,7 @@ worker_loop(0, _) -> ok; worker_loop(N, Config) -> Funcs = { md5, md5_update, md5_mac, md5_mac_io, sha, sha_update, des_cbc, - aes_cfb, aes_cbc, des_cbc_iter, rand_uniform_test, + aes_cfb, aes_cbc, des_cbc_iter, rand_uniform_test, strong_rand_test, rsa_verify_test, exor_test, rc4_test, rc4_stream_test, mod_exp_test }, F = element(random:uniform(size(Funcs)),Funcs), diff --git a/lib/crypto/vsn.mk b/lib/crypto/vsn.mk index e2d6fd0b37..740c68d8fa 100644 --- a/lib/crypto/vsn.mk +++ b/lib/crypto/vsn.mk @@ -1 +1 @@ -CRYPTO_VSN = 2.0.2.1 +CRYPTO_VSN = 2.0.2.2 diff --git a/lib/debugger/test/Makefile b/lib/debugger/test/Makefile index 4409cd2b38..2296bd0ae6 100644 --- a/lib/debugger/test/Makefile +++ b/lib/debugger/test/Makefile @@ -100,7 +100,7 @@ release_tests_spec: make_emakefile $(INSTALL_DIR) $(RELSYSDIR) $(INSTALL_DATA) $(EMAKEFILE) $(ERL_FILES) $(RELSYSDIR) $(INSTALL_DATA) debugger.spec debugger.cover $(RELSYSDIR) - chmod -f -R u+w $(RELSYSDIR) + chmod -R u+w $(RELSYSDIR) @tar cf - *_SUITE_data | (cd $(RELSYSDIR); tar xf -) release_docs_spec: diff --git a/lib/dialyzer/doc/manual.txt b/lib/dialyzer/doc/manual.txt index 1d7a1a6222..d519ac960b 100644 --- a/lib/dialyzer/doc/manual.txt +++ b/lib/dialyzer/doc/manual.txt @@ -37,7 +37,7 @@ The parameters are: The analysis starts from .beam bytecode files. The files must be compiled with +debug_info. - Source code: - The analysis starts from .erl files. + The analysis starts from .erl files. Controlling the discrepancies reported by the Dialyzer ====================================================== @@ -131,7 +131,7 @@ Usage: dialyzer [--help] [--version] [--shell] [--quiet] [--verbose] [--check_plt] [--no_check_plt] [--plt_info] [--get_warnings] [--no_native] [--fullpath] -Options: +Options: files_or_dirs (for backwards compatibility also as: -c files_or_dirs) Use Dialyzer from the command line to detect defects in the specified files or directories containing .erl or .beam files, @@ -169,7 +169,7 @@ Options: --output_plt file Store the plt at the specified file after building it. --plt plt - Use the specified plt as the initial plt (if the plt was built + Use the specified plt as the initial plt (if the plt was built during setup the files will be checked for consistency). --plts plt* Merge the specified plts to create the initial plt -- requires @@ -204,8 +204,8 @@ Options: --add_to_plt The plt is extended to also include the files specified with -c and -r. Use --plt to specify which plt to start from, and --output_plt to - specify where to put the plt. Note that the analysis might include - files from the plt if they depend on the new files. + specify where to put the plt. Note that the analysis might include + files from the plt if they depend on the new files. This option only works with beam files. --remove_from_plt The information from the files specified with -c and -r is removed @@ -269,13 +269,13 @@ Warning options: Include warnings about behaviour callbacks which drift from the published recommended interfaces. -Wunderspecs *** - Warn about underspecified functions + Warn about underspecified functions (those whose -spec is strictly more allowing than the success typing). The following options are also available but their use is not recommended: (they are mostly for Dialyzer developers and internal debugging) -Woverspecs *** - Warn about overspecified functions + Warn about overspecified functions (those whose -spec is strictly less allowing than the success typing). -Wspecdiffs *** Warn when the -spec is different than the success typing. @@ -306,8 +306,8 @@ dialyzer:run(OptList) -> Warnings Warnings :: [{tag(), id(), msg()}] tag() :: 'warn_return_no_exit' | 'warn_return_only_exit' | 'warn_not_called' | 'warn_non_proper_list' | 'warn_fun_app' | 'warn_matching' - | 'warn_failing_call' | 'warn_contract_types' - | 'warn_contract_syntax' | 'warn_contract_not_equal' + | 'warn_failing_call' | 'warn_contract_types' + | 'warn_contract_syntax' | 'warn_contract_not_equal' | 'warn_contract_subtype' | 'warn_contract_supertype' id() :: {File :: string(), Line :: integer()} msg() :: Undefined @@ -319,24 +319,31 @@ Option :: {files, [Filename :: string()]} | {from, src_code | byte_code} %% Defaults to byte_code | {init_plt, FileName :: string()} %% If changed from default | {plts, [FileName :: string()]} %% If changed from default - | {include_dirs, [DirName :: string()]} + | {include_dirs, [DirName :: string()]} | {output_file, FileName :: string()} | {output_plt, FileName :: string()} | {analysis_type, 'succ_typings' | 'plt_add' | 'plt_build' | 'plt_check' | 'plt_remove'} | {warnings, [WarnOpts]} + | {get_warnings, bool()} WarnOpts :: no_return | no_unused | no_improper_lists | no_fun_app | no_match + | no_opaque | no_fail_call - | unmatched_returns | error_handling + | race_conditions + | behaviours + | unmatched_returns + | overspecs + | underspecs + | specdiffs dialyzer:format_warning({tag(), id(), msg()}) -> string() - + Returns a string representation of the warnings as returned by dialyzer:run/1. dialyzer:plt_info(string()) -> {'ok', [{atom(), any()}]} | {'error', atom()} @@ -392,7 +399,7 @@ files that depend on these files. Note that this consistency check will be performed automatically the next time you run Dialyzer with this plt. The --check_plt option is merely for doing so without doing any other analysis. - + ----------------------------------------------- -- -- Feedback & bug reports diff --git a/lib/dialyzer/doc/src/dialyzer.xml b/lib/dialyzer/doc/src/dialyzer.xml index b6547b11e1..4080dfdf77 100644 --- a/lib/dialyzer/doc/src/dialyzer.xml +++ b/lib/dialyzer/doc/src/dialyzer.xml @@ -241,7 +241,7 @@ <item>Include warnings about behaviour callbacks which drift from the published recommended interfaces.</item> <tag><c><![CDATA[-Wunderspecs]]></c>***</tag> - <item>Warn about underspecified functions + <item>Warn about underspecified functions (the -spec is strictly more allowing than the success typing).</item> </taglist> <p>The following options are also available but their use is not @@ -249,7 +249,7 @@ debugging)</p> <taglist> <tag><c><![CDATA[-Woverspecs]]></c>***</tag> - <item>Warn about overspecified functions + <item>Warn about overspecified functions (the -spec is strictly less allowing than the success typing).</item> <tag><c><![CDATA[-Wspecdiffs]]></c>***</tag> <item>Warn when the -spec is different than the success typing.</item> @@ -278,34 +278,34 @@ <desc> <p>Dialyzer GUI version.</p> <code type="none"><![CDATA[ -OptList : [Option] -Option : {files, [Filename : string()]} - | {files_rec, [DirName : string()]} - | {defines, [{Macro: atom(), Value : term()}]} - | {from, src_code | byte_code} %% Defaults to byte_code - | {init_plt, FileName : string()} %% If changed from default - | {plts, [FileName :: string()]} %% If changed from default - | {include_dirs, [DirName : string()]} - | {output_file, FileName : string()} - | {output_plt, FileName :: string()} - | {analysis_type, 'succ_typings' | 'plt_add' | 'plt_build' | 'plt_check' | 'plt_remove'} - | {warnings, [WarnOpts]} - | {get_warnings, bool()} +OptList :: [Option] +Option :: {files, [Filename :: string()]} + | {files_rec, [DirName :: string()]} + | {defines, [{Macro: atom(), Value : term()}]} + | {from, src_code | byte_code} %% Defaults to byte_code + | {init_plt, FileName :: string()} %% If changed from default + | {plts, [FileName :: string()]} %% If changed from default + | {include_dirs, [DirName :: string()]} + | {output_file, FileName :: string()} + | {output_plt, FileName :: string()} + | {analysis_type, 'succ_typings' | 'plt_add' | 'plt_build' | 'plt_check' | 'plt_remove'} + | {warnings, [WarnOpts]} + | {get_warnings, bool()} -WarnOpts : no_return - | no_unused - | no_improper_lists - | no_fun_app - | no_match - | no_opaque - | no_fail_call - | error_handling - | race_conditions - | behaviours - | unmatched_returns - | overspecs - | underspecs - | specdiffs +WarnOpts :: no_return + | no_unused + | no_improper_lists + | no_fun_app + | no_match + | no_opaque + | no_fail_call + | error_handling + | race_conditions + | behaviours + | unmatched_returns + | overspecs + | underspecs + | specdiffs ]]></code> </desc> </func> @@ -320,12 +320,12 @@ WarnOpts : no_return <p>Dialyzer command line version.</p> <code type="none"><![CDATA[ Warnings :: [{Tag, Id, Msg}] -Tag : 'warn_return_no_exit' | 'warn_return_only_exit' - | 'warn_not_called' | 'warn_non_proper_list' - | 'warn_fun_app' | 'warn_matching' - | 'warn_failing_call' | 'warn_contract_types' - | 'warn_contract_syntax' | 'warn_contract_not_equal' - | 'warn_contract_subtype' | 'warn_contract_supertype' +Tag :: 'warn_return_no_exit' | 'warn_return_only_exit' + | 'warn_not_called' | 'warn_non_proper_list' + | 'warn_fun_app' | 'warn_matching' + | 'warn_failing_call' | 'warn_contract_types' + | 'warn_contract_syntax' | 'warn_contract_not_equal' + | 'warn_contract_subtype' | 'warn_contract_supertype' Id = {File :: string(), Line :: integer()} Msg = msg() -- Undefined ]]></code> 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) -> diff --git a/lib/dialyzer/src/dialyzer_succ_typings.erl b/lib/dialyzer/src/dialyzer_succ_typings.erl index 24d6013692..b8da57d3f9 100644 --- a/lib/dialyzer/src/dialyzer_succ_typings.erl +++ b/lib/dialyzer/src/dialyzer_succ_typings.erl @@ -155,19 +155,24 @@ postprocess_dataflow_warns(RawWarnings, State, WarnAcc) -> postprocess_dataflow_warns([], _State, WAcc, Acc) -> {WAcc, lists:reverse(Acc)}; -postprocess_dataflow_warns([{?WARN_CONTRACT_RANGE, {File, CallL}, Msg}|Rest], +postprocess_dataflow_warns([{?WARN_CONTRACT_RANGE, {CallF, CallL}, Msg}|Rest], #st{codeserver = Codeserver} = State, WAcc, Acc) -> {contract_range, [Contract, M, F, A, ArgStrings, CRet]} = Msg, - {ok, {{File, _ContrL} = FileLine, _C}} = + {ok, {{ContrF, _ContrL} = FileLine, _C}} = dialyzer_codeserver:lookup_mfa_contract({M,F,A}, Codeserver), - NewMsg = - {contract_range, [Contract, M, F, ArgStrings, CallL, CRet]}, - W = {?WARN_CONTRACT_RANGE, FileLine, NewMsg}, - Filter = - fun({?WARN_CONTRACT_TYPES, FL, _}) when FL =:= FileLine -> false; - (_) -> true - end, - postprocess_dataflow_warns(Rest, State, lists:filter(Filter, WAcc), [W|Acc]); + case CallF =:= ContrF of + true -> + NewMsg = {contract_range, [Contract, M, F, ArgStrings, CallL, CRet]}, + W = {?WARN_CONTRACT_RANGE, FileLine, NewMsg}, + Filter = + fun({?WARN_CONTRACT_TYPES, FL, _}) when FL =:= FileLine -> false; + (_) -> true + end, + FilterWAcc = lists:filter(Filter, WAcc), + postprocess_dataflow_warns(Rest, State, FilterWAcc, [W|Acc]); + false -> + postprocess_dataflow_warns(Rest, State, WAcc, Acc) + end; postprocess_dataflow_warns([W|Rest], State, Wacc, Acc) -> postprocess_dataflow_warns(Rest, State, Wacc, [W|Acc]). diff --git a/lib/dialyzer/test/small_tests_SUITE.erl b/lib/dialyzer/test/small_tests_SUITE.erl index 21a2c76160..dbcc044eea 100644 --- a/lib/dialyzer/test/small_tests_SUITE.erl +++ b/lib/dialyzer/test/small_tests_SUITE.erl @@ -18,18 +18,18 @@ contract5/1, disj_norm_form/1, eqeq/1, ets_select/1, exhaust_case/1, failing_guard1/1, flatten/1, fun_app/1, fun_ref_match/1, fun_ref_record/1, gencall/1, gs_make/1, - inf_loop2/1, letrec1/1, list_match/1, lzip/1, make_tuple/1, - minus_minus/1, mod_info/1, my_filter/1, my_sofs/1, no_match/1, - no_unused_fun/1, no_unused_fun2/1, non_existing/1, - not_guard_crash/1, or_bug/1, orelsebug/1, orelsebug2/1, - overloaded1/1, port_info_test/1, process_info_test/1, pubsub/1, - receive1/1, record_construct/1, record_pat/1, - record_send_test/1, record_test/1, recursive_types1/1, - recursive_types2/1, recursive_types3/1, recursive_types4/1, - recursive_types5/1, recursive_types6/1, recursive_types7/1, - refine_bug1/1, toth/1, trec/1, try1/1, tuple1/1, - unsafe_beamcode_bug/1, unused_cases/1, unused_clauses/1, - zero_tuple/1]). + inf_loop2/1, invalid_specs/1, letrec1/1, list_match/1, lzip/1, + make_tuple/1, minus_minus/1, mod_info/1, my_filter/1, + my_sofs/1, no_match/1, no_unused_fun/1, no_unused_fun2/1, + non_existing/1, not_guard_crash/1, or_bug/1, orelsebug/1, + orelsebug2/1, overloaded1/1, port_info_test/1, + process_info_test/1, pubsub/1, receive1/1, record_construct/1, + record_pat/1, record_send_test/1, record_test/1, + recursive_types1/1, recursive_types2/1, recursive_types3/1, + recursive_types4/1, recursive_types5/1, recursive_types6/1, + recursive_types7/1, refine_bug1/1, toth/1, trec/1, try1/1, + tuple1/1, unsafe_beamcode_bug/1, unused_cases/1, + unused_clauses/1, zero_tuple/1]). suite() -> [{timetrap, {minutes, 1}}]. @@ -51,10 +51,10 @@ all() -> atom_guard,atom_widen,bs_fail_constr,bs_utf8,cerl_hipeify,comm_layer, compare1,confusing_warning,contract2,contract3,contract5,disj_norm_form, eqeq,ets_select,exhaust_case,failing_guard1,flatten,fun_app,fun_ref_match, - fun_ref_record,gencall,gs_make,inf_loop2,letrec1,list_match,lzip, - make_tuple,minus_minus,mod_info,my_filter,my_sofs,no_match,no_unused_fun, - no_unused_fun2,non_existing,not_guard_crash,or_bug,orelsebug,orelsebug2, - overloaded1,port_info_test,process_info_test,pubsub,receive1, + fun_ref_record,gencall,gs_make,inf_loop2,invalid_specs,letrec1,list_match, + lzip,make_tuple,minus_minus,mod_info,my_filter,my_sofs,no_match, + no_unused_fun,no_unused_fun2,non_existing,not_guard_crash,or_bug,orelsebug, + orelsebug2,overloaded1,port_info_test,process_info_test,pubsub,receive1, record_construct,record_pat,record_send_test,record_test,recursive_types1, recursive_types2,recursive_types3,recursive_types4,recursive_types5, recursive_types6,recursive_types7,refine_bug1,toth,trec,try1,tuple1, @@ -235,6 +235,12 @@ inf_loop2(Config) -> Error -> ct:fail(Error) end. +invalid_specs(Config) -> + case dialyze(Config, invalid_specs) of + 'same' -> 'same'; + Error -> ct:fail(Error) + end. + letrec1(Config) -> case dialyze(Config, letrec1) of 'same' -> 'same'; diff --git a/lib/dialyzer/test/small_tests_SUITE_data/results/invalid_specs b/lib/dialyzer/test/small_tests_SUITE_data/results/invalid_specs new file mode 100644 index 0000000000..c95c0ff1f8 --- /dev/null +++ b/lib/dialyzer/test/small_tests_SUITE_data/results/invalid_specs @@ -0,0 +1,3 @@ + +invalid_spec1.erl:5: Invalid type specification for function invalid_spec1:get_plan_dirty/1. The success typing is ([string()]) -> {maybe_improper_list(),[atom()]} +invalid_spec2.erl:5: Function foo/0 has no local return diff --git a/lib/dialyzer/test/small_tests_SUITE_data/src/invalid_specs/invalid_spec1.erl b/lib/dialyzer/test/small_tests_SUITE_data/src/invalid_specs/invalid_spec1.erl new file mode 100644 index 0000000000..06ab2f9a22 --- /dev/null +++ b/lib/dialyzer/test/small_tests_SUITE_data/src/invalid_specs/invalid_spec1.erl @@ -0,0 +1,28 @@ +-module(invalid_spec1). + +-export([get_plan_dirty/1]). + +-spec get_plan_dirty([string()]) -> {{atom(), any()}, [atom()]}. + +get_plan_dirty(ClassL) -> + get_plan_dirty(ClassL, [], []). + +get_plan_dirty([], Res, FoundClassList) -> + {Res,FoundClassList}; +get_plan_dirty([Class|ClassL], Res, FoundClassList) -> + ClassPlan = list_to_atom(Class ++ "_plan"), + case catch mnesia:dirty_all_keys(ClassPlan) of + {'EXIT',_} -> + get_plan_dirty(ClassL, Res, FoundClassList); + [] -> + get_plan_dirty(ClassL, Res, FoundClassList); + KeyL -> + ClassAtom = list_to_atom(Class), + Res2 = + lists:foldl(fun(Key, Acc) -> + [{ClassAtom,Key}|Acc] + end, + Res, + KeyL), + get_plan_dirty(ClassL, Res2, [ClassAtom|FoundClassList]) + end. diff --git a/lib/dialyzer/test/small_tests_SUITE_data/src/invalid_specs/invalid_spec2.erl b/lib/dialyzer/test/small_tests_SUITE_data/src/invalid_specs/invalid_spec2.erl new file mode 100644 index 0000000000..e49f73d014 --- /dev/null +++ b/lib/dialyzer/test/small_tests_SUITE_data/src/invalid_specs/invalid_spec2.erl @@ -0,0 +1,11 @@ +-module(invalid_spec2). + +-export([foo/0]). + +foo() -> + case + invalid_spec1:get_plan_dirty(mnesia:dirty_all_keys(cmClassInfo)) + of + {[],[]} -> foo; + { _, _} -> bar + end. diff --git a/lib/docbuilder/test/Makefile b/lib/docbuilder/test/Makefile index 96b940033e..53dff193dc 100644 --- a/lib/docbuilder/test/Makefile +++ b/lib/docbuilder/test/Makefile @@ -72,7 +72,7 @@ release_spec: opt release_tests_spec: make_emakefile $(INSTALL_DIR) $(RELSYSDIR) $(INSTALL_DATA) $(SPEC_FILES) docb.cover $(EMAKEFILE) $(ERL_FILES) $(RELSYSDIR) - chmod -f -R u+w $(RELSYSDIR) + chmod -R u+w $(RELSYSDIR) @tar cf - *_SUITE_data | (cd $(RELSYSDIR); tar xf -) release_docs_spec: diff --git a/lib/edoc/src/edoc_wiki.erl b/lib/edoc/src/edoc_wiki.erl index b36aaae6ce..9a31bc9a82 100644 --- a/lib/edoc/src/edoc_wiki.erl +++ b/lib/edoc/src/edoc_wiki.erl @@ -296,6 +296,8 @@ push_uri(Us, Ss, As) -> strip_empty_lines(Cs) -> strip_empty_lines(Cs, 0). +strip_empty_lines([], N) -> + {[], N}; % reached the end of input strip_empty_lines(Cs, N) -> {Cs1, Cs2} = edoc_lib:split_at(Cs, $\n), case edoc_lib:is_space(Cs1) of diff --git a/lib/edoc/test/Makefile b/lib/edoc/test/Makefile index f77bbaa09b..2dbdb77eff 100644 --- a/lib/edoc/test/Makefile +++ b/lib/edoc/test/Makefile @@ -60,7 +60,7 @@ release_tests_spec: make_emakefile $(INSTALL_DIR) $(RELSYSDIR) $(INSTALL_DATA) $(EMAKEFILE) $(ERL_FILES) $(RELSYSDIR) $(INSTALL_DATA) edoc.spec edoc.cover $(RELSYSDIR) - chmod -f -R u+w $(RELSYSDIR) + chmod -R u+w $(RELSYSDIR) @tar cf - *_SUITE_data | (cd $(RELSYSDIR); tar xf -) release_docs_spec: diff --git a/lib/erl_interface/src/connect/ei_connect.c b/lib/erl_interface/src/connect/ei_connect.c index 158c1ec430..34362b4b9f 100644 --- a/lib/erl_interface/src/connect/ei_connect.c +++ b/lib/erl_interface/src/connect/ei_connect.c @@ -1197,7 +1197,7 @@ static char *hex(char digest[16], char buff[33]) char *p = buff; int i; - for (i = 0; i < sizeof(digest); ++i) { + for (i = 0; i < 16; ++i) { *p++ = tab[(int)((*d) >> 4)]; *p++ = tab[(int)((*d++) & 0xF)]; } diff --git a/lib/erl_interface/src/legacy/erl_timeout.c b/lib/erl_interface/src/legacy/erl_timeout.c index d9560eebc8..146a106e7c 100644 --- a/lib/erl_interface/src/legacy/erl_timeout.c +++ b/lib/erl_interface/src/legacy/erl_timeout.c @@ -43,6 +43,7 @@ # endif #endif +#include "erl_interface.h" #include "erl_timeout.h" typedef struct jmp_s { diff --git a/lib/erl_interface/test/Makefile b/lib/erl_interface/test/Makefile index 8ed6834443..4faf89c0d6 100644 --- a/lib/erl_interface/test/Makefile +++ b/lib/erl_interface/test/Makefile @@ -73,7 +73,7 @@ release_spec: release_tests_spec: opt $(INSTALL_DIR) $(RELSYSDIR) $(INSTALL_DATA) $(SPEC_FILES) $(COVER_FILE) $(ERL_FILES) $(RELSYSDIR) - chmod -f -R u+w $(RELSYSDIR) + chmod -R u+w $(RELSYSDIR) @tar cf - *_SUITE_data | (cd $(RELSYSDIR); tar xf -) release_docs_spec: diff --git a/lib/et/test/Makefile b/lib/et/test/Makefile index 9a24e3281b..e10a2a1587 100644 --- a/lib/et/test/Makefile +++ b/lib/et/test/Makefile @@ -74,7 +74,7 @@ release_tests_spec: opt $(INSTALL_DATA) et.spec et.cover $(ERL_FILES) $(HRL_FILES) $(RELSYSDIR) $(INSTALL_SCRIPT) ett $(RELSYSDIR) $(INSTALL_DATA) $(INSTALL_PROGS) $(RELSYSDIR) -# chmod -f -R u+w $(RELSYSDIR) +# chmod -R u+w $(RELSYSDIR) # @tar cf - *_SUITE_data | (cd $(RELSYSDIR); tar xf -) release_docs_spec: diff --git a/lib/eunit/src/eunit_lib.erl b/lib/eunit/src/eunit_lib.erl index 4751f1094a..45d2387e7b 100644 --- a/lib/eunit/src/eunit_lib.erl +++ b/lib/eunit/src/eunit_lib.erl @@ -33,7 +33,7 @@ -export([dlist_next/1, uniq/1, fun_parent/1, is_string/1, command/1, command/2, command/3, trie_new/0, trie_store/2, trie_match/2, split_node/1, consult_file/1, list_dir/1, format_exit_term/1, - format_exception/1, format_error/1]). + format_exception/1, format_exception/2, format_error/1]). %% Type definitions for describing exceptions @@ -55,21 +55,23 @@ %% --------------------------------------------------------------------- %% Formatting of error descriptors +format_exception(Exception) -> + format_exception(Exception, 20). -format_exception({Class,Term,Trace}) +format_exception({Class,Term,Trace}, Depth) when is_atom(Class), is_list(Trace) -> case is_stacktrace(Trace) of true -> io_lib:format("~w:~P\n~s", - [Class, Term, 20, format_stacktrace(Trace)]); + [Class, Term, Depth, format_stacktrace(Trace)]); false -> - format_term(Term) + format_term(Term, Depth) end; -format_exception(Term) -> - format_term(Term). +format_exception(Term, Depth) -> + format_term(Term, Depth). -format_term(Term) -> - io_lib:format("~P\n", [Term, 15]). +format_term(Term, Depth) -> + io_lib:format("~P\n", [Term, Depth]). format_exit_term(Term) -> {Reason, Trace} = analyze_exit_term(Term), diff --git a/lib/eunit/src/eunit_surefire.erl b/lib/eunit/src/eunit_surefire.erl index eb994a990a..f289cd724a 100644 --- a/lib/eunit/src/eunit_surefire.erl +++ b/lib/eunit/src/eunit_surefire.erl @@ -323,7 +323,7 @@ write_testcase( format_testcase_result(ok) -> [<<>>]; format_testcase_result({failed, {error, {Type, _}, _} = Exception}) when is_atom(Type) -> [?INDENT, ?INDENT, <<"<failure type=\"">>, escape_attr(atom_to_list(Type)), <<"\">">>, ?NEWLINE, - <<"::">>, escape_text(eunit_lib:format_exception(Exception)), + <<"::">>, escape_text(eunit_lib:format_exception(Exception, 100)), ?INDENT, ?INDENT, <<"</failure>">>, ?NEWLINE]; format_testcase_result({failed, Term}) -> [?INDENT, ?INDENT, <<"<failure type=\"unknown\">">>, ?NEWLINE, @@ -331,7 +331,7 @@ format_testcase_result({failed, Term}) -> ?INDENT, ?INDENT, <<"</failure>">>, ?NEWLINE]; format_testcase_result({aborted, {Class, _Term, _Trace} = Exception}) when is_atom(Class) -> [?INDENT, ?INDENT, <<"<error type=\"">>, escape_attr(atom_to_list(Class)), <<"\">">>, ?NEWLINE, - <<"::">>, escape_text(eunit_lib:format_exception(Exception)), + <<"::">>, escape_text(eunit_lib:format_exception(Exception, 100)), ?INDENT, ?INDENT, <<"</error>">>, ?NEWLINE]; format_testcase_result({aborted, Term}) -> [?INDENT, ?INDENT, <<"<error type=\"unknown\">">>, ?NEWLINE, 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 -> 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(). 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; 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)]. 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.</p> <p>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.</p> <marker id="config"></marker> @@ -472,7 +472,7 @@ http://your.server.org/eval?httpd_example:print(atom_to_list(apply(erlang,halt,[ <tag><em>bytes</em></tag> <item>The content-length of the document transferred. </item> </taglist> - <p>Internal server errors are recorde in the error log file. The + <p>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: </p> 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: - <code>{erl_script_alias, {"/cgi-bin/example" [httpd_example]} + <code>{erl_script_alias, {"/cgi-bin/example", [httpd_example]} </code> 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. </item> diff --git a/lib/inets/doc/src/mod_esi.xml b/lib/inets/doc/src/mod_esi.xml index 3c473d3f94..e81308a502 100644 --- a/lib/inets/doc/src/mod_esi.xml +++ b/lib/inets/doc/src/mod_esi.xml @@ -78,24 +78,24 @@ </type> <desc> <p>The <c>Module</c> must be found in the code path and export - <c>Function</c> with an arity of two. An erlScriptAlias must + <c>Function</c> with an arity of three. An erlScriptAlias must also be set up in the configuration file for the Web server.</p> - <p>If the HTTP request is a post request and a body is sent + <p>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 <em>?</em> in the url.</p> <p>ParsedHeader is the HTTP request as a key value tuple list. The keys in parsed header will be the in lower case.</p> <p>SessionID is a identifier - the server use when <c>deliver/2</c> is called, do not - assume any-thing about the datatype.</p> + the server uses when <c>deliver/2</c> is called; do not + assume anything about the datatype.</p> <p>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 <c>deliver/2</c>. 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 - <em>End of HTTP header</em> that is <c>"\r\n\r\n"</c> + will generate. If the first chunk does not contain the + <em>End of HTTP the header</em>, that is <c>"\r\n\r\n",</c> the server will assume that no HTTP header fields will be generated.</p> </desc> @@ -106,11 +106,12 @@ <type> <v>Env = [EnvironmentDirectives] ++ ParsedHeader</v> <v>EnvironmentDirectives = {Key,Value}</v> - <v>Key = query_string | content_length | server_software | gateway_interface | server_protocol | server_port | request_method | remote_addr | script_name. <v>Input = string()</v> + <v>Key = query_string | content_length | server_software | gateway_interface | server_protocol | server_port | request_method | remote_addr | script_name.</v> + <v>Input = string()</v> <v>Response = string()</v> </type> <desc> - <p>This callback format consumes quite much memory since the + <p>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/inets/test/Makefile b/lib/inets/test/Makefile index 110ad54c3c..87ca60e4b3 100644 --- a/lib/inets/test/Makefile +++ b/lib/inets/test/Makefile @@ -308,11 +308,11 @@ release_spec: opt release_tests_spec: opt $(INSTALL_DIR) $(RELTESTSYSDIR) $(INSTALL_DATA) $(RELTEST_FILES) $(RELTESTSYSDIR) - chmod -f -R u+w $(RELTESTSYSDIR) + chmod -R u+w $(RELTESTSYSDIR) tar chf - $(DATADIRS) | (cd $(RELTESTSYSDIR); tar xf -) $(INSTALL_DIR) $(RELTESTSYSALLDATADIR) $(INSTALL_DIR) $(RELTESTSYSBINDIR) - chmod -f -R +x $(RELTESTSYSBINDIR) + chmod -R +x $(RELTESTSYSBINDIR) $(INSTALL_DIR) $(RELTESTSYSALLDATADIR)/win32/lib release_docs_spec: diff --git a/lib/inviso/test/Makefile b/lib/inviso/test/Makefile index cd372624b5..c1df29d631 100644 --- a/lib/inviso/test/Makefile +++ b/lib/inviso/test/Makefile @@ -53,7 +53,7 @@ release_spec: opt release_tests_spec: make_emakefile $(INSTALL_DIR) $(RELSYSDIR) $(INSTALL_DATA) inviso.spec inviso.cover $(ERL_FILES) $(RELSYSDIR) - chmod -f -R u+w $(RELSYSDIR) + chmod -R u+w $(RELSYSDIR) @tar cf - *_SUITE_data | (cd $(RELSYSDIR); tar xf -) release_docs_spec: diff --git a/lib/kernel/doc/src/inet.xml b/lib/kernel/doc/src/inet.xml index a22c0a8346..f05a224f33 100644 --- a/lib/kernel/doc/src/inet.xml +++ b/lib/kernel/doc/src/inet.xml @@ -432,7 +432,7 @@ fe80::204:acff:fe17:bf38 </desc> </func> <func> - <name>port(Socket) -> {ok, Port}</name> + <name>port(Socket) -> {ok, Port} | {error, any()}</name> <fsummary>Return the local port number for a socket</fsummary> <type> <v>Socket = socket()</v> diff --git a/lib/kernel/doc/src/rpc.xml b/lib/kernel/doc/src/rpc.xml index 86c6ea9178..2b81de170d 100644 --- a/lib/kernel/doc/src/rpc.xml +++ b/lib/kernel/doc/src/rpc.xml @@ -454,7 +454,7 @@ </desc> </func> <func> - <name>pmap({Module, Function}, ExtraArgs, List2) -> List1</name> + <name>pmap({Module, Function}, ExtraArgs, List1) -> List2</name> <fsummary>Parallell evaluation of mapping a function over a list </fsummary> <type> <v>Module = Function = atom()</v> 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 diff --git a/lib/kernel/src/inet_res.erl b/lib/kernel/src/inet_res.erl index de0f23bf24..93563c6011 100644 --- a/lib/kernel/src/inet_res.erl +++ b/lib/kernel/src/inet_res.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1997-2010. All Rights Reserved. +%% Copyright Ericsson AB 1997-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 @@ -539,27 +539,41 @@ udp_send(#sock{inet=I}, {A,B,C,D}=IP, Port, Buffer) when ?ip(A,B,C,D), ?port(Port) -> gen_udp:send(I, IP, Port, Buffer). -udp_recv(#sock{inet6=I}, {A,B,C,D,E,F,G,H}=IP, Port, Timeout) +udp_recv(#sock{inet6=I}, {A,B,C,D,E,F,G,H}=IP, Port, Timeout, Decode) when ?ip6(A,B,C,D,E,F,G,H), ?port(Port) -> - do_udp_recv(fun(T) -> gen_udp:recv(I, 0, T) end, IP, Port, Timeout); -udp_recv(#sock{inet=I}, {A,B,C,D}=IP, Port, Timeout) + do_udp_recv(I, IP, Port, Timeout, Decode, erlang:now(), Timeout); +udp_recv(#sock{inet=I}, {A,B,C,D}=IP, Port, Timeout, Decode) when ?ip(A,B,C,D), ?port(Port) -> - do_udp_recv(fun(T) -> gen_udp:recv(I, 0, T) end, IP, Port, Timeout). - -do_udp_recv(Recv, IP, Port, Timeout) -> - do_udp_recv(Recv, IP, Port, Timeout, - if Timeout =/= 0 -> erlang:now(); true -> undefined end). - -do_udp_recv(Recv, IP, Port, Timeout, Then) -> - case Recv(Timeout) of - {ok,{IP,Port,Answer}} -> - {ok,Answer,erlang:max(0, Timeout - now_ms(erlang:now(), Then))}; - {ok,_} when Timeout =:= 0 -> - {error,timeout}; - {ok,_} -> - Now = erlang:now(), - T = erlang:max(0, Timeout - now_ms(Now, Then)), - do_udp_recv(Recv, IP, Port, T, Now); + do_udp_recv(I, IP, Port, Timeout, Decode, erlang:now(), Timeout). + +do_udp_recv(_I, _IP, _Port, 0, _Decode, _Start, _T) -> + timeout; +do_udp_recv(I, IP, Port, Timeout, Decode, Start, T) -> + case gen_udp:recv(I, 0, T) of + {ok,Reply} -> + case Decode(Reply) of + false when T =:= 0 -> + %% This is a compromize between the hard way i.e + %% in the clause below if NewT becomes 0 bailout + %% immediately and risk that the right reply lies + %% ahead after some bad id replies, and the + %% forgiving way i.e go on with Timeout 0 until + %% the right reply comes or no reply (timeout) + %% which opens for a DOS attack by a malicious + %% DNS server flooding with bad id replies causing + %% an infinite loop here. + %% + %% Timeout is used as a sanity limit counter + %% just to put an end to the loop. + NewTimeout = erlang:max(0, Timeout - 50), + do_udp_recv(I, IP, Port, NewTimeout, Decode, Start, T); + false -> + Now = erlang:now(), + NewT = erlang:max(0, Timeout - now_ms(Now, Start)), + do_udp_recv(I, IP, Port, Timeout, Decode, Start, NewT); + Result -> + Result + end; Error -> Error end. @@ -580,6 +594,17 @@ udp_close(#sock{inet=I,inet6=I6}) -> %% end %% end %% +%% But that man page also says dig always use num_servers = 1. +%% +%% Our man page says: timeout/retry, then double for next retry, i.e +%% for i = 0 to retry - 1 +%% foreach nameserver +%% send query +%% wait((time * (2**i)) / retry) +%% end +%% end +%% +%% And that is what the code seems to do, now fixed, hopefully... do_query(_Q, [], _Timer) -> {error,nxdomain}; @@ -589,19 +614,16 @@ do_query(#q{options=#options{retry=Retry}}=Q, NSs, Timer) -> query_retries(_Q, _NSs, _Timer, Retry, Retry, S) -> udp_close(S), {error,timeout}; +query_retries(_Q, [], _Timer, _Retry, _I, S) -> + udp_close(S), + {error,timeout}; query_retries(Q, NSs, Timer, Retry, I, S0) -> - Num = length(NSs), - if Num =:= 0 -> - udp_close(S0), - {error,timeout}; - true -> - case query_nss(Q, NSs, Timer, Retry, I, S0, []) of - {S,{noanswer,ErrNSs}} -> %% remove unreachable nameservers - query_retries(Q, NSs--ErrNSs, Timer, Retry, I+1, S); - {S,Result} -> - udp_close(S), - Result - end + case query_nss(Q, NSs, Timer, Retry, I, S0, []) of + {S,{noanswer,ErrNSs}} -> %% remove unreachable nameservers + query_retries(Q, NSs--ErrNSs, Timer, Retry, I+1, S); + {S,Result} -> + udp_close(S), + Result end. query_nss(_Q, [], _Timer, _Retry, _I, S, ErrNSs) -> @@ -611,13 +633,13 @@ query_nss(#q{edns=undefined}=Q, NSs, Timer, Retry, I, S, ErrNSs) -> query_nss(Q, NSs, Timer, Retry, I, S, ErrNSs) -> query_nss_edns(Q, NSs, Timer, Retry, I, S, ErrNSs). -query_nss_edns(#q{options=#options{udp_payload_size=PSz}=Options, - edns={Id,Buffer}}=Q, - [{IP,Port}=NS|NSs]=NSs0, Timer, Retry, I, S0, ErrNSs) -> - {S,Res}=Reply = query_ns(S0, Id, Buffer, IP, Port, Timer, - Retry, I, Options, PSz), +query_nss_edns( + #q{options=#options{udp_payload_size=PSz}=Options,edns={Id,Buffer}}=Q, + [{IP,Port}=NS|NSs]=NSs0, Timer, Retry, I, S0, ErrNSs) -> + {S,Res}=Reply = + query_ns(S0, Id, Buffer, IP, Port, Timer, Retry, I, Options, PSz), case Res of - timeout -> {S,{error,timeout}}; + timeout -> {S,{error,timeout}}; % Bailout timeout {ok,_} -> Reply; {error,{nxdomain,_}} -> Reply; {error,{E,_}} when E =:= qfmterror; E =:= notimp; E =:= servfail; @@ -629,17 +651,19 @@ query_nss_edns(#q{options=#options{udp_payload_size=PSz}=Options, query_nss(Q, NSs, Timer, Retry, I, S, ErrNSs) end. -query_nss_dns(#q{dns=Qdns}=Q0, [{IP,Port}=NS|NSs], - Timer, Retry, I, S0, ErrNSs) -> +query_nss_dns( + #q{dns=Qdns}=Q0, + [{IP,Port}=NS|NSs], Timer, Retry, I, S0, ErrNSs) -> #q{options=Options,dns={Id,Buffer}}=Q = if is_function(Qdns, 0) -> Q0#q{dns=Qdns()}; true -> Q0 end, - {S,Res}=Reply = query_ns(S0, Id, Buffer, IP, Port, Timer, - Retry, I, Options, ?PACKETSZ), + {S,Res}=Reply = + query_ns( + S0, Id, Buffer, IP, Port, Timer, Retry, I, Options, ?PACKETSZ), case Res of - timeout -> {S,{error,timeout}}; + timeout -> {S,{error,timeout}}; % Bailout timeout {ok,_} -> Reply; {error,{E,_}} when E =:= nxdomain; E =:= qfmterror -> Reply; {error,E} when E =:= fmt; E =:= enetunreach; E =:= econnrefused -> @@ -653,48 +677,66 @@ query_ns(S0, Id, Buffer, IP, Port, Timer, Retry, I, PSz) -> case UseVC orelse iolist_size(Buffer) > PSz of true -> - {S0,query_tcp(Tm, Id, Buffer, IP, Port, Timer, Verbose)}; + TcpTimeout = inet:timeout(Tm*5, Timer), + {S0,query_tcp(TcpTimeout, Id, Buffer, IP, Port, Verbose)}; false -> case udp_open(S0, IP) of {ok,S} -> - {S,case query_udp(S, Id, Buffer, IP, Port, Timer, - Retry, I, Tm, Verbose) of - {ok,#dns_rec{header=H}} when H#dns_header.tc -> - query_tcp(Tm, Id, Buffer, - IP, Port, Timer, Verbose); - Reply -> Reply - end}; + Timeout = + inet:timeout( (Tm * (1 bsl I)) div Retry, Timer), + {S, + case query_udp( + S, Id, Buffer, IP, Port, Timeout, Verbose) of + {ok,#dns_rec{header=H}} when H#dns_header.tc -> + TcpTimeout = inet:timeout(Tm*5, Timer), + query_tcp( + TcpTimeout, Id, Buffer, IP, Port, Verbose); + Reply -> Reply + end}; Error -> {S0,Error} end end. -query_udp(S, Id, Buffer, IP, Port, Timer, Retry, I, Tm, Verbose) -> - Timeout = inet:timeout( (Tm * (1 bsl I)) div Retry, Timer), +query_udp(_S, _Id, _Buffer, _IP, _Port, 0, Verbose) -> + timeout; +query_udp(S, Id, Buffer, IP, Port, Timeout, Verbose) -> ?verbose(Verbose, "Try UDP server : ~p:~p (timeout=~w)\n", - [IP, Port, Timeout]), - udp_connect(S, IP, Port), - udp_send(S, IP, Port, Buffer), - query_udp_recv(S, IP, Port, Id, Timeout, Verbose). - -query_udp_recv(S, IP, Port, Id, Timeout, Verbose) -> - case udp_recv(S, IP, Port, Timeout) of - {ok,Answer,T} -> - case decode_answer(Answer, Id, Verbose) of - {error, badid} -> - query_udp_recv(S, IP, Port, Id, T, Verbose); - Reply -> Reply + [IP,Port,Timeout]), + case + case udp_connect(S, IP, Port) of + ok -> + udp_send(S, IP, Port, Buffer); + E1 -> + E1 end of + ok -> + Decode = + fun ({RecIP,RecPort,Answer}) + when RecIP =:= IP, RecPort =:= Port -> + case decode_answer(Answer, Id, Verbose) of + {error,badid} -> + false; + Reply -> + Reply + end; + ({_,_,_}) -> + false + end, + case udp_recv(S, IP, Port, Timeout, Decode) of + {ok,_}=Result -> + Result; + E2 -> + ?verbose(Verbose, "UDP server error: ~p\n", [E2]), + E2 end; - {error, timeout} when Timeout =:= 0 -> - ?verbose(Verbose, "UDP server timeout\n", []), - timeout; - Error -> - ?verbose(Verbose, "UDP server error: ~p\n", [Error]), - Error + E3 -> + ?verbose(Verbose, "UDP send failed: ~p\n", [E3]), + {error,econnrefused} end. -query_tcp(Tm, Id, Buffer, IP, Port, Timer, Verbose) -> - Timeout = inet:timeout(Tm*5, Timer), +query_tcp(0, _Id, _Buffer, _IP, _Port, Verbose) -> + timeout; +query_tcp(Timeout, Id, Buffer, IP, Port, Verbose) -> ?verbose(Verbose, "Try TCP server : ~p:~p (timeout=~w)\n", [IP, Port, Timeout]), Family = case IP of @@ -716,19 +758,10 @@ query_tcp(Tm, Id, Buffer, IP, Port, Timer, Verbose) -> end; Error -> gen_tcp:close(S), - case Error of - {error, timeout} when Timeout =:= 0 -> - ?verbose(Verbose, "TCP server recv timeout\n", []), - timeout; - _ -> - ?verbose(Verbose, "TCP server recv error: ~p\n", - [Error]), - Error - end + ?verbose(Verbose, "TCP server recv error: ~p\n", + [Error]), + Error end; - {error, timeout} when Timeout =:= 0 -> - ?verbose(Verbose, "TCP server connect timeout\n", []), - timeout; Error -> ?verbose(Verbose, "TCP server error: ~p\n", [Error]), Error diff --git a/lib/kernel/src/net_kernel.erl b/lib/kernel/src/net_kernel.erl index 49a02359b0..5228d4fe01 100644 --- a/lib/kernel/src/net_kernel.erl +++ b/lib/kernel/src/net_kernel.erl @@ -1249,7 +1249,7 @@ protocol_childspecs([H|T]) -> epmd_module() -> case init:get_argument(epmd_module) of {ok,[[Module]]} -> - Module; + list_to_atom(Module); _ -> erl_epmd end. diff --git a/lib/kernel/test/Makefile b/lib/kernel/test/Makefile index 5f8f3a6bf6..95517ffd6a 100644 --- a/lib/kernel/test/Makefile +++ b/lib/kernel/test/Makefile @@ -144,7 +144,7 @@ release_tests_spec: make_emakefile $(INSTALL_DATA) $(APP_FILES) $(RELSYSDIR) $(INSTALL_DATA) kernel.spec $(EMAKEFILE)\ $(COVERFILE) $(RELSYSDIR) - chmod -f -R u+w $(RELSYSDIR) + chmod -R u+w $(RELSYSDIR) @tar cf - *_SUITE_data | (cd $(RELSYSDIR); tar xf -) release_docs_spec: diff --git a/lib/kernel/test/file_SUITE.erl b/lib/kernel/test/file_SUITE.erl index 8078c7d021..2f73394c4e 100644 --- a/lib/kernel/test/file_SUITE.erl +++ b/lib/kernel/test/file_SUITE.erl @@ -2055,6 +2055,10 @@ try_read_file_list(Fd) -> ?line Title = "Real Programmers Don't Use PASCAL</TITLE>\n", ?line Title = io:get_line(Fd, ''), + %% Seek past the end of the file. + + ?line {ok, _} = ?FILE_MODULE:position(Fd, 25000), + %% Done. ?line ?FILE_MODULE:close(Fd), diff --git a/lib/kernel/test/gen_tcp_misc_SUITE.erl b/lib/kernel/test/gen_tcp_misc_SUITE.erl index 3b313a6c21..b1ef8826d5 100644 --- a/lib/kernel/test/gen_tcp_misc_SUITE.erl +++ b/lib/kernel/test/gen_tcp_misc_SUITE.erl @@ -39,7 +39,7 @@ accept_timeouts_in_order/1,accept_timeouts_in_order2/1, accept_timeouts_in_order3/1,accept_timeouts_mixed/1, killing_acceptor/1,killing_multi_acceptors/1,killing_multi_acceptors2/1, - several_accepts_in_one_go/1,active_once_closed/1, send_timeout/1, + several_accepts_in_one_go/1,active_once_closed/1, send_timeout/1, send_timeout_active/1, otp_7731/1, zombie_sockets/1, otp_7816/1, otp_8102/1]). %% Internal exports. @@ -71,7 +71,7 @@ all() -> accept_timeouts_in_order3, accept_timeouts_mixed, killing_acceptor, killing_multi_acceptors, killing_multi_acceptors2, several_accepts_in_one_go, - active_once_closed, send_timeout, otp_7731, + active_once_closed, send_timeout, send_timeout_active, otp_7731, zombie_sockets, otp_7816, otp_8102]. groups() -> @@ -1957,6 +1957,60 @@ send_timeout(Config) when is_list(Config) -> ParaFun(false), ParaFun(true), ok. +mad_sender(S) -> + {_, _, USec} = now(), + case gen_tcp:send(S, integer_to_list(USec)) of + ok -> + mad_sender(S); + Err -> + Err + end. + + +flush() -> + receive + _X -> + %erlang:display(_X), + flush() + after 0 -> + ok + end. + +send_timeout_active(suite) -> + []; +send_timeout_active(doc) -> + ["Test the send_timeout socket option for active sockets"]; +send_timeout_active(Config) when is_list(Config) -> + Dog = test_server:timetrap(test_server:seconds(20)), + %% Basic + BasicFun = + fun(AutoClose) -> + ?line {Loop,A,RNode,C} = setup_active_timeout_sink(1, AutoClose), + inet:setopts(A, [{active, once}]), + ?line Mad = spawn_link(RNode,fun() -> mad_sender(C) end), + ?line {error,timeout} = + Loop(fun() -> + receive + {tcp, Sock, _Data} -> + inet:setopts(A, [{active, once}]), + Res = gen_tcp:send(A,lists:duplicate(1000, $a)), + %erlang:display(Res), + Res; + Err -> + io:format("sock closed: ~p~n", [Err]), + Err + end + end), + unlink(Mad), + exit(Mad,kill), + ?line test_server:stop_node(RNode) + end, + BasicFun(false), + flush(), + BasicFun(true), + flush(), + test_server:timetrap_cancel(Dog), + ok. after_send_timeout(AutoClose) -> case AutoClose of @@ -2039,35 +2093,35 @@ setup_closed_ao() -> {Loop,A}. setup_timeout_sink(Timeout, AutoClose) -> - Dir = filename:dirname(code:which(?MODULE)), - {ok,R} = test_server:start_node(test_default_options_slave,slave, + ?line Dir = filename:dirname(code:which(?MODULE)), + ?line {ok,R} = test_server:start_node(test_default_options_slave,slave, [{args,"-pa " ++ Dir}]), - Host = list_to_atom(lists:nth(2,string:tokens(atom_to_list(node()),"@"))), - {ok, L} = gen_tcp:listen(0, [{active,false},{packet,2}, + ?line Host = list_to_atom(lists:nth(2,string:tokens(atom_to_list(node()),"@"))), + ?line {ok, L} = gen_tcp:listen(0, [{active,false},{packet,2}, {send_timeout,Timeout}, {send_timeout_close,AutoClose}]), - Fun = fun(F) -> + ?line Fun = fun(F) -> receive {From,X} when is_function(X) -> From ! {self(),X()}, F(F); die -> ok end end, - Pid = rpc:call(R,erlang,spawn,[fun() -> Fun(Fun) end]), - {ok, Port} = inet:port(L), - Remote = fun(Fu) -> + ?line Pid = rpc:call(R,erlang,spawn,[fun() -> Fun(Fun) end]), + ?line {ok, Port} = inet:port(L), + ?line Remote = fun(Fu) -> Pid ! {self(), Fu}, receive {Pid,X} -> X end end, - {ok, C} = Remote(fun() -> + ?line {ok, C} = Remote(fun() -> gen_tcp:connect(Host,Port, [{active,false},{packet,2}]) end), - {ok,A} = gen_tcp:accept(L), - gen_tcp:send(A,"Hello"), - {ok, "Hello"} = Remote(fun() -> gen_tcp:recv(C,0) end), - Loop2 = fun(_,_,0) -> + ?line {ok,A} = gen_tcp:accept(L), + ?line gen_tcp:send(A,"Hello"), + ?line {ok, "Hello"} = Remote(fun() -> gen_tcp:recv(C,0) end), + ?line Loop2 = fun(_,_,0) -> {failure, timeout}; (L2,F2,N) -> Ret = F2(), @@ -2078,9 +2132,53 @@ setup_timeout_sink(Timeout, AutoClose) -> Other -> Other end end, - Loop = fun(F3) -> Loop2(Loop2,F3,1000) end, + ?line Loop = fun(F3) -> Loop2(Loop2,F3,1000) end, {Loop,A,R}. - + +setup_active_timeout_sink(Timeout, AutoClose) -> + ?line Dir = filename:dirname(code:which(?MODULE)), + ?line {ok,R} = test_server:start_node(test_default_options_slave,slave, + [{args,"-pa " ++ Dir}]), + ?line Host = list_to_atom(lists:nth(2,string:tokens(atom_to_list(node()),"@"))), + ?line {ok, L} = gen_tcp:listen(0, [binary,{active,false},{packet,0},{nodelay, true},{keepalive, true}, + {send_timeout,Timeout}, + {send_timeout_close,AutoClose}]), + ?line Fun = fun(F) -> + receive + {From,X} when is_function(X) -> + From ! {self(),X()}, F(F); + die -> ok + end + end, + ?line Pid = rpc:call(R,erlang,spawn,[fun() -> Fun(Fun) end]), + ?line {ok, Port} = inet:port(L), + ?line Remote = fun(Fu) -> + Pid ! {self(), Fu}, + receive {Pid,X} -> X + end + end, + ?line {ok, C} = Remote(fun() -> + gen_tcp:connect(Host,Port, + [{active,false}]) + end), + ?line {ok,A} = gen_tcp:accept(L), + ?line gen_tcp:send(A,"Hello"), + ?line {ok, "H"++_} = Remote(fun() -> gen_tcp:recv(C,0) end), + ?line Loop2 = fun(_,_,0) -> + {failure, timeout}; + (L2,F2,N) -> + Ret = F2(), + io:format("~p~n",[Ret]), + case Ret of + ok -> receive after 1 -> ok end, + L2(L2,F2,N-1); + Other -> Other + end + end, + ?line Loop = fun(F3) -> Loop2(Loop2,F3,1000) end, + {Loop,A,R,C}. + + millistamp() -> {Mega, Secs, Micros} = erlang:now(), (Micros div 1000) + Secs * 1000 + Mega * 1000000000. diff --git a/lib/kernel/test/heart_SUITE.erl b/lib/kernel/test/heart_SUITE.erl index 043c753cf8..233e438dc9 100644 --- a/lib/kernel/test/heart_SUITE.erl +++ b/lib/kernel/test/heart_SUITE.erl @@ -22,7 +22,7 @@ -export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1, init_per_group/2,end_per_group/2, start/1, restart/1, - reboot/1, set_cmd/1, clear_cmd/1, + reboot/1, set_cmd/1, clear_cmd/1, get_cmd/1, dont_drop/1, kill_pid/1]). -export([init_per_testcase/2, end_per_testcase/2]). @@ -58,7 +58,7 @@ end_per_testcase(_Func, Config) -> suite() -> [{ct_hooks,[ts_install_cth]}]. all() -> - [start, restart, reboot, set_cmd, clear_cmd, kill_pid]. + [start, restart, reboot, set_cmd, clear_cmd, get_cmd, kill_pid]. groups() -> []. @@ -246,6 +246,15 @@ clear_cmd(Config) when is_list(Config) -> end, ok. +get_cmd(suite) -> []; +get_cmd(Config) when is_list(Config) -> + ?line {ok, Node} = start_check(slave, heart_test), + Cmd = "test", + ?line ok = rpc:call(Node, heart, set_cmd, [Cmd]), + ?line {ok, Cmd} = rpc:call(Node, heart, get_cmd, []), + stop_node(Node), + ok. + dont_drop(suite) -> %%% Removed as it may crash epmd/distribution in colourful %%% ways. While we ARE finding out WHY, it would diff --git a/lib/kernel/test/inet_res_SUITE.erl b/lib/kernel/test/inet_res_SUITE.erl index 5fc8df475d..6064a9b2d9 100644 --- a/lib/kernel/test/inet_res_SUITE.erl +++ b/lib/kernel/test/inet_res_SUITE.erl @@ -27,7 +27,8 @@ -export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1, init_per_group/2,end_per_group/2, init_per_testcase/2, end_per_testcase/2]). --export([basic/1, resolve/1, edns0/1, txt_record/1, files_monitor/1]). +-export([basic/1, resolve/1, edns0/1, txt_record/1, files_monitor/1, + last_ms_answer/1]). -export([ gethostbyaddr/0, gethostbyaddr/1, gethostbyaddr_v6/0, gethostbyaddr_v6/1, @@ -45,6 +46,7 @@ suite() -> [{ct_hooks,[ts_install_cth]}]. all() -> [basic, resolve, edns0, txt_record, files_monitor, + last_ms_answer, gethostbyaddr, gethostbyaddr_v6, gethostbyname, gethostbyname_v6, getaddr, getaddr_v6, ipv4_to_ipv6, host_and_addr]. @@ -64,16 +66,15 @@ init_per_group(_GroupName, Config) -> end_per_group(_GroupName, Config) -> Config. -zone_dir(basic) -> - otptest; -zone_dir(resolve) -> - otptest; -zone_dir(edns0) -> - otptest; -zone_dir(files_monitor) -> - otptest; -zone_dir(_) -> - undefined. +zone_dir(TC) -> + case TC of + basic -> otptest; + resolve -> otptest; + edns0 -> otptest; + files_monitor -> otptest; + last_ms_answer -> otptest; + _ -> undefined + end. init_per_testcase(Func, Config) -> PrivDir = ?config(priv_dir, Config), @@ -184,6 +185,88 @@ ns_printlog(Fname) -> ok end. +%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% Behaviour modifying nameserver proxy + +proxy_start(TC, {NS,P}) -> + Tag = make_ref(), + Parent = self(), + Pid = + spawn_link( + fun () -> + try proxy_start(TC, NS, P, Parent, Tag) + catch C:X -> + io:format( + "~w: ~w:~p ~p~n", + [self(),C,X,erlang:get_stacktrace()]) + end + end), + receive {started,Tag,Port} -> + ProxyNS = {{127,0,0,1},Port}, + {proxy,Pid,Tag,ProxyNS} + end. + +proxy_start(TC, NS, P, Parent, Tag) -> + {ok,Outbound} = gen_udp:open(0, [binary]), + ok = gen_udp:connect(Outbound, NS, P), + {ok,Inbound} = gen_udp:open(0, [binary]), + {ok,Port} = inet:port(Inbound), + Parent ! {started,Tag,Port}, + proxy(TC, Outbound, NS, P, Inbound). + + +%% To provoke the last_ms_answer bug (OTP-9221) the proxy +%% * Relays the query to the right nameserver +%% * Intercepts the reply but holds it until the timer that +%% was started when receiving the query fires. +%% * Repeats the reply with incorrect query ID a number of +%% times with a short interval. +%% * Sends the correct reply, to give a correct test result +%% after bug correction. +%% +%% The repetition of an incorrect answer with tight interval will keep +%% inet_res in an inner loop in the code that decrements the remaining +%% time until it hits 0 which triggers a crash, if the outer timeout +%% parameter to inet_res:resolve is so short that it runs out during +%% these repetitions. +proxy(last_ms_answer, Outbound, NS, P, Inbound) -> + receive + {udp,Inbound,SrcIP,SrcPort,Data} -> + Time = + inet_db:res_option(timeout) div inet_db:res_option(retry), + Tag = erlang:make_ref(), + erlang:send_after(Time - 10, self(), {time,Tag}), + ok = gen_udp:send(Outbound, NS, P, Data), + receive + {udp,Outbound,NS,P,Reply} -> + {ok,Msg} = inet_dns:decode(Reply), + Hdr = inet_dns:msg(Msg, header), + Id = inet_dns:header(Hdr, id), + BadHdr = + inet_dns:make_header(Hdr, id, (Id+1) band 16#ffff), + BadMsg = inet_dns:make_msg(Msg, header, BadHdr), + BadReply = inet_dns:encode(BadMsg), + receive + {time,Tag} -> + proxy__last_ms_answer( + Inbound, SrcIP, SrcPort, BadReply, Reply, 30) + end + end + end. + +proxy__last_ms_answer(Socket, IP, Port, _, Reply, 0) -> + ok = gen_udp:send(Socket, IP, Port, Reply); +proxy__last_ms_answer(Socket, IP, Port, BadReply, Reply, N) -> + ok = gen_udp:send(Socket, IP, Port, BadReply), + receive after 1 -> ok end, + proxy__last_ms_answer(Socket, IP, Port, BadReply, Reply, N-1). + +proxy_wait({proxy,Pid,_,_}) -> + Mref = erlang:monitor(process, Pid), + receive {'DOWN',Mref,_,_,_} -> ok end. + +proxy_ns({proxy,_,_,ProxyNS}) -> ProxyNS. + %% %% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -204,7 +287,7 @@ basic(Config) when is_list(Config) -> {ok,Msg1} = inet_dns:decode(Bin1), %% %% resolve - {ok,Msg2} = inet_res:resolve(Name, in, a, [{nameservers,[NS]}]), + {ok,Msg2} = inet_res:resolve(Name, in, a, [{nameservers,[NS]},verbose]), io:format("~p~n", [Msg2]), [RR2] = inet_dns:msg(Msg2, anlist), IP = inet_dns:rr(RR2, data), @@ -474,6 +557,26 @@ do_files_monitor(Config) -> ok. %% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +last_ms_answer(doc) -> + ["Answer just when timeout is triggered (OTP-9221)"]; +last_ms_answer(Config) when is_list(Config) -> + NS = ns(Config), + Name = "ns.otptest", + %%IP = {127,0,0,254}, + Time = inet_db:res_option(timeout) div inet_db:res_option(retry), + PSpec = proxy_start(last_ms_answer, NS), + ProxyNS = proxy_ns(PSpec), + %% + %% resolve; whith short timeout to trigger Timeout =:= 0 in inet_res + {error,timeout} = + inet_res:resolve( + Name, in, a, [{nameservers,[ProxyNS]},verbose], Time + 10), + %% + proxy_wait(PSpec), + ok. + +%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% Compatibility tests. Call the inet_SUITE tests, but with %% lookup = [file,dns] instead of [native] diff --git a/lib/kernel/test/init_SUITE.erl b/lib/kernel/test/init_SUITE.erl index 06bfe97bc4..2db0f7dcb8 100644 --- a/lib/kernel/test/init_SUITE.erl +++ b/lib/kernel/test/init_SUITE.erl @@ -24,6 +24,7 @@ init_per_group/2,end_per_group/2]). -export([get_arguments/1, get_argument/1, boot_var/1, restart/1, + many_restarts/1, get_plain_arguments/1, reboot/1, stop/1, get_status/1, script_id/1]). -export([boot1/1, boot2/1]). @@ -43,6 +44,7 @@ suite() -> [{ct_hooks,[ts_install_cth]}]. all() -> [get_arguments, get_argument, boot_var, + many_restarts, get_plain_arguments, restart, get_status, script_id, {group, boot}]. @@ -317,6 +319,73 @@ is_real_system(KernelVsn, StdlibVsn) -> %% Therefore the slave process must be killed %% before restart. %% ------------------------------------------------ +many_restarts(doc) -> []; +many_restarts(suite) -> + case ?t:os_type() of + {Fam, _} when Fam == unix; Fam == win32 -> + {req, [distribution, {local_slave_nodes, 1}, {time, 5}]}; + _ -> + {skip, "Only run on unix and win32"} + end; + +many_restarts(Config) when is_list(Config) -> + ?line Dog = ?t:timetrap(?t:seconds(480)), + ?line {ok, Node} = loose_node:start(init_test, "", ?DEFAULT_TIMEOUT_SEC), + ?line loop_restart(30,Node,rpc:call(Node,erlang,whereis,[error_logger])), + ?line loose_node:stop(Node), + ?line ?t:timetrap_cancel(Dog), + ok. + +loop_restart(0,_,_) -> + ok; +loop_restart(N,Node,EHPid) -> + ?line erlang:monitor_node(Node, true), + ?line ok = rpc:call(Node, init, restart, []), + ?line receive + {nodedown, Node} -> + ok + after 10000 -> + loose_node:stop(Node), + ?t:fail(not_stopping) + end, + ?line ok = wait_for(30, Node, EHPid), + ?line loop_restart(N-1,Node,rpc:call(Node,erlang,whereis,[error_logger])). + +wait_for(0,Node,_) -> + loose_node:stop(Node), + error; +wait_for(N,Node,EHPid) -> + ?line case rpc:call(Node, erlang, whereis, [error_logger]) of + Pid when is_pid(Pid), Pid =/= EHPid -> + %% ?line erlang:display(ok), + ?line ok; + _X -> + %% ?line erlang:display(_X), + %% ?line Procs = rpc:call(Node, erlang, processes, []), + %% ?line erlang:display(Procs), + %% case is_list(Procs) of + %% true -> + %% ?line [(catch erlang:display( + %% rpc:call(Node, + %% erlang, + %% process_info, + %% [Y,registered_name]))) + %% || Y <- Procs]; + %% _ -> + %% ok + %% end, + receive + after 100 -> + ok + end, + ?line wait_for(N-1,Node,EHPid) + end. + +%% ------------------------------------------------ +%% Slave executes erlang:halt() on master nodedown. +%% Therefore the slave process must be killed +%% before restart. +%% ------------------------------------------------ restart(doc) -> []; restart(suite) -> case ?t:os_type() of diff --git a/lib/megaco/test/Makefile b/lib/megaco/test/Makefile index 682b83d368..88f6f06e73 100644 --- a/lib/megaco/test/Makefile +++ b/lib/megaco/test/Makefile @@ -754,5 +754,5 @@ release_tests_spec: tests # $(HRL_FILES) $(ERL_FILES) \ # $(RELSYSDIR) # - chmod -f -R u+w $(RELSYSDIR) + chmod -R u+w $(RELSYSDIR) 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.</p> - <section><title>Mnesia 4.4.17</title> + <section><title>Mnesia 4.4.18</title> + + <section><title>Fixed Bugs and Malfunctions</title> + <list> + <item> + <p> + Call chmod without the "-f" flag</p> + <p> + "-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�)</p> + <p> + Own Id: OTP-9170</p> + </item> + <item> + <p> + Mnesia sometimes failed to update meta-information in + large systems, which could cause table content to be + inconsistent between nodes.</p> + <p> + Own Id: OTP-9186 Aux Id: seq11728 </p> + </item> + </list> + </section> + +</section> + +<section><title>Mnesia 4.4.17</title> <section><title>Fixed Bugs and Malfunctions</title> <list> 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/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) -> diff --git a/lib/mnesia/test/Makefile b/lib/mnesia/test/Makefile index 973ac2900a..b165924ef2 100644 --- a/lib/mnesia/test/Makefile +++ b/lib/mnesia/test/Makefile @@ -110,7 +110,7 @@ release_tests_spec: opt $(INSTALL_DIR) $(RELSYSDIR) $(INSTALL_DATA) mnesia.spec mnesia.cover $(ERL_FILES) $(HRL_FILES) $(RELSYSDIR) $(INSTALL_SCRIPT) mt $(INSTALL_PROGS) $(RELSYSDIR) -# chmod -f -R u+w $(RELSYSDIR) +# chmod -R u+w $(RELSYSDIR) # @tar cf - *_SUITE_data | (cd $(RELSYSDIR); tar xf -) release_docs_spec: 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 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) -> diff --git a/lib/orber/test/Makefile b/lib/orber/test/Makefile index 88aeacbfe8..b682bcf24b 100644 --- a/lib/orber/test/Makefile +++ b/lib/orber/test/Makefile @@ -226,7 +226,7 @@ release_tests_spec: tests $(INSTALL_DATA) $(IDL_FILES) $(TEST_SPEC_FILE) $(COVER_FILE) \ $(ERL_FILES) $(RELSYSDIR) $(INSTALL_DATA) $(SUITE_TARGET_FILES) $(RELSYSDIR) - chmod -f -R u+w $(RELSYSDIR) + chmod -R u+w $(RELSYSDIR) $(INSTALL_DIR) $(RELSYSDIR)/$(IDLOUTDIR) $(INSTALL_DATA) $(GEN_TARGET_FILES) $(GEN_FILES) \ $(RELSYSDIR)/$(IDLOUTDIR) diff --git a/lib/os_mon/src/disksup.erl b/lib/os_mon/src/disksup.erl index 3340f7ee72..3ee1df759f 100644 --- a/lib/os_mon/src/disksup.erl +++ b/lib/os_mon/src/disksup.erl @@ -103,6 +103,7 @@ init([]) -> Flavor==darwin; Flavor==linux; Flavor==openbsd; + Flavor==netbsd; Flavor==irix64; Flavor==irix -> start_portprogram(); @@ -267,6 +268,9 @@ check_disk_space({unix, freebsd}, Port, Threshold) -> check_disk_space({unix, openbsd}, Port, Threshold) -> Result = my_cmd("/bin/df -k -t ffs", Port), check_disks_solaris(skip_to_eol(Result), Threshold); +check_disk_space({unix, netbsd}, Port, Threshold) -> + Result = my_cmd("/bin/df -k -t ffs", Port), + check_disks_solaris(skip_to_eol(Result), Threshold); check_disk_space({unix, sunos4}, Port, Threshold) -> Result = my_cmd("df", Port), check_disks_solaris(skip_to_eol(Result), Threshold); diff --git a/lib/os_mon/src/memsup.erl b/lib/os_mon/src/memsup.erl index 822e1f939c..cc4941ee7d 100644 --- a/lib/os_mon/src/memsup.erl +++ b/lib/os_mon/src/memsup.erl @@ -176,9 +176,11 @@ init([]) -> PortMode = case OS of {unix, darwin} -> false; {unix, freebsd} -> false; + {unix, dragonfly} -> false; % Linux supports this. {unix, linux} -> true; {unix, openbsd} -> true; + {unix, netbsd} -> true; {unix, irix64} -> true; {unix, irix} -> true; {unix, sunos} -> true; @@ -610,8 +612,10 @@ code_change(Vsn, PrevState, "1.8") -> PortMode = case OS of {unix, darwin} -> false; {unix, freebsd} -> false; + {unix, dragonfly} -> false; {unix, linux} -> false; {unix, openbsd} -> true; + {unix, netbsd} -> true; {unix, sunos} -> true; {win32, _OSname} -> false; vxworks -> true @@ -687,6 +691,7 @@ get_os_wordsize({unix, linux}) -> get_os_wordsize_with_uname(); get_os_wordsize({unix, darwin}) -> get_os_wordsize_with_uname(); get_os_wordsize({unix, netbsd}) -> get_os_wordsize_with_uname(); get_os_wordsize({unix, freebsd}) -> get_os_wordsize_with_uname(); +get_os_wordsize({unix, dragonfly}) -> get_os_wordsize_with_uname(); get_os_wordsize({unix, openbsd}) -> get_os_wordsize_with_uname(); get_os_wordsize(_) -> unsupported_os. @@ -736,7 +741,7 @@ get_memory_usage({unix,darwin}) -> %% FreeBSD: Look in /usr/include/sys/vmmeter.h for the format of struct %% vmmeter -get_memory_usage({unix,freebsd}) -> +get_memory_usage({unix,OSname}) when OSname == freebsd; OSname == dragonfly -> PageSize = freebsd_sysctl("vm.stats.vm.v_page_size"), PageCount = freebsd_sysctl("vm.stats.vm.v_page_count"), FreeCount = freebsd_sysctl("vm.stats.vm.v_free_count"), @@ -779,6 +784,9 @@ get_ext_memory_usage(OS, {Alloc, Total}) -> {unix, freebsd} -> [{total_memory, Total}, {free_memory, Total-Alloc}, {system_total_memory, Total}]; + {unix, dragonfly} -> + [{total_memory, Total}, {free_memory, Total-Alloc}, + {system_total_memory, Total}]; {unix, darwin} -> [{total_memory, Total}, {free_memory, Total-Alloc}, {system_total_memory, Total}]; diff --git a/lib/parsetools/test/Makefile b/lib/parsetools/test/Makefile index dfb686d7ba..624c4e6975 100644 --- a/lib/parsetools/test/Makefile +++ b/lib/parsetools/test/Makefile @@ -72,7 +72,7 @@ release_spec: opt release_tests_spec: make_emakefile $(INSTALL_DIR) $(RELSYSDIR) $(INSTALL_DATA) parsetools.spec parsetools.cover $(EMAKEFILE) $(ERL_FILES) $(RELSYSDIR) - chmod -f -R u+w $(RELSYSDIR) + chmod -R u+w $(RELSYSDIR) # @tar cf - *_SUITE_data | (cd $(RELSYSDIR); tar xf -) release_docs_spec: diff --git a/lib/percept/test/Makefile b/lib/percept/test/Makefile index 5e8c438c5c..d927386d1c 100644 --- a/lib/percept/test/Makefile +++ b/lib/percept/test/Makefile @@ -83,7 +83,7 @@ release_spec: opt release_tests_spec: make_emakefile $(INSTALL_DIR) $(RELSYSDIR) $(INSTALL_DATA) percept.spec percept.cover $(EMAKEFILE) $(SOURCE) $(RELSYSDIR) - chmod -f -R u+w $(RELSYSDIR) + chmod -R u+w $(RELSYSDIR) @tar cf - *_SUITE_data | (cd $(RELSYSDIR); tar xf -) release_docs_spec: diff --git a/lib/public_key/doc/src/public_key.xml b/lib/public_key/doc/src/public_key.xml index 81aedaea56..c5f57214b1 100644 --- a/lib/public_key/doc/src/public_key.xml +++ b/lib/public_key/doc/src/public_key.xml @@ -56,44 +56,43 @@ <p><em>Data Types </em></p> - <p><c>boolean() = true | false</c></p> + <p><code>boolean() = true | false</code></p> - <p><c>string = [bytes()]</c></p> + <p><code>string = [bytes()]</code></p> - <p><c>der_encoded() = binary() </c></p> - - <p><c>decrypt_der() = binary() </c></p> + <p><code>pki_asn1_type() = 'Certificate' | 'RSAPrivateKey'| 'RSAPublicKey' + 'DSAPrivateKey' | 'DSAPublicKey' | 'DHParameter' | 'SubjectPublicKeyInfo'</code></p> - <p><c>pki_asn1_type() = 'Certificate' | 'RSAPrivateKey'| 'RSAPublicKey' - 'DSAPrivateKey' | 'DSAPublicKey' | 'DHParameter' | 'SubjectPublicKeyInfo'</c></p> - - <p><c>pem_entry () = {pki_asn1_type(), der_encoded() | decrypt_der(), not_encrypted | - {"DES-CBC" | "DES-EDE3-CBC", crypto:rand_bytes(8)}}.</c></p> - - <p><c>rsa_public_key() = #'RSAPublicKey'{}</c></p> + <p><code>pem_entry () = {pki_asn1_type(), binary() %% DER or encrypted DER + not_encrypted | {"DES-CBC" | "DES-EDE3-CBC", crypto:rand_bytes(8)}}.</code></p> - <p><c>rsa_private_key() = #'RSAPrivateKey'{} </c></p> + <p><code>rsa_public_key() = #'RSAPublicKey'{}</code></p> + + <p><code>rsa_private_key() = #'RSAPrivateKey'{} </code></p> - <p><c>dsa_public_key() = {integer(), #'Dss-Parms'{}} </c></p> + <p><code>dsa_public_key() = {integer(), #'Dss-Parms'{}} </code></p> - <p><c>rsa_private_key() = #'RSAPrivateKey'{} </c></p> + <p><code>rsa_private_key() = #'RSAPrivateKey'{} </code></p> - <p><c>dsa_private_key() = #'DSAPrivateKey'{}</c></p> + <p><code>dsa_private_key() = #'DSAPrivateKey'{}</code></p> - <p><c> public_crypt_options() = [{rsa_pad, rsa_padding()}]. </c></p> + <p><code> public_crypt_options() = [{rsa_pad, rsa_padding()}]. </code></p> - <p><c> rsa_padding() = 'rsa_pkcs1_padding' | 'rsa_pkcs1_oaep_padding' - | 'rsa_no_padding'</c></p> + <p><code> rsa_padding() = 'rsa_pkcs1_padding' | 'rsa_pkcs1_oaep_padding' + | 'rsa_no_padding'</code></p> - <p><c> rsa_digest_type() = 'md5' | 'sha' </c></p> - - <p><c> dss_digest_type() = 'none' | 'sha' </c></p> + <p><code> rsa_digest_type() = 'md5' | 'sha' </code></p> + + <p><code> dss_digest_type() = 'none' | 'sha' </code></p> + + <p><code> ssh_file() = openssh_public_key | rfc4716_public_key | + known_hosts | auth_keys </code></p> -<!-- <p><c>policy_tree() = [Root, Children]</c></p> --> +<!-- <p><code>policy_tree() = [Root, Children]</code></p> --> -<!-- <p><c>Root = #policy_tree_node{}</c></p> --> +<!-- <p><code>Root = #policy_tree_node{}</code></p> --> -<!-- <p><c>Children = [] | policy_tree()</c></p> --> +<!-- <p><code>Children = [] | policy_tree()</code></p> --> <!-- <p> The policy_tree_node record has the following fields:</p> --> @@ -403,6 +402,55 @@ </func> <func> + <name>ssh_decode(SshBin, Type) -> [{public_key(), Attributes::list()}]</name> + <fsummary>Decodes a ssh file-binary. </fsummary> + <type> + <v>SshBin = binary()</v> + <d>Example {ok, SshBin} = file:read_file("known_hosts").</d> + <v> Type = public_key | ssh_file()</v> + <d>If <c>Type</c> is <c>public_key</c> the binary may be either + a rfc4716 public key or a openssh public key.</d> + </type> + <desc> + <p> Decodes a ssh file-binary. In the case of know_hosts or + auth_keys the binary may include one or more lines of the + file. Returns a list of public keys and their attributes, possible + attribute values depends on the file type represented by the + binary. + </p> + + <taglist> + <tag>rfc4716 attributes - see RFC 4716</tag> + <item>{headers, [{string(), utf8_string()}]}</item> + <tag>auth_key attributes - see man sshd </tag> + <item>{comment, string()}</item> + <item>{options, [string()]}</item> + <item>{bits, integer()} - In ssh version 1 files</item> + <tag>known_host attributes - see man sshd</tag> + <item>{hostnames, [string()]}</item> + <item>{comment, string()}</item> + <item>{bits, integer()} - In ssh version 1 files</item> + </taglist> + + </desc> + </func> + + <func> + <name>ssh_encode([{Key, Attributes}], Type) -> binary()</name> + <fsummary> Encodes a list of ssh file entries to a binary.</fsummary> + <type> + <v>Key = public_key()</v> + <v>Attributes = list()</v> + <v>Type = ssh_file()</v> + </type> + <desc> + <p>Encodes a list of ssh file entries (public keys and attributes) to a binary. Possible + attributes depends on the file type, see <seealso + marker="ssh_decode"> ssh_decode/2 </seealso></p> + </desc> + </func> + + <func> <name>verify(Msg, DigestType, Signature, Key) -> boolean()</name> <fsummary>Verifies a digital signature.</fsummary> <type> diff --git a/lib/public_key/include/public_key.hrl b/lib/public_key/include/public_key.hrl index 3498a2a433..5f97d80f7e 100644 --- a/lib/public_key/include/public_key.hrl +++ b/lib/public_key/include/public_key.hrl @@ -70,14 +70,18 @@ interim_reasons_mask }). - --type der_encoded() :: binary(). --type decrypt_der() :: binary(). +-type public_key() :: rsa_public_key() | dsa_public_key(). +-type rsa_public_key() :: #'RSAPublicKey'{}. +-type rsa_private_key() :: #'RSAPrivateKey'{}. +-type dsa_private_key() :: #'DSAPrivateKey'{}. +-type dsa_public_key() :: {integer(), #'Dss-Parms'{}}. -type pki_asn1_type() :: 'Certificate' | 'RSAPrivateKey' | 'RSAPublicKey' | 'DSAPrivateKey' | 'DSAPublicKey' | 'DHParameter' | 'SubjectPublicKeyInfo'. --type pem_entry() :: {pki_asn1_type(), der_encoded() | decrypt_der(), +-type pem_entry() :: {pki_asn1_type(), binary(), %% DER or Encrypted DER not_encrypted | {Cipher :: string(), Salt :: binary()}}. -type asn1_type() :: atom(). %% see "OTP-PUB-KEY.hrl +-type ssh_file() :: openssh_public_key | rfc4716_public_key | known_hosts | + auth_keys. -endif. % -ifdef(public_key). diff --git a/lib/public_key/src/Makefile b/lib/public_key/src/Makefile index b042b0c30a..5a24b02d2a 100644 --- a/lib/public_key/src/Makefile +++ b/lib/public_key/src/Makefile @@ -41,6 +41,7 @@ RELSYSDIR = $(RELEASE_PATH)/lib/public_key-$(VSN) MODULES = \ public_key \ pubkey_pem \ + pubkey_ssh \ pubkey_cert \ pubkey_cert_records diff --git a/lib/public_key/src/pubkey_cert.erl b/lib/public_key/src/pubkey_cert.erl index fadb993ed9..5ab9642279 100644 --- a/lib/public_key/src/pubkey_cert.erl +++ b/lib/public_key/src/pubkey_cert.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2010. All Rights Reserved. +%% Copyright Ericsson AB 2008-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 @@ -38,7 +38,7 @@ %%==================================================================== %%-------------------------------------------------------------------- --spec verify_data(der_encoded()) -> {md5 | sha, binary(), binary()}. +-spec verify_data(DER::binary()) -> {md5 | sha, binary(), binary()}. %% %% Description: Extracts data from DerCert needed to call public_key:verify/4. %%-------------------------------------------------------------------- @@ -146,7 +146,7 @@ validate_issuer(OtpCert, Issuer, UserState, VerifyFun) -> verify_fun(OtpCert, {bad_cert, invalid_issuer}, UserState, VerifyFun) end. %%-------------------------------------------------------------------- --spec validate_signature(#'OTPCertificate'{}, der_encoded(), +-spec validate_signature(#'OTPCertificate'{}, DER::binary(), term(),term(), term(), fun()) -> term(). %% diff --git a/lib/public_key/src/pubkey_cert_records.erl b/lib/public_key/src/pubkey_cert_records.erl index 2441cfc0e0..b86d7a1f0c 100644 --- a/lib/public_key/src/pubkey_cert_records.erl +++ b/lib/public_key/src/pubkey_cert_records.erl @@ -30,7 +30,7 @@ %%==================================================================== %%-------------------------------------------------------------------- --spec decode_cert(der_encoded()) -> {ok, #'OTPCertificate'{}}. +-spec decode_cert(DerCert::binary()) -> {ok, #'OTPCertificate'{}}. %% %% Description: Recursively decodes a Certificate. %%-------------------------------------------------------------------- diff --git a/lib/public_key/src/pubkey_pem.erl b/lib/public_key/src/pubkey_pem.erl index c8c69bcdd0..c26815bc04 100644 --- a/lib/public_key/src/pubkey_pem.erl +++ b/lib/public_key/src/pubkey_pem.erl @@ -69,8 +69,9 @@ encode(PemEntries) -> encode_pem_entries(PemEntries). %%-------------------------------------------------------------------- --spec decipher({pki_asn1_type(), decrypt_der(),{Cipher :: string(), Salt :: binary()}}, string()) -> - der_encoded(). +-spec decipher({pki_asn1_type(), DerEncrypted::binary(),{Cipher :: string(), + Salt :: binary()}}, + string()) -> Der::binary(). %% %% Description: Deciphers a decrypted pem entry. %%-------------------------------------------------------------------- @@ -78,7 +79,8 @@ decipher({_, DecryptDer, {Cipher,Salt}}, Password) -> decode_key(DecryptDer, Password, Cipher, Salt). %%-------------------------------------------------------------------- --spec cipher(der_encoded(),{Cipher :: string(), Salt :: binary()} , string()) -> binary(). +-spec cipher(Der::binary(),{Cipher :: string(), Salt :: binary()} , + string()) -> binary(). %% %% Description: Ciphers a PEM entry %%-------------------------------------------------------------------- @@ -91,11 +93,11 @@ cipher(Der, {Cipher,Salt}, Password)-> encode_pem_entries(Entries) -> [encode_pem_entry(Entry) || Entry <- Entries]. -encode_pem_entry({Asn1Type, Der, not_encrypted}) -> - StartStr = pem_start(Asn1Type), +encode_pem_entry({Type, Der, not_encrypted}) -> + StartStr = pem_start(Type), [StartStr, "\n", b64encode_and_split(Der), "\n", pem_end(StartStr) ,"\n\n"]; -encode_pem_entry({Asn1Type, Der, {Cipher, Salt}}) -> - StartStr = pem_start(Asn1Type), +encode_pem_entry({Type, Der, {Cipher, Salt}}) -> + StartStr = pem_start(Type), [StartStr,"\n", pem_decrypt(),"\n", pem_decrypt_info(Cipher, Salt),"\n", b64encode_and_split(Der), "\n", pem_end(StartStr) ,"\n\n"]. @@ -115,17 +117,17 @@ decode_pem_entries([Start| Lines], Entries) -> end. decode_pem_entry(Start, [<<"Proc-Type: 4,ENCRYPTED", _/binary>>, Line | Lines]) -> - Asn1Type = asn1_type(Start), + Type = asn1_type(Start), Cs = erlang:iolist_to_binary(Lines), Decoded = base64:mime_decode(Cs), [_, DekInfo0] = string:tokens(binary_to_list(Line), ": "), [Cipher, Salt] = string:tokens(DekInfo0, ","), - {Asn1Type, Decoded, {Cipher, unhex(Salt)}}; + {Type, Decoded, {Cipher, unhex(Salt)}}; decode_pem_entry(Start, Lines) -> - Asn1Type = asn1_type(Start), + Type = asn1_type(Start), Cs = erlang:iolist_to_binary(Lines), - Der = base64:mime_decode(Cs), - {Asn1Type, Der, not_encrypted}. + Decoded = base64:mime_decode(Cs), + {Type, Decoded, not_encrypted}. split_bin(Bin) -> split_bin(0, Bin). @@ -153,17 +155,7 @@ split_lines(Bin) -> [Bin]. %% Ignore white space at end of line -join_entry([<<"-----END CERTIFICATE-----", _/binary>>| Lines], Entry) -> - {lists:reverse(Entry), Lines}; -join_entry([<<"-----END RSA PRIVATE KEY-----", _/binary>>| Lines], Entry) -> - {lists:reverse(Entry), Lines}; -join_entry([<<"-----END PUBLIC KEY-----", _/binary>>| Lines], Entry) -> - {lists:reverse(Entry), Lines}; -join_entry([<<"-----END RSA PUBLIC KEY-----", _/binary>>| Lines], Entry) -> - {lists:reverse(Entry), Lines}; -join_entry([<<"-----END DSA PRIVATE KEY-----", _/binary>>| Lines], Entry) -> - {lists:reverse(Entry), Lines}; -join_entry([<<"-----END DH PARAMETERS-----", _/binary>>| Lines], Entry) -> +join_entry([<<"-----END ", _/binary>>| Lines], Entry) -> {lists:reverse(Entry), Lines}; join_entry([Line | Lines], Entry) -> join_entry(Lines, [Line | Entry]). diff --git a/lib/public_key/src/pubkey_ssh.erl b/lib/public_key/src/pubkey_ssh.erl new file mode 100644 index 0000000000..f342eab159 --- /dev/null +++ b/lib/public_key/src/pubkey_ssh.erl @@ -0,0 +1,431 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2011-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% +%% +-module(pubkey_ssh). + +-include("public_key.hrl"). + +-export([decode/2, encode/2]). + +-define(UINT32(X), X:32/unsigned-big-integer). +%% Max encoded line length is 72, but conformance examples use 68 +%% Comment from rfc 4716: "The following are some examples of public +%% key files that are compliant (note that the examples all wrap +%% before 72 bytes to meet IETF document requirements; however, they +%% are still compliant.)" So we choose to use 68 also. +-define(ENCODED_LINE_LENGTH, 68). + +%%==================================================================== +%% Internal application API +%%==================================================================== + +%%-------------------------------------------------------------------- +-spec decode(binary(), public_key | ssh_file()) -> [{public_key(), Attributes::list()}]. +%% +%% Description: Decodes a ssh file-binary. +%%-------------------------------------------------------------------- +decode(Bin, public_key)-> + case binary:match(Bin, begin_marker()) of + nomatch -> + openssh_decode(Bin, openssh_public_key); + _ -> + rfc4716_decode(Bin) + end; +decode(Bin, rfc4716_public_key) -> + rfc4716_decode(Bin); +decode(Bin, Type) -> + openssh_decode(Bin, Type). + +%%-------------------------------------------------------------------- +-spec encode([{public_key(), Attributes::list()}], ssh_file()) -> + binary(). +%% +%% Description: Encodes a list of ssh file entries. +%%-------------------------------------------------------------------- +encode(Entries, Type) -> + erlang:iolist_to_binary(lists:map(fun({Key, Attributes}) -> + do_encode(Type, Key, Attributes) + end, Entries)). + +%%-------------------------------------------------------------------- +%%% Internal functions +%%-------------------------------------------------------------------- +begin_marker() -> + <<"---- BEGIN SSH2 PUBLIC KEY ----">>. +end_marker() -> + <<"---- END SSH2 PUBLIC KEY ----">>. + +rfc4716_decode(Bin) -> + Lines = binary:split(Bin, <<"\n">>, [global]), + do_rfc4716_decode(Lines, []). + +do_rfc4716_decode([<<"---- BEGIN SSH2 PUBLIC KEY ----", _/binary>> | Lines], Acc) -> + do_rfc4716_decode(Lines, Acc); +%% Ignore empty lines before or after begin/end - markers. +do_rfc4716_decode([<<>> | Lines], Acc) -> + do_rfc4716_decode(Lines, Acc); +do_rfc4716_decode([], Acc) -> + lists:reverse(Acc); +do_rfc4716_decode(Lines, Acc) -> + {Headers, PubKey, Rest} = rfc4716_decode_lines(Lines, []), + case Headers of + [_|_] -> + do_rfc4716_decode(Rest, [{PubKey, [{headers, Headers}]} | Acc]); + _ -> + do_rfc4716_decode(Rest, [{PubKey, []} | Acc]) + end. + +rfc4716_decode_lines([Line | Lines], Acc) -> + case binary:last(Line) of + $\\ -> + NewLine = binary:replace(Line,<<"\\">>, hd(Lines), []), + rfc4716_decode_lines([NewLine | tl(Lines)], Acc); + _ -> + rfc4716_decode_line(Line, Lines, Acc) + end. + +rfc4716_decode_line(Line, Lines, Acc) -> + case binary:split(Line, <<":">>) of + [Tag, Value] -> + rfc4716_decode_lines(Lines, [{string_decode(Tag), unicode_decode(Value)} | Acc]); + _ -> + {Body, Rest} = join_entry([Line | Lines], []), + {lists:reverse(Acc), rfc4716_pubkey_decode(base64:mime_decode(Body)), Rest} + end. + +join_entry([<<"---- END SSH2 PUBLIC KEY ----", _/binary>>| Lines], Entry) -> + {lists:reverse(Entry), Lines}; +join_entry([Line | Lines], Entry) -> + join_entry(Lines, [Line | Entry]). + + +rfc4716_pubkey_decode(<<?UINT32(Len), Type:Len/binary, + ?UINT32(SizeE), E:SizeE/binary, + ?UINT32(SizeN), N:SizeN/binary>>) when Type == <<"ssh-rsa">> -> + #'RSAPublicKey'{modulus = erlint(SizeN, N), + publicExponent = erlint(SizeE, E)}; + +rfc4716_pubkey_decode(<<?UINT32(Len), Type:Len/binary, + ?UINT32(SizeP), P:SizeP/binary, + ?UINT32(SizeQ), Q:SizeQ/binary, + ?UINT32(SizeG), G:SizeG/binary, + ?UINT32(SizeY), Y:SizeY/binary>>) when Type == <<"ssh-dss">> -> + {erlint(SizeY, Y), + #'Dss-Parms'{p = erlint(SizeP, P), + q = erlint(SizeQ, Q), + g = erlint(SizeG, G)}}. + +openssh_decode(Bin, FileType) -> + Lines = binary:split(Bin, <<"\n">>, [global]), + do_openssh_decode(FileType, Lines, []). + +do_openssh_decode(_, [], Acc) -> + lists:reverse(Acc); +%% Ignore empty lines +do_openssh_decode(FileType, [<<>> | Lines], Acc) -> + do_openssh_decode(FileType, Lines, Acc); +%% Ignore lines that start with # +do_openssh_decode(FileType,[<<"#", _/binary>> | Lines], Acc) -> + do_openssh_decode(FileType, Lines, Acc); +do_openssh_decode(auth_keys = FileType, [Line | Lines], Acc) -> + Split = binary:split(Line, <<" ">>, [global]), + case mend_split(Split, []) of + %% ssh2 + [Options, KeyType, Base64Enc, Comment] when KeyType == <<"ssh-rsa">>; + KeyType == <<"ssh-dss">> -> + do_openssh_decode(FileType, Lines, + [{openssh_pubkey_decode(KeyType, Base64Enc), + [{comment, string_decode(Comment)}, + {options, comma_list_decode(Options)}]} + | Acc]); + + [KeyType, Base64Enc, Comment] when KeyType == <<"ssh-rsa">>; + KeyType == <<"ssh-dss">> -> + do_openssh_decode(FileType, Lines, + [{openssh_pubkey_decode(KeyType, Base64Enc), + [{comment, string_decode(Comment)}]} | Acc]); + %% ssh1 + [Options, Bits, Exponent, Modulus, Comment] -> + do_openssh_decode(FileType, Lines, + [{ssh1_rsa_pubkey_decode(Modulus, Exponent), + [{comment, string_decode(Comment)}, + {options, comma_list_decode(Options)}, + {bits, integer_decode(Bits)}]} | Acc]); + [Bits, Exponent, Modulus, Comment] -> + do_openssh_decode(FileType, Lines, + [{ssh1_rsa_pubkey_decode(Modulus, Exponent), + [{comment, string_decode(Comment)}, + {bits, integer_decode(Bits)}]} | Acc]) + end; + +do_openssh_decode(known_hosts = FileType, [Line | Lines], Acc) -> + case binary:split(Line, <<" ">>, [global]) of + %% ssh 2 + [HostNames, KeyType, Base64Enc] when KeyType == <<"ssh-rsa">>; + KeyType == <<"ssh-dss">> -> + do_openssh_decode(FileType, Lines, + [{openssh_pubkey_decode(KeyType, Base64Enc), + [{hostnames, comma_list_decode(HostNames)}]}| Acc]); + [HostNames, KeyType, Base64Enc, Comment] when KeyType == <<"ssh-rsa">>; + KeyType == <<"ssh-dss">> -> + do_openssh_decode(FileType, Lines, + [{openssh_pubkey_decode(KeyType, Base64Enc), + [{comment, string_decode(Comment)}, + {hostnames, comma_list_decode(HostNames)}]} | Acc]); + %% ssh 1 + [HostNames, Bits, Exponent, Modulus, Comment] -> + do_openssh_decode(FileType, Lines, + [{ssh1_rsa_pubkey_decode(Modulus, Exponent), + [{comment, string_decode(Comment)}, + {hostnames, comma_list_decode(HostNames)}, + {bits, integer_decode(Bits)}]} | Acc]); + [HostNames, Bits, Exponent, Modulus] -> + do_openssh_decode(FileType, Lines, + [{ssh1_rsa_pubkey_decode(Modulus, Exponent), + [{comment, []}, + {hostnames, comma_list_decode(HostNames)}, + {bits, integer_decode(Bits)}]} | Acc]) + end; + +do_openssh_decode(openssh_public_key = FileType, [Line | Lines], Acc) -> + case binary:split(Line, <<" ">>, [global]) of + [KeyType, Base64Enc, Comment0] when KeyType == <<"ssh-rsa">>; + KeyType == <<"ssh-dss">> -> + Comment = string:strip(binary_to_list(Comment0), right, $\n), + do_openssh_decode(FileType, Lines, + [{openssh_pubkey_decode(KeyType, Base64Enc), + [{comment, Comment}]} | Acc]) + end. + + +openssh_pubkey_decode(<<"ssh-rsa">>, Base64Enc) -> + <<?UINT32(StrLen), _:StrLen/binary, + ?UINT32(SizeE), E:SizeE/binary, + ?UINT32(SizeN), N:SizeN/binary>> + = base64:mime_decode(Base64Enc), + #'RSAPublicKey'{modulus = erlint(SizeN, N), + publicExponent = erlint(SizeE, E)}; + +openssh_pubkey_decode(<<"ssh-dss">>, Base64Enc) -> + <<?UINT32(StrLen), _:StrLen/binary, + ?UINT32(SizeP), P:SizeP/binary, + ?UINT32(SizeQ), Q:SizeQ/binary, + ?UINT32(SizeG), G:SizeG/binary, + ?UINT32(SizeY), Y:SizeY/binary>> + = base64:mime_decode(Base64Enc), + {erlint(SizeY, Y), + #'Dss-Parms'{p = erlint(SizeP, P), + q = erlint(SizeQ, Q), + g = erlint(SizeG, G)}}. + +erlint(MPIntSize, MPIntValue) -> + Bits= MPIntSize * 8, + <<Integer:Bits/integer>> = MPIntValue, + Integer. + +ssh1_rsa_pubkey_decode(MBin, EBin) -> + #'RSAPublicKey'{modulus = integer_decode(MBin), + publicExponent = integer_decode(EBin)}. + +integer_decode(BinStr) -> + list_to_integer(binary_to_list(BinStr)). + +string_decode(BinStr) -> + binary_to_list(BinStr). + +unicode_decode(BinStr) -> + unicode:characters_to_list(BinStr). + +comma_list_decode(BinOpts) -> + CommaList = binary:split(BinOpts, <<",">>, [global]), + lists:map(fun(Item) -> + binary_to_list(Item) + end, CommaList). + +do_encode(rfc4716_public_key, Key, Attributes) -> + rfc4716_encode(Key, proplists:get_value(headers, Attributes, []), []); + +do_encode(Type, Key, Attributes) -> + openssh_encode(Type, Key, Attributes). + +rfc4716_encode(Key, [],[]) -> + erlang:iolist_to_binary([begin_marker(),"\n", + split_lines(base64:encode(ssh2_pubkey_encode(Key))), + "\n", end_marker(), "\n"]); +rfc4716_encode(Key, [], [_|_] = Acc) -> + erlang:iolist_to_binary([begin_marker(), "\n", + lists:reverse(Acc), + split_lines(base64:encode(ssh2_pubkey_encode(Key))), + "\n", end_marker(), "\n"]); +rfc4716_encode(Key, [ Header | Headers], Acc) -> + LinesStr = rfc4716_encode_header(Header), + rfc4716_encode(Key, Headers, [LinesStr | Acc]). + +rfc4716_encode_header({Tag, Value}) -> + TagLen = length(Tag), + ValueLen = length(Value), + case TagLen + 1 + ValueLen of + N when N > ?ENCODED_LINE_LENGTH -> + NumOfChars = ?ENCODED_LINE_LENGTH - (TagLen + 1), + {First, Rest} = lists:split(NumOfChars, Value), + [Tag,":" , First, [$\\], "\n", rfc4716_encode_value(Rest) , "\n"]; + _ -> + [Tag, ":", Value, "\n"] + end. + +rfc4716_encode_value(Value) -> + case length(Value) of + N when N > ?ENCODED_LINE_LENGTH -> + {First, Rest} = lists:split(?ENCODED_LINE_LENGTH, Value), + [First, [$\\], "\n", rfc4716_encode_value(Rest)]; + _ -> + Value + end. + +openssh_encode(openssh_public_key, Key, Attributes) -> + Comment = proplists:get_value(comment, Attributes), + Enc = base64:encode(ssh2_pubkey_encode(Key)), + erlang:iolist_to_binary([key_type(Key), " ", Enc, " ", Comment, "\n"]); + +openssh_encode(auth_keys, Key, Attributes) -> + Comment = proplists:get_value(comment, Attributes, ""), + Options = proplists:get_value(options, Attributes, undefined), + Bits = proplists:get_value(bits, Attributes, undefined), + case Bits of + undefined -> + openssh_ssh2_auth_keys_encode(Options, Key, Comment); + _ -> + openssh_ssh1_auth_keys_encode(Options, Bits, Key, Comment) + end; +openssh_encode(known_hosts, Key, Attributes) -> + Comment = proplists:get_value(comment, Attributes, ""), + Hostnames = proplists:get_value(hostnames, Attributes), + Bits = proplists:get_value(bits, Attributes, undefined), + case Bits of + undefined -> + openssh_ssh2_know_hosts_encode(Hostnames, Key, Comment); + _ -> + openssh_ssh1_known_hosts_encode(Hostnames, Bits, Key, Comment) + end. + +openssh_ssh2_auth_keys_encode(undefined, Key, Comment) -> + erlang:iolist_to_binary([key_type(Key)," ", base64:encode(ssh2_pubkey_encode(Key)), line_end(Comment)]); +openssh_ssh2_auth_keys_encode(Options, Key, Comment) -> + erlang:iolist_to_binary([comma_list_encode(Options, []), " ", + key_type(Key)," ", base64:encode(ssh2_pubkey_encode(Key)), line_end(Comment)]). + +openssh_ssh1_auth_keys_encode(undefined, Bits, + #'RSAPublicKey'{modulus = N, publicExponent = E}, + Comment) -> + erlang:iolist_to_binary([integer_to_list(Bits), " ", integer_to_list(E), " ", integer_to_list(N), + line_end(Comment)]); +openssh_ssh1_auth_keys_encode(Options, Bits, + #'RSAPublicKey'{modulus = N, publicExponent = E}, + Comment) -> + erlang:iolist_to_binary([comma_list_encode(Options, []), " ", integer_to_list(Bits), + " ", integer_to_list(E), " ", integer_to_list(N), line_end(Comment)]). + +openssh_ssh2_know_hosts_encode(Hostnames, Key, Comment) -> + erlang:iolist_to_binary([comma_list_encode(Hostnames, []), " ", + key_type(Key)," ", base64:encode(ssh2_pubkey_encode(Key)), line_end(Comment)]). + +openssh_ssh1_known_hosts_encode(Hostnames, Bits, + #'RSAPublicKey'{modulus = N, publicExponent = E}, + Comment) -> + erlang:iolist_to_binary([comma_list_encode(Hostnames, [])," ", integer_to_list(Bits)," ", + integer_to_list(E)," ", integer_to_list(N), line_end(Comment)]). + +line_end("") -> + "\n"; +line_end(Comment) -> + [" ", Comment, "\n"]. + +key_type(#'RSAPublicKey'{}) -> + <<"ssh-rsa">>; +key_type({_, #'Dss-Parms'{}}) -> + <<"ssh-dss">>. + +comma_list_encode([Option], []) -> + Option; +comma_list_encode([Option], Acc) -> + Acc ++ "," ++ Option; +comma_list_encode([Option | Rest], []) -> + comma_list_encode(Rest, Option); +comma_list_encode([Option | Rest], Acc) -> + comma_list_encode(Rest, Acc ++ "," ++ Option). + +ssh2_pubkey_encode(#'RSAPublicKey'{modulus = N, publicExponent = E}) -> + TypeStr = <<"ssh-rsa">>, + StrLen = size(TypeStr), + EBin = crypto:mpint(E), + NBin = crypto:mpint(N), + <<?UINT32(StrLen), TypeStr:StrLen/binary, + EBin/binary, + NBin/binary>>; +ssh2_pubkey_encode({Y, #'Dss-Parms'{p = P, q = Q, g = G}}) -> + TypeStr = <<"ssh-dss">>, + StrLen = size(TypeStr), + PBin = crypto:mpint(P), + QBin = crypto:mpint(Q), + GBin = crypto:mpint(G), + YBin = crypto:mpint(Y), + <<?UINT32(StrLen), TypeStr:StrLen/binary, + PBin/binary, + QBin/binary, + GBin/binary, + YBin/binary>>. + +mend_split([Part1, Part2 | Rest] = List, Acc) -> + case option_end(Part1, Part2) of + true -> + lists:reverse(Acc) ++ List; + false -> + case length(binary:matches(Part1, <<"\"">>)) of + N when N rem 2 == 0 -> + mend_split(Rest, [Part1 | Acc]); + _ -> + mend_split([<<Part1/binary, Part2/binary>> | Rest], Acc) + end + end. + +option_end(Part1, Part2) -> + (is_key_field(Part1) orelse is_bits_field(Part1)) + orelse + (is_key_field(Part2) orelse is_bits_field(Part2)). + +is_key_field(<<"ssh-dss">>) -> + true; +is_key_field(<<"ssh-rsa">>) -> + true; +is_key_field(_) -> + false. + +is_bits_field(Part) -> + try list_to_integer(binary_to_list(Part)) of + _ -> + true + catch _:_ -> + false + end. + +split_lines(<<Text:?ENCODED_LINE_LENGTH/binary>>) -> + [Text]; +split_lines(<<Text:?ENCODED_LINE_LENGTH/binary, Rest/binary>>) -> + [Text, $\n | split_lines(Rest)]; +split_lines(Bin) -> + [Bin]. diff --git a/lib/public_key/src/public_key.app.src b/lib/public_key/src/public_key.app.src index 60487946fa..1963bd05d4 100644 --- a/lib/public_key/src/public_key.app.src +++ b/lib/public_key/src/public_key.app.src @@ -1,9 +1,9 @@ {application, public_key, [{description, "Public key infrastructure"}, {vsn, "%VSN%"}, - {modules, [ - public_key, - pubkey_pem, + {modules, [ public_key, + pubkey_pem, + pubkey_ssh, pubkey_cert, pubkey_cert_records, 'OTP-PUB-KEY' diff --git a/lib/public_key/src/public_key.appup.src b/lib/public_key/src/public_key.appup.src index c65ac7bc99..4986801dad 100644 --- a/lib/public_key/src/public_key.appup.src +++ b/lib/public_key/src/public_key.appup.src @@ -1,6 +1,16 @@ %% -*- erlang -*- {"%VSN%", [ + {"0.11", + [ + {update, public_key, soft, soft_purge, soft_purge, []}, + {update, pubkey_pem, soft, soft_purge, soft_purge, []}, + {add_module, pubkey_ssh, soft, soft_purge, soft_purge}, + {update, pubkey_cert, soft, soft_purge, soft_purge, []}, + {update, pubkey_cert_records, soft, soft_purge, soft_purge, []} + ] + }, + {"0.10", [ {update, public_key, soft, soft_purge, soft_purge, []}, @@ -25,6 +35,16 @@ } ], [ + {"0.11", + [ + {update, public_key, soft, soft_purge, soft_purge, []}, + {update, pubkey_pem, soft, soft_purge, soft_purge, []}, + {delete_module, pubkey_ssh, soft, soft_purge, soft_purge}, + {update, pubkey_cert, soft, soft_purge, soft_purge, []}, + {update, pubkey_cert_records, soft, soft_purge, soft_purge, []} + ] + }, + {"0.10", [ {update, public_key, soft, soft_purge, soft_purge, []}, diff --git a/lib/public_key/src/public_key.erl b/lib/public_key/src/public_key.erl index 7e022da7e5..2901020e83 100644 --- a/lib/public_key/src/public_key.erl +++ b/lib/public_key/src/public_key.erl @@ -41,7 +41,8 @@ pkix_is_issuer/2, pkix_issuer_id/2, pkix_normalize_name/1, - pkix_path_validation/3 + pkix_path_validation/3, + ssh_decode/2, ssh_encode/2 ]). %% Deprecated @@ -51,10 +52,6 @@ -deprecated({decode_private_key, 1, next_major_release}). -deprecated({decode_private_key, 2, next_major_release}). --type rsa_public_key() :: #'RSAPublicKey'{}. --type rsa_private_key() :: #'RSAPrivateKey'{}. --type dsa_private_key() :: #'DSAPrivateKey'{}. --type dsa_public_key() :: {integer(), #'Dss-Parms'{}}. -type rsa_padding() :: 'rsa_pkcs1_padding' | 'rsa_pkcs1_oaep_padding' | 'rsa_no_padding'. -type public_crypt_options() :: [{rsa_pad, rsa_padding()}]. @@ -67,7 +64,6 @@ %%==================================================================== %% API %%==================================================================== - %%-------------------------------------------------------------------- -spec pem_decode(binary()) -> [pem_entry()]. %% @@ -152,7 +148,7 @@ pem_entry_encode(Asn1Type, Entity, {Asn1Type, DecryptDer, CipherInfo}. %%-------------------------------------------------------------------- --spec der_decode(asn1_type(), der_encoded()) -> term(). +-spec der_decode(asn1_type(), Der::binary()) -> term(). %% %% Description: Decodes a public key asn1 der encoded entity. %%-------------------------------------------------------------------- @@ -166,7 +162,7 @@ der_decode(Asn1Type, Der) when is_atom(Asn1Type), is_binary(Der) -> end. %%-------------------------------------------------------------------- --spec der_encode(asn1_type(), term()) -> der_encoded(). +-spec der_encode(asn1_type(), term()) -> Der::binary(). %% %% Description: Encodes a public key entity with asn1 DER encoding. %%-------------------------------------------------------------------- @@ -180,7 +176,7 @@ der_encode(Asn1Type, Entity) when is_atom(Asn1Type) -> end. %%-------------------------------------------------------------------- --spec pkix_decode_cert(der_encoded(), plain | otp) -> +-spec pkix_decode_cert(Cert::binary(), plain | otp) -> #'Certificate'{} | #'OTPCertificate'{}. %% %% Description: Decodes an asn1 der encoded pkix certificate. The otp @@ -201,7 +197,7 @@ pkix_decode_cert(DerCert, otp) when is_binary(DerCert) -> end. %%-------------------------------------------------------------------- --spec pkix_encode(asn1_type(), term(), otp | plain) -> der_encoded(). +-spec pkix_encode(asn1_type(), term(), otp | plain) -> Der::binary(). %% %% Description: Der encodes a certificate or part of a certificate. %% This function must be used for encoding certificates or parts of certificates @@ -361,7 +357,7 @@ verify(PlainText, sha, Signature, {Key, #'Dss-Parms'{p = P, q = Q, g = G}}) crypto:mpint(G), crypto:mpint(Key)]). %%-------------------------------------------------------------------- -spec pkix_sign(#'OTPTBSCertificate'{}, - rsa_private_key() | dsa_private_key()) -> der_encoded(). + rsa_private_key() | dsa_private_key()) -> Der::binary(). %% %% Description: Sign a pkix x.509 certificate. Returns the corresponding %% der encoded 'Certificate'{} @@ -370,7 +366,7 @@ pkix_sign(#'OTPTBSCertificate'{signature = #'SignatureAlgorithm'{algorithm = Alg} = SigAlg} = TBSCert, Key) -> - Msg = pkix_encode('OTPTBSCertificate', TBSCert, otp), + Msg = pkix_encode('OTPTBSCertificate', TBSCert, otp), DigestType = pubkey_cert:digest_type(Alg), Signature = sign(Msg, DigestType, Key), Cert = #'OTPCertificate'{tbsCertificate= TBSCert, @@ -380,7 +376,7 @@ pkix_sign(#'OTPTBSCertificate'{signature = pkix_encode('OTPCertificate', Cert, otp). %%-------------------------------------------------------------------- --spec pkix_verify(der_encoded(), rsa_public_key()| +-spec pkix_verify(Cert::binary(), rsa_public_key()| dsa_public_key()) -> boolean(). %% %% Description: Verify pkix x.509 certificate signature. @@ -396,9 +392,9 @@ pkix_verify(DerCert, #'RSAPublicKey'{} = RSAKey) verify(PlainText, DigestType, Signature, RSAKey). %%-------------------------------------------------------------------- --spec pkix_is_issuer(Cert :: der_encoded()| #'OTPCertificate'{}, - IssuerCert :: der_encoded()| - #'OTPCertificate'{}) -> boolean(). +-spec pkix_is_issuer(Cert::binary()| #'OTPCertificate'{}, + IssuerCert::binary()| + #'OTPCertificate'{}) -> boolean(). %% %% Description: Checks if <IssuerCert> issued <Cert>. %%-------------------------------------------------------------------- @@ -414,7 +410,7 @@ pkix_is_issuer(#'OTPCertificate'{tbsCertificate = TBSCert}, Candidate#'OTPTBSCertificate'.subject). %%-------------------------------------------------------------------- --spec pkix_is_self_signed(der_encoded()| #'OTPCertificate'{}) -> boolean(). +-spec pkix_is_self_signed(Cert::binary()| #'OTPCertificate'{}) -> boolean(). %% %% Description: Checks if a Certificate is self signed. %%-------------------------------------------------------------------- @@ -425,7 +421,7 @@ pkix_is_self_signed(Cert) when is_binary(Cert) -> pkix_is_self_signed(OtpCert). %%-------------------------------------------------------------------- --spec pkix_is_fixed_dh_cert(der_encoded()| #'OTPCertificate'{}) -> boolean(). +-spec pkix_is_fixed_dh_cert(Cert::binary()| #'OTPCertificate'{}) -> boolean(). %% %% Description: Checks if a Certificate is a fixed Diffie-Hellman Cert. %%-------------------------------------------------------------------- @@ -436,14 +432,14 @@ pkix_is_fixed_dh_cert(Cert) when is_binary(Cert) -> pkix_is_fixed_dh_cert(OtpCert). %%-------------------------------------------------------------------- --spec pkix_issuer_id(der_encoded()| #'OTPCertificate'{}, - IssuedBy :: self | other) -> - {ok, {SerialNr :: integer(), - Issuer :: {rdnSequence, - [#'AttributeTypeAndValue'{}]}}} +-spec pkix_issuer_id(Cert::binary()| #'OTPCertificate'{}, + IssuedBy :: self | other) -> + {ok, {SerialNr :: integer(), + Issuer :: {rdnSequence, + [#'AttributeTypeAndValue'{}]}}} | {error, Reason :: term()}. % -%% Description: Returns the issuer id. +%% Description: Returns the issuer id. %%-------------------------------------------------------------------- pkix_issuer_id(#'OTPCertificate'{} = OtpCert, self) -> pubkey_cert:issuer_id(OtpCert, self); @@ -456,8 +452,8 @@ pkix_issuer_id(Cert, Signed) when is_binary(Cert) -> pkix_issuer_id(OtpCert, Signed). %%-------------------------------------------------------------------- --spec pkix_normalize_name({rdnSequence, - [#'AttributeTypeAndValue'{}]}) -> +-spec pkix_normalize_name({rdnSequence, + [#'AttributeTypeAndValue'{}]}) -> {rdnSequence, [#'AttributeTypeAndValue'{}]}. %% @@ -468,8 +464,8 @@ pkix_normalize_name(Issuer) -> pubkey_cert:normalize_general_name(Issuer). %%-------------------------------------------------------------------- --spec pkix_path_validation(der_encoded()| #'OTPCertificate'{} | atom(), - CertChain :: [der_encoded()] , +-spec pkix_path_validation(Cert::binary()| #'OTPCertificate'{} | atom(), + CertChain :: [binary()] , Options :: list()) -> {ok, {PublicKeyInfo :: term(), PolicyTree :: term()}} | @@ -496,7 +492,7 @@ pkix_path_validation(TrustedCert, CertChain, Options) when is_binary(TrustedCert) -> OtpCert = pkix_decode_cert(TrustedCert, otp), pkix_path_validation(OtpCert, CertChain, Options); -pkix_path_validation(#'OTPCertificate'{} = TrustedCert, CertChain, Options) +pkix_path_validation(#'OTPCertificate'{} = TrustedCert, CertChain, Options) when is_list(CertChain), is_list(Options) -> MaxPathDefault = length(CertChain), ValidationState = pubkey_cert:init_validation_state(TrustedCert, @@ -505,6 +501,37 @@ pkix_path_validation(#'OTPCertificate'{} = TrustedCert, CertChain, Options) path_validation(CertChain, ValidationState). %%-------------------------------------------------------------------- +-spec ssh_decode(binary(), public_key | ssh_file()) -> [{public_key(), Attributes::list()}]. +%% +%% Description: Decodes a ssh file-binary. In the case of know_hosts +%% or auth_keys the binary may include one or more lines of the +%% file. Returns a list of public keys and their attributes, possible +%% attribute values depends on the file type represented by the +%% binary. +%%-------------------------------------------------------------------- +ssh_decode(SshBin, Type) when is_binary(SshBin), + Type == public_key; + Type == rfc4716_public_key; + Type == openssh_public_key; + Type == auth_keys; + Type == known_hosts -> + pubkey_ssh:decode(SshBin, Type). + +%%-------------------------------------------------------------------- +-spec ssh_encode([{public_key(), Attributes::list()}], ssh_file()) -> + binary(). +%% Description: Encodes a list of ssh file entries (public keys and +%% attributes) to a binary. Possible attributes depends on the file +%% type. +%%-------------------------------------------------------------------- +ssh_encode(Entries, Type) when is_list(Entries), + Type == rfc4716_public_key; + Type == openssh_public_key; + Type == auth_keys; + Type == known_hosts -> + pubkey_ssh:encode(Entries, Type). + +%%-------------------------------------------------------------------- %%% Internal functions %%-------------------------------------------------------------------- @@ -518,7 +545,6 @@ decrypt_public(CipherText, N,E, Options) -> crypto:rsa_public_decrypt(CipherText,[crypto:mpint(E), crypto:mpint(N)], Padding). - path_validation([], #path_validation_state{working_public_key_algorithm = Algorithm, working_public_key = diff --git a/lib/public_key/test/Makefile b/lib/public_key/test/Makefile index e20b903942..6889ae9a8a 100644 --- a/lib/public_key/test/Makefile +++ b/lib/public_key/test/Makefile @@ -80,7 +80,7 @@ release_tests_spec: opt $(INSTALL_DIR) $(RELSYSDIR) $(INSTALL_DATA) $(SPEC_FILES) $(ERL_FILES) $(COVER_FILE) $(HRL_FILES) $(RELSYSDIR) $(INSTALL_DATA) $(TARGET_FILES) $(RELSYSDIR) - chmod -f -R u+w $(RELSYSDIR) + chmod -R u+w $(RELSYSDIR) @tar cf - *_SUITE_data | (cd $(RELSYSDIR); tar xf -) release_docs_spec: diff --git a/lib/public_key/test/pkits_SUITE.erl b/lib/public_key/test/pkits_SUITE.erl index 660af4e8ab..a325a975e9 100644 --- a/lib/public_key/test/pkits_SUITE.erl +++ b/lib/public_key/test/pkits_SUITE.erl @@ -26,7 +26,6 @@ -compile(export_all). -include_lib("public_key/include/public_key.hrl"). -%%-include("public_key.hrl"). -define(error(Format,Args), error(Format,Args,?FILE,?LINE)). -define(warning(Format,Args), warning(Format,Args,?FILE,?LINE)). @@ -42,18 +41,65 @@ -define(NIST5, "2.16.840.1.101.3.2.1.48.5"). -define(NIST6, "2.16.840.1.101.3.2.1.48.6"). +-record(verify_state, { + certs_db, + crl_info, + revoke_state}). %% -suite() -> [{ct_hooks,[ts_install_cth]}]. +suite() -> + [{ct_hooks,[ts_install_cth]}]. all() -> - [signature_verification, validity_periods, - verifying_name_chaining, - verifying_paths_with_self_issued_certificates, - verifying_basic_constraints, key_usage, - name_constraints, private_certificate_extensions]. + [{group, signature_verification}, + {group, validity_periods}, + {group, verifying_name_chaining}, + {group, verifying_paths_with_self_issued_certificates}, + %%{group, basic_certificate_revocation_tests}, + %%{group, delta_crls}, + %%{group, distribution_points}, + {group, verifying_basic_constraints}, + {group, key_usage}, + {group, name_constraints}, + {group, private_certificate_extensions}]. groups() -> - []. + [{signature_verification, [], [valid_rsa_signature, + invalid_rsa_signature, valid_dsa_signature, + invalid_dsa_signature]}, + {validity_periods, [], + [not_before_invalid, not_before_valid, not_after_invalid, not_after_valid]}, + {verifying_name_chaining, [], + [invalid_name_chain, whitespace_name_chain, capitalization_name_chain, + uid_name_chain, attrib_name_chain, string_name_chain]}, + {verifying_paths_with_self_issued_certificates, [], + [basic_valid, basic_invalid, crl_signing_valid, crl_signing_invalid]}, + %% {basic_certificate_revocation_tests, [], + %% [missing_CRL, revoked_CA, revoked_peer, invalid_CRL_signature, + %% invalid_CRL_issuer, invalid_CRL, valid_CRL, + %% unknown_CRL_extension, old_CRL, fresh_CRL, valid_serial, + %% invalid_serial, valid_seperate_keys, invalid_separate_keys]}, + %% {delta_crls, [], [delta_without_crl, valid_delta_crls, invalid_delta_crls]}, + %% {distribution_points, [], [valid_distribution_points, + %% valid_distribution_points_no_issuing_distribution_point, + %% invalid_distribution_points, valid_only_contains, + %% invalid_only_contains, valid_only_some_reasons, + %% invalid_only_some_reasons, valid_indirect_crl, + %% invalid_indirect_crl, valid_crl_issuer, invalid_crl_issuer]}, + {verifying_basic_constraints,[], + [missing_basic_constraints, valid_basic_constraint, invalid_path_constraints, + valid_path_constraints]}, + {key_usage, [], + [invalid_key_usage, valid_key_usage]}, + {name_constraints, [], + [valid_DN_name_constraints, invalid_DN_name_constraints, + valid_rfc822_name_constraints, + invalid_rfc822_name_constraints, valid_DN_and_rfc822_name_constraints, + invalid_DN_and_rfc822_name_constraints, valid_dns_name_constraints, + invalid_dns_name_constraints, valid_uri_name_constraints, + invalid_uri_name_constraints]}, + {private_certificate_extensions, [], + [unknown_critical_extension, unknown_not_critical_extension]} + ]. init_per_group(_GroupName, Config) -> Config. @@ -61,112 +107,706 @@ init_per_group(_GroupName, Config) -> end_per_group(_GroupName, Config) -> Config. +init_per_testcase(_Func, Config) -> + Datadir = proplists:get_value(data_dir, Config), + put(datadir, Datadir), + Config. + +end_per_testcase(_Func, Config) -> + Config. + +init_per_suite(Config) -> + {skip, "PKIX Conformance test certificates expired 14 of April 2011," + " new conformance test suite uses new format so skip until PKCS-12 support is implemented"}. + %% try crypto:start() of + %% ok -> + %% Config + %% catch _:_ -> + %% {skip, "Crypto did not start"} + %% end. + +end_per_suite(_Config) -> + application:stop(crypto). + +%%----------------------------------------------------------------------------- +valid_rsa_signature(doc) -> + ["Test rsa signatur verification"]; +valid_rsa_signature(suite) -> + []; +valid_rsa_signature(Config) when is_list(Config) -> + run([{ "4.1.1", "Valid Signatures Test1", ok}]). + +invalid_rsa_signature(doc) -> + ["Test rsa signatur verification"]; +invalid_rsa_signature(suite) -> + []; +invalid_rsa_signature(Config) when is_list(Config) -> + run([{ "4.1.2", "Invalid CA Signature Test2", {bad_cert,invalid_signature}}, + { "4.1.3", "Invalid EE Signature Test3", {bad_cert,invalid_signature}}]). + +valid_dsa_signature(doc) -> + ["Test dsa signatur verification"]; +valid_dsa_signature(suite) -> + []; +valid_dsa_signature(Config) when is_list(Config) -> + run([{ "4.1.4", "Valid DSA Signatures Test4", ok}, + { "4.1.5", "Valid DSA Parameter Inheritance Test5", ok}]). + +invalid_dsa_signature(doc) -> + ["Test dsa signatur verification"]; +invalid_dsa_signature(suite) -> + []; +invalid_dsa_signature(Config) when is_list(Config) -> + run([{ "4.1.6", "Invalid DSA Signature Test6",{bad_cert,invalid_signature}}]). +%%----------------------------------------------------------------------------- +not_before_invalid(doc) -> + [""]; +not_before_invalid(suite) -> + []; +not_before_invalid(Config) when is_list(Config) -> + run([{ "4.2.1", "Invalid CA notBefore Date Test1",{bad_cert, cert_expired}}, + { "4.2.2", "Invalid EE notBefore Date Test2",{bad_cert, cert_expired}}]). + +not_before_valid(doc) -> + [""]; +not_before_valid(suite) -> + []; +not_before_valid(Config) when is_list(Config) -> + run([{ "4.2.3", "Valid pre2000 UTC notBefore Date Test3", ok}, + { "4.2.4", "Valid GeneralizedTime notBefore Date Test4", ok}]). + +not_after_invalid(doc) -> + [""]; +not_after_invalid(suite) -> + []; +not_after_invalid(Config) when is_list(Config) -> + run([{ "4.2.5", "Invalid CA notAfter Date Test5", {bad_cert, cert_expired}}, + { "4.2.6", "Invalid EE notAfter Date Test6", {bad_cert, cert_expired}}, + { "4.2.7", "Invalid pre2000 UTC EE notAfter Date Test7",{bad_cert, cert_expired}}]). + +not_after_valid(doc) -> + [""]; +not_after_valid(suite) -> + []; +not_after_valid(Config) when is_list(Config) -> + run([{ "4.2.8", "Valid GeneralizedTime notAfter Date Test8", ok}]). +%%----------------------------------------------------------------------------- +invalid_name_chain(doc) -> + [""]; +invalid_name_chain(suite) -> + []; +invalid_name_chain(Config) when is_list(Config) -> + run([{ "4.3.1", "Invalid Name Chaining EE Test1", {bad_cert, invalid_issuer}}, + { "4.3.2", "Invalid Name Chaining Order Test2", {bad_cert, invalid_issuer}}]). + +whitespace_name_chain(doc) -> + [""]; +whitespace_name_chain(suite) -> + []; +whitespace_name_chain(Config) when is_list(Config) -> + run([{ "4.3.3", "Valid Name Chaining Whitespace Test3", ok}, + { "4.3.4", "Valid Name Chaining Whitespace Test4", ok}]). + +capitalization_name_chain(doc) -> + [""]; +capitalization_name_chain(suite) -> + []; +capitalization_name_chain(Config) when is_list(Config) -> + run([{ "4.3.5", "Valid Name Chaining Capitalization Test5",ok}]). + +uid_name_chain(doc) -> + [""]; +uid_name_chain(suite) -> + []; +uid_name_chain(Config) when is_list(Config) -> + run([{ "4.3.6", "Valid Name Chaining UIDs Test6",ok}]). + +attrib_name_chain(doc) -> + [""]; +attrib_name_chain(suite) -> + []; +attrib_name_chain(Config) when is_list(Config) -> + run([{ "4.3.7", "Valid RFC3280 Mandatory Attribute Types Test7", ok}, + { "4.3.8", "Valid RFC3280 Optional Attribute Types Test8", ok}]). + +string_name_chain(doc) -> + [""]; +string_name_chain(suite) -> + []; +string_name_chain(Config) when is_list(Config) -> + run([{ "4.3.9", "Valid UTF8String Encoded Names Test9", ok}, + { "4.3.10", "Valid Rollover from PrintableString to UTF8String Test10", ok}, + { "4.3.11", "Valid UTF8String Case Insensitive Match Test11", ok}]). + +%%----------------------------------------------------------------------------- + +basic_valid(doc) -> + [""]; +basic_valid(suite) -> + []; +basic_valid(Config) when is_list(Config) -> + run([{ "4.5.1", "Valid Basic Self-Issued Old With New Test1", ok}, + { "4.5.3", "Valid Basic Self-Issued New With Old Test3", ok}, + { "4.5.4", "Valid Basic Self-Issued New With Old Test4", ok} + ]). + +basic_invalid(doc) -> + [""]; +basic_invalid(suite) -> + []; +basic_invalid(Config) when is_list(Config) -> + run([{"4.5.2", "Invalid Basic Self-Issued Old With New Test2", + {bad_cert, {revoked, keyCompromise}}}, + {"4.5.5", "Invalid Basic Self-Issued New With Old Test5", + {bad_cert, {revoked, keyCompromise}}} + ]). + +crl_signing_valid(doc) -> + [""]; +crl_signing_valid(suite) -> + []; +crl_signing_valid(Config) when is_list(Config) -> + run([{ "4.5.6", "Valid Basic Self-Issued CRL Signing Key Test6", ok}]). + +crl_signing_invalid(doc) -> + [""]; +crl_signing_invalid(suite) -> + []; +crl_signing_invalid(Config) when is_list(Config) -> + run([{ "4.5.7", "Invalid Basic Self-Issued CRL Signing Key Test7", + {bad_cert, {revoked, keyCompromise}}}, + { "4.5.8", "Invalid Basic Self-Issued CRL Signing Key Test8", + {bad_cert, invalid_key_usage}} + ]). + +%%----------------------------------------------------------------------------- +missing_CRL(doc) -> + [""]; +missing_CRL(suite) -> + []; +missing_CRL(Config) when is_list(Config) -> + run([{ "4.4.1", "Missing CRL Test1",{bad_cert, + revocation_status_undetermined}}]). + +revoked_CA(doc) -> + [""]; +revoked_CA(suite) -> + []; +revoked_CA(Config) when is_list(Config) -> + run([{ "4.4.2", "Invalid Revoked CA Test2", {bad_cert, + {revoked, keyCompromise}}}]). + +revoked_peer(doc) -> + [""]; +revoked_peer(suite) -> + []; +revoked_peer(Config) when is_list(Config) -> + run([{ "4.4.3", "Invalid Revoked EE Test3", {bad_cert, + {revoked, keyCompromise}}}]). + +invalid_CRL_signature(doc) -> + [""]; +invalid_CRL_signature(suite) -> + []; +invalid_CRL_signature(Config) when is_list(Config) -> + run([{ "4.4.4", "Invalid Bad CRL Signature Test4", + {bad_cert, revocation_status_undetermined}}]). + +invalid_CRL_issuer(doc) -> + [""]; +invalid_CRL_issuer(suite) -> + []; +invalid_CRL_issuer(Config) when is_list(Config) -> + run({ "4.4.5", "Invalid Bad CRL Issuer Name Test5", + {bad_cert, revocation_status_undetermined}}). + +invalid_CRL(doc) -> + [""]; +invalid_CRL(suite) -> + []; +invalid_CRL(Config) when is_list(Config) -> + run([{ "4.4.6", "Invalid Wrong CRL Test6", + {bad_cert, revocation_status_undetermined}}]). + +valid_CRL(doc) -> + [""]; +valid_CRL(suite) -> + []; +valid_CRL(Config) when is_list(Config) -> + run([{ "4.4.7", "Valid Two CRLs Test7", ok}]). + +unknown_CRL_extension(doc) -> + [""]; +unknown_CRL_extension(suite) -> + []; +unknown_CRL_extension(Config) when is_list(Config) -> + run([{ "4.4.8", "Invalid Unknown CRL Entry Extension Test8", + {bad_cert, {revoked, keyCompromise}}}, + { "4.4.9", "Invalid Unknown CRL Extension Test9", + {bad_cert, {revoked, keyCompromise}}}, + { "4.4.10", "Invalid Unknown CRL Extension Test10", + {bad_cert, revocation_status_undetermined}}]). + +old_CRL(doc) -> + [""]; +old_CRL(suite) -> + []; +old_CRL(Config) when is_list(Config) -> + run([{ "4.4.11", "Invalid Old CRL nextUpdate Test11", + {bad_cert, revocation_status_undetermined}}, + { "4.4.12", "Invalid pre2000 CRL nextUpdate Test12", + {bad_cert, revocation_status_undetermined}}]). + +fresh_CRL(doc) -> + [""]; +fresh_CRL(suite) -> + []; +fresh_CRL(Config) when is_list(Config) -> + run([{ "4.4.13", "Valid GeneralizedTime CRL nextUpdate Test13", ok}]). + +valid_serial(doc) -> + [""]; +valid_serial(suite) -> + []; +valid_serial(Config) when is_list(Config) -> + run([ + { "4.4.14", "Valid Negative Serial Number Test14",ok}, + { "4.4.16", "Valid Long Serial Number Test16", ok}, + { "4.4.17", "Valid Long Serial Number Test17", ok} + ]). + +invalid_serial(doc) -> + [""]; +invalid_serial(suite) -> + []; +invalid_serial(Config) when is_list(Config) -> + run([{ "4.4.15", "Invalid Negative Serial Number Test15", + {bad_cert, {revoked, keyCompromise}}}, + { "4.4.18", "Invalid Long Serial Number Test18", + {bad_cert, {revoked, keyCompromise}}}]). + +valid_seperate_keys(doc) -> + [""]; +valid_seperate_keys(suite) -> + []; +valid_seperate_keys(Config) when is_list(Config) -> + run([{ "4.4.19", "Valid Separate Certificate and CRL Keys Test19", ok}]). + +invalid_separate_keys(doc) -> + [""]; +invalid_separate_keys(suite) -> + []; +invalid_separate_keys(Config) when is_list(Config) -> + run([{ "4.4.20", "Invalid Separate Certificate and CRL Keys Test20", + {bad_cert, {revoked, keyCompromise}}}, + { "4.4.21", "Invalid Separate Certificate and CRL Keys Test21", + {bad_cert, revocation_status_undetermined}} + ]). +%%----------------------------------------------------------------------------- +missing_basic_constraints(doc) -> + [""]; +missing_basic_constraints(suite) -> + []; +missing_basic_constraints(Config) when is_list(Config) -> + run([{ "4.6.1", "Invalid Missing basicConstraints Test1", + {bad_cert, missing_basic_constraint}}, + { "4.6.2", "Invalid cA False Test2", + {bad_cert, missing_basic_constraint}}, + { "4.6.3", "Invalid cA False Test3", + {bad_cert, missing_basic_constraint}}]). + +valid_basic_constraint(doc) -> + [""]; +valid_basic_constraint(suite) -> + []; +valid_basic_constraint(Config) when is_list(Config) -> + run([{"4.6.4", "Valid basicConstraints Not Critical Test4", ok}]). + +invalid_path_constraints(doc) -> + [""]; +invalid_path_constraints(suite) -> + []; +invalid_path_constraints(Config) when is_list(Config) -> + run([{ "4.6.5", "Invalid pathLenConstraint Test5", {bad_cert, max_path_length_reached}}, + { "4.6.6", "Invalid pathLenConstraint Test6", {bad_cert, max_path_length_reached}}, + { "4.6.9", "Invalid pathLenConstraint Test9", {bad_cert, max_path_length_reached}}, + { "4.6.10", "Invalid pathLenConstraint Test10", {bad_cert, max_path_length_reached}}, + { "4.6.11", "Invalid pathLenConstraint Test11", {bad_cert, max_path_length_reached}}, + { "4.6.12", "Invalid pathLenConstraint Test12", {bad_cert, max_path_length_reached}}, + { "4.6.16", "Invalid Self-Issued pathLenConstraint Test16", + {bad_cert, max_path_length_reached}}]). -signature_verification(doc) -> [""]; -signature_verification(suite) -> []; -signature_verification(Config) when is_list(Config) -> - run(signature_verification()). -validity_periods(doc) -> [""]; -validity_periods(suite) -> []; -validity_periods(Config) when is_list(Config) -> - run(validity_periods()). -verifying_name_chaining(doc) -> [""]; -verifying_name_chaining(suite) -> []; -verifying_name_chaining(Config) when is_list(Config) -> - run(verifying_name_chaining()). -basic_certificate_revocation_tests(doc) -> [""]; -basic_certificate_revocation_tests(suite) -> []; -basic_certificate_revocation_tests(Config) when is_list(Config) -> - run(basic_certificate_revocation_tests()). -verifying_paths_with_self_issued_certificates(doc) -> [""]; -verifying_paths_with_self_issued_certificates(suite) -> []; -verifying_paths_with_self_issued_certificates(Config) when is_list(Config) -> - run(verifying_paths_with_self_issued_certificates()). -verifying_basic_constraints(doc) -> [""]; -verifying_basic_constraints(suite) -> []; -verifying_basic_constraints(Config) when is_list(Config) -> - run(verifying_basic_constraints()). -key_usage(doc) -> [""]; -key_usage(suite) -> []; -key_usage(Config) when is_list(Config) -> - run(key_usage()). +valid_path_constraints(doc) -> + [""]; +valid_path_constraints(suite) -> + []; +valid_path_constraints(Config) when is_list(Config) -> + run([{ "4.6.7", "Valid pathLenConstraint Test7", ok}, + { "4.6.8", "Valid pathLenConstraint Test8", ok}, + { "4.6.13", "Valid pathLenConstraint Test13", ok}, + { "4.6.14", "Valid pathLenConstraint Test14", ok}, + { "4.6.15", "Valid Self-Issued pathLenConstraint Test15", ok}, + { "4.6.17", "Valid Self-Issued pathLenConstraint Test17", ok}]). + +%%----------------------------------------------------------------------------- +invalid_key_usage(doc) -> + [""]; +invalid_key_usage(suite) -> + []; +invalid_key_usage(Config) when is_list(Config) -> + run([{ "4.7.1", "Invalid keyUsage Critical keyCertSign False Test1", + {bad_cert,invalid_key_usage} }, + { "4.7.2", "Invalid keyUsage Not Critical keyCertSign False Test2", + {bad_cert,invalid_key_usage}}, + { "4.7.4", "Invalid keyUsage Critical cRLSign False Test4", + {bad_cert, revocation_status_undetermined}}, + { "4.7.5", "Invalid keyUsage Not Critical cRLSign False Test5", + {bad_cert, revocation_status_undetermined}} + ]). + +valid_key_usage(doc) -> + [""]; +valid_key_usage(suite) -> + []; +valid_key_usage(Config) when is_list(Config) -> + run([{ "4.7.3", "Valid keyUsage Not Critical Test3", ok}]). + +%%----------------------------------------------------------------------------- certificate_policies(doc) -> [""]; certificate_policies(suite) -> []; certificate_policies(Config) when is_list(Config) -> run(certificate_policies()). +%%----------------------------------------------------------------------------- require_explicit_policy(doc) -> [""]; require_explicit_policy(suite) -> []; require_explicit_policy(Config) when is_list(Config) -> run(require_explicit_policy()). +%%----------------------------------------------------------------------------- policy_mappings(doc) -> [""]; policy_mappings(suite) -> []; policy_mappings(Config) when is_list(Config) -> run(policy_mappings()). +%%----------------------------------------------------------------------------- inhibit_policy_mapping(doc) -> [""]; inhibit_policy_mapping(suite) -> []; inhibit_policy_mapping(Config) when is_list(Config) -> run(inhibit_policy_mapping()). +%%----------------------------------------------------------------------------- inhibit_any_policy(doc) -> [""]; inhibit_any_policy(suite) -> []; inhibit_any_policy(Config) when is_list(Config) -> run(inhibit_any_policy()). -name_constraints(doc) -> [""]; -name_constraints(suite) -> []; -name_constraints(Config) when is_list(Config) -> - run(name_constraints()). -distribution_points(doc) -> [""]; -distribution_points(suite) -> []; -distribution_points(Config) when is_list(Config) -> - run(distribution_points()). -delta_crls(doc) -> [""]; -delta_crls(suite) -> []; -delta_crls(Config) when is_list(Config) -> - run(delta_crls()). -private_certificate_extensions(doc) -> [""]; -private_certificate_extensions(suite) -> []; -private_certificate_extensions(Config) when is_list(Config) -> - run(private_certificate_extensions()). - -run() -> - Tests = - [signature_verification(), - validity_periods(), - verifying_name_chaining(), - %%basic_certificate_revocation_tests(), - verifying_paths_with_self_issued_certificates(), - verifying_basic_constraints(), - key_usage(), - %%certificate_policies(), - %%require_explicit_policy(), - %%policy_mappings(), - %%inhibit_policy_mapping(), - %%inhibit_any_policy(), - name_constraints(), - %distribution_points(), - %delta_crls(), - private_certificate_extensions() - ], - run(lists:append(Tests)). +%%----------------------------------------------------------------------------- + +valid_DN_name_constraints(doc) -> + [""]; +valid_DN_name_constraints(suite) -> + []; +valid_DN_name_constraints(Config) when is_list(Config) -> + run([{ "4.13.1", "Valid DN nameConstraints Test1", ok}, + { "4.13.4", "Valid DN nameConstraints Test4", ok}, + { "4.13.5", "Valid DN nameConstraints Test5", ok}, + { "4.13.6", "Valid DN nameConstraints Test6", ok}, + { "4.13.11", "Valid DN nameConstraints Test11", ok}, + { "4.13.14", "Valid DN nameConstraints Test14", ok}, + { "4.13.18", "Valid DN nameConstraints Test18", ok}, + { "4.13.19", "Valid Self-Issued DN nameConstraints Test19", ok}]). + +invalid_DN_name_constraints(doc) -> + [""]; +invalid_DN_name_constraints(suite) -> + []; +invalid_DN_name_constraints(Config) when is_list(Config) -> + run([{ "4.13.2", "Invalid DN nameConstraints Test2", {bad_cert, name_not_permitted}}, + { "4.13.3", "Invalid DN nameConstraints Test3", {bad_cert, name_not_permitted}}, + { "4.13.7", "Invalid DN nameConstraints Test7", {bad_cert, name_not_permitted}}, + { "4.13.8", "Invalid DN nameConstraints Test8", {bad_cert, name_not_permitted}}, + { "4.13.9", "Invalid DN nameConstraints Test9", {bad_cert, name_not_permitted}}, + { "4.13.10", "Invalid DN nameConstraints Test10",{bad_cert, name_not_permitted}}, + { "4.13.12", "Invalid DN nameConstraints Test12",{bad_cert, name_not_permitted}}, + { "4.13.13", "Invalid DN nameConstraints Test13",{bad_cert, name_not_permitted}}, + { "4.13.15", "Invalid DN nameConstraints Test15",{bad_cert, name_not_permitted}}, + { "4.13.16", "Invalid DN nameConstraints Test16",{bad_cert, name_not_permitted}}, + { "4.13.17", "Invalid DN nameConstraints Test17",{bad_cert, name_not_permitted}}, + { "4.13.20", "Invalid Self-Issued DN nameConstraints Test20", + {bad_cert, name_not_permitted}}]). + +valid_rfc822_name_constraints(doc) -> + [""]; +valid_rfc822_name_constraints(suite) -> + []; +valid_rfc822_name_constraints(Config) when is_list(Config) -> + run([{ "4.13.21", "Valid RFC822 nameConstraints Test21", ok}, + { "4.13.23", "Valid RFC822 nameConstraints Test23", ok}, + { "4.13.25", "Valid RFC822 nameConstraints Test25", ok}]). + + +invalid_rfc822_name_constraints(doc) -> + [""]; +invalid_rfc822_name_constraints(suite) -> + []; +invalid_rfc822_name_constraints(Config) when is_list(Config) -> + run([{ "4.13.22", "Invalid RFC822 nameConstraints Test22", + {bad_cert, name_not_permitted}}, + { "4.13.24", "Invalid RFC822 nameConstraints Test24", + {bad_cert, name_not_permitted}}, + { "4.13.26", "Invalid RFC822 nameConstraints Test26", + {bad_cert, name_not_permitted}}]). + +valid_DN_and_rfc822_name_constraints(doc) -> + [""]; +valid_DN_and_rfc822_name_constraints(suite) -> + []; +valid_DN_and_rfc822_name_constraints(Config) when is_list(Config) -> + run([{ "4.13.27", "Valid DN and RFC822 nameConstraints Test27", ok}]). + +invalid_DN_and_rfc822_name_constraints(doc) -> + [""]; +invalid_DN_and_rfc822_name_constraints(suite) -> + []; +invalid_DN_and_rfc822_name_constraints(Config) when is_list(Config) -> + run([{ "4.13.28", "Invalid DN and RFC822 nameConstraints Test28", + {bad_cert, name_not_permitted}}, + { "4.13.29", "Invalid DN and RFC822 nameConstraints Test29", + {bad_cert, name_not_permitted}}]). + +valid_dns_name_constraints(doc) -> + [""]; +valid_dns_name_constraints(suite) -> + []; +valid_dns_name_constraints(Config) when is_list(Config) -> + run([{ "4.13.30", "Valid DNS nameConstraints Test30", ok}, + { "4.13.32", "Valid DNS nameConstraints Test32", ok}]). + +invalid_dns_name_constraints(doc) -> + [""]; +invalid_dns_name_constraints(suite) -> + []; +invalid_dns_name_constraints(Config) when is_list(Config) -> + run([{ "4.13.31", "Invalid DNS nameConstraints Test31", {bad_cert, name_not_permitted}}, + { "4.13.33", "Invalid DNS nameConstraints Test33", {bad_cert, name_not_permitted}}, + { "4.13.38", "Invalid DNS nameConstraints Test38", {bad_cert, name_not_permitted}}]). + +valid_uri_name_constraints(doc) -> + [""]; +valid_uri_name_constraints(suite) -> + []; +valid_uri_name_constraints(Config) when is_list(Config) -> + run([{ "4.13.34", "Valid URI nameConstraints Test34", ok}, + { "4.13.36", "Valid URI nameConstraints Test36", ok}]). + +invalid_uri_name_constraints(doc) -> + [""]; +invalid_uri_name_constraints(suite) -> + []; +invalid_uri_name_constraints(Config) when is_list(Config) -> + run([{ "4.13.35", "Invalid URI nameConstraints Test35",{bad_cert, name_not_permitted}}, + { "4.13.37", "Invalid URI nameConstraints Test37",{bad_cert, name_not_permitted}}]). + +%%----------------------------------------------------------------------------- +delta_without_crl(doc) -> + [""]; +delta_without_crl(suite) -> + []; +delta_without_crl(Config) when is_list(Config) -> + run([{ "4.15.1", "Invalid deltaCRLIndicator No Base Test1",{bad_cert, + revocation_status_undetermined}}, + {"4.15.10", "Invalid delta-CRL Test10", {bad_cert, + revocation_status_undetermined}}]). + +valid_delta_crls(doc) -> + [""]; +valid_delta_crls(suite) -> + []; +valid_delta_crls(Config) when is_list(Config) -> + run([{ "4.15.2", "Valid delta-CRL Test2", ok}, + { "4.15.5", "Valid delta-CRL Test5", ok}, + { "4.15.7", "Valid delta-CRL Test7", ok}, + { "4.15.8", "Valid delta-CRL Test8", ok} + ]). + +invalid_delta_crls(doc) -> + [""]; +invalid_delta_crls(suite) -> + []; +invalid_delta_crls(Config) when is_list(Config) -> + run([{ "4.15.3", "Invalid delta-CRL Test3", {bad_cert,{revoked, keyCompromise}}}, + { "4.15.4", "Invalid delta-CRL Test4", {bad_cert,{revoked, keyCompromise}}}, + { "4.15.6", "Invalid delta-CRL Test6", {bad_cert,{revoked, keyCompromise}}}, + { "4.15.9", "Invalid delta-CRL Test9", {bad_cert,{revoked, keyCompromise}}}]). + +%%----------------------------------------------------------------------------- + +valid_distribution_points(doc) -> + [""]; +valid_distribution_points(suite) -> + []; +valid_distribution_points(Config) when is_list(Config) -> + run([{ "4.14.1", "Valid distributionPoint Test1", ok}, + { "4.14.4", "Valid distributionPoint Test4", ok}, + { "4.14.5", "Valid distributionPoint Test5", ok}, + { "4.14.7", "Valid distributionPoint Test7", ok} + ]). + +valid_distribution_points_no_issuing_distribution_point(doc) -> + [""]; +valid_distribution_points_no_issuing_distribution_point(suite) -> + []; +valid_distribution_points_no_issuing_distribution_point(Config) when is_list(Config) -> + run([{ "4.14.10", "Valid No issuingDistributionPoint Test10", ok} + ]). + +invalid_distribution_points(doc) -> + [""]; +invalid_distribution_points(suite) -> + []; +invalid_distribution_points(Config) when is_list(Config) -> + run([{ "4.14.2", "Invalid distributionPoint Test2", {bad_cert,{revoked, keyCompromise}}}, + { "4.14.3", "Invalid distributionPoint Test3", {bad_cert, + revocation_status_undetermined}}, + { "4.14.6", "Invalid distributionPoint Test6", {bad_cert,{revoked, keyCompromise}}}, + { "4.14.8", "Invalid distributionPoint Test8", {bad_cert, + revocation_status_undetermined}}, + { "4.14.9", "Invalid distributionPoint Test9", {bad_cert, + revocation_status_undetermined}} + ]). + +valid_only_contains(doc) -> + [""]; +valid_only_contains(suite) -> + []; +valid_only_contains(Config) when is_list(Config) -> + run([{ "4.14.13", "Valid onlyContainsCACerts CRL Test13", ok}]). + +invalid_only_contains(doc) -> + [""]; +invalid_only_contains(suite) -> + []; +invalid_only_contains(Config) when is_list(Config) -> + run([{ "4.14.11", "Invalid onlyContainsUserCerts CRL Test11", + {bad_cert, revocation_status_undetermined}}, + { "4.14.12", "Invalid onlyContainsCACerts CRL Test12", + {bad_cert, revocation_status_undetermined}}, + { "4.14.14", "Invalid onlyContainsAttributeCerts Test14", + {bad_cert, revocation_status_undetermined}} + ]). + +valid_only_some_reasons(doc) -> + [""]; +valid_only_some_reasons(suite) -> + []; +valid_only_some_reasons(Config) when is_list(Config) -> + run([{ "4.14.18", "Valid onlySomeReasons Test18", ok}, + { "4.14.19", "Valid onlySomeReasons Test19", ok} + ]). + +invalid_only_some_reasons(doc) -> + [""]; +invalid_only_some_reasons(suite) -> + []; +invalid_only_some_reasons(Config) when is_list(Config) -> + run([{ "4.14.15", "Invalid onlySomeReasons Test15", + {bad_cert,{revoked, keyCompromise}}}, + { "4.14.16", "Invalid onlySomeReasons Test16", + {bad_cert,{revoked, certificateHold}}}, + { "4.14.17", "Invalid onlySomeReasons Test17", + {bad_cert, revocation_status_undetermined}}, + { "4.14.20", "Invalid onlySomeReasons Test20", + {bad_cert,{revoked, keyCompromise}}}, + { "4.14.21", "Invalid onlySomeReasons Test21", + {bad_cert,{revoked, affiliationChanged}}} + ]). + +valid_indirect_crl(doc) -> + [""]; +valid_indirect_crl(suite) -> + []; +valid_indirect_crl(Config) when is_list(Config) -> + run([{ "4.14.22", "Valid IDP with indirectCRL Test22", ok}, + { "4.14.24", "Valid IDP with indirectCRL Test24", ok}, + { "4.14.25", "Valid IDP with indirectCRL Test25", ok} + ]). + +invalid_indirect_crl(doc) -> + [""]; +invalid_indirect_crl(suite) -> + []; +invalid_indirect_crl(Config) when is_list(Config) -> + run([{ "4.14.23", "Invalid IDP with indirectCRL Test23", + {bad_cert,{revoked, keyCompromise}}}, + { "4.14.26", "Invalid IDP with indirectCRL Test26", + {bad_cert, revocation_status_undetermined}} + ]). + +valid_crl_issuer(doc) -> + [""]; +valid_crl_issuer(suite) -> + []; +valid_crl_issuer(Config) when is_list(Config) -> + run([{ "4.14.28", "Valid cRLIssuer Test28", ok}%%, + %%{ "4.14.29", "Valid cRLIssuer Test29", ok}, + %%{ "4.14.33", "Valid cRLIssuer Test33", ok} + ]). + +invalid_crl_issuer(doc) -> + [""]; +invalid_crl_issuer(suite) -> + []; +invalid_crl_issuer(Config) when is_list(Config) -> + run([ + { "4.14.27", "Invalid cRLIssuer Test27", {bad_cert, revocation_status_undetermined}}, + { "4.14.31", "Invalid cRLIssuer Test31", {bad_cert,{revoked, keyCompromise}}}, + { "4.14.32", "Invalid cRLIssuer Test32", {bad_cert,{revoked, keyCompromise}}}, + { "4.14.34", "Invalid cRLIssuer Test34", {bad_cert,{revoked, keyCompromise}}}, + { "4.14.35", "Invalid cRLIssuer Test35", {bad_cert, revocation_status_undetermined}} + ]). + + +%%distribution_points() -> + %%{ "4.14", "Distribution Points" }, +%% [ + %% Although this test is valid it has a circular dependency. As a result + %% an attempt is made to reursively checks a CRL path and rejected due to + %% a CRL path validation error. PKITS notes suggest this test does not + %% need to be run due to this issue. +%% { "4.14.30", "Valid cRLIssuer Test30", 54 }]. + + +%%----------------------------------------------------------------------------- + +unknown_critical_extension(doc) -> + [""]; +unknown_critical_extension(suite) -> + []; +unknown_critical_extension(Config) when is_list(Config) -> + run([{ "4.16.2", "Invalid Unknown Critical Certificate Extension Test2", + {bad_cert,unknown_critical_extension}}]). + +unknown_not_critical_extension(doc) -> + [""]; +unknown_not_critical_extension(suite) -> + []; +unknown_not_critical_extension(Config) when is_list(Config) -> + run([{ "4.16.1", "Valid Unknown Not Critical Certificate Extension Test1", ok}]). + +%%----------------------------------------------------------------------------- run(Tests) -> File = file(?CERTS,"TrustAnchorRootCertificate.crt"), {ok, TA} = file:read_file(File), run(Tests, TA). run({Chap, Test, Result}, TA) -> - CertChain = sort_chain(read_certs(Test),TA, [], false), - try public_key:pkix_path_validation(TA, CertChain, []) of - {Result, _} -> ok; + CertChain = sort_chain(read_certs(Test),TA, [], false, Chap), + Options = path_validation_options(TA, Chap,Test), + try public_key:pkix_path_validation(TA, CertChain, Options) of + {Result, _} -> ok; {error,Result} when Result =/= ok -> ok; - {error,Error} when is_integer(Result) -> - ?warning(" ~p~n Got ~p expected ~p~n",[Test, Error, Result]); - {error,Error} when Result =/= ok -> - ?error(" minor ~p~n Got ~p expected ~p~n",[Test, Error, Result]); {error, Error} -> ?error(" ~p ~p~n Expected ~p got ~p ~n", [Chap, Test, Result, Error]), fail; - {ok, _} when Result =/= ok -> + {ok, _OK} when Result =/= ok -> ?error(" ~p ~p~n Expected ~p got ~p ~n", [Chap, Test, Result, ok]), fail catch Type:Reason -> @@ -181,14 +821,318 @@ run([Test|Rest],TA) -> run(Rest,TA); run([],_) -> ok. +path_validation_options(TA, Chap, Test) -> + case needs_crl_options(Chap) of + true -> + crl_options(TA, Test); + false -> + Fun = + fun(_,{bad_cert, _} = Reason, _) -> + {fail, Reason}; + (_,{extension, _}, UserState) -> + {unknown, UserState}; + (_, Valid, UserState) when Valid == valid; + Valid == valid_peer -> + {valid, UserState} + end, + [{verify_fun, {Fun, []}}] + end. + +needs_crl_options("4.4" ++ _) -> + true; +needs_crl_options("4.5" ++ _) -> + true; +needs_crl_options("4.7.4" ++ _) -> + true; +needs_crl_options("4.7.5" ++ _) -> + true; +needs_crl_options("4.14" ++ _) -> + true; +needs_crl_options("4.15" ++ _) -> + true; +needs_crl_options(_) -> + false. + +crl_options(TA, Test) -> + case read_crls(Test) of + [] -> + []; + CRLs -> + Fun = + fun(_,{bad_cert, _} = Reason, _) -> + {fail, Reason}; + (_,{extension, + #'Extension'{extnID = ?'id-ce-cRLDistributionPoints', + extnValue = Value}}, UserState0) -> + UserState = update_crls(Value, UserState0), + {valid, UserState}; + (_,{extension, _}, UserState) -> + {unknown, UserState}; + (OtpCert, Valid, UserState) when Valid == valid; + Valid == valid_peer -> + {ErlCerts, CRLs} = UserState#verify_state.crl_info, + CRLInfo0 = + crl_info(OtpCert, + ErlCerts,[{DerCRL, public_key:der_decode('CertificateList', + DerCRL)} || DerCRL <- CRLs], + []), + CRLInfo = lists:reverse(CRLInfo0), + Certs = UserState#verify_state.certs_db, + Fun = fun(DP, CRLtoValidate, Id, CertsDb) -> + trusted_cert_and_path(DP, CRLtoValidate, Id, CertsDb) + end, + Ignore = ignore_sign_test_when_building_path(Test), + case public_key:pkix_crls_validate(OtpCert, CRLInfo, + [{issuer_fun,{Fun, {Ignore, Certs}}}]) of + valid -> + {valid, UserState}; + Reason -> + {fail, Reason} + end + end, + + Certs = read_certs(Test), + ErlCerts = [public_key:pkix_decode_cert(Cert, otp) || Cert <- Certs], + + [{verify_fun, {Fun, #verify_state{certs_db = [TA| Certs], + crl_info = {ErlCerts, CRLs}}}}] + end. + +crl_info(_, _, [], Acc) -> + Acc; +crl_info(OtpCert, Certs, [{_, #'CertificateList'{tbsCertList = + #'TBSCertList'{issuer = Issuer, + crlExtensions = CRLExtensions}}} + = CRL | Rest], Acc) -> + OtpTBSCert = OtpCert#'OTPCertificate'.tbsCertificate, + Extensions = OtpTBSCert#'OTPTBSCertificate'.extensions, + ExtList = pubkey_cert:extensions_list(CRLExtensions), + DPs = case pubkey_cert:select_extension(?'id-ce-cRLDistributionPoints', Extensions) of + #'Extension'{extnValue = Value} -> + lists:map(fun(Point) -> pubkey_cert_records:transform(Point, decode) end, Value); + _ -> + case same_issuer(OtpCert, Issuer) of + true -> + [make_dp(ExtList, asn1_NOVALUE, Issuer)]; + false -> + [make_dp(ExtList, Issuer, ignore)] + end + end, + DPsCRLs = lists:map(fun(DP) -> {DP, CRL} end, DPs), + crl_info(OtpCert, Certs, Rest, DPsCRLs ++ Acc). + +ignore_sign_test_when_building_path("Invalid Bad CRL Signature Test4") -> + true; +ignore_sign_test_when_building_path(_) -> + false. + +same_issuer(OTPCert, Issuer) -> + DecIssuer = pubkey_cert_records:transform(Issuer, decode), + OTPTBSCert = OTPCert#'OTPCertificate'.tbsCertificate, + CertIssuer = OTPTBSCert#'OTPTBSCertificate'.issuer, + pubkey_cert:is_issuer(DecIssuer, CertIssuer). + +make_dp(Extensions, Issuer0, DpInfo) -> + {Issuer, Point} = mk_issuer_dp(Issuer0, DpInfo), + case pubkey_cert:select_extension('id-ce-cRLReason', Extensions) of + #'Extension'{extnValue = Reasons} -> + #'DistributionPoint'{cRLIssuer = Issuer, + reasons = Reasons, + distributionPoint = Point}; + _ -> + #'DistributionPoint'{cRLIssuer = Issuer, + reasons = [unspecified, keyCompromise, + cACompromise, affiliationChanged, superseded, + cessationOfOperation, certificateHold, + removeFromCRL, privilegeWithdrawn, aACompromise], + distributionPoint = Point} + end. + +mk_issuer_dp(asn1_NOVALUE, Issuer) -> + {asn1_NOVALUE, {fullName, [{directoryName, Issuer}]}}; +mk_issuer_dp(Issuer, _) -> + {[{directoryName, Issuer}], asn1_NOVALUE}. + +update_crls(_, State) -> + State. + +trusted_cert_and_path(DP, CRL, Id, {Ignore, CertsList}) -> + case crl_issuer(crl_issuer_name(DP), CRL, Id, CertsList, CertsList, Ignore) of + {ok, IssuerCert, DerIssuerCert} -> + Certs = [{public_key:pkix_decode_cert(Cert, otp), Cert} || Cert <- CertsList], + CertChain = build_chain(Certs, Certs, IssuerCert, Ignore, [DerIssuerCert]), + {ok, public_key:pkix_decode_cert(hd(CertChain), otp), CertChain}; + Other -> + Other + end. + +crl_issuer_name(#'DistributionPoint'{cRLIssuer = asn1_NOVALUE}) -> + undefined; +crl_issuer_name(#'DistributionPoint'{cRLIssuer = [{directoryName, Issuer}]}) -> + pubkey_cert_records:transform(Issuer, decode). + +build_chain([],_, _, _,Acc) -> + Acc; + +build_chain([{First, DerFirst}|Certs], All, Cert, Ignore, Acc) -> + case public_key:pkix_is_self_signed(Cert) andalso is_test_root(Cert) of + true -> + Acc; + false -> + case public_key:pkix_is_issuer(Cert, First) + %%andalso check_extension_cert_signer(First) + andalso is_signer(First, Cert, Ignore) + of + true -> + build_chain(All, All, First, Ignore, [DerFirst | Acc]); + false -> + build_chain(Certs, All, Cert, Ignore, Acc) + end + end. + +is_signer(_,_, true) -> + true; +is_signer(Signer, #'OTPCertificate'{} = Cert,_) -> + TBSCert = Signer#'OTPCertificate'.tbsCertificate, + PublicKeyInfo = TBSCert#'OTPTBSCertificate'.subjectPublicKeyInfo, + PublicKey = PublicKeyInfo#'OTPSubjectPublicKeyInfo'.subjectPublicKey, + AlgInfo = PublicKeyInfo#'OTPSubjectPublicKeyInfo'.algorithm, + PublicKeyParams = AlgInfo#'PublicKeyAlgorithm'.parameters, + try pubkey_cert:validate_signature(Cert, public_key:pkix_encode('OTPCertificate', + Cert, otp), + PublicKey, PublicKeyParams, true, ?DEFAULT_VERIFYFUN) of + true -> + true + catch + _:_ -> + false + end; +is_signer(Signer, #'CertificateList'{} = CRL, _) -> + TBSCert = Signer#'OTPCertificate'.tbsCertificate, + PublicKeyInfo = TBSCert#'OTPTBSCertificate'.subjectPublicKeyInfo, + PublicKey = PublicKeyInfo#'OTPSubjectPublicKeyInfo'.subjectPublicKey, + AlgInfo = PublicKeyInfo#'OTPSubjectPublicKeyInfo'.algorithm, + PublicKeyParams = AlgInfo#'PublicKeyAlgorithm'.parameters, + pubkey_crl:verify_crl_signature(CRL, public_key:pkix_encode('CertificateList', + CRL, plain), + PublicKey, PublicKeyParams). + +is_test_root(OtpCert) -> + TBSCert = OtpCert#'OTPCertificate'.tbsCertificate, + {rdnSequence, AtterList} = TBSCert#'OTPTBSCertificate'.issuer, + lists:member([{'AttributeTypeAndValue',{2,5,4,3},{printableString,"Trust Anchor"}}], + AtterList). + +check_extension_cert_signer(OtpCert) -> + TBSCert = OtpCert#'OTPCertificate'.tbsCertificate, + Extensions = TBSCert#'OTPTBSCertificate'.extensions, + case pubkey_cert:select_extension(?'id-ce-keyUsage', Extensions) of + #'Extension'{extnValue = KeyUse} -> + lists:member(keyCertSign, KeyUse); + _ -> + true + end. + +check_extension_crl_signer(OtpCert) -> + TBSCert = OtpCert#'OTPCertificate'.tbsCertificate, + Extensions = TBSCert#'OTPTBSCertificate'.extensions, + case pubkey_cert:select_extension(?'id-ce-keyUsage', Extensions) of + #'Extension'{extnValue = KeyUse} -> + lists:member(cRLSign, KeyUse); + _ -> + true + end. + +crl_issuer(undefined, CRL, issuer_not_found, _, CertsList, Ignore) -> + crl_issuer(CRL, CertsList, Ignore); + +crl_issuer(IssuerName, CRL, issuer_not_found, CertsList, CertsList, Ignore) -> + crl_issuer(IssuerName, CRL, IssuerName, CertsList, CertsList, Ignore); + +crl_issuer(undefined, CRL, Id, [Cert | Rest], All, false) -> + ErlCert = public_key:pkix_decode_cert(Cert, otp), + TBSCertificate = ErlCert#'OTPCertificate'.tbsCertificate, + SerialNumber = TBSCertificate#'OTPTBSCertificate'.serialNumber, + Issuer = public_key:pkix_normalize_name( + TBSCertificate#'OTPTBSCertificate'.subject), + Bool = is_signer(ErlCert, CRL, false), + case {SerialNumber, Issuer} of + Id when Bool == true -> + {ok, ErlCert, Cert}; + _ -> + crl_issuer(undefined, CRL, Id, Rest, All, false) + end; + +crl_issuer(IssuerName, CRL, Id, [Cert | Rest], All, false) -> + ErlCert = public_key:pkix_decode_cert(Cert, otp), + TBSCertificate = ErlCert#'OTPCertificate'.tbsCertificate, + SerialNumber = TBSCertificate#'OTPTBSCertificate'.serialNumber, + %%Issuer = public_key:pkix_normalize_name( + %% TBSCertificate#'OTPTBSCertificate'.subject), + Bool = is_signer(ErlCert, CRL, false), + case {SerialNumber, IssuerName} of + Id when Bool == true -> + {ok, ErlCert, Cert}; + {_, IssuerName} when Bool == true -> + {ok, ErlCert, Cert}; + _ -> + crl_issuer(IssuerName, CRL, Id, Rest, All, false) + end; + +crl_issuer(undefined, CRL, _, [], CertsList, Ignore) -> + crl_issuer(CRL, CertsList, Ignore); +crl_issuer(CRLName, CRL, _, [], CertsList, Ignore) -> + crl_issuer(CRLName, CRL, CertsList, Ignore). + + +crl_issuer(_, [],_) -> + {error, issuer_not_found}; +crl_issuer(CRL, [Cert | Rest], Ignore) -> + ErlCert = public_key:pkix_decode_cert(Cert, otp), + case public_key:pkix_is_issuer(CRL, ErlCert) andalso + check_extension_crl_signer(ErlCert) andalso + is_signer(ErlCert, CRL, Ignore) + of + true -> + {ok, ErlCert,Cert}; + false -> + crl_issuer(CRL, Rest, Ignore) + end. + +crl_issuer(_,_, [],_) -> + {error, issuer_not_found}; +crl_issuer(IssuerName, CRL, [Cert | Rest], Ignore) -> + ErlCert = public_key:pkix_decode_cert(Cert, otp), + TBSCertificate = ErlCert#'OTPCertificate'.tbsCertificate, + Issuer = public_key:pkix_normalize_name( + TBSCertificate#'OTPTBSCertificate'.subject), + + case + public_key:pkix_is_issuer(CRL, ErlCert) andalso + check_extension_crl_signer(ErlCert) andalso + is_signer(ErlCert, CRL, Ignore) + of + true -> + case pubkey_cert:is_issuer(Issuer, IssuerName) of + true -> + {ok, ErlCert,Cert}; + false -> + crl_issuer(IssuerName, CRL, Rest, Ignore) + end; + false -> + crl_issuer(IssuerName, CRL, Rest, Ignore) + end. read_certs(Test) -> File = test_file(Test), - %% io:format("Read ~p ",[File]), Ders = erl_make_certs:pem_to_der(File), - %% io:format("Ders ~p ~n",[length(Ders)]), [Cert || {'Certificate', Cert, not_encrypted} <- Ders]. +read_crls(Test) -> + File = test_file(Test), + Ders = erl_make_certs:pem_to_der(File), + [CRL || {'CertificateList', CRL, not_encrypted} <- Ders]. + test_file(Test) -> file(?CONV, lists:append(string:tokens(Test, " -")) ++ ".pem"). @@ -206,118 +1150,89 @@ file(Sub,File) -> end, AbsFile. -sort_chain([First|Certs], TA, Try, Found) -> +sort_chain(Certs, TA, Acc, Bool, Chap) when Chap == "4.5.3"-> + [CA, Entity, Self] = do_sort_chain(Certs, TA, Acc, Bool, Chap), + [CA, Self, Entity]; +sort_chain(Certs, TA, Acc, Bool, Chap) when Chap == "4.5.4"; + Chap == "4.5.5" -> + [CA, Entity, _Self] = do_sort_chain(Certs, TA, Acc, Bool, Chap), + [CA, Entity]; + +sort_chain(Certs, TA, Acc, Bool, Chap) when Chap == "4.14.24"; + Chap == "4.14.25"; + Chap == "4.14.26"; + Chap == "4.14.27"; + Chap == "4.14.31"; + Chap == "4.14.32"; + Chap == "4.14.33" -> + [_OtherCA, Entity, CA] = do_sort_chain(Certs, TA, Acc, Bool, Chap), + [CA, Entity]; + +sort_chain(Certs, TA, Acc, Bool, Chap) when Chap == "4.14.28"; + Chap == "4.14.29" -> + [CA, _OtherCA, Entity] = do_sort_chain(Certs, TA, Acc, Bool, Chap), + [CA, Entity]; + + +sort_chain(Certs, TA, Acc, Bool, Chap) when Chap == "4.14.33" -> + [Entity, CA, _OtherCA] = do_sort_chain(Certs, TA, Acc, Bool, Chap), + [CA, Entity]; + + +sort_chain(Certs, TA, Acc, Bool, Chap) -> + do_sort_chain(Certs, TA, Acc, Bool, Chap). + +do_sort_chain([First], TA, Try, Found, Chap) when Chap == "4.5.6"; + Chap == "4.5.7"; + Chap == "4.4.19"; + Chap == "4.4.20"; + Chap == "4.4.21"-> case public_key:pkix_is_issuer(First,TA) of true -> - [First|sort_chain(Certs,First,Try,true)]; + [First|do_sort_chain([],First,Try,true, Chap)]; false -> - sort_chain(Certs,TA,[First|Try],Found) + do_sort_chain([],TA,[First|Try],Found, Chap) end; -sort_chain([], _, [],_) -> []; -sort_chain([], Valid, Check, true) -> - sort_chain(lists:reverse(Check), Valid, [], false); -sort_chain([], _Valid, Check, false) -> +do_sort_chain([First|Certs], TA, Try, Found, Chap) when Chap == "4.5.6"; + Chap == "4.5.7"; + Chap == "4.4.19"; + Chap == "4.4.20"; + Chap == "4.4.21"-> +%% case check_extension_cert_signer(public_key:pkix_decode_cert(First, otp)) of +%% true -> + case public_key:pkix_is_issuer(First,TA) of + true -> + [First|do_sort_chain(Certs,First,Try,true, Chap)]; + false -> + do_sort_chain(Certs,TA,[First|Try],Found, Chap) + end; +%% false -> +%% do_sort_chain(Certs, TA, Try, Found, Chap) +%% end; + +do_sort_chain([First|Certs], TA, Try, Found, Chap) -> + case public_key:pkix_is_issuer(First,TA) of + true -> + [First|do_sort_chain(Certs,First,Try,true, Chap)]; + false -> + do_sort_chain(Certs,TA,[First|Try],Found, Chap) + end; + +do_sort_chain([], _, [],_, _) -> []; +do_sort_chain([], Valid, Check, true, Chap) -> + do_sort_chain(lists:reverse(Check), Valid, [], false, Chap); +do_sort_chain([], _Valid, Check, false, _) -> Check. -signature_verification() -> - %% "4.1", "Signature Verification" , - [{ "4.1.1", "Valid Signatures Test1", ok}, - { "4.1.2", "Invalid CA Signature Test2", {bad_cert,invalid_signature}}, - { "4.1.3", "Invalid EE Signature Test3", {bad_cert,invalid_signature}}, - { "4.1.4", "Valid DSA Signatures Test4", ok}, - { "4.1.5", "Valid DSA Parameter Inheritance Test5", ok}, - { "4.1.6", "Invalid DSA Signature Test6", {bad_cert,invalid_signature}}]. -validity_periods() -> - %% { "4.2", "Validity Periods" }, - [{ "4.2.1", "Invalid CA notBefore Date Test1", {bad_cert, cert_expired}}, - { "4.2.2", "Invalid EE notBefore Date Test2", {bad_cert, cert_expired}}, - { "4.2.3", "Valid pre2000 UTC notBefore Date Test3", ok}, - { "4.2.4", "Valid GeneralizedTime notBefore Date Test4", ok}, - { "4.2.5", "Invalid CA notAfter Date Test5", {bad_cert, cert_expired}}, - { "4.2.6", "Invalid EE notAfter Date Test6", {bad_cert, cert_expired}}, - { "4.2.7", "Invalid pre2000 UTC EE notAfter Date Test7", {bad_cert, cert_expired}}, - { "4.2.8", "Valid GeneralizedTime notAfter Date Test8", ok}]. -verifying_name_chaining() -> - %%{ "4.3", "Verifying Name Chaining" }, - [{ "4.3.1", "Invalid Name Chaining EE Test1", {bad_cert, invalid_issuer}}, - { "4.3.2", "Invalid Name Chaining Order Test2", {bad_cert, invalid_issuer}}, - { "4.3.3", "Valid Name Chaining Whitespace Test3", ok}, - { "4.3.4", "Valid Name Chaining Whitespace Test4", ok}, - { "4.3.5", "Valid Name Chaining Capitalization Test5", ok}, - { "4.3.6", "Valid Name Chaining UIDs Test6", ok}, - { "4.3.7", "Valid RFC3280 Mandatory Attribute Types Test7", ok}, - { "4.3.8", "Valid RFC3280 Optional Attribute Types Test8", ok}, - { "4.3.9", "Valid UTF8String Encoded Names Test9", ok}, - { "4.3.10", "Valid Rollover from PrintableString to UTF8String Test10", ok}, - { "4.3.11", "Valid UTF8String Case Insensitive Match Test11", ok}]. -basic_certificate_revocation_tests() -> - %%{ "4.4", "Basic Certificate Revocation Tests" }, - [{ "4.4.1", "Missing CRL Test1", 3 }, - { "4.4.2", "Invalid Revoked CA Test2", 23 }, - { "4.4.3", "Invalid Revoked EE Test3", 23 }, - { "4.4.4", "Invalid Bad CRL Signature Test4", 8 }, - { "4.4.5", "Invalid Bad CRL Issuer Name Test5", 3 }, - { "4.4.6", "Invalid Wrong CRL Test6", 3 }, - { "4.4.7", "Valid Two CRLs Test7", ok}, - - %% The test document suggests these should return certificate revoked... - %% Subsquent discussion has concluded they should not due to unhandle - %% critical CRL extensions. - { "4.4.8", "Invalid Unknown CRL Entry Extension Test8", 36 }, - { "4.4.9", "Invalid Unknown CRL Extension Test9", 36 }, - - { "4.4.10", "Invalid Unknown CRL Extension Test10", 36 }, - { "4.4.11", "Invalid Old CRL nextUpdate Test11", 12 }, - { "4.4.12", "Invalid pre2000 CRL nextUpdate Test12", 12 }, - { "4.4.13", "Valid GeneralizedTime CRL nextUpdate Test13", ok}, - { "4.4.14", "Valid Negative Serial Number Test14", ok}, - { "4.4.15", "Invalid Negative Serial Number Test15", 23 }, - { "4.4.16", "Valid Long Serial Number Test16", ok}, - { "4.4.17", "Valid Long Serial Number Test17", ok}, - { "4.4.18", "Invalid Long Serial Number Test18", 23 }, - { "4.4.19", "Valid Separate Certificate and CRL Keys Test19", ok}, - { "4.4.20", "Invalid Separate Certificate and CRL Keys Test20", 23 }, - - %% CRL path is revoked so get a CRL path validation error - { "4.4.21", "Invalid Separate Certificate and CRL Keys Test21", 54 }]. -verifying_paths_with_self_issued_certificates() -> - %%{ "4.5", "Verifying Paths with Self-Issued Certificates" }, - [{ "4.5.1", "Valid Basic Self-Issued Old With New Test1", ok}, - %%{ "4.5.2", "Invalid Basic Self-Issued Old With New Test2", 23 }, - %%{ "4.5.3", "Valid Basic Self-Issued New With Old Test3", ok}, - %%{ "4.5.4", "Valid Basic Self-Issued New With Old Test4", ok}, - { "4.5.5", "Invalid Basic Self-Issued New With Old Test5", 23 }, - %%{ "4.5.6", "Valid Basic Self-Issued CRL Signing Key Test6", ok}, - { "4.5.7", "Invalid Basic Self-Issued CRL Signing Key Test7", 23 }, - { "4.5.8", "Invalid Basic Self-Issued CRL Signing Key Test8", {bad_cert,invalid_key_usage} }]. -verifying_basic_constraints() -> - [%%{ "4.6", "Verifying Basic Constraints" }, - { "4.6.1", "Invalid Missing basicConstraints Test1", - {bad_cert, missing_basic_constraint} }, - { "4.6.2", "Invalid cA False Test2", {bad_cert, missing_basic_constraint}}, - { "4.6.3", "Invalid cA False Test3", {bad_cert, missing_basic_constraint}}, - { "4.6.4", "Valid basicConstraints Not Critical Test4", ok}, - { "4.6.5", "Invalid pathLenConstraint Test5", {bad_cert, max_path_length_reached}}, - { "4.6.6", "Invalid pathLenConstraint Test6", {bad_cert, max_path_length_reached}}, - { "4.6.7", "Valid pathLenConstraint Test7", ok}, - { "4.6.8", "Valid pathLenConstraint Test8", ok}, - { "4.6.9", "Invalid pathLenConstraint Test9", {bad_cert, max_path_length_reached}}, - { "4.6.10", "Invalid pathLenConstraint Test10", {bad_cert, max_path_length_reached}}, - { "4.6.11", "Invalid pathLenConstraint Test11", {bad_cert, max_path_length_reached}}, - { "4.6.12", "Invalid pathLenConstraint Test12", {bad_cert, max_path_length_reached}}, - { "4.6.13", "Valid pathLenConstraint Test13", ok}, - { "4.6.14", "Valid pathLenConstraint Test14", ok}, - { "4.6.15", "Valid Self-Issued pathLenConstraint Test15", ok}, - { "4.6.16", "Invalid Self-Issued pathLenConstraint Test16", {bad_cert, max_path_length_reached}}, - { "4.6.17", "Valid Self-Issued pathLenConstraint Test17", ok}]. -key_usage() -> - %%{ "4.7", "Key Usage" }, - [{ "4.7.1", "Invalid keyUsage Critical keyCertSign False Test1", {bad_cert,invalid_key_usage} }, - { "4.7.2", "Invalid keyUsage Not Critical keyCertSign False Test2", {bad_cert,invalid_key_usage} }, - { "4.7.3", "Valid keyUsage Not Critical Test3", ok} - %%,{ "4.7.4", "Invalid keyUsage Critical cRLSign False Test4", 35 } - %%,{ "4.7.5", "Invalid keyUsage Not Critical cRLSign False Test5", 35 } - ]. +error(Format, Args, File0, Line) -> + File = filename:basename(File0), + Pid = group_leader(), + Pid ! {failed, File, Line}, + io:format(Pid, "~s(~p): ERROR"++Format, [File,Line|Args]). + +warning(Format, Args, File0, Line) -> + File = filename:basename(File0), + io:format("~s(~p): Warning "++Format, [File,Line|Args]). %% Certificate policy tests need special handling. They can have several %% sub tests and we need to check the outputs are correct. @@ -425,182 +1340,3 @@ inhibit_any_policy() -> {"4.12.8", "Invalid Self-Issued inhibitAnyPolicy Test8", 43 }, {"4.12.9", "Valid Self-Issued inhibitAnyPolicy Test9", ok}, {"4.12.10", "Invalid Self-Issued inhibitAnyPolicy Test10", 43 }]. - -name_constraints() -> - %%{ "4.13", "Name Constraints" }, - [{ "4.13.1", "Valid DN nameConstraints Test1", ok}, - { "4.13.2", "Invalid DN nameConstraints Test2", {bad_cert, name_not_permitted}}, - { "4.13.3", "Invalid DN nameConstraints Test3", {bad_cert, name_not_permitted}}, - { "4.13.4", "Valid DN nameConstraints Test4", ok}, - { "4.13.5", "Valid DN nameConstraints Test5", ok}, - { "4.13.6", "Valid DN nameConstraints Test6", ok}, - { "4.13.7", "Invalid DN nameConstraints Test7", {bad_cert, name_not_permitted}}, - { "4.13.8", "Invalid DN nameConstraints Test8", {bad_cert, name_not_permitted}}, - { "4.13.9", "Invalid DN nameConstraints Test9", {bad_cert, name_not_permitted}}, - { "4.13.10", "Invalid DN nameConstraints Test10", {bad_cert, name_not_permitted}}, - { "4.13.11", "Valid DN nameConstraints Test11", ok}, - { "4.13.12", "Invalid DN nameConstraints Test12", {bad_cert, name_not_permitted}}, - { "4.13.13", "Invalid DN nameConstraints Test13", {bad_cert, name_not_permitted}}, - { "4.13.14", "Valid DN nameConstraints Test14", ok}, - { "4.13.15", "Invalid DN nameConstraints Test15", {bad_cert, name_not_permitted}}, - { "4.13.16", "Invalid DN nameConstraints Test16", {bad_cert, name_not_permitted}}, - { "4.13.17", "Invalid DN nameConstraints Test17", {bad_cert, name_not_permitted}}, - { "4.13.18", "Valid DN nameConstraints Test18", ok}, - { "4.13.19", "Valid Self-Issued DN nameConstraints Test19", ok}, - { "4.13.20", "Invalid Self-Issued DN nameConstraints Test20", {bad_cert, name_not_permitted} }, - { "4.13.21", "Valid RFC822 nameConstraints Test21", ok}, - { "4.13.22", "Invalid RFC822 nameConstraints Test22", {bad_cert, name_not_permitted} }, - { "4.13.23", "Valid RFC822 nameConstraints Test23", ok}, - { "4.13.24", "Invalid RFC822 nameConstraints Test24", {bad_cert, name_not_permitted} }, - { "4.13.25", "Valid RFC822 nameConstraints Test25", ok}, - { "4.13.26", "Invalid RFC822 nameConstraints Test26", {bad_cert, name_not_permitted}}, - { "4.13.27", "Valid DN and RFC822 nameConstraints Test27", ok}, - { "4.13.28", "Invalid DN and RFC822 nameConstraints Test28", {bad_cert, name_not_permitted} }, - { "4.13.29", "Invalid DN and RFC822 nameConstraints Test29", {bad_cert, name_not_permitted} }, - { "4.13.30", "Valid DNS nameConstraints Test30", ok}, - { "4.13.31", "Invalid DNS nameConstraints Test31", {bad_cert, name_not_permitted} }, - { "4.13.32", "Valid DNS nameConstraints Test32", ok}, - { "4.13.33", "Invalid DNS nameConstraints Test33", {bad_cert, name_not_permitted}}, - { "4.13.34", "Valid URI nameConstraints Test34", ok}, - { "4.13.35", "Invalid URI nameConstraints Test35", {bad_cert, name_not_permitted} }, - { "4.13.36", "Valid URI nameConstraints Test36", ok}, - { "4.13.37", "Invalid URI nameConstraints Test37", {bad_cert, name_not_permitted}}, - { "4.13.38", "Invalid DNS nameConstraints Test38", {bad_cert, name_not_permitted} }]. -distribution_points() -> - %%{ "4.14", "Distribution Points" }, - [{ "4.14.1", "Valid distributionPoint Test1", ok}, - { "4.14.2", "Invalid distributionPoint Test2", 23 }, - { "4.14.3", "Invalid distributionPoint Test3", 44 }, - { "4.14.4", "Valid distributionPoint Test4", ok}, - { "4.14.5", "Valid distributionPoint Test5", ok}, - { "4.14.6", "Invalid distributionPoint Test6", 23 }, - { "4.14.7", "Valid distributionPoint Test7", ok}, - { "4.14.8", "Invalid distributionPoint Test8", 44 }, - { "4.14.9", "Invalid distributionPoint Test9", 44 }, - { "4.14.10", "Valid No issuingDistributionPoint Test10", ok}, - { "4.14.11", "Invalid onlyContainsUserCerts CRL Test11", 44 }, - { "4.14.12", "Invalid onlyContainsCACerts CRL Test12", 44 }, - { "4.14.13", "Valid onlyContainsCACerts CRL Test13", ok}, - { "4.14.14", "Invalid onlyContainsAttributeCerts Test14", 44 }, - { "4.14.15", "Invalid onlySomeReasons Test15", 23 }, - { "4.14.16", "Invalid onlySomeReasons Test16", 23 }, - { "4.14.17", "Invalid onlySomeReasons Test17", 3 }, - { "4.14.18", "Valid onlySomeReasons Test18", ok}, - { "4.14.19", "Valid onlySomeReasons Test19", ok}, - { "4.14.20", "Invalid onlySomeReasons Test20", 23 }, - { "4.14.21", "Invalid onlySomeReasons Test21", 23 }, - { "4.14.22", "Valid IDP with indirectCRL Test22", ok}, - { "4.14.23", "Invalid IDP with indirectCRL Test23", 23 }, - { "4.14.24", "Valid IDP with indirectCRL Test24", ok}, - { "4.14.25", "Valid IDP with indirectCRL Test25", ok}, - { "4.14.26", "Invalid IDP with indirectCRL Test26", 44 }, - { "4.14.27", "Invalid cRLIssuer Test27", 3 }, - { "4.14.28", "Valid cRLIssuer Test28", ok}, - { "4.14.29", "Valid cRLIssuer Test29", ok}, - - %% Although this test is valid it has a circular dependency. As a result - %% an attempt is made to reursively checks a CRL path and rejected due to - %% a CRL path validation error. PKITS notes suggest this test does not - %% need to be run due to this issue. - { "4.14.30", "Valid cRLIssuer Test30", 54 }, - { "4.14.31", "Invalid cRLIssuer Test31", 23 }, - { "4.14.32", "Invalid cRLIssuer Test32", 23 }, - { "4.14.33", "Valid cRLIssuer Test33", ok}, - { "4.14.34", "Invalid cRLIssuer Test34", 23 }, - { "4.14.35", "Invalid cRLIssuer Test35", 44 }]. -delta_crls() -> - %%{ "4.15", "Delta-CRLs" }, - [{ "4.15.1", "Invalid deltaCRLIndicator No Base Test1", 3 }, - { "4.15.2", "Valid delta-CRL Test2", ok}, - { "4.15.3", "Invalid delta-CRL Test3", 23 }, - { "4.15.4", "Invalid delta-CRL Test4", 23 }, - { "4.15.5", "Valid delta-CRL Test5", ok}, - { "4.15.6", "Invalid delta-CRL Test6", 23 }, - { "4.15.7", "Valid delta-CRL Test7", ok}, - { "4.15.8", "Valid delta-CRL Test8", ok}, - { "4.15.9", "Invalid delta-CRL Test9", 23 }, - { "4.15.10", "Invalid delta-CRL Test10", 12 }]. -private_certificate_extensions() -> - %%{ "4.16", "Private Certificate Extensions" }, - [{ "4.16.1", "Valid Unknown Not Critical Certificate Extension Test1", ok}, - { "4.16.2", "Invalid Unknown Critical Certificate Extension Test2", - {bad_cert,unknown_critical_extension}}]. - - -convert() -> - Tests = [signature_verification(), - validity_periods(), - verifying_name_chaining(), - basic_certificate_revocation_tests(), - verifying_paths_with_self_issued_certificates(), - verifying_basic_constraints(), - key_usage(), - certificate_policies(), - require_explicit_policy(), - policy_mappings(), - inhibit_policy_mapping(), - inhibit_any_policy(), - name_constraints(), - distribution_points(), - delta_crls(), - private_certificate_extensions()], - [convert(Test) || Test <- lists:flatten(Tests)]. - -convert({_,Test,_}) -> - convert1(Test); -convert({_,Test,_,_,_,_,_}) -> - convert1(Test). - -convert1(Test) -> - FName = lists:append(string:tokens(Test, " -")), - File = filename:join(?MIME, "Signed" ++ FName ++ ".eml"), - io:format("Convert ~p~n",[File]), - {ok, Mail} = file:read_file(File), - Base64 = skip_lines(Mail), - %%io:format("~s",[Base64]), - Tmp = base64:mime_decode(Base64), - file:write_file("pkits/smime-pem/tmp-pkcs7.der", Tmp), - Cmd = "openssl pkcs7 -inform der -in pkits/smime-pem/tmp-pkcs7.der" - " -print_certs -out pkits/smime-pem/" ++ FName ++ ".pem", - case os:cmd(Cmd) of - "" -> ok; - Err -> - io:format("~s",[Err]), - erlang:error(bad_cmd) - end. - -skip_lines(<<"\r\n\r\n", Rest/binary>>) -> Rest; -skip_lines(<<"\n\n", Rest/binary>>) -> Rest; -skip_lines(<<_:8, Rest/binary>>) -> - skip_lines(Rest). - -init_per_testcase(_Func, Config) -> - Datadir = proplists:get_value(data_dir, Config), - put(datadir, Datadir), - Config. - -end_per_testcase(_Func, Config) -> - %% Nodes = select_nodes(all, Config, ?FILE, ?LINE), - %% rpc:multicall(Nodes, mnesia, lkill, []), - Config. - -init_per_suite(Config) -> - try crypto:start() of - ok -> - Config - catch _:_ -> - {skip, "Crypto did not start"} - end. - -end_per_suite(_Config) -> - application:stop(crypto). - -error(Format, Args, File0, Line) -> - File = filename:basename(File0), - Pid = group_leader(), - Pid ! {failed, File, Line}, - io:format(Pid, "~s(~p): ERROR"++Format, [File,Line|Args]). - -warning(Format, Args, File0, Line) -> - File = filename:basename(File0), - io:format("~s(~p): Warning "++Format, [File,Line|Args]). diff --git a/lib/public_key/test/public_key_SUITE.erl b/lib/public_key/test/public_key_SUITE.erl index 6c482f9c30..b11e4d092a 100644 --- a/lib/public_key/test/public_key_SUITE.erl +++ b/lib/public_key/test/public_key_SUITE.erl @@ -102,11 +102,23 @@ end_per_testcase(_TestCase, Config) -> suite() -> [{ct_hooks,[ts_install_cth]}]. all() -> - [app, pk_decode_encode, encrypt_decrypt, sign_verify, + [app, + {group, pem_decode_encode}, + {group, ssh_public_key_decode_encode}, + encrypt_decrypt, + {group, sign_verify}, pkix, pkix_path_validation, deprecated]. groups() -> - []. + [{pem_decode_encode, [], [dsa_pem, rsa_pem, encrypted_pem, + dh_pem, cert_pem]}, + {ssh_public_key_decode_encode, [], + [ssh_rsa_public_key, ssh_dsa_public_key, ssh_rfc4716_rsa_comment, + ssh_rfc4716_dsa_comment, ssh_rfc4716_rsa_subject, ssh_known_hosts, + ssh_auth_keys, ssh1_known_hosts, ssh1_auth_keys, ssh_openssh_public_key_with_comment, + ssh_openssh_public_key_long_header]}, + {sign_verify, [], [rsa_sign_verify, dsa_sign_verify]} + ]. init_per_group(_GroupName, Config) -> Config. @@ -125,22 +137,20 @@ app(suite) -> app(Config) when is_list(Config) -> ok = test_server:app_test(public_key). -pk_decode_encode(doc) -> - ["Tests pem_decode/1, pem_encode/1, " - "der_decode/2, der_encode/2, " - "pem_entry_decode/1, pem_entry_decode/2," - "pem_entry_encode/2, pem_entry_encode/3."]; +%%-------------------------------------------------------------------- -pk_decode_encode(suite) -> +dsa_pem(doc) -> + [""]; +dsa_pem(suite) -> []; -pk_decode_encode(Config) when is_list(Config) -> +dsa_pem(Config) when is_list(Config) -> Datadir = ?config(data_dir, Config), - [{'DSAPrivateKey', DerDSAKey, not_encrypted} = Entry0 ] = - erl_make_certs:pem_to_der(filename:join(Datadir, "dsa.pem")), - + [{'DSAPrivateKey', DerDSAKey, not_encrypted} = Entry0 ] = + erl_make_certs:pem_to_der(filename:join(Datadir, "dsa.pem")), + DSAKey = public_key:der_decode('DSAPrivateKey', DerDSAKey), - + DSAKey = public_key:pem_entry_decode(Entry0), {ok, DSAPubPem} = file:read_file(filename:join(Datadir, "dsa_pub.pem")), @@ -150,74 +160,107 @@ pk_decode_encode(Config) when is_list(Config) -> true = check_entry_type(DSAPubKey, 'DSAPublicKey'), PubEntry0 = public_key:pem_entry_encode('SubjectPublicKeyInfo', DSAPubKey), DSAPubPemNoEndNewLines = strip_ending_newlines(DSAPubPem), - DSAPubPemEndNoNewLines = strip_ending_newlines(public_key:pem_encode([PubEntry0])), - - [{'RSAPrivateKey', DerRSAKey, not_encrypted} = Entry1 ] = + DSAPubPemNoEndNewLines = strip_ending_newlines(public_key:pem_encode([PubEntry0])). + +%%-------------------------------------------------------------------- + +rsa_pem(doc) -> + [""]; +rsa_pem(suite) -> + []; +rsa_pem(Config) when is_list(Config) -> + Datadir = ?config(data_dir, Config), + [{'RSAPrivateKey', DerRSAKey, not_encrypted} = Entry0 ] = erl_make_certs:pem_to_der(filename:join(Datadir, "client_key.pem")), - + RSAKey0 = public_key:der_decode('RSAPrivateKey', DerRSAKey), + + RSAKey0 = public_key:pem_entry_decode(Entry0), - RSAKey0 = public_key:pem_entry_decode(Entry1), - - [{'RSAPrivateKey', _, {_,_}} = Entry2] = + [{'RSAPrivateKey', _, {_,_}} = Entry1] = erl_make_certs:pem_to_der(filename:join(Datadir, "rsa.pem")), - - true = check_entry_type(public_key:pem_entry_decode(Entry2, "abcd1234"), + + true = check_entry_type(public_key:pem_entry_decode(Entry1, "abcd1234"), 'RSAPrivateKey'), {ok, RSAPubPem} = file:read_file(filename:join(Datadir, "rsa_pub.pem")), - [{'SubjectPublicKeyInfo', _, _} = PubEntry1] = + [{'SubjectPublicKeyInfo', _, _} = PubEntry0] = public_key:pem_decode(RSAPubPem), - RSAPubKey = public_key:pem_entry_decode(PubEntry1), + RSAPubKey = public_key:pem_entry_decode(PubEntry0), true = check_entry_type(RSAPubKey, 'RSAPublicKey'), - PubEntry1 = public_key:pem_entry_encode('SubjectPublicKeyInfo', RSAPubKey), + PubEntry0 = public_key:pem_entry_encode('SubjectPublicKeyInfo', RSAPubKey), RSAPubPemNoEndNewLines = strip_ending_newlines(RSAPubPem), - RSAPubPemNoEndNewLines = strip_ending_newlines(public_key:pem_encode([PubEntry1])), + RSAPubPemNoEndNewLines = strip_ending_newlines(public_key:pem_encode([PubEntry0])), {ok, RSARawPem} = file:read_file(filename:join(Datadir, "rsa_pub_key.pem")), - [{'RSAPublicKey', _, _} = PubEntry2] = + [{'RSAPublicKey', _, _} = PubEntry1] = public_key:pem_decode(RSARawPem), - RSAPubKey = public_key:pem_entry_decode(PubEntry2), + RSAPubKey = public_key:pem_entry_decode(PubEntry1), RSARawPemNoEndNewLines = strip_ending_newlines(RSARawPem), - RSARawPemNoEndNewLines = strip_ending_newlines(public_key:pem_encode([PubEntry2])), + RSARawPemNoEndNewLines = strip_ending_newlines(public_key:pem_encode([PubEntry1])). + +%%-------------------------------------------------------------------- + +encrypted_pem(doc) -> + [""]; +encrypted_pem(suite) -> + []; +encrypted_pem(Config) when is_list(Config) -> + Datadir = ?config(data_dir, Config), + + [{'RSAPrivateKey', DerRSAKey, not_encrypted}] = + erl_make_certs:pem_to_der(filename:join(Datadir, "client_key.pem")), + + RSAKey = public_key:der_decode('RSAPrivateKey', DerRSAKey), Salt0 = crypto:rand_bytes(8), - Entry3 = public_key:pem_entry_encode('RSAPrivateKey', RSAKey0, + Entry0 = public_key:pem_entry_encode('RSAPrivateKey', RSAKey, {{"DES-EDE3-CBC", Salt0}, "1234abcd"}), - - RSAKey0 = public_key:pem_entry_decode(Entry3,"1234abcd"), - + RSAKey = public_key:pem_entry_decode(Entry0,"1234abcd"), Des3KeyFile = filename:join(Datadir, "des3_client_key.pem"), + erl_make_certs:der_to_pem(Des3KeyFile, [Entry0]), + [{'RSAPrivateKey', _, {"DES-EDE3-CBC", Salt0}}] = + erl_make_certs:pem_to_der(Des3KeyFile), - erl_make_certs:der_to_pem(Des3KeyFile, [Entry3]), - - [{'RSAPrivateKey', _, {"DES-EDE3-CBC", Salt0}}] = erl_make_certs:pem_to_der(Des3KeyFile), - Salt1 = crypto:rand_bytes(8), - Entry4 = public_key:pem_entry_encode('RSAPrivateKey', RSAKey0, + Entry1 = public_key:pem_entry_encode('RSAPrivateKey', RSAKey, {{"DES-CBC", Salt1}, "4567efgh"}), - - DesKeyFile = filename:join(Datadir, "des_client_key.pem"), + erl_make_certs:der_to_pem(DesKeyFile, [Entry1]), + [{'RSAPrivateKey', _, {"DES-CBC", Salt1}} =Entry2] = + erl_make_certs:pem_to_der(DesKeyFile), + true = check_entry_type(public_key:pem_entry_decode(Entry2, "4567efgh"), + 'RSAPrivateKey'). - erl_make_certs:der_to_pem(DesKeyFile, [Entry4]), - - [{'RSAPrivateKey', _, {"DES-CBC", Salt1}} =Entry5] = erl_make_certs:pem_to_der(DesKeyFile), - - - true = check_entry_type(public_key:pem_entry_decode(Entry5, "4567efgh"), - 'RSAPrivateKey'), +%%-------------------------------------------------------------------- - [{'DHParameter', DerDH, not_encrypted} = Entry6] = +dh_pem(doc) -> + [""]; +dh_pem(suite) -> + []; +dh_pem(Config) when is_list(Config) -> + Datadir = ?config(data_dir, Config), + [{'DHParameter', DerDH, not_encrypted} = Entry] = erl_make_certs:pem_to_der(filename:join(Datadir, "dh.pem")), - - erl_make_certs:der_to_pem(filename:join(Datadir, "new_dh.pem"), [Entry6]), + + erl_make_certs:der_to_pem(filename:join(Datadir, "new_dh.pem"), [Entry]), DHParameter = public_key:der_decode('DHParameter', DerDH), - DHParameter = public_key:pem_entry_decode(Entry6), + DHParameter = public_key:pem_entry_decode(Entry), - Entry6 = public_key:pem_entry_encode('DHParameter', DHParameter), + Entry = public_key:pem_entry_encode('DHParameter', DHParameter). +%%-------------------------------------------------------------------- +cert_pem(doc) -> + [""]; +cert_pem(suite) -> + []; +cert_pem(Config) when is_list(Config) -> + Datadir = ?config(data_dir, Config), + + [Entry0] = + erl_make_certs:pem_to_der(filename:join(Datadir, "dsa.pem")), + [{'Certificate', DerCert, not_encrypted} = Entry7] = erl_make_certs:pem_to_der(filename:join(Datadir, "client_cert.pem")), @@ -227,15 +270,232 @@ pk_decode_encode(Config) when is_list(Config) -> CertEntries = [{'Certificate', _, not_encrypted} = CertEntry0, {'Certificate', _, not_encrypted} = CertEntry1] = erl_make_certs:pem_to_der(filename:join(Datadir, "cacerts.pem")), - + ok = erl_make_certs:der_to_pem(filename:join(Datadir, "wcacerts.pem"), CertEntries), ok = erl_make_certs:der_to_pem(filename:join(Datadir, "wdsa.pem"), [Entry0]), NewCertEntries = erl_make_certs:pem_to_der(filename:join(Datadir, "wcacerts.pem")), true = lists:member(CertEntry0, NewCertEntries), true = lists:member(CertEntry1, NewCertEntries), - [Entry0] = erl_make_certs:pem_to_der(filename:join(Datadir, "wdsa.pem")), - ok. + [Entry0] = erl_make_certs:pem_to_der(filename:join(Datadir, "wdsa.pem")). + +%%-------------------------------------------------------------------- +ssh_rsa_public_key(doc) -> + ""; +ssh_rsa_public_key(suite) -> + []; +ssh_rsa_public_key(Config) when is_list(Config) -> + Datadir = ?config(data_dir, Config), + + {ok, RSARawSsh2} = file:read_file(filename:join(Datadir, "ssh2_rsa_pub")), + [{PubKey, Attributes1}] = public_key:ssh_decode(RSARawSsh2, public_key), + [{PubKey, Attributes1}] = public_key:ssh_decode(RSARawSsh2, rfc4716_public_key), + + {ok, RSARawOpenSsh} = file:read_file(filename:join(Datadir, "openssh_rsa_pub")), + [{PubKey, Attributes2}] = public_key:ssh_decode(RSARawOpenSsh, public_key), + [{PubKey, Attributes2}] = public_key:ssh_decode(RSARawOpenSsh, openssh_public_key), + + %% Can not check EncodedSSh == RSARawSsh2 and EncodedOpenSsh + %% = RSARawOpenSsh as line breakpoints may differ + + EncodedSSh = public_key:ssh_encode([{PubKey, Attributes1}], rfc4716_public_key), + EncodedOpenSsh = public_key:ssh_encode([{PubKey, Attributes2}], openssh_public_key), + + [{PubKey, Attributes1}] = + public_key:ssh_decode(EncodedSSh, public_key), + [{PubKey, Attributes2}] = + public_key:ssh_decode(EncodedOpenSsh, public_key). + +%%-------------------------------------------------------------------- + +ssh_dsa_public_key(doc) -> + ""; +ssh_dsa_public_key(suite) -> + []; +ssh_dsa_public_key(Config) when is_list(Config) -> + Datadir = ?config(data_dir, Config), + + {ok, DSARawSsh2} = file:read_file(filename:join(Datadir, "ssh2_dsa_pub")), + [{PubKey, Attributes1}] = public_key:ssh_decode(DSARawSsh2, public_key), + [{PubKey, Attributes1}] = public_key:ssh_decode(DSARawSsh2, rfc4716_public_key), + + {ok, DSARawOpenSsh} = file:read_file(filename:join(Datadir, "openssh_dsa_pub")), + [{PubKey, Attributes2}] = public_key:ssh_decode(DSARawOpenSsh, public_key), + [{PubKey, Attributes2}] = public_key:ssh_decode(DSARawOpenSsh, openssh_public_key), + + %% Can not check EncodedSSh == DSARawSsh2 and EncodedOpenSsh + %% = DSARawOpenSsh as line breakpoints may differ + + EncodedSSh = public_key:ssh_encode([{PubKey, Attributes1}], rfc4716_public_key), + EncodedOpenSsh = public_key:ssh_encode([{PubKey, Attributes2}], openssh_public_key), + + [{PubKey, Attributes1}] = + public_key:ssh_decode(EncodedSSh, public_key), + [{PubKey, Attributes2}] = + public_key:ssh_decode(EncodedOpenSsh, public_key). + +%%-------------------------------------------------------------------- +ssh_rfc4716_rsa_comment(doc) -> + "Test comment header and rsa key"; +ssh_rfc4716_rsa_comment(suite) -> + []; +ssh_rfc4716_rsa_comment(Config) when is_list(Config) -> + Datadir = ?config(data_dir, Config), + + {ok, RSARawSsh2} = file:read_file(filename:join(Datadir, "ssh2_rsa_comment_pub")), + [{#'RSAPublicKey'{} = PubKey, Attributes}] = + public_key:ssh_decode(RSARawSsh2, public_key), + + Headers = proplists:get_value(headers, Attributes), + + Value = proplists:get_value("Comment", Headers, undefined), + true = Value =/= undefined, + RSARawSsh2 = public_key:ssh_encode([{PubKey, Attributes}], rfc4716_public_key). + +%%-------------------------------------------------------------------- +ssh_rfc4716_dsa_comment(doc) -> + "Test comment header and dsa key"; +ssh_rfc4716_dsa_comment(suite) -> + []; +ssh_rfc4716_dsa_comment(Config) when is_list(Config) -> + Datadir = ?config(data_dir, Config), + + {ok, DSARawSsh2} = file:read_file(filename:join(Datadir, "ssh2_dsa_comment_pub")), + [{{_, #'Dss-Parms'{}} = PubKey, Attributes}] = + public_key:ssh_decode(DSARawSsh2, public_key), + + Headers = proplists:get_value(headers, Attributes), + + Value = proplists:get_value("Comment", Headers, undefined), + true = Value =/= undefined, + + %% Can not check Encoded == DSARawSsh2 as line continuation breakpoints may differ + Encoded = public_key:ssh_encode([{PubKey, Attributes}], rfc4716_public_key), + [{PubKey, Attributes}] = + public_key:ssh_decode(Encoded, public_key). + +%%-------------------------------------------------------------------- +ssh_rfc4716_rsa_subject(doc) -> + "Test another header value than comment"; +ssh_rfc4716_rsa_subject(suite) -> + []; +ssh_rfc4716_rsa_subject(Config) when is_list(Config) -> + Datadir = ?config(data_dir, Config), + + {ok, RSARawSsh2} = file:read_file(filename:join(Datadir, "ssh2_subject_pub")), + [{#'RSAPublicKey'{} = PubKey, Attributes}] = + public_key:ssh_decode(RSARawSsh2, public_key), + + Headers = proplists:get_value(headers, Attributes), + + Value = proplists:get_value("Subject", Headers, undefined), + true = Value =/= undefined, + + %% Can not check Encoded == RSARawSsh2 as line continuation breakpoints may differ + Encoded = public_key:ssh_encode([{PubKey, Attributes}], rfc4716_public_key), + [{PubKey, Attributes}] = + public_key:ssh_decode(Encoded, public_key). + +%%-------------------------------------------------------------------- +ssh_known_hosts(doc) -> + ""; +ssh_known_hosts(suite) -> + []; +ssh_known_hosts(Config) when is_list(Config) -> + Datadir = ?config(data_dir, Config), + + {ok, SshKnownHosts} = file:read_file(filename:join(Datadir, "known_hosts")), + [{#'RSAPublicKey'{}, Attributes1}, {#'RSAPublicKey'{}, Attributes2}] = Decoded = + public_key:ssh_decode(SshKnownHosts, known_hosts), + + Value1 = proplists:get_value(hostnames, Attributes1, undefined), + Value2 = proplists:get_value(hostnames, Attributes2, undefined), + true = (Value1 =/= undefined) and (Value2 =/= undefined), + + Encoded = public_key:ssh_encode(Decoded, known_hosts), + Decoded = public_key:ssh_decode(Encoded, known_hosts). + +%%-------------------------------------------------------------------- + +ssh1_known_hosts(doc) -> + ""; +ssh1_known_hosts(suite) -> + []; +ssh1_known_hosts(Config) when is_list(Config) -> + Datadir = ?config(data_dir, Config), + + {ok, SshKnownHosts} = file:read_file(filename:join(Datadir, "ssh1_known_hosts")), + [{#'RSAPublicKey'{}, Attributes1}, {#'RSAPublicKey'{}, Attributes2}] = Decoded = + public_key:ssh_decode(SshKnownHosts, known_hosts), + + Value1 = proplists:get_value(hostnames, Attributes1, undefined), + Value2 = proplists:get_value(hostnames, Attributes2, undefined), + true = (Value1 =/= undefined) and (Value2 =/= undefined), + + Encoded = public_key:ssh_encode(Decoded, known_hosts), + Decoded = public_key:ssh_decode(Encoded, known_hosts). + +%%-------------------------------------------------------------------- +ssh_auth_keys(doc) -> + ""; +ssh_auth_keys(suite) -> + []; +ssh_auth_keys(Config) when is_list(Config) -> + Datadir = ?config(data_dir, Config), + + {ok, SshAuthKeys} = file:read_file(filename:join(Datadir, "auth_keys")), + [{#'RSAPublicKey'{}, Attributes1}, {{_, #'Dss-Parms'{}}, _Attributes2}] = Decoded = + public_key:ssh_decode(SshAuthKeys, auth_keys), + + Value1 = proplists:get_value(options, Attributes1, undefined), + true = Value1 =/= undefined, + + Encoded = public_key:ssh_encode(Decoded, auth_keys), + Decoded = public_key:ssh_decode(Encoded, auth_keys). + +%%-------------------------------------------------------------------- +ssh1_auth_keys(doc) -> + ""; +ssh1_auth_keys(suite) -> + []; +ssh1_auth_keys(Config) when is_list(Config) -> + Datadir = ?config(data_dir, Config), + + {ok, SshAuthKeys} = file:read_file(filename:join(Datadir, "ssh1_auth_keys")), + [{#'RSAPublicKey'{}, Attributes1}, {#'RSAPublicKey'{}, Attributes2}] = Decoded = + public_key:ssh_decode(SshAuthKeys, auth_keys), + + Value1 = proplists:get_value(bits, Attributes1, undefined), + Value2 = proplists:get_value(bits, Attributes2, undefined), + true = (Value1 =/= undefined) and (Value2 =/= undefined), + + Encoded = public_key:ssh_encode(Decoded, auth_keys), + Decoded = public_key:ssh_decode(Encoded, auth_keys). + +%%-------------------------------------------------------------------- +ssh_openssh_public_key_with_comment(doc) -> + "Test that emty lines and lines starting with # are ignored"; +ssh_openssh_public_key_with_comment(suite) -> + []; +ssh_openssh_public_key_with_comment(Config) when is_list(Config) -> + Datadir = ?config(data_dir, Config), + + {ok, DSARawOpenSsh} = file:read_file(filename:join(Datadir, "openssh_dsa_with_comment_pub")), + [{{_, #'Dss-Parms'{}}, _}] = public_key:ssh_decode(DSARawOpenSsh, openssh_public_key). + +%%-------------------------------------------------------------------- +ssh_openssh_public_key_long_header(doc) -> + "Test that long headers are handled"; +ssh_openssh_public_key_long_header(suite) -> + []; +ssh_openssh_public_key_long_header(Config) when is_list(Config) -> + Datadir = ?config(data_dir, Config), + + {ok,RSARawOpenSsh} = file:read_file(filename:join(Datadir, "ssh_rsa_long_header_pub")), + [{#'RSAPublicKey'{}, _}] = Decoded = public_key:ssh_decode(RSARawOpenSsh, public_key), + + Encoded = public_key:ssh_encode(Decoded, rfc4716_public_key), + Decoded = public_key:ssh_decode(Encoded, rfc4716_public_key). %%-------------------------------------------------------------------- encrypt_decrypt(doc) -> @@ -258,44 +518,49 @@ encrypt_decrypt(Config) when is_list(Config) -> ok. %%-------------------------------------------------------------------- -sign_verify(doc) -> - ["Checks that we can sign and verify signatures."]; -sign_verify(suite) -> +rsa_sign_verify(doc) -> + ["Checks that we can sign and verify rsa signatures."]; +rsa_sign_verify(suite) -> []; -sign_verify(Config) when is_list(Config) -> - %% Make cert signs and validates the signature using RSA and DSA +rsa_sign_verify(Config) when is_list(Config) -> Ca = {_, CaKey} = erl_make_certs:make_cert([]), + {Cert1, _} = erl_make_certs:make_cert([{key, dsa}, {issuer, Ca}]), PrivateRSA = #'RSAPrivateKey'{modulus=Mod, publicExponent=Exp} = public_key:pem_entry_decode(CaKey), - - CertInfo = {Cert1,CertKey1} = erl_make_certs:make_cert([{key, dsa}, {issuer, Ca}]), - PublicRSA = #'RSAPublicKey'{modulus=Mod, publicExponent=Exp}, true = public_key:pkix_verify(Cert1, PublicRSA), - {Cert2,_CertKey} = erl_make_certs:make_cert([{issuer, CertInfo}]), - - #'DSAPrivateKey'{p=P, q=Q, g=G, y=Y, x=_X} = - public_key:pem_entry_decode(CertKey1), - true = public_key:pkix_verify(Cert2, {Y, #'Dss-Parms'{p=P, q=Q, g=G}}), - - %% RSA sign Msg = list_to_binary(lists:duplicate(5, "Foo bar 100")), - RSASign = public_key:sign(Msg, sha, PrivateRSA), true = public_key:verify(Msg, sha, RSASign, PublicRSA), false = public_key:verify(<<1:8, Msg/binary>>, sha, RSASign, PublicRSA), false = public_key:verify(Msg, sha, <<1:8, RSASign/binary>>, PublicRSA), RSASign1 = public_key:sign(Msg, md5, PrivateRSA), - true = public_key:verify(Msg, md5, RSASign1, PublicRSA), + true = public_key:verify(Msg, md5, RSASign1, PublicRSA). - %% DSA sign +%%-------------------------------------------------------------------- + +dsa_sign_verify(doc) -> + ["Checks that we can sign and verify dsa signatures."]; +dsa_sign_verify(suite) -> + []; +dsa_sign_verify(Config) when is_list(Config) -> + Ca = erl_make_certs:make_cert([]), + CertInfo = {_,CertKey1} = erl_make_certs:make_cert([{key, dsa}, {issuer, Ca}]), + {Cert2,_CertKey} = erl_make_certs:make_cert([{issuer, CertInfo}]), + + #'DSAPrivateKey'{p=P, q=Q, g=G, y=Y, x=_X} = + public_key:pem_entry_decode(CertKey1), + true = public_key:pkix_verify(Cert2, {Y, #'Dss-Parms'{p=P, q=Q, g=G}}), + Datadir = ?config(data_dir, Config), [DsaKey = {'DSAPrivateKey', _, _}] = erl_make_certs:pem_to_der(filename:join(Datadir, "dsa.pem")), DSAPrivateKey = public_key:pem_entry_decode(DsaKey), #'DSAPrivateKey'{p=P1, q=Q1, g=G1, y=Y1, x=_X1} = DSAPrivateKey, + + Msg = list_to_binary(lists:duplicate(5, "Foo bar 100")), DSASign = public_key:sign(Msg, sha, DSAPrivateKey), DSAPublicKey = Y1, DSAParams = #'Dss-Parms'{p=P1, q=Q1, g=G1}, @@ -312,9 +577,8 @@ sign_verify(Config) when is_list(Config) -> false = public_key:verify(<<1:8, RestDigest/binary>>, none, DigestSign, {DSAPublicKey, DSAParams}), false = public_key:verify(Digest, none, <<1:8, DigestSign/binary>>, - {DSAPublicKey, DSAParams}), - - ok. + {DSAPublicKey, DSAParams}). + %%-------------------------------------------------------------------- pkix(doc) -> "Misc pkix tests not covered elsewhere"; diff --git a/lib/public_key/test/public_key_SUITE_data/auth_keys b/lib/public_key/test/public_key_SUITE_data/auth_keys new file mode 100644 index 0000000000..0c4b47edde --- /dev/null +++ b/lib/public_key/test/public_key_SUITE_data/auth_keys @@ -0,0 +1,3 @@ +command="dump /home",no-pty,no-port-forwarding ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAgEAwrr66r8n6B8Y0zMF3dOpXEapIQD9DiYQ6D6/zwor9o39jSkHNiMMER/GETBbzP83LOcekm02aRjo55ArO7gPPVvCXbrirJu9pkm4AC4BBre5xSLS7soyzwbigFruM8G63jSXqpHqJ/ooi168sKMC2b0Ncsi+JlTfNYlDXJVLKEeZgZOInQyMmtisaDTUQWTIv1snAizf4iIYENuAkGYGNCL77u5Y5VOu5eQipvFajTnps9QvUx/zdSFYn9e2sulWM3Bxc/S4IJ67JWHVRpfJxGi3hinRBH8WQdXuUwdJJTiJHKPyYrrM7Q6Xq4TOMFtcRuLDC6u3BXM1L0gBvHPNOnD5l2Lp5EjUkQ9CBf2j4A4gfH+iWQZyk08esAG/iwArAVxkl368+dkbMWOXL8BN4x5zYgdzoeypQZZ2RKH780MCTSo4WQ19DP8pw+9q3bSFC9H3xYAxrKAJNWjeTUJOTrTe+mWXXU770gYyQTxa2ycnYrlZucn1S3vsvn6eq7NZZ8NRbyv1n15Ocg+nHK4fuKOrwPhU3NbKQwtjb0Wsxx1gAmQqIOLTpAdsrAauPxC7TPYA5qQVCphvimKuhQM/1gMV225JrnjspVlthCzuFYUjXOKC3wxz6FFEtwnXu3uC5bVVkmkNadJmD21gD23yk4BraGXVYpRMIB+X+OTUUI8= dhopson@VMUbuntu-DSH + +ssh-dss AAAAB3NzaC1kc3MAAACBAPY8ZOHY2yFSJA6XYC9HRwNHxaehvx5wOJ0rzZdzoSOXxbETW6ToHv8D1UJ/z+zHo9Fiko5XybZnDIaBDHtblQ+Yp7StxyltHnXF1YLfKD1G4T6JYrdHYI14Om1eg9e4NnCRleaqoZPF3UGfZia6bXrGTQf3gJq2e7Yisk/gF+1VAAAAFQDb8D5cvwHWTZDPfX0D2s9Rd7NBvQAAAIEAlN92+Bb7D4KLYk3IwRbXblwXdkPggA4pfdtW9vGfJ0/RHd+NjB4eo1D+0dix6tXwYGN7PKS5R/FXPNwxHPapcj9uL1Jn2AWQ2dsknf+i/FAAvioUPkmdMc0zuWoSOEsSNhVDtX3WdvVcGcBq9cetzrtOKWOocJmJ80qadxTRHtUAAACBAN7CY+KKv1gHpRzFwdQm7HK9bb1LAo2KwaoXnadFgeptNBQeSXG1vO+JsvphVMBJc9HSn24VYtYtsMu74qXviYjziVucWKjjKEb11juqnF0GDlB3VVmxHLmxnAz643WK42Z7dLM5sY29ouezv4Xz2PuMch5VGPP+CDqzCM4loWgV dhopson@VMUbuntu-DSH diff --git a/lib/public_key/test/public_key_SUITE_data/known_hosts b/lib/public_key/test/public_key_SUITE_data/known_hosts new file mode 100644 index 0000000000..30fc3b1fe8 --- /dev/null +++ b/lib/public_key/test/public_key_SUITE_data/known_hosts @@ -0,0 +1,3 @@ +hostname.domain.com,192.168.0.1 ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAIEA1XY18+zA8VNK2YkzygOkMqUxHSTfxT1Xxx8CgDZgcQH8HUhPssW5ttvG8nKetlPQZAVk1C4WkWS1y5b3ekBhZTIxocp9Joc6V1+f2EOfO2mSLRwB16RGrdw6q7msrBXTC/dl+hF45kMMzVNzqxnSMVOa0sEPK2zK6Sg3Vi9fCSM= + +|1|BWO5qDxk/cFH0wa05JLdHn+j6xQ=|rXQvIxh5cDD3C43k5DPDamawVNA= ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAIEA1XY18+zA8VNK2YkzygOkMqUxHSTfxT1Xxx8CgDZgcQH8HUhPssW5ttvG8nKetlPQZAVk1C4WkWS1y5b3ekBhZTIxocp9Joc6V1+f2EOfO2mSLRwB16RGrdw6q7msrBXTC/dl+hF45kMMzVNzqxnSMVOa0sEPK2zK6Sg3Vi9fCSM= [email protected] diff --git a/lib/public_key/test/public_key_SUITE_data/openssh_dsa_pub b/lib/public_key/test/public_key_SUITE_data/openssh_dsa_pub new file mode 100644 index 0000000000..a765ba8189 --- /dev/null +++ b/lib/public_key/test/public_key_SUITE_data/openssh_dsa_pub @@ -0,0 +1 @@ +ssh-dss AAAAB3NzaC1kc3MAAACBAPY8ZOHY2yFSJA6XYC9HRwNHxaehvx5wOJ0rzZdzoSOXxbETW6ToHv8D1UJ/z+zHo9Fiko5XybZnDIaBDHtblQ+Yp7StxyltHnXF1YLfKD1G4T6JYrdHYI14Om1eg9e4NnCRleaqoZPF3UGfZia6bXrGTQf3gJq2e7Yisk/gF+1VAAAAFQDb8D5cvwHWTZDPfX0D2s9Rd7NBvQAAAIEAlN92+Bb7D4KLYk3IwRbXblwXdkPggA4pfdtW9vGfJ0/RHd+NjB4eo1D+0dix6tXwYGN7PKS5R/FXPNwxHPapcj9uL1Jn2AWQ2dsknf+i/FAAvioUPkmdMc0zuWoSOEsSNhVDtX3WdvVcGcBq9cetzrtOKWOocJmJ80qadxTRHtUAAACBAN7CY+KKv1gHpRzFwdQm7HK9bb1LAo2KwaoXnadFgeptNBQeSXG1vO+JsvphVMBJc9HSn24VYtYtsMu74qXviYjziVucWKjjKEb11juqnF0GDlB3VVmxHLmxnAz643WK42Z7dLM5sY29ouezv4Xz2PuMch5VGPP+CDqzCM4loWgV dhopson@VMUbuntu-DSH diff --git a/lib/public_key/test/public_key_SUITE_data/openssh_dsa_with_comment_pub b/lib/public_key/test/public_key_SUITE_data/openssh_dsa_with_comment_pub new file mode 100644 index 0000000000..d5a34a3f78 --- /dev/null +++ b/lib/public_key/test/public_key_SUITE_data/openssh_dsa_with_comment_pub @@ -0,0 +1,3 @@ +#This should be ignored!! + +ssh-dss AAAAB3NzaC1kc3MAAACBAPY8ZOHY2yFSJA6XYC9HRwNHxaehvx5wOJ0rzZdzoSOXxbETW6ToHv8D1UJ/z+zHo9Fiko5XybZnDIaBDHtblQ+Yp7StxyltHnXF1YLfKD1G4T6JYrdHYI14Om1eg9e4NnCRleaqoZPF3UGfZia6bXrGTQf3gJq2e7Yisk/gF+1VAAAAFQDb8D5cvwHWTZDPfX0D2s9Rd7NBvQAAAIEAlN92+Bb7D4KLYk3IwRbXblwXdkPggA4pfdtW9vGfJ0/RHd+NjB4eo1D+0dix6tXwYGN7PKS5R/FXPNwxHPapcj9uL1Jn2AWQ2dsknf+i/FAAvioUPkmdMc0zuWoSOEsSNhVDtX3WdvVcGcBq9cetzrtOKWOocJmJ80qadxTRHtUAAACBAN7CY+KKv1gHpRzFwdQm7HK9bb1LAo2KwaoXnadFgeptNBQeSXG1vO+JsvphVMBJc9HSn24VYtYtsMu74qXviYjziVucWKjjKEb11juqnF0GDlB3VVmxHLmxnAz643WK42Z7dLM5sY29ouezv4Xz2PuMch5VGPP+CDqzCM4loWgV dhopson@VMUbuntu-DSH diff --git a/lib/public_key/test/public_key_SUITE_data/openssh_rsa_pub b/lib/public_key/test/public_key_SUITE_data/openssh_rsa_pub new file mode 100644 index 0000000000..0a0838db40 --- /dev/null +++ b/lib/public_key/test/public_key_SUITE_data/openssh_rsa_pub @@ -0,0 +1 @@ +ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAgEAwrr66r8n6B8Y0zMF3dOpXEapIQD9DiYQ6D6/zwor9o39jSkHNiMMER/GETBbzP83LOcekm02aRjo55ArO7gPPVvCXbrirJu9pkm4AC4BBre5xSLS7soyzwbigFruM8G63jSXqpHqJ/ooi168sKMC2b0Ncsi+JlTfNYlDXJVLKEeZgZOInQyMmtisaDTUQWTIv1snAizf4iIYENuAkGYGNCL77u5Y5VOu5eQipvFajTnps9QvUx/zdSFYn9e2sulWM3Bxc/S4IJ67JWHVRpfJxGi3hinRBH8WQdXuUwdJJTiJHKPyYrrM7Q6Xq4TOMFtcRuLDC6u3BXM1L0gBvHPNOnD5l2Lp5EjUkQ9CBf2j4A4gfH+iWQZyk08esAG/iwArAVxkl368+dkbMWOXL8BN4x5zYgdzoeypQZZ2RKH780MCTSo4WQ19DP8pw+9q3bSFC9H3xYAxrKAJNWjeTUJOTrTe+mWXXU770gYyQTxa2ycnYrlZucn1S3vsvn6eq7NZZ8NRbyv1n15Ocg+nHK4fuKOrwPhU3NbKQwtjb0Wsxx1gAmQqIOLTpAdsrAauPxC7TPYA5qQVCphvimKuhQM/1gMV225JrnjspVlthCzuFYUjXOKC3wxz6FFEtwnXu3uC5bVVkmkNadJmD21gD23yk4BraGXVYpRMIB+X+OTUUI8= dhopson@VMUbuntu-DSH diff --git a/lib/public_key/test/public_key_SUITE_data/ssh1_auth_keys b/lib/public_key/test/public_key_SUITE_data/ssh1_auth_keys new file mode 100644 index 0000000000..c91f4e4679 --- /dev/null +++ b/lib/public_key/test/public_key_SUITE_data/ssh1_auth_keys @@ -0,0 +1,3 @@ +1024 35 794430685278501116412873221867658581245241426828503388129294124540165981586596106773643485704743298698207838825035605868404742682423919455523383721081589378970796492944950066480951790660582889972423189943567111507801410254720228911513553205592856585541922662924268445466959576882300405064708497308004255650466014242855505233634626075778108365396568863197935915425650388910408127232583533503834009244199384570662092164277923946411149853110048365318587554141774139652307149492021035538341281427025252592933784473453522113124752189378715431529801894015739903371171585194505182320772654217490509848165365152457990491089951560694728469571221819385402117009544812199223715540348068497710535492913376699508575875577554607325905000745578091554027803374110357015655416894607641289462159580964951182385869168785183135763253784745647466464331174922663455073627501620274348748413309761116542324505123795743603781806636788810617169341018091186028310551725315297135354426735951943325476221811539822892501042385411792050504283745898099390893596941969752683246939665141002098430129617772928840718016009187577151479855846883928332010147501182201528575840364152774917950524127063432334646746291719251739989499132767590205934821590545762802261107691663 dhopson@VMUbuntu-DSH + +command="dump /home",no-pty,no-port-forwarding 1024 35 794430685278501116412873221867658581245241426828503388129294124540165981586596106773643485704743298698207838825035605868404742682423919455523383721081589378970796492944950066480951790660582889972423189943567111507801410254720228911513553205592856585541922662924268445466959576882300405064708497308004255650466014242855505233634626075778108365396568863197935915425650388910408127232583533503834009244199384570662092164277923946411149853110048365318587554141774139652307149492021035538341281427025252592933784473453522113124752189378715431529801894015739903371171585194505182320772654217490509848165365152457990491089951560694728469571221819385402117009544812199223715540348068497710535492913376699508575875577554607325905000745578091554027803374110357015655416894607641289462159580964951182385869168785183135763253784745647466464331174922663455073627501620274348748413309761116542324505123795743603781806636788810617169341018091186028310551725315297135354426735951943325476221811539822892501042385411792050504283745898099390893596941969752683246939665141002098430129617772928840718016009187577151479855846883928332010147501182201528575840364152774917950524127063432334646746291719251739989499132767590205934821590545762802261107691663 dhopson@VMUbuntu-DSH diff --git a/lib/public_key/test/public_key_SUITE_data/ssh1_known_hosts b/lib/public_key/test/public_key_SUITE_data/ssh1_known_hosts new file mode 100644 index 0000000000..ec668fe05b --- /dev/null +++ b/lib/public_key/test/public_key_SUITE_data/ssh1_known_hosts @@ -0,0 +1,2 @@ +hostname.domain.com,192.168.0.1 1024 35 794430685278501116412873221867658581245241426828503388129294124540165981586596106773643485704743298698207838825035605868404742682423919455523383721081589378970796492944950066480951790660582889972423189943567111507801410254720228911513553205592856585541922662924268445466959576882300405064708497308004255650466014242855505233634626075778108365396568863197935915425650388910408127232583533503834009244199384570662092164277923946411149853110048365318587554141774139652307149492021035538341281427025252592933784473453522113124752189378715431529801894015739903371171585194505182320772654217490509848165365152457990491089951560694728469571221819385402117009544812199223715540348068497710535492913376699508575875577554607325905000745578091554027803374110357015655416894607641289462159580964951182385869168785183135763253784745647466464331174922663455073627501620274348748413309761116542324505123795743603781806636788810617169341018091186028310551725315297135354426735951943325476221811539822892501042385411792050504283745898099390893596941969752683246939665141002098430129617772928840718016009187577151479855846883928332010147501182201528575840364152774917950524127063432334646746291719251739989499132767590205934821590545762802261107691663 dhopson@VMUbuntu-DSH +hostname2.domain.com,192.168.0.2 1024 35 794430685278501116412873221867658581245241426828503388129294124540165981586596106773643485704743298698207838825035605868404742682423919455523383721081589378970796492944950066480951790660582889972423189943567111507801410254720228911513553205592856585541922662924268445466959576882300405064708497308004255650466014242855505233634626075778108365396568863197935915425650388910408127232583533503834009244199384570662092164277923946411149853110048365318587554141774139652307149492021035538341281427025252592933784473453522113124752189378715431529801894015739903371171585194505182320772654217490509848165365152457990491089951560694728469571221819385402117009544812199223715540348068497710535492913376699508575875577554607325905000745578091554027803374110357015655416894607641289462159580964951182385869168785183135763253784745647466464331174922663455073627501620274348748413309761116542324505123795743603781806636788810617169341018091186028310551725315297135354426735951943325476221811539822892501042385411792050504283745898099390893596941969752683246939665141002098430129617772928840718016009187577151479855846883928332010147501182201528575840364152774917950524127063432334646746291719251739989499132767590205934821590545762802261107691663 diff --git a/lib/public_key/test/public_key_SUITE_data/ssh2_dsa_comment_pub b/lib/public_key/test/public_key_SUITE_data/ssh2_dsa_comment_pub new file mode 100644 index 0000000000..ca5089dbd7 --- /dev/null +++ b/lib/public_key/test/public_key_SUITE_data/ssh2_dsa_comment_pub @@ -0,0 +1,13 @@ +---- BEGIN SSH2 PUBLIC KEY ---- +Comment: This is my public key for use on \ +servers which I don't like. +AAAAB3NzaC1kc3MAAACBAPY8ZOHY2yFSJA6XYC9HRwNHxaehvx5wOJ0rzZdzoSOXxbET +W6ToHv8D1UJ/z+zHo9Fiko5XybZnDIaBDHtblQ+Yp7StxyltHnXF1YLfKD1G4T6JYrdH +YI14Om1eg9e4NnCRleaqoZPF3UGfZia6bXrGTQf3gJq2e7Yisk/gF+1VAAAAFQDb8D5c +vwHWTZDPfX0D2s9Rd7NBvQAAAIEAlN92+Bb7D4KLYk3IwRbXblwXdkPggA4pfdtW9vGf +J0/RHd+NjB4eo1D+0dix6tXwYGN7PKS5R/FXPNwxHPapcj9uL1Jn2AWQ2dsknf+i/FAA +vioUPkmdMc0zuWoSOEsSNhVDtX3WdvVcGcBq9cetzrtOKWOocJmJ80qadxTRHtUAAACB +AN7CY+KKv1gHpRzFwdQm7HK9bb1LAo2KwaoXnadFgeptNBQeSXG1vO+JsvphVMBJc9HS +n24VYtYtsMu74qXviYjziVucWKjjKEb11juqnF0GDlB3VVmxHLmxnAz643WK42Z7dLM5 +sY29ouezv4Xz2PuMch5VGPP+CDqzCM4loWgV +---- END SSH2 PUBLIC KEY ---- diff --git a/lib/public_key/test/public_key_SUITE_data/ssh2_dsa_pub b/lib/public_key/test/public_key_SUITE_data/ssh2_dsa_pub new file mode 100644 index 0000000000..a5e38be81a --- /dev/null +++ b/lib/public_key/test/public_key_SUITE_data/ssh2_dsa_pub @@ -0,0 +1,12 @@ +---- BEGIN SSH2 PUBLIC KEY ---- +Comment: DSA Public Key for use with MyIsp +AAAAB3NzaC1kc3MAAACBAPY8ZOHY2yFSJA6XYC9HRwNHxaehvx5wOJ0rzZdzoSOXxbET +W6ToHv8D1UJ/z+zHo9Fiko5XybZnDIaBDHtblQ+Yp7StxyltHnXF1YLfKD1G4T6JYrdH +YI14Om1eg9e4NnCRleaqoZPF3UGfZia6bXrGTQf3gJq2e7Yisk/gF+1VAAAAFQDb8D5c +vwHWTZDPfX0D2s9Rd7NBvQAAAIEAlN92+Bb7D4KLYk3IwRbXblwXdkPggA4pfdtW9vGf +J0/RHd+NjB4eo1D+0dix6tXwYGN7PKS5R/FXPNwxHPapcj9uL1Jn2AWQ2dsknf+i/FAA +vioUPkmdMc0zuWoSOEsSNhVDtX3WdvVcGcBq9cetzrtOKWOocJmJ80qadxTRHtUAAACB +AN7CY+KKv1gHpRzFwdQm7HK9bb1LAo2KwaoXnadFgeptNBQeSXG1vO+JsvphVMBJc9HS +n24VYtYtsMu74qXviYjziVucWKjjKEb11juqnF0GDlB3VVmxHLmxnAz643WK42Z7dLM5 +sY29ouezv4Xz2PuMch5VGPP+CDqzCM4loWgV +---- END SSH2 PUBLIC KEY ---- diff --git a/lib/public_key/test/public_key_SUITE_data/ssh2_rsa_comment_pub b/lib/public_key/test/public_key_SUITE_data/ssh2_rsa_comment_pub new file mode 100644 index 0000000000..e4d446147c --- /dev/null +++ b/lib/public_key/test/public_key_SUITE_data/ssh2_rsa_comment_pub @@ -0,0 +1,7 @@ +---- BEGIN SSH2 PUBLIC KEY ---- +Comment: "1024-bit RSA, converted from OpenSSH by [email protected]" +x-command: /home/me/bin/lock-in-guest.sh +AAAAB3NzaC1yc2EAAAABIwAAAIEA1on8gxCGJJWSRT4uOrR13mUaUk0hRf4RzxSZ1zRb +YYFw8pfGesIFoEuVth4HKyF8k1y4mRUnYHP1XNMNMJl1JcEArC2asV8sHf6zSPVffozZ +5TT4SfsUu/iKy9lUcCfXzwre4WWZSXXcPff+EHtWshahu3WzBdnGxm5Xoi89zcE= +---- END SSH2 PUBLIC KEY ---- diff --git a/lib/public_key/test/public_key_SUITE_data/ssh2_rsa_pub b/lib/public_key/test/public_key_SUITE_data/ssh2_rsa_pub new file mode 100644 index 0000000000..761088b517 --- /dev/null +++ b/lib/public_key/test/public_key_SUITE_data/ssh2_rsa_pub @@ -0,0 +1,13 @@ +---- BEGIN SSH2 PUBLIC KEY ---- +AAAAB3NzaC1yc2EAAAABIwAAAgEAwrr66r8n6B8Y0zMF3dOpXEapIQD9DiYQ6D6/zwor9o +39jSkHNiMMER/GETBbzP83LOcekm02aRjo55ArO7gPPVvCXbrirJu9pkm4AC4BBre5xSLS +7soyzwbigFruM8G63jSXqpHqJ/ooi168sKMC2b0Ncsi+JlTfNYlDXJVLKEeZgZOInQyMmt +isaDTUQWTIv1snAizf4iIYENuAkGYGNCL77u5Y5VOu5eQipvFajTnps9QvUx/zdSFYn9e2 +sulWM3Bxc/S4IJ67JWHVRpfJxGi3hinRBH8WQdXuUwdJJTiJHKPyYrrM7Q6Xq4TOMFtcRu +LDC6u3BXM1L0gBvHPNOnD5l2Lp5EjUkQ9CBf2j4A4gfH+iWQZyk08esAG/iwArAVxkl368 ++dkbMWOXL8BN4x5zYgdzoeypQZZ2RKH780MCTSo4WQ19DP8pw+9q3bSFC9H3xYAxrKAJNW +jeTUJOTrTe+mWXXU770gYyQTxa2ycnYrlZucn1S3vsvn6eq7NZZ8NRbyv1n15Ocg+nHK4f +uKOrwPhU3NbKQwtjb0Wsxx1gAmQqIOLTpAdsrAauPxC7TPYA5qQVCphvimKuhQM/1gMV22 +5JrnjspVlthCzuFYUjXOKC3wxz6FFEtwnXu3uC5bVVkmkNadJmD21gD23yk4BraGXVYpRM +IB+X+OTUUI8= +---- END SSH2 PUBLIC KEY ---- diff --git a/lib/public_key/test/public_key_SUITE_data/ssh2_subject_pub b/lib/public_key/test/public_key_SUITE_data/ssh2_subject_pub new file mode 100644 index 0000000000..8b8ccda8ba --- /dev/null +++ b/lib/public_key/test/public_key_SUITE_data/ssh2_subject_pub @@ -0,0 +1,8 @@ +---- BEGIN SSH2 PUBLIC KEY ---- +Subject: me +Comment: 1024-bit rsa, created by [email protected] Mon Jan 15 \ +08:31:24 2001 +AAAAB3NzaC1yc2EAAAABJQAAAIEAiPWx6WM4lhHNedGfBpPJNPpZ7yKu+dnn1SJejgt4 +596k6YjzGGphH2TUxwKzxcKDKKezwkpfnxPkSMkuEspGRt/aZZ9wa++Oi7Qkr8prgHc4 +soW6NUlfDzpvZK2H5E7eQaSeP3SAwGmQKUFHCddNaP0L+hM7zhFNzjFvpaMgJw0= +---- END SSH2 PUBLIC KEY ---- diff --git a/lib/public_key/test/public_key_SUITE_data/ssh_rsa_long_comment_pub b/lib/public_key/test/public_key_SUITE_data/ssh_rsa_long_comment_pub new file mode 100644 index 0000000000..7b42ced93e --- /dev/null +++ b/lib/public_key/test/public_key_SUITE_data/ssh_rsa_long_comment_pub @@ -0,0 +1,9 @@ +---- BEGIN SSH2 PUBLIC KEY ---- +Comment: This is an example of a very very very very looooooooooooo\ +ooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong\ +commment +x-command: /home/me/bin/lock-in-guest.sh +AAAAB3NzaC1yc2EAAAABIwAAAIEA1on8gxCGJJWSRT4uOrR13mUaUk0hRf4RzxSZ1zRb +YYFw8pfGesIFoEuVth4HKyF8k1y4mRUnYHP1XNMNMJl1JcEArC2asV8sHf6zSPVffozZ +5TT4SfsUu/iKy9lUcCfXzwre4WWZSXXcPff+EHtWshahu3WzBdnGxm5Xoi89zcE= +---- END SSH2 PUBLIC KEY ---- diff --git a/lib/public_key/test/public_key_SUITE_data/ssh_rsa_long_header_pub b/lib/public_key/test/public_key_SUITE_data/ssh_rsa_long_header_pub new file mode 100644 index 0000000000..7b42ced93e --- /dev/null +++ b/lib/public_key/test/public_key_SUITE_data/ssh_rsa_long_header_pub @@ -0,0 +1,9 @@ +---- BEGIN SSH2 PUBLIC KEY ---- +Comment: This is an example of a very very very very looooooooooooo\ +ooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong\ +commment +x-command: /home/me/bin/lock-in-guest.sh +AAAAB3NzaC1yc2EAAAABIwAAAIEA1on8gxCGJJWSRT4uOrR13mUaUk0hRf4RzxSZ1zRb +YYFw8pfGesIFoEuVth4HKyF8k1y4mRUnYHP1XNMNMJl1JcEArC2asV8sHf6zSPVffozZ +5TT4SfsUu/iKy9lUcCfXzwre4WWZSXXcPff+EHtWshahu3WzBdnGxm5Xoi89zcE= +---- END SSH2 PUBLIC KEY ---- diff --git a/lib/public_key/vsn.mk b/lib/public_key/vsn.mk index c99fd6fee1..3c6b012152 100644 --- a/lib/public_key/vsn.mk +++ b/lib/public_key/vsn.mk @@ -1 +1 @@ -PUBLIC_KEY_VSN = 0.11 +PUBLIC_KEY_VSN = 0.12 diff --git a/lib/reltool/src/reltool_server.erl b/lib/reltool/src/reltool_server.erl index d7cad8b29e..9743289ca6 100644 --- a/lib/reltool/src/reltool_server.erl +++ b/lib/reltool/src/reltool_server.erl @@ -1318,7 +1318,7 @@ decode(#sys{} = Sys, [{Key, Val} | KeyVals], Status) -> Val =:= none; Val =:= undefined -> {Sys#sys{embedded_app_type = Val}, Status}; - app_file when Val =:= keep; Val =:= strip, Val =:= all -> + app_file when Val =:= keep; Val =:= strip; Val =:= all -> {Sys#sys{app_file = Val}, Status}; debug_info when Val =:= keep; Val =:= strip -> {Sys#sys{debug_info = Val}, Status}; diff --git a/lib/reltool/test/Makefile b/lib/reltool/test/Makefile index abd2e81cdf..62fe05238b 100644 --- a/lib/reltool/test/Makefile +++ b/lib/reltool/test/Makefile @@ -76,7 +76,7 @@ release_tests_spec: opt $(INSTALL_DATA) reltool.spec reltool.cover $(ERL_FILES) $(HRL_FILES) $(RELSYSDIR) $(INSTALL_SCRIPT) rtt $(INSTALL_PROGS) $(RELSYSDIR) $(INSTALL_DATA) $(INSTALL_PROGS) $(RELSYSDIR) -# chmod -f -R u+w $(RELSYSDIR) +# chmod -R u+w $(RELSYSDIR) # @tar cf - *_SUITE_data | (cd $(RELSYSDIR); tar xf -) release_docs_spec: diff --git a/lib/reltool/test/reltool_app_SUITE.erl b/lib/reltool/test/reltool_app_SUITE.erl index 97076589ba..a6e00cde08 100644 --- a/lib/reltool/test/reltool_app_SUITE.erl +++ b/lib/reltool/test/reltool_app_SUITE.erl @@ -45,15 +45,16 @@ init_per_suite(Config) -> end_per_suite(Config) -> reltool_test_lib:end_per_suite(Config). +init_per_testcase(undef_funcs=Case, Config) -> + case test_server:is_debug() of + true -> + {skip,"Debug-compiled emulator -- far too slow"}; + false -> + Config2 = [{tc_timeout, timer:minutes(10)} | Config], + reltool_test_lib:init_per_testcase(Case, Config2) + end; init_per_testcase(Case, Config) -> - Config2 = - case Case of - undef_funcs -> - [{tc_timeout, timer:minutes(10)} | Config]; - _ -> - Config - end, - reltool_test_lib:init_per_testcase(Case, Config2). + reltool_test_lib:init_per_testcase(Case, Config). end_per_testcase(Func,Config) -> reltool_test_lib:end_per_testcase(Func,Config). diff --git a/lib/reltool/test/reltool_server_SUITE.erl b/lib/reltool/test/reltool_server_SUITE.erl index ef3076f305..b77560db94 100644 --- a/lib/reltool/test/reltool_server_SUITE.erl +++ b/lib/reltool/test/reltool_server_SUITE.erl @@ -52,7 +52,8 @@ suite() -> [{ct_hooks,[ts_install_cth]}]. all() -> [start_server, set_config, create_release, create_script, create_target, create_embedded, - create_standalone, create_old_target]. + create_standalone, create_old_target, + otp_9135]. groups() -> []. @@ -110,6 +111,37 @@ set_config(_Config) -> ok. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% OTP-9135, test that app_file option can be set to all | keep | strip + +otp_9135(TestInfo) when is_atom(TestInfo) -> + reltool_test_lib:tc_info(TestInfo); +otp_9135(_Config) -> + Libs = lists:sort(erl_libs()), + StrippedDefaultSys = + case Libs of + [] -> []; + _ -> {lib_dirs, Libs} + end, + + Config1 = {sys,[{app_file, keep}]}, % this is the default + {ok, Pid1} = ?msym({ok, _}, reltool:start_server([{config, Config1}])), + ?m({ok, {sys,StrippedDefaultSys}}, reltool:get_config(Pid1)), + ?m(ok, reltool:stop(Pid1)), + + Config2 = {sys,[{app_file, strip}]}, + {ok, Pid2} = ?msym({ok, _}, reltool:start_server([{config, Config2}])), + ExpectedConfig2 = StrippedDefaultSys++[{app_file,strip}], + ?m({ok, {sys,ExpectedConfig2}}, reltool:get_config(Pid2)), + ?m(ok, reltool:stop(Pid2)), + + Config3 = {sys,[{app_file, all}]}, + {ok, Pid3} = ?msym({ok, _}, reltool:start_server([{config, Config3}])), + ExpectedConfig3 = StrippedDefaultSys++[{app_file,all}], + ?m({ok, {sys,ExpectedConfig3}}, reltool:get_config(Pid3)), + ?m(ok, reltool:stop(Pid3)), + ok. + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% Generate releases create_release(TestInfo) when is_atom(TestInfo) -> diff --git a/lib/runtime_tools/test/Makefile b/lib/runtime_tools/test/Makefile index 7dc7a015e1..cfaf420d65 100644 --- a/lib/runtime_tools/test/Makefile +++ b/lib/runtime_tools/test/Makefile @@ -59,7 +59,7 @@ release_tests_spec: make_emakefile $(INSTALL_DIR) $(RELSYSDIR) $(INSTALL_DATA) runtime_tools.spec runtime_tools.cover $(ERL_FILES) $(RELSYSDIR) $(INSTALL_DATA) $(EMAKEFILE) runtime_tools.cover $(RELSYSDIR) - chmod -f -R u+w $(RELSYSDIR) + chmod -R u+w $(RELSYSDIR) @tar cf - *_SUITE_data | (cd $(RELSYSDIR); tar xf -) release_docs_spec: 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 @@ <fsummary>Generate a boot script <c>.script/.boot</c>.</fsummary> <type> <v>Name = string()</v> - <v>Opt = no_module_tests | {path,[Dir]} | local | {variables,[Var]} | exref | {exref,[App]}] | silent | {outdir,Dir}</v> + <v>Opt = src_tests | {path,[Dir]} | local | {variables,[Var]} | exref | {exref,[App]}] | silent | {outdir,Dir}</v> <v> Dir = string()</v> <v> Var = {VarName,Prefix}</v> <v> VarName = Prefix = string()</v> @@ -174,15 +174,13 @@ the applications.</p> </item> <item> - <p>There should no duplicated modules, that is, modules with + <p>There should be no duplicated modules, that is, modules with the same name but belonging to different applications.</p> </item> <item> - <p>A warning is issued if the source code for a module is - missing or newer than the object code. <br></br> - - If the <c>no_module_tests</c> option is specified, this - check is omitted.</p> + <p>If the <c>src_tests</c> option is specified, a + warning is issued if the source code for a module is + missing or newer than the object code.</p> </item> </list> <p>The applications are sorted according to the dependencies @@ -242,7 +240,7 @@ <fsummary>Create a release package.</fsummary> <type> <v>Name = string()</v> - <v>Opt = {dirs,[IncDir]} | {path,[Dir]} | {variables,[Var]} | {var_tar,VarTar} | {erts,Dir} | no_module_tests | exref | {exref,[App]} | silent | {outdir,Dir}</v> + <v>Opt = {dirs,[IncDir]} | {path,[Dir]} | {variables,[Var]} | {var_tar,VarTar} | {erts,Dir} | src_tests | exref | {exref,[App]} | silent | {outdir,Dir}</v> <v> Dir = string()</v> <v> IncDir = src | include | atom()</v> <v> Var = {VarName,PreFix}</v> @@ -330,7 +328,7 @@ myapp-1/ebin/myapp.app system <c>{erts,Dir}</c> is copied to <c>erts-ErtsVsn/bin</c>.</p> <p>All checks performed with the <c>make_script</c> function are performed before the release package is created. The - <c>no_module_tests</c> and <c>exref</c> options are also + <c>src_tests</c> and <c>exref</c> options are also valid here.</p> <p>The return value and the handling of errors and warnings are the same as described for <c>make_script</c> above.</p> diff --git a/lib/sasl/src/rb.erl b/lib/sasl/src/rb.erl index 38e486b7a7..13753565d8 100644 --- a/lib/sasl/src/rb.erl +++ b/lib/sasl/src/rb.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 @@ -169,7 +169,7 @@ print_filters() -> print_dates() -> io:format(" - {StartDate, EndDate}~n"), - io:format(" StartDate = EndDate = {{Y-M-D},{H,M,S}} ~n"), + io:format(" StartDate = EndDate = {{Y,M,D},{H,M,S}} ~n"), io:format(" prints the reports with date between StartDate and EndDate~n"), io:format(" - {StartDate, from}~n"), io:format(" prints the reports with date greater than StartDate~n"), diff --git a/lib/sasl/src/release_handler.erl b/lib/sasl/src/release_handler.erl index 4c43277848..b60aa847df 100644 --- a/lib/sasl/src/release_handler.erl +++ b/lib/sasl/src/release_handler.erl @@ -791,7 +791,7 @@ check_rel(Root, RelFile, Masters) -> check_rel(Root, RelFile, LibDirs, Masters) -> case consult(RelFile, Masters) of {ok, [RelData]} -> - check_rel_data(RelData, Root, LibDirs); + check_rel_data(RelData, Root, LibDirs, Masters); {ok, _} -> throw({error, {bad_rel_file, RelFile}}); {error, Reason} when is_tuple(Reason) -> @@ -800,7 +800,8 @@ check_rel(Root, RelFile, LibDirs, Masters) -> throw({error, {FileError, RelFile}}) end. -check_rel_data({release, {Name, Vsn}, {erts, EVsn}, Libs}, Root, LibDirs) -> +check_rel_data({release, {Name, Vsn}, {erts, EVsn}, Libs}, Root, LibDirs, + Masters) -> Libs2 = lists:map(fun(LibSpec) -> Lib = element(1, LibSpec), @@ -810,7 +811,7 @@ check_rel_data({release, {Name, Vsn}, {erts, EVsn}, Libs}, Root, LibDirs) -> case lists:keysearch(Lib, 1, LibDirs) of {value, {_Lib, _Vsn, Dir}} -> Path = filename:join(Dir,LibName), - check_path(Path), + check_path(Path, Masters), Path; _ -> filename:join([Root, "lib", LibName]) @@ -820,19 +821,34 @@ check_rel_data({release, {Name, Vsn}, {erts, EVsn}, Libs}, Root, LibDirs) -> Libs), #release{name = Name, vsn = Vsn, erts_vsn = EVsn, libs = Libs2, status = unpacking}; -check_rel_data(RelData, _Root, _LibDirs) -> +check_rel_data(RelData, _Root, _LibDirs, _Masters) -> throw({error, {bad_rel_data, RelData}}). check_path(Path) -> - case file:read_file_info(Path) of - {ok, Info} when Info#file_info.type==directory -> - ok; - {ok, _Info} -> - throw({error, {not_a_directory, Path}}); - {error, _Reason} -> - throw({error, {no_such_directory, Path}}) - end. - + check_path_response(Path, file:read_file_info(Path)). +check_path(Path, false) -> check_path(Path); +check_path(Path, Masters) -> check_path_master(Masters, Path). + +%%----------------------------------------------------------------- +%% check_path at any master node. +%% If the path does not exist or is not a directory +%% at one node it should not exist at any other node either. +%%----------------------------------------------------------------- +check_path_master([Master|Ms], Path) -> + case rpc:call(Master, file, read_file_info, [Path]) of + {badrpc, _} -> consult_master(Ms, Path); + Res -> check_path_response(Path, Res) + end; +check_path_master([], _Path) -> + {error, no_master}. + +check_path_response(_Path, {ok, Info}) when Info#file_info.type==directory -> + ok; +check_path_response(Path, {ok, _Info}) -> + throw({error, {not_a_directory, Path}}); +check_path_response(Path, {error, _Reason}) -> + throw({error, {no_such_directory, Path}}). + do_check_install_release(RelDir, Vsn, Releases, Masters) -> case lists:keysearch(Vsn, #release.vsn, Releases) of {value, #release{status = current}} -> diff --git a/lib/sasl/src/release_handler_1.erl b/lib/sasl/src/release_handler_1.erl index 9c0edf4e99..8d050fb7b0 100644 --- a/lib/sasl/src/release_handler_1.erl +++ b/lib/sasl/src/release_handler_1.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 @@ -20,7 +20,7 @@ %% External exports -export([eval_script/3, eval_script/4, check_script/2]). --export([get_vsn/1]). %% exported because used in a test case +-export([get_current_vsn/1]). %% exported because used in a test case -record(eval_state, {bins = [], stopped = [], suspended = [], apps = [], libdirs, unpurged = [], vsns = [], newlibs = [], @@ -223,7 +223,7 @@ eval({load_object_code, {Lib, LibVsn, Modules}}, EvalState) -> FName = filename:join(Ebin, File), case erl_prim_loader:get_file(FName) of {ok, Bin, FName2} -> - NVsns = add_new_vsn(Mod, FName2, Vsns), + NVsns = add_new_vsn(Mod, Bin, Vsns), {[{Mod, Bin, FName2} | Bins],NVsns}; error -> throw({error, {no_such_file,FName}}) @@ -609,17 +609,17 @@ sync_nodes(Id, Nodes) -> add_old_vsn(Mod, Vsns) -> case lists:keysearch(Mod, 1, Vsns) of {value, {Mod, undefined, NewVsn}} -> - OldVsn = get_vsn(code:which(Mod)), + OldVsn = get_current_vsn(Mod), lists:keyreplace(Mod, 1, Vsns, {Mod, OldVsn, NewVsn}); {value, {Mod, _OldVsn, _NewVsn}} -> Vsns; false -> - OldVsn = get_vsn(code:which(Mod)), + OldVsn = get_current_vsn(Mod), [{Mod, OldVsn, undefined} | Vsns] end. -add_new_vsn(Mod, File, Vsns) -> - NewVsn = get_vsn(File), +add_new_vsn(Mod, Bin, Vsns) -> + NewVsn = get_vsn(Bin), case lists:keysearch(Mod, 1, Vsns) of {value, {Mod, OldVsn, undefined}} -> lists:keyreplace(Mod, 1, Vsns, {Mod, OldVsn, NewVsn}); @@ -627,17 +627,35 @@ add_new_vsn(Mod, File, Vsns) -> [{Mod, undefined, NewVsn} | Vsns] end. - +%%----------------------------------------------------------------- +%% Func: get_current_vsn/1 +%% Args: Mod = atom() +%% Purpose: This function returns the equivalent of +%% beam_lib:version(code:which(Mod)), but it will also handle the +%% case when using erl_prim_loader loader different from 'efile'. +%% The reason for not using the Binary from the 'bins' or the +%% version directly from the 'vsns' state field is that these are +%% updated already by load_object_code, and this function is called +%% from load and remove. +%% Returns: Vsn = term() +%%----------------------------------------------------------------- +get_current_vsn(Mod) -> + File = code:which(Mod), + case erl_prim_loader:get_file(File) of + {ok, Bin, _File2} -> + get_vsn(Bin); + error -> + throw({error, {no_such_file, File}}) + end. %%----------------------------------------------------------------- %% Func: get_vsn/1 -%% Args: File = string() +%% Args: Bin = binary() %% Purpose: Finds the version attribute of a module. -%% Returns: Vsn -%% Vsn = term() +%% Returns: Vsn = term() %%----------------------------------------------------------------- -get_vsn(File) -> - {ok, {_Mod, Vsn}} = beam_lib:version(File), +get_vsn(Bin) -> + {ok, {_Mod, Vsn}} = beam_lib:version(Bin), case misc_supp:is_string(Vsn) of true -> Vsn; 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} -> diff --git a/lib/snmp/test/Makefile b/lib/snmp/test/Makefile index 86af2460f5..b7975024b4 100644 --- a/lib/snmp/test/Makefile +++ b/lib/snmp/test/Makefile @@ -227,7 +227,7 @@ release_spec: release_tests_spec: opt $(INSTALL_DIR) $(RELSYSDIR) $(INSTALL_DATA) $(RELTEST_FILES) $(COVER_SPEC_FILE) $(RELSYSDIR) - chmod -f -R u+w $(RELSYSDIR) + chmod -R u+w $(RELSYSDIR) tar cf - snmp_test_data | (cd $(RELSYSDIR); tar xf -) release_docs_spec: diff --git a/lib/ssh/doc/src/notes.xml b/lib/ssh/doc/src/notes.xml index af667b1a71..4f546a37ed 100644 --- a/lib/ssh/doc/src/notes.xml +++ b/lib/ssh/doc/src/notes.xml @@ -29,6 +29,33 @@ <file>notes.xml</file> </header> +<section><title>Ssh 2.0.6</title> + <section><title>Fixed Bugs and Malfunctions</title> + <list> + <item> + <p> + A memory leak has been fixed. I.e. per terminated connection the size of + a pid and the length of a user name string was not cleared.</p> + <p> + Own Id: OTP-9232</p> + </item> + </list> + </section> +</section> + +<section><title>Ssh 2.0.5</title> + <section><title>Improvements and New Features</title> + <list> + <item> + <p> + Strengthened random number generation. (Thanks to Geoff Cant)</p> + <p> + Own Id: OTP-9225</p> + </item> + </list> + </section> +</section> + <section><title>Ssh 2.0.4</title> <section><title>Fixed Bugs and Malfunctions</title> <list> diff --git a/lib/ssh/src/ssh.appup.src b/lib/ssh/src/ssh.appup.src index 501da8ceb9..37f24e2463 100644 --- a/lib/ssh/src/ssh.appup.src +++ b/lib/ssh/src/ssh.appup.src @@ -19,34 +19,12 @@ {"%VSN%", [ - {"2.0.3", [{load_module, ssh_file, soft_purge, soft_purge, []}, - {load_module, ssh, soft_purge, soft_purge, []}, - {load_module, ssh_rsa, soft_purge, soft_purge, []}, - {load_module, ssh_acceptor, soft_purge, soft_purge, []}, - {load_module, ssh_transport, soft_purge, soft_purge, []}, - {load_module, ssh_connection_manager, soft_purge, soft_purge, []}]}, - {"2.0.2", [{load_module, ssh_file, soft_purge, soft_purge, []}, - {load_module, ssh, soft_purge, soft_purge, []}, - {load_module, ssh_rsa, soft_purge, soft_purge, []}, - {load_module, ssh_acceptor, soft_purge, soft_purge, []}, - {load_module, ssh_transport, soft_purge, soft_purge, []}, - {load_module, ssh_connection_manager, soft_purge, soft_purge, []}]}, - {"2.0.1", [{restart_application, ssh}]} + {"2.0.5", [{load_module, ssh_userreg, soft_purge, soft_purge, []}, + {load_module, ssh_connection_handler, soft_purge, soft_purge, [ssh_userreg]}]} ], [ - {"2.0.3", [{load_module, ssh_file, soft_purge, soft_purge, []}, - {load_module, ssh, soft_purge, soft_purge, []}, - {load_module, ssh_rsa, soft_purge, soft_purge, []}, - {load_module, ssh_acceptor, soft_purge, soft_purge, []}, - {load_module, ssh_transport, soft_purge, soft_purge, []}, - {load_module, ssh_connection_manager, soft_purge, soft_purge, []}]}, - {"2.0.2", [{load_module, ssh_file, soft_purge, soft_purge, []}, - {load_module, ssh, soft_purge, soft_purge, []}, - {load_module, ssh_rsa, soft_purge, soft_purge, []}, - {load_module, ssh_acceptor, soft_purge, soft_purge, []}, - {load_module, ssh_transport, soft_purge, soft_purge, []}, - {load_module, ssh_connection_manager, soft_purge, soft_purge, []}]}, - {"2.0.1", [{restart_application, ssh}]} + {"2.0.5", [{load_module, ssh_userreg, soft_purge, soft_purge, []}, + {load_module, ssh_connection_handler, soft_purge, soft_purge, [ssh_userreg]}]} ] }. diff --git a/lib/ssh/src/ssh_bits.erl b/lib/ssh/src/ssh_bits.erl index 399581a0fd..3f0a06575c 100755 --- a/lib/ssh/src/ssh_bits.erl +++ b/lib/ssh/src/ssh_bits.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2005-2010. All Rights Reserved. +%% Copyright Ericsson AB 2005-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 @@ -34,7 +34,7 @@ %% integer utils -export([isize/1]). -export([irandom/1, irandom/3]). --export([random/1, random/3]). +-export([random/1]). -export([xor_bits/2, fill_bits/2]). -export([i2bin/2, bin2i/1]). @@ -401,9 +401,6 @@ xor_bits(XBits, YBits) -> irandom(Bits) -> irandom(Bits, 1, 0). -%% irandom_odd(Bits) -> -%% irandom(Bits, 1, 1). - %% %% irandom(N, Top, Bottom) %% @@ -414,57 +411,16 @@ irandom(Bits) -> %% Bot = 0 - do not set the least signifcant bit %% Bot = 1 - set the least signifcant bit (i.e always odd) %% -irandom(0, _Top, _Bottom) -> - 0; -irandom(Bits, Top, Bottom) -> - Bytes = (Bits+7) div 8, - Skip = (8-(Bits rem 8)) rem 8, - TMask = case Top of - 0 -> 0; - 1 -> 16#80; - 2 -> 16#c0 - end, - BMask = case Bottom of - 0 -> 0; - 1 -> (1 bsl Skip) - end, - <<X:Bits/big-unsigned-integer, _:Skip>> = random(Bytes, TMask, BMask), - X. +irandom(Bits, Top, Bottom) when is_integer(Top), + 0 =< Top, Top =< 2 -> + crypto:erlint(crypto:strong_rand_mpint(Bits, Top - 1, Bottom)). %% %% random/1 %% Generate N random bytes %% random(N) -> - random(N, 0, 0). - -random(N, TMask, BMask) -> - list_to_binary(rnd(N, TMask, BMask)). - -%% random/3 -%% random(Bytes, TopMask, BotMask) -%% where -%% Bytes is the number of bytes to generate -%% TopMask is bitwised or'ed to the first byte -%% BotMask is bitwised or'ed to the last byte -%% -rnd(0, _TMask, _BMask) -> - []; -rnd(1, TMask, BMask) -> - [(rand8() bor TMask) bor BMask]; -rnd(N, TMask, BMask) -> - [(rand8() bor TMask) | rnd_n(N-1, BMask)]. - -rnd_n(1, BMask) -> - [rand8() bor BMask]; -rnd_n(I, BMask) -> - [rand8() | rnd_n(I-1, BMask)]. - -rand8() -> - (rand32() bsr 8) band 16#ff. - -rand32() -> - random:uniform(16#100000000) -1. + crypto:strong_rand_bytes(N). %% %% Base 64 encode/decode diff --git a/lib/ssh/src/ssh_cli.erl b/lib/ssh/src/ssh_cli.erl index cb78acb84c..781e01b9d1 100644 --- a/lib/ssh/src/ssh_cli.erl +++ b/lib/ssh/src/ssh_cli.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2005-2010. All Rights Reserved. +%% Copyright Ericsson AB 2005-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 diff --git a/lib/ssh/src/ssh_connection_handler.erl b/lib/ssh/src/ssh_connection_handler.erl index 0ba11b0a26..3193be2510 100644 --- a/lib/ssh/src/ssh_connection_handler.erl +++ b/lib/ssh/src/ssh_connection_handler.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2010. All Rights Reserved. +%% Copyright Ericsson AB 2008-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 @@ -106,8 +106,6 @@ peer_address(ConnectionHandler) -> %% initialize. %%-------------------------------------------------------------------- init([Role, Manager, Socket, SshOpts]) -> - {A,B,C} = erlang:now(), - random:seed(A, B, C), {NumVsn, StrVsn} = ssh_transport:versions(Role, SshOpts), ssh_bits:install_messages(ssh_transport:transport_messages(NumVsn)), {Protocol, Callback, CloseTag} = @@ -580,7 +578,9 @@ handle_info({CloseTag, _Socket}, _StateName, %% Reason. The return value is ignored. %%-------------------------------------------------------------------- terminate(normal, _, #state{transport_cb = Transport, - socket = Socket}) -> + socket = Socket, + manager = Pid}) -> + (catch ssh_userreg:delete_user(Pid)), (catch Transport:close(Socket)), ok; @@ -812,7 +812,7 @@ handle_disconnect(#ssh_msg_disconnect{} = Msg, #state{ssh_params = Ssh0, manager = Pid} = State) -> {SshPacket, Ssh} = ssh_transport:ssh_packet(Msg, Ssh0), try - send_msg(SshPacket, State), + send_msg(SshPacket, State), ssh_connection_manager:event(Pid, Msg) catch exit:{noproc, _Reason} -> @@ -824,6 +824,7 @@ handle_disconnect(#ssh_msg_disconnect{} = Msg, [Msg, Exit]), error_logger:info_report(Report) end, + (catch ssh_userreg:delete_user(Pid)), {stop, normal, State#state{ssh_params = Ssh}}. counterpart_versions(NumVsn, StrVsn, #ssh{role = server} = Ssh) -> diff --git a/lib/ssh/src/ssh_userreg.erl b/lib/ssh/src/ssh_userreg.erl index 33c801f490..f901461aea 100644 --- a/lib/ssh/src/ssh_userreg.erl +++ b/lib/ssh/src/ssh_userreg.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2010. All Rights Reserved. +%% Copyright Ericsson AB 2008-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 @@ -25,11 +25,18 @@ -behaviour(gen_server). %% API --export([start_link/0, register_user/2, lookup_user/1]). +-export([start_link/0, + register_user/2, + lookup_user/1, + delete_user/1]). %% gen_server callbacks --export([init/1, handle_call/3, handle_cast/2, handle_info/2, - terminate/2, code_change/3]). +-export([init/1, + handle_call/3, + handle_cast/2, + handle_info/2, + terminate/2, + code_change/3]). -record(state, {user_db = []}). @@ -46,6 +53,9 @@ start_link() -> register_user(User, Cm) -> gen_server:cast(?MODULE, {register, {User, Cm}}). +delete_user(Cm) -> + gen_server:cast(?MODULE, {delete, Cm}). + lookup_user(Cm) -> gen_server:call(?MODULE, {get_user, Cm}, infinity). @@ -82,9 +92,10 @@ handle_call({get_user, Cm}, _From, #state{user_db = Db} = State) -> %% {stop, Reason, State} %% Description: Handling cast messages %%-------------------------------------------------------------------- -handle_cast({register, UserCm}, State0) -> - State = insert(UserCm, State0), - {noreply, State}. +handle_cast({register, UserCm}, State) -> + {noreply, insert(UserCm, State)}; +handle_cast({delete, UserCm}, State) -> + {noreply, delete(UserCm, State)}. %%-------------------------------------------------------------------- %% Function: handle_info(Info, State) -> {noreply, State} | @@ -118,6 +129,9 @@ code_change(_OldVsn, State, _Extra) -> insert({User, Cm}, #state{user_db = Db} = State) -> State#state{user_db = [{User, Cm} | Db]}. +delete(Cm, #state{user_db = Db} = State) -> + State#state{user_db = lists:keydelete(Cm, 2, Db)}. + lookup(_, []) -> undefined; lookup(Cm, [{User, Cm} | _Rest]) -> diff --git a/lib/ssh/vsn.mk b/lib/ssh/vsn.mk index 51f9f47446..d0861b3ddc 100644 --- a/lib/ssh/vsn.mk +++ b/lib/ssh/vsn.mk @@ -1,5 +1,5 @@ #-*-makefile-*- ; force emacs to enter makefile-mode -SSH_VSN = 2.0.4 +SSH_VSN = 2.0.6 APP_VSN = "ssh-$(SSH_VSN)" diff --git a/lib/ssl/doc/src/ssl.xml b/lib/ssl/doc/src/ssl.xml index cd5c9281cd..0da6bbee5b 100644 --- a/lib/ssl/doc/src/ssl.xml +++ b/lib/ssl/doc/src/ssl.xml @@ -53,13 +53,11 @@ <p>The following data types are used in the functions below: </p> - <p><c>boolean() = true | false</c></p> - - <p><c>property() = atom()</c></p> - + <p><c>boolean() = true | false</c></p> + <p><c>option() = socketoption() | ssloption() | transportoption()</c></p> - <p><c>socketoption() = [{property(), term()}] - defaults to + <p><c>socketoption() = proplists:property() - The default socket options are [{mode,list},{packet, 0},{header, 0},{active, true}]. </c></p> @@ -266,7 +264,7 @@ fun(OtpCert :: #'OTPCertificate'{}, Event :: {bad_cert, Reason :: atom()} | <p>Possible path validation errors: </p> -<p> {bad_cert, cert_expired}, {bad_cert, invalid_issuer}, {bad_cert, invalid_signature}, {bad_cert, unknown_ca}, {bad_cert, name_not_permitted}, {bad_cert, missing_basic_constraint}, {bad_cert, invalid_key_usage}</p> +<p> {bad_cert, cert_expired}, {bad_cert, invalid_issuer}, {bad_cert, invalid_signature}, {bad_cert, unknown_ca},{bad_cert, selfsigned_peer}, {bad_cert, name_not_permitted}, {bad_cert, missing_basic_constraint}, {bad_cert, invalid_key_usage}</p> </item> <tag>{hibernate_after, integer()|undefined}</tag> @@ -488,7 +486,7 @@ fun(OtpCert :: #'OTPCertificate'{}, Event :: {bad_cert, Reason :: atom()} | <fsummary>Get the value of the specified options.</fsummary> <type> <v>Socket = sslsocket()</v> - <v>OptionNames = [property()]</v> + <v>OptionNames = [atom()]</v> </type> <desc> <p>Get the value of the specified socket options, if no @@ -583,7 +581,7 @@ fun(OtpCert :: #'OTPCertificate'{}, Event :: {bad_cert, Reason :: atom()} | <fsummary>Write data to a socket.</fsummary> <type> <v>Socket = sslsocket()</v> - <v>Data = iolist() | binary()</v> + <v>Data = iodata()</v> </type> <desc> <p>Writes <c>Data</c> to <c>Socket</c>. </p> diff --git a/lib/ssl/examples/certs/Makefile b/lib/ssl/examples/certs/Makefile index b811b461dc..a4f067ade6 100644 --- a/lib/ssl/examples/certs/Makefile +++ b/lib/ssl/examples/certs/Makefile @@ -57,5 +57,5 @@ release_spec: opt $(INSTALL_DIR) $(RELSYSDIR)/examples/certs tar cf - etc | \ (cd $(RELSYSDIR)/examples/certs; tar xf -) - chmod -f -R ug+rw $(RELSYSDIR)/examples + chmod -R ug+rw $(RELSYSDIR)/examples release_docs_spec: diff --git a/lib/ssl/examples/src/Makefile b/lib/ssl/examples/src/Makefile index 46c0507b3a..ae5881d49b 100644 --- a/lib/ssl/examples/src/Makefile +++ b/lib/ssl/examples/src/Makefile @@ -66,7 +66,7 @@ release_spec: opt $(INSTALL_DIR) $(RELSYSDIR)/examples/src $(INSTALL_DIR) $(RELSYSDIR)/examples/ebin (cd ..; tar cf - src ebin | (cd $(RELSYSDIR)/examples; tar xf -)) - chmod -f -R ug+w $(RELSYSDIR)/examples + chmod -R ug+w $(RELSYSDIR)/examples release_docs_spec: diff --git a/lib/ssl/src/ssl.appup.src b/lib/ssl/src/ssl.appup.src index d3e426f254..a0ecb4ac6f 100644 --- a/lib/ssl/src/ssl.appup.src +++ b/lib/ssl/src/ssl.appup.src @@ -1,6 +1,7 @@ %% -*- erlang -*- {"%VSN%", [ + {"4.1.4", [{restart_application, ssl}]}, {"4.1.3", [{restart_application, ssl}]}, {"4.1.2", [{restart_application, ssl}]}, {"4.1.1", [{restart_application, ssl}]}, @@ -8,6 +9,7 @@ {"4.0.1", [{restart_application, ssl}]} ], [ + {"4.1.4", [{restart_application, ssl}]}, {"4.1.3", [{restart_application, ssl}]}, {"4.1.2", [{restart_application, ssl}]}, {"4.1.1", [{restart_application, ssl}]}, diff --git a/lib/ssl/src/ssl.erl b/lib/ssl/src/ssl.erl index 3512e194bc..380c59b058 100644 --- a/lib/ssl/src/ssl.erl +++ b/lib/ssl/src/ssl.erl @@ -50,15 +50,13 @@ cb %% Callback info }). -type option() :: socketoption() | ssloption() | transportoption(). --type socketoption() :: [{property(), term()}]. %% See gen_tcp and inet --type property() :: atom(). - +-type socketoption() :: term(). %% See gen_tcp and inet, import spec later when there is one to import -type ssloption() :: {verify, verify_type()} | {verify_fun, {fun(), InitialUserState::term()}} | {fail_if_no_peer_cert, boolean()} | {depth, integer()} | - {cert, der_encoded()} | {certfile, path()} | {key, der_encoded()} | - {keyfile, path()} | {password, string()} | {cacerts, [der_encoded()]} | - {cacertfile, path()} | {dh, der_encoded()} | {dhfile, path()} | + {cert, Der::binary()} | {certfile, path()} | {key, Der::binary()} | + {keyfile, path()} | {password, string()} | {cacerts, [Der::binary()]} | + {cacertfile, path()} | {dh, Der::binary()} | {dhfile, path()} | {ciphers, ciphers()} | {ssl_imp, ssl_imp()} | {reuse_sessions, boolean()} | {reuse_session, fun()} | {hibernate_after, integer()|undefined}. @@ -265,7 +263,7 @@ close(Socket = #sslsocket{}) -> ssl_broker:close(Socket). %%-------------------------------------------------------------------- --spec send(#sslsocket{}, iolist()) -> ok | {error, reason()}. +-spec send(#sslsocket{}, iodata()) -> ok | {error, reason()}. %% %% Description: Sends data over the ssl connection %%-------------------------------------------------------------------- @@ -404,9 +402,9 @@ cipher_suites(openssl) -> [ssl_cipher:openssl_suite_name(S) || S <- ssl_cipher:suites(Version)]. %%-------------------------------------------------------------------- --spec getopts(#sslsocket{}, [atom()]) -> {ok, [{atom(), term()}]}| {error, reason()}. +-spec getopts(#sslsocket{}, [atom()]) -> {ok, [{atom(), term()}]} | {error, reason()}. %% -%% Description: +%% Description: Gets options %%-------------------------------------------------------------------- getopts(#sslsocket{fd = new_ssl, pid = Pid}, OptTags) when is_pid(Pid) -> ssl_connection:get_opts(Pid, OptTags); @@ -417,9 +415,9 @@ getopts(#sslsocket{} = Socket, Options) -> ssl_broker:getopts(Socket, Options). %%-------------------------------------------------------------------- --spec setopts(#sslsocket{}, [{atom(), term()}]) -> ok | {error, reason()}. +-spec setopts(#sslsocket{}, [proplist:property()]) -> ok | {error, reason()}. %% -%% Description: +%% Description: Sets options %%-------------------------------------------------------------------- setopts(#sslsocket{fd = new_ssl, pid = Pid}, Opts0) when is_pid(Pid) -> Opts = proplists:expand([{binary, [{mode, binary}]}, diff --git a/lib/ssl/src/ssl_connection.erl b/lib/ssl/src/ssl_connection.erl index 574e1e9468..0a86e9bd29 100644 --- a/lib/ssl/src/ssl_connection.erl +++ b/lib/ssl/src/ssl_connection.erl @@ -107,12 +107,14 @@ %%==================================================================== %%-------------------------------------------------------------------- --spec send(pid(), iolist()) -> ok | {error, reason()}. +-spec send(pid(), iodata()) -> ok | {error, reason()}. %% %% Description: Sends data over the ssl connection %%-------------------------------------------------------------------- send(Pid, Data) -> sync_send_all_state_event(Pid, {application_data, + %% iolist_to_binary should really + %% be called iodata_to_binary() erlang:iolist_to_binary(Data)}, infinity). %%-------------------------------------------------------------------- diff --git a/lib/ssl/src/ssl_handshake.hrl b/lib/ssl/src/ssl_handshake.hrl index 8ae4d2332e..fb0ebac7d1 100644 --- a/lib/ssl/src/ssl_handshake.hrl +++ b/lib/ssl/src/ssl_handshake.hrl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2007-2010. All Rights Reserved. +%% Copyright Ericsson AB 2007-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 @@ -29,9 +29,8 @@ -include_lib("public_key/include/public_key.hrl"). -type algo_oid() :: ?'rsaEncryption' | ?'id-dsa'. --type public_key() :: #'RSAPublicKey'{} | integer(). -type public_key_params() :: #'Dss-Parms'{} | term(). --type public_key_info() :: {algo_oid(), public_key(), public_key_params()}. +-type public_key_info() :: {algo_oid(), #'RSAPublicKey'{} | integer() , public_key_params()}. -record(session, { session_id, diff --git a/lib/ssl/test/Makefile b/lib/ssl/test/Makefile index fd3b6d06ad..53b2223035 100644 --- a/lib/ssl/test/Makefile +++ b/lib/ssl/test/Makefile @@ -128,7 +128,7 @@ release_tests_spec: opt $(INSTALL_DIR) $(RELSYSDIR) $(INSTALL_DATA) $(ERL_FILES) $(HRL_FILES) $(HRL_FILES_NEEDED_IN_TEST) $(COVER_FILE) $(RELSYSDIR) $(INSTALL_DATA) ssl.spec ssl.cover $(RELSYSDIR) - chmod -f -R u+w $(RELSYSDIR) + chmod -R u+w $(RELSYSDIR) @tar cf - *_SUITE_data | (cd $(RELSYSDIR); tar xf -) release_docs_spec: diff --git a/lib/ssl/vsn.mk b/lib/ssl/vsn.mk index 2f1edfa186..0e80e42637 100644 --- a/lib/ssl/vsn.mk +++ b/lib/ssl/vsn.mk @@ -1 +1 @@ -SSL_VSN = 4.1.4 +SSL_VSN = 4.1.5 diff --git a/lib/stdlib/doc/src/binary.xml b/lib/stdlib/doc/src/binary.xml index c5eb81a86a..c81023862e 100644 --- a/lib/stdlib/doc/src/binary.xml +++ b/lib/stdlib/doc/src/binary.xml @@ -485,7 +485,7 @@ <code> 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>> </code> diff --git a/lib/stdlib/doc/src/dict.xml b/lib/stdlib/doc/src/dict.xml index 40e61d7d33..0cc76e0c78 100644 --- a/lib/stdlib/doc/src/dict.xml +++ b/lib/stdlib/doc/src/dict.xml @@ -55,10 +55,8 @@ dictionary() </type> <desc> <p>This function appends a new <c>Value</c> to the current list - of values associated with <c>Key</c>. An exception is - generated if the initial value associated with <c>Key</c> is - not a list of values.</p> - </desc> + of values associated with <c>Key</c>.</p> + </desc> </func> <func> <name>append_list(Key, ValList, Dict1) -> Dict2</name> diff --git a/lib/stdlib/doc/src/supervisor.xml b/lib/stdlib/doc/src/supervisor.xml index 45fa0847a8..d6203bdaa0 100644 --- a/lib/stdlib/doc/src/supervisor.xml +++ b/lib/stdlib/doc/src/supervisor.xml @@ -4,7 +4,7 @@ <erlref> <header> <copyright> - <year>1996</year><year>2010</year> + <year>1996</year><year>2011</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> @@ -83,11 +83,17 @@ supervisor, where all child processes are dynamically added instances of the same process type, i.e. running the same code.</p> - <p>The functions <c>terminate_child/2</c>, <c>delete_child/2</c> + <p>The functions <c>delete_child/2</c> and <c>restart_child/2</c> are invalid for <c>simple_one_for_one</c> supervisors and will return <c>{error,simple_one_for_one}</c> if the specified supervisor uses this restart strategy.</p> + <p>The function <c>terminate_child/2</c> can be used for + children under <c>simple_one_for_one</c> supervisors by + giving the child's <c>pid()</c> as the second argument. If + instead the child specification identifier is used, + <c>terminate_child/2</c> will return + <c>{error,simple_one_for_one}</c>.</p> </item> </list> <p>To prevent a supervisor from getting into an infinite loop of @@ -311,24 +317,33 @@ child_spec() = {Id,StartFunc,Restart,Shutdown,Type,Modules} <type> <v>SupRef = Name | {Name,Node} | {global,Name} | pid()</v> <v> Name = Node = atom()</v> - <v>Id = term()</v> + <v>Id = pid() | term()</v> <v>Result = ok | {error,Error}</v> <v> Error = not_found | simple_one_for_one</v> </type> <desc> - <p>Tells the supervisor <c>SupRef</c> to terminate the child - process corresponding to the child specification identified - by <c>Id</c>. The process, if there is one, is terminated but - the child specification is kept by the supervisor. This means - that the child process may be later be restarted by - the supervisor. The child process can also be restarted - explicitly by calling <c>restart_child/2</c>. Use - <c>delete_child/2</c> to remove the child specification.</p> + <p>Tells the supervisor <c>SupRef</c> to terminate the given + child.</p> + <p>If the supervisor is not <c>simple_one_for_one</c>, + <c>Id</c> must be the child specification identifier. The + process, if there is one, is terminated but the child + specification is kept by the supervisor. The child process + may later be restarted by the supervisor. The child process + can also be restarted explicitly by calling + <c>restart_child/2</c>. Use <c>delete_child/2</c> to remove + the child specification.</p> + <p>If the supervisor is <c>simple_one_for_one</c>, <c>Id</c> + must be the child process' <c>pid()</c>. I the specified + process is alive, but is not a child of the given + supervisor, the function will return + <c>{error,not_found}</c>. If the child specification + identifier is given instead instead of a <c>pid()</c>, the + function will return <c>{error,simple_one_for_one}</c>.</p> + <p>If successful, the function returns <c>ok</c>. If there is + no child specification with the specified <c>Id</c>, the + function returns <c>{error,not_found}</c>.</p> <p>See <c>start_child/2</c> for a description of <c>SupRef</c>.</p> - <p>If successful, the function returns <c>ok</c>. If there is - no child specification with the specified <c>Id</c>, - the function returns <c>{error,not_found}</c>.</p> </desc> </func> <func> diff --git a/lib/stdlib/doc/src/unicode.xml b/lib/stdlib/doc/src/unicode.xml index e3a25a407b..cb1cfa8ed0 100644 --- a/lib/stdlib/doc/src/unicode.xml +++ b/lib/stdlib/doc/src/unicode.xml @@ -164,10 +164,16 @@ latin1_charlist() = [latin1_char() | latin1_binary() | latin1_charlist()] <item>Integers out of range - If <c>InEncoding</c> is <c>latin1</c>, an error occurs whenever an integer greater than 255 is found in the lists. If <c>InEncoding</c> is - of a Unicode type, error occurs whenever an integer greater than - <c>16#10FFFF</c> (the maximum unicode character) or in the - range <c>16#D800</c> to <c>16#DFFF</c> (invalid unicode - range) is found.</item> + of a Unicode type, an error occurs whenever an integer + <list type="bulleted"> + <item>greater than <c>16#10FFFF</c> + (the maximum unicode character),</item> + <item>in the range <c>16#D800</c> to <c>16#DFFF</c> + (invalid unicode range)</item> + <item>or equal to 16#FFFE or 16#FFFF (non characters)</item> + </list> + is found. + </item> <item>UTF encoding incorrect - If <c>InEncoding</c> is one of the UTF types, the bytes in any binaries have to be valid diff --git a/lib/stdlib/doc/src/zip.xml b/lib/stdlib/doc/src/zip.xml index 4d98a20206..529a70a23d 100644 --- a/lib/stdlib/doc/src/zip.xml +++ b/lib/stdlib/doc/src/zip.xml @@ -34,11 +34,11 @@ <module>zip</module> <modulesummary>Utility for reading and creating 'zip' archives.</modulesummary> <description> - <p>The <c>zip</c> module archives and extract files to and from a zip + <p>The <c>zip</c> module archives and extracts files to and from a zip archive. The zip format is specified by the "ZIP Appnote.txt" file available on PKWare's website www.pkware.com.</p> <p>The zip module supports zip archive versions up to 6.1. However, - password-protection and Zip64 is not supported.</p> + password-protection and Zip64 are not supported.</p> <p>By convention, the name of a zip file should end in "<c>.zip</c>". To abide to the convention, you'll need to add "<c>.zip</c>" yourself to the name.</p> @@ -52,7 +52,7 @@ <seealso marker="#unzip_2">unzip/2</seealso> function. (They are also available as <c>extract</c>.)</p> <p>To fold a function over all files in a zip archive, use the - <seealso marker="#foldl_3">foldl_3</seealso>.</p> + <seealso marker="#foldl_3">foldl_3</seealso> function.</p> <p>To return a list of the files in a zip archive, use the <seealso marker="#list_dir_1">list_dir/1</seealso> or the <seealso marker="#list_dir_2">list_dir/2</seealso> function. (They @@ -155,13 +155,13 @@ zip_file() </code> <p>Files will be compressed using the DEFLATE compression, as described in the Appnote.txt file. However, files will be stored without compression if they already are compressed. - The <c>zip/2</c> and <c>zip/3</c> checks the file extension + The <c>zip/2</c> and <c>zip/3</c> functions check the file extension to see whether the file should be stored without compression. Files with the following extensions are not compressed: <c>.Z</c>, <c>.zip</c>, <c>.zoo</c>, <c>.arc</c>, <c>.lzh</c>, <c>.arj</c>.</p> <p>It is possible to override the default behavior and - explicitly control what types of files that should be + explicitly control what types of files should be compressed by using the <c>{compress, What}</c> and <c>{uncompress, What}</c> options. It is possible to have several <c>compress</c> and <c>uncompress</c> options. In @@ -208,7 +208,7 @@ zip_file() </code> </item> <tag><c>{compress, What}</c></tag> <item> - <p>Controls what types of files that will be + <p>Controls what types of files will be compressed. It is by default set to <c>all</c>. The following values of <c>What</c> are allowed:</p> <taglist> @@ -228,7 +228,7 @@ zip_file() </code> </item> <tag><c>{uncompress, What}</c></tag> <item> - <p>Controls what types of files that will be uncompressed. It is by + <p>Controls what types of files will be uncompressed. It is by default set to <c>[".Z",".zip",".zoo",".arc",".lzh",".arj"]</c>. The following values of <c>What</c> are allowed:</p> <taglist> @@ -292,7 +292,7 @@ zip_file() </code> <p>By default, the <c>open/2</c> function will open the zip file in <c>raw</c> mode, which is faster but does not allow a remote (erlang) file server to be used. Adding <c>cooked</c> - to the mode list will override the default and open zip file + to the mode list will override the default and open the zip file without the <c>raw</c> option. The same goes for the files extracted.</p> </item> @@ -301,7 +301,7 @@ zip_file() </code> <p>By default, all existing files with the same name as file in the zip archive will be overwritten. With the <c>keep_old_files</c> option, the <c>unzip/2</c> function will not overwrite any existing - files. Not that even with the <c>memory</c> option given, which + files. Note that even with the <c>memory</c> option given, which means that no files will be overwritten, files existing will be excluded from the result.</p> </item> @@ -418,7 +418,7 @@ zip_file() </code> <p>By default, the <c>open/2</c> function will open the zip file in <c>raw</c> mode, which is faster but does not allow a remote (erlang) file server to be used. Adding <c>cooked</c> - to the mode list will override the default and open zip file + to the mode list will override the default and open the zip file without the <c>raw</c> option.</p> </item> </taglist> diff --git a/lib/stdlib/src/erl_parse.yrl b/lib/stdlib/src/erl_parse.yrl index bb4b18cf9b..15b45d72f4 100644 --- a/lib/stdlib/src/erl_parse.yrl +++ b/lib/stdlib/src/erl_parse.yrl @@ -2,7 +2,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 @@ -757,7 +757,8 @@ record_fields([{typed,Expr,TypeInfo}|Fields]) -> {atom, La, _} -> case has_undefined(TypeInfo) of false -> - lift_unions(abstract(undefined, La), TypeInfo); + TypeInfo2 = maybe_add_paren(TypeInfo), + lift_unions(abstract(undefined, La), TypeInfo2); true -> TypeInfo end @@ -778,6 +779,11 @@ has_undefined({type,_,union,Ts}) -> has_undefined(_) -> false. +maybe_add_paren({ann_type,L,T}) -> + {paren_type,L,[{ann_type,L,T}]}; +maybe_add_paren(T) -> + T. + term(Expr) -> try normalise(Expr) catch _:_R -> ret_err(?line(Expr), "bad attribute") diff --git a/lib/stdlib/src/erl_pp.erl b/lib/stdlib/src/erl_pp.erl index df4a20b833..66c80a45cb 100644 --- a/lib/stdlib/src/erl_pp.erl +++ b/lib/stdlib/src/erl_pp.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 @@ -558,17 +558,11 @@ record_field({typed_record_field,{record_field,_,F,Val},Type}, Hook) -> Fl = lexpr(F, L, Hook), Vl = typed(lexpr(Val, R, Hook), Type), {list,[{cstep,[Fl,' ='],Vl}]}; -record_field({typed_record_field,Field,Type0}, Hook) -> - Type = remove_undefined(Type0), +record_field({typed_record_field,Field,Type}, Hook) -> typed(record_field(Field, Hook), Type); record_field({record_field,_,F}, Hook) -> lexpr(F, 0, Hook). -remove_undefined({type,L,union,[{atom,_,undefined}|T]}) -> - {type,L,union,T}; -remove_undefined(T) -> % cannot happen - T. - list({cons,_,H,T}, Es, Hook) -> list(T, [H|Es], Hook); list({nil,_}, Es, Hook) -> diff --git a/lib/stdlib/src/gen.erl b/lib/stdlib/src/gen.erl index 43df6f621d..574146b1cd 100644 --- a/lib/stdlib/src/gen.erl +++ b/lib/stdlib/src/gen.erl @@ -29,6 +29,8 @@ -export([init_it/6, init_it/7]). +-export([format_status_header/2]). + -define(default_timeout, 5000). %%----------------------------------------------------------------- @@ -315,3 +317,10 @@ debug_options(Opts) -> {ok, Options} -> sys:debug_options(Options); _ -> [] end. + +format_status_header(TagLine, Pid) when is_pid(Pid) -> + lists:concat([TagLine, " ", pid_to_list(Pid)]); +format_status_header(TagLine, RegName) when is_atom(RegName) -> + lists:concat([TagLine, " ", RegName]); +format_status_header(TagLine, Name) -> + {TagLine, Name}. diff --git a/lib/stdlib/src/gen_event.erl b/lib/stdlib/src/gen_event.erl index b1e9e3a02f..b00910771f 100644 --- a/lib/stdlib/src/gen_event.erl +++ b/lib/stdlib/src/gen_event.erl @@ -724,7 +724,8 @@ get_modules(MSL) -> %%----------------------------------------------------------------- format_status(Opt, StatusData) -> [PDict, SysState, Parent, _Debug, [ServerName, MSL, _Hib]] = StatusData, - Header = lists:concat(["Status for event handler ", ServerName]), + Header = gen:format_status_header("Status for event handler", + ServerName), FmtMSL = [case erlang:function_exported(Mod, format_status, 2) of true -> Args = [PDict, State], diff --git a/lib/stdlib/src/gen_fsm.erl b/lib/stdlib/src/gen_fsm.erl index 7d9960b912..f2f1365d3d 100644 --- a/lib/stdlib/src/gen_fsm.erl +++ b/lib/stdlib/src/gen_fsm.erl @@ -614,15 +614,8 @@ get_msg(Msg) -> Msg. format_status(Opt, StatusData) -> [PDict, SysState, Parent, Debug, [Name, StateName, StateData, Mod, _Time]] = StatusData, - StatusHdr = "Status for state machine", - Header = if - is_pid(Name) -> - lists:concat([StatusHdr, " ", pid_to_list(Name)]); - is_atom(Name); is_list(Name) -> - lists:concat([StatusHdr, " ", Name]); - true -> - {StatusHdr, Name} - end, + Header = gen:format_status_header("Status for state machine", + Name), Log = sys:get_debug(log, Debug, []), DefaultStatus = [{data, [{"StateData", StateData}]}], Specfic = diff --git a/lib/stdlib/src/gen_server.erl b/lib/stdlib/src/gen_server.erl index ac81df9cab..09d94a9c40 100644 --- a/lib/stdlib/src/gen_server.erl +++ b/lib/stdlib/src/gen_server.erl @@ -840,15 +840,8 @@ name_to_pid(Name) -> %%----------------------------------------------------------------- format_status(Opt, StatusData) -> [PDict, SysState, Parent, Debug, [Name, State, Mod, _Time]] = StatusData, - StatusHdr = "Status for generic server", - Header = if - is_pid(Name) -> - lists:concat([StatusHdr, " ", pid_to_list(Name)]); - is_atom(Name); is_list(Name) -> - lists:concat([StatusHdr, " ", Name]); - true -> - {StatusHdr, Name} - end, + Header = gen:format_status_header("Status for generic server", + Name), Log = sys:get_debug(log, Debug, []), DefaultStatus = [{data, [{"State", State}]}], Specfic = diff --git a/lib/stdlib/src/log_mf_h.erl b/lib/stdlib/src/log_mf_h.erl index 2729f27e51..5fa5360fa1 100644 --- a/lib/stdlib/src/log_mf_h.erl +++ b/lib/stdlib/src/log_mf_h.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 @@ -185,13 +185,19 @@ read_index_file(Dir) -> %%----------------------------------------------------------------- %% Write the index file. This file contains one binary with %% the last used filename (an integer). +%% Write a temporary file and rename it in order to make the update +%% atomic. %%----------------------------------------------------------------- write_index_file(Dir, Index) -> - case file:open(Dir ++ "/index", [raw, write]) of + File = Dir ++ "/index", + TmpFile = File ++ ".tmp", + case file:open(TmpFile, [raw, write]) of {ok, Fd} -> - file:write(Fd, [Index]), - ok = file:close(Fd); + ok = file:write(Fd, [Index]), + ok = file:close(Fd), + ok = file:rename(TmpFile,File), + ok; _ -> exit(open_index_file) end. diff --git a/lib/stdlib/src/pool.erl b/lib/stdlib/src/pool.erl index 7f5f23e26d..a3c9927ee9 100644 --- a/lib/stdlib/src/pool.erl +++ b/lib/stdlib/src/pool.erl @@ -95,6 +95,9 @@ pspawn_link(M, F, A) -> start_nodes([], _, _) -> []; start_nodes([Host|Tail], Name, Args) -> case slave:start(Host, Name, Args) of + {error, {already_running, Node}} -> + io:format("Can't start node on host ~w due to ~w~n",[Host, {already_running, Node}]), + [Node | start_nodes(Tail, Name, Args)]; {error, R} -> io:format("Can't start node on host ~w due to ~w~n",[Host, R]), start_nodes(Tail, Name, Args); diff --git a/lib/stdlib/src/supervisor.erl b/lib/stdlib/src/supervisor.erl index 3c5800effa..4fd7f1d47c 100644 --- a/lib/stdlib/src/supervisor.erl +++ b/lib/stdlib/src/supervisor.erl @@ -138,7 +138,7 @@ delete_child(Supervisor, Name) -> %%----------------------------------------------------------------- -type term_err() :: 'not_found' | 'simple_one_for_one'. --spec terminate_child(sup_ref(), term()) -> 'ok' | {'error', term_err()}. +-spec terminate_child(sup_ref(), pid() | term()) -> 'ok' | {'error', term_err()}. terminate_child(Supervisor, Name) -> call(Supervisor, {terminate_child, Name}). @@ -297,8 +297,26 @@ handle_call({start_child, EArgs}, _From, State) when ?is_simple(State) -> {reply, What, State} end; -%%% The requests terminate_child, delete_child and restart_child are -%%% invalid for simple_one_for_one supervisors. +%% terminate_child for simple_one_for_one can only be done with pid +handle_call({terminate_child, Name}, _From, State) when not is_pid(Name), + ?is_simple(State) -> + {reply, {error, simple_one_for_one}, State}; + +handle_call({terminate_child, Name}, _From, State) -> + case get_child(Name, State, ?is_simple(State)) of + {value, Child} -> + case do_terminate(Child, State#state.name) of + #child{restart_type=RT} when RT=:=temporary; ?is_simple(State) -> + {reply, ok, state_del_child(Child, State)}; + NChild -> + {reply, ok, replace_child(NChild, State)} + end; + false -> + {reply, {error, not_found}, State} + end; + +%%% The requests delete_child and restart_child are invalid for +%%% simple_one_for_one supervisors. handle_call({_Req, _Data}, _From, State) when ?is_simple(State) -> {reply, {error, simple_one_for_one}, State}; @@ -341,15 +359,6 @@ handle_call({delete_child, Name}, _From, State) -> {reply, {error, not_found}, State} end; -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)}; - _ -> - {reply, {error, not_found}, State} - end; - handle_call(which_children, _From, #state{children = [#child{restart_type = temporary, child_type = CT, modules = Mods}]} = @@ -817,8 +826,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]) -> @@ -841,7 +854,28 @@ split_child(_, [], After) -> {lists:reverse(After), []}. get_child(Name, State) -> + get_child(Name, State, false). +get_child(Pid, State, AllowPid) when AllowPid, is_pid(Pid) -> + get_dynamic_child(Pid, State); +get_child(Name, State, _) -> lists:keysearch(Name, #child.name, State#state.children). + +get_dynamic_child(Pid, #state{children=[Child], dynamics=Dynamics}) -> + case is_dynamic_pid(Pid, dynamics_db(Child#child.restart_type, Dynamics)) of + true -> + {value, Child#child{pid=Pid}}; + false -> + case erlang:is_process_alive(Pid) of + true -> false; + false -> {value, Child} + end + end. + +is_dynamic_pid(Pid, Dynamics) when is_list(Dynamics) -> + lists:member(Pid, Dynamics); +is_dynamic_pid(Pid, Dynamics) -> + dict:is_key(Pid, Dynamics). + replace_child(Child, State) -> Chs = do_replace_child(Child, State#state.children), State#state{children = Chs}. diff --git a/lib/stdlib/test/Makefile b/lib/stdlib/test/Makefile index 3dd0a91870..5502c69fa5 100644 --- a/lib/stdlib/test/Makefile +++ b/lib/stdlib/test/Makefile @@ -135,7 +135,7 @@ release_tests_spec: make_emakefile $(INSTALL_DIR) $(RELSYSDIR) $(INSTALL_DATA) stdlib.spec $(EMAKEFILE) \ $(ERL_FILES) $(COVERFILE) $(RELSYSDIR) - chmod -f -R u+w $(RELSYSDIR) + chmod -R u+w $(RELSYSDIR) @tar cf - *_SUITE_data | (cd $(RELSYSDIR); tar xf -) release_docs_spec: diff --git a/lib/stdlib/test/erl_eval_SUITE.erl b/lib/stdlib/test/erl_eval_SUITE.erl index 6b2eb78e2c..4b59cee99e 100644 --- a/lib/stdlib/test/erl_eval_SUITE.erl +++ b/lib/stdlib/test/erl_eval_SUITE.erl @@ -571,6 +571,17 @@ otp_5269(Config) when is_list(Config) -> B:A>> <- [<<16:8,19:16>>], <<X:8>> <- [<<B:8>>]].", [19]), + ?line check(fun() -> + (fun (<<A:1/binary, B:8/integer, _C:B/binary>>) -> + case A of + B -> wrong; + _ -> ok + end + end)(<<1,2,3,4>>) end, + "(fun(<<A:1/binary, B:8/integer, _C:B/binary>>) ->" + " case A of B -> wrong; _ -> ok end" + " end)(<<1, 2, 3, 4>>).", + ok), ok. otp_6539(doc) -> diff --git a/lib/stdlib/test/erl_pp_SUITE.erl b/lib/stdlib/test/erl_pp_SUITE.erl index 822886cb8a..bc811355ab 100644 --- a/lib/stdlib/test/erl_pp_SUITE.erl +++ b/lib/stdlib/test/erl_pp_SUITE.erl @@ -48,7 +48,7 @@ neg_indent/1, otp_6321/1, otp_6911/1, otp_6914/1, otp_8150/1, otp_8238/1, - otp_8473/1, otp_8522/1, otp_8567/1, otp_8664/1]). + otp_8473/1, otp_8522/1, otp_8567/1, otp_8664/1, otp_9147/1]). %% Internal export. -export([ehook/6]). @@ -79,7 +79,7 @@ groups() -> {attributes, [], [misc_attrs, import_export]}, {tickets, [], [otp_6321, otp_6911, otp_6914, otp_8150, otp_8238, - otp_8473, otp_8522, otp_8567, otp_8664]}]. + otp_8473, otp_8522, otp_8567, otp_8664, otp_9147]}]. init_per_suite(Config) -> Config. @@ -1047,6 +1047,26 @@ otp_8664(Config) when is_list(Config) -> ok. +otp_9147(doc) -> + "OTP_9147. Create well-formed types when adding 'undefined'."; +otp_9147(suite) -> []; +otp_9147(Config) when is_list(Config) -> + FileName = filename('otp_9147.erl', Config), + C1 = <<"-module(otp_9147).\n" + "-export_type([undef/0]).\n" + "-record(undef, {f1 :: F1 :: a | b}).\n" + "-type undef() :: #undef{}.\n">>, + ?line ok = file:write_file(FileName, C1), + ?line {ok, _, []} = + compile:file(FileName, [return,'P',{outdir,?privdir}]), + PFileName = filename('otp_9147.P', Config), + ?line {ok, Bin} = file:read_file(PFileName), + %% The parentheses around "F1 :: a | b" are new (bugfix). + ?line true = + lists:member("-record(undef,{f1 :: undefined | (F1 :: a | b)}).", + string:tokens(binary_to_list(Bin), "\n")), + ok. + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% compile(Config, Tests) -> diff --git a/lib/stdlib/test/gen_event_SUITE.erl b/lib/stdlib/test/gen_event_SUITE.erl index 9e3e717e7d..b3a7edc140 100644 --- a/lib/stdlib/test/gen_event_SUITE.erl +++ b/lib/stdlib/test/gen_event_SUITE.erl @@ -25,13 +25,14 @@ -export([start/1, add_handler/1, add_sup_handler/1, delete_handler/1, swap_handler/1, swap_sup_handler/1, notify/1, sync_notify/1, call/1, info/1, hibernate/1, - call_format_status/1, error_format_status/1]). + call_format_status/1, call_format_status_anon/1, + error_format_status/1]). suite() -> [{ct_hooks,[ts_install_cth]}]. all() -> [start, {group, test_all}, hibernate, - call_format_status, error_format_status]. + call_format_status, call_format_status_anon, error_format_status]. groups() -> [{test_all, [], @@ -888,6 +889,22 @@ call_format_status(Config) when is_list(Config) -> ?line {"Installed handlers", [{_,dummy1_h,_,FmtState,_}]} = HandlerInfo2, ok. +call_format_status_anon(suite) -> + []; +call_format_status_anon(doc) -> + ["Test that sys:get_status/1,2 calls format_status/2 for anonymous gen_event processes"]; +call_format_status_anon(Config) when is_list(Config) -> + ?line {ok, Pid} = gen_event:start(), + %% The 'Name' of the gen_event process will be a pid() here, so + %% the next line will crash if format_status can't string-ify pids. + ?line Status1 = sys:get_status(Pid), + ?line ok = gen_event:stop(Pid), + Header = "Status for event handler " ++ pid_to_list(Pid), + ?line {status, Pid, _, [_, _, Pid, [], Data1]} = Status1, + ?line Header = proplists:get_value(header, Data1), + ok. + + error_format_status(suite) -> []; error_format_status(doc) -> diff --git a/lib/stdlib/test/supervisor_SUITE.erl b/lib/stdlib/test/supervisor_SUITE.erl index 6e927da2ab..cc271bd047 100644 --- a/lib/stdlib/test/supervisor_SUITE.erl +++ b/lib/stdlib/test/supervisor_SUITE.erl @@ -20,7 +20,8 @@ -module(supervisor_SUITE). --include_lib("test_server/include/test_server.hrl"). +-include_lib("common_test/include/ct.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), + ignore = start_link(ignore), + check_exit_reason(normal). - 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. - - -%------------------------------------------------------------------------- +%%------------------------------------------------------------------------- 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), + {error, Term} = start_link(invalid), + 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_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), + {error, {invalid_shutdown,infinity}} = + supervisor:start_child(sup_test, Child2), - ?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, - 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,124 @@ 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} = - supervisor:start_child(sup_test, Child), + {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), + + %% Terminate with Pid not allowed when not simple_one_for_one + {error,not_found} = supervisor:terminate_child(sup_test, CPid3), + [{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} = - supervisor:terminate_child(sup_test, child1), + {error, simple_one_for_one} = supervisor:terminate_child(sup_test, child1), + [1,2,0,2] = get_child_counts(sup_test), + ok = supervisor:terminate_child(sup_test,CPid1), + [_] = supervisor:which_children(sup_test), + [1,1,0,1] = get_child_counts(sup_test), + false = erlang:is_process_alive(CPid1), + %% Terminate non-existing proccess is ok + ok = supervisor:terminate_child(sup_test,CPid1), + [_] = supervisor:which_children(sup_test), + [1,1,0,1] = get_child_counts(sup_test), + %% Terminate pid which is not a child of this supervisor is not ok + NoChildPid = spawn_link(fun() -> receive after infinity -> ok end end), + {error, not_found} = supervisor:terminate_child(sup_test, NoChildPid), + true = erlang:is_process_alive(NoChildPid), %% Restart - ?line {error, simple_one_for_one} = - supervisor:restart_child(sup_test, child1), - + {error, simple_one_for_one} = supervisor:restart_child(sup_test, child1), + %% Deletion - ?line {error, simple_one_for_one} = - supervisor:delete_child(sup_test, child1), + {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 +455,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! %% <Modules> (last parameter in a child spec) can be [] as we do %% not test code upgrade here. @@ -560,327 +464,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 +726,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 +759,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 +786,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 +807,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 +856,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 +891,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 +926,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 +982,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 +1006,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 +1019,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 +1040,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 +1055,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 +1116,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 +1144,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. 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)]; diff --git a/lib/syntax_tools/test/Makefile b/lib/syntax_tools/test/Makefile index e793dec566..3e31bdbd50 100644 --- a/lib/syntax_tools/test/Makefile +++ b/lib/syntax_tools/test/Makefile @@ -60,6 +60,6 @@ release_tests_spec: make_emakefile $(INSTALL_DIR) $(RELSYSDIR) $(INSTALL_DATA) $(EMAKEFILE) $(ERL_FILES) $(RELSYSDIR) $(INSTALL_DATA) syntax_tools.spec syntax_tools.cover $(RELSYSDIR) - chmod -f -R u+w $(RELSYSDIR) + chmod -R u+w $(RELSYSDIR) release_docs_spec: diff --git a/lib/test_server/src/test_server.erl b/lib/test_server/src/test_server.erl index 7f0011bd68..591329b361 100644 --- a/lib/test_server/src/test_server.erl +++ b/lib/test_server/src/test_server.erl @@ -36,7 +36,7 @@ -export([capture_start/0,capture_stop/0,capture_get/0]). -export([messages_get/0]). -export([hours/1,minutes/1,seconds/1,sleep/1,adjusted_sleep/1,timecall/3]). --export([timetrap_scale_factor/0,timetrap/1,timetrap_cancel/1]). +-export([timetrap_scale_factor/0,timetrap/1,timetrap_cancel/1,timetrap_cancel/0]). -export([m_out_of_n/3,do_times/4,do_times/2]). -export([call_crash/3,call_crash/4,call_crash/5]). -export([temp_name/1]). @@ -1077,7 +1077,7 @@ run_test_case_eval(Mod, Func, Args0, Name, Ref, RunInit, {{Time,Value},Loc,Opts} = case test_server_sup:framework_call(init_tc,[?pl2a(Mod),Func,Args0], - {ok, Args0}) of + {ok,Args0}) of {ok,Args} -> run_test_case_eval1(Mod, Func, Args, Name, RunInit, TCCallback); Error = {error,_Reason} -> @@ -1085,18 +1085,17 @@ run_test_case_eval(Mod, Func, Args0, Name, Ref, RunInit, {skip,{failed,Error}}), {{0,NewResult},{Mod,Func},[]}; {fail,Reason} -> - [Conf] = Args0, - Conf1 = [{tc_status,{failed,Reason}} | Conf], + Conf = [{tc_status,{failed,Reason}} | hd(Args0)], fw_error_notify(Mod, Func, Conf, Reason), - NewResult = do_end_tc_call(Mod,Func, {{error,Reason},[Conf1]}, - {fail, Reason}), + NewResult = do_end_tc_call(Mod,Func, {{error,Reason},[Conf]}, + {fail,Reason}), {{0,NewResult},{Mod,Func},[]}; Skip = {skip,_Reason} -> NewResult = do_end_tc_call(Mod,Func,{Skip,Args0},Skip), {{0,NewResult},{Mod,Func},[]}; {auto_skip,Reason} -> NewResult = do_end_tc_call(Mod, Func, {{skip,Reason},Args0}, - {skip, {fw_auto_skip,Reason}}), + {skip,{fw_auto_skip,Reason}}), {{0,NewResult},{Mod,Func},[]} end, exit({Ref,Time,Value,Loc,Opts}). @@ -1116,9 +1115,15 @@ run_test_case_eval1(Mod, Func, Args, Name, RunInit, TCCallback) -> {skip_and_save,Reason,SaveCfg} -> Line = get_loc(), Conf = [{tc_status,{skipped,Reason}},{save_config,SaveCfg}], - NewRes = do_end_tc_call(Mod, Func, {{skip, Reason}, [Conf]}, + NewRes = do_end_tc_call(Mod, Func, {{skip,Reason},[Conf]}, {skip, Reason}), {{0,NewRes},Line,[]}; + FailTC = {fail,Reason} -> % user fails the testcase + EndConf = [{tc_status,{failed,Reason}} | hd(Args)], + fw_error_notify(Mod, Func, EndConf, Reason), + NewRes = do_end_tc_call(Mod, Func, {{error,Reason},[EndConf]}, + FailTC), + {{0,NewRes},{Mod,Func},[]}; {ok,NewConf} -> put(test_server_init_or_end_conf,undefined), %% call user callback function if defined @@ -1153,8 +1158,9 @@ run_test_case_eval1(Mod, Func, Args, Name, RunInit, TCCallback) -> {FWReturn1,TSReturn1,EndConf2} = case end_per_testcase(Mod, Func, EndConf1) of SaveCfg1={save_config,_} -> - {FWReturn,TSReturn,[SaveCfg1|lists:keydelete(save_config, 1, EndConf1)]}; - {fail,ReasonToFail} -> % user has failed the testcase + {FWReturn,TSReturn,[SaveCfg1|lists:keydelete(save_config,1, + EndConf1)]}; + {fail,ReasonToFail} -> % user has failed the testcase fw_error_notify(Mod, Func, EndConf1, ReasonToFail), {{error,ReasonToFail},{failed,ReasonToFail},EndConf1}; {failed,{_,end_per_testcase,_}} = Failure -> % unexpected termination @@ -1193,11 +1199,10 @@ run_test_case_eval1(Mod, Func, Args, Name, RunInit, TCCallback) -> do_end_tc_call(M,F,Res,Return) -> Ref = make_ref(), - case test_server_sup:framework_call( - end_tc, [?pl2a(M),F,Res], Ref) of - {fail,FWReason} -> - {failed,FWReason}; - Ref -> + case os:getenv("TEST_SERVER_FRAMEWORK") of + FW when FW == "ct_framework"; + FW == "undefined"; + FW == false -> case test_server_sup:framework_call( end_tc, [?pl2a(M),F,Res, Return], ok) of {fail,FWReason} -> @@ -1212,8 +1217,14 @@ do_end_tc_call(M,F,Res,Return) -> NewReturn -> NewReturn end; - _ -> - Return + Other -> + case test_server_sup:framework_call( + end_tc, [Other,F,Res], Ref) of + {fail,FWReason} -> + {failed,FWReason}; + _Else -> + Return + end end. %% the return value is a list and we have to check if it contains @@ -1296,7 +1307,7 @@ init_per_testcase(Mod, Func, Args) -> false -> code:load_file(Mod); _ -> ok end, -%% init_per_testcase defined, returns new configuration + %% init_per_testcase defined, returns new configuration case erlang:function_exported(Mod,init_per_testcase,2) of true -> case catch my_apply(Mod, init_per_testcase, [Func|Args]) of @@ -1316,6 +1327,8 @@ init_per_testcase(Mod, Func, Args) -> "bad elements in Config: ~p\n",[Bad]}, {skip,{failed,{Mod,init_per_testcase,bad_return}}} end; + {'$test_server_ok',Res={fail,_Reason}} -> + Res; {'$test_server_ok',_Other} -> group_leader() ! {printout,12, "ERROR! init_per_testcase did not return " @@ -1690,7 +1703,7 @@ fail() -> break(Comment) -> case erase(test_server_timetraps) of undefined -> ok; - List -> lists:foreach(fun(Ref) -> timetrap_cancel(Ref) end,List) + List -> lists:foreach(fun({Ref,_}) -> timetrap_cancel(Ref) end, List) end, io:format(user, "\n\n\n--- SEMIAUTOMATIC TESTING ---" @@ -1771,14 +1784,16 @@ timetrap(Timeout0) -> {undefined,false} -> timetrap1(Timeout, false); {undefined,_} -> timetrap1(Timeout, true); {infinity,_} -> infinity; + {_Int,_Scale} when Timeout == infinity -> infinity; {Int,Scale} -> timetrap1(Timeout*Int, Scale) end. timetrap1(Timeout, Scale) -> - Ref = spawn_link(test_server_sup,timetrap,[Timeout,Scale,self()]), + TCPid = self(), + Ref = spawn_link(test_server_sup,timetrap,[Timeout,Scale,TCPid]), case get(test_server_timetraps) of - undefined -> put(test_server_timetraps,[Ref]); - List -> put(test_server_timetraps,[Ref|List]) + undefined -> put(test_server_timetraps,[{Ref,TCPid}]); + List -> put(test_server_timetraps,[{Ref,TCPid}|List]) end, Ref. @@ -1791,14 +1806,16 @@ ensure_timetrap(Config) -> undefined -> ok; Garbage -> erase(test_server_default_timetrap), - format("=== WARNING: garbage in test_server_default_timetrap: ~p~n", + format("=== WARNING: garbage in " + "test_server_default_timetrap: ~p~n", [Garbage]) end, DTmo = case lists:keysearch(default_timeout,1,Config) of {value,{default_timeout,Tmo}} -> Tmo; _ -> ?DEFAULT_TIMETRAP_SECS end, - format("=== test_server setting default timetrap of ~p seconds~n", + format("=== test_server setting default " + "timetrap of ~p seconds~n", [DTmo]), put(test_server_default_timetrap, timetrap(seconds(DTmo))) end. @@ -1810,11 +1827,13 @@ cancel_default_timetrap() -> TimeTrap when is_pid(TimeTrap) -> timetrap_cancel(TimeTrap), erase(test_server_default_timetrap), - format("=== test_server canceled default timetrap since another timetrap was set~n"), + format("=== test_server canceled default timetrap " + "since another timetrap was set~n"), ok; Garbage -> erase(test_server_default_timetrap), - format("=== WARNING: garbage in test_server_default_timetrap: ~p~n", + format("=== WARNING: garbage in " + "test_server_default_timetrap: ~p~n", [Garbage]), error end. @@ -1828,6 +1847,7 @@ time_ms({Other,_N}) -> "Should be seconds, minutes, or hours.~n", [Other]), exit({invalid_time_spec,Other}); time_ms(Ms) when is_integer(Ms) -> Ms; +time_ms(infinity) -> infinity; time_ms(Other) -> exit({invalid_time_spec,Other}). @@ -1841,11 +1861,29 @@ timetrap_cancel(infinity) -> timetrap_cancel(Handle) -> case get(test_server_timetraps) of undefined -> ok; - [Handle] -> erase(test_server_timetraps); - List -> put(test_server_timetraps,lists:delete(Handle,List)) + [{Handle,_}] -> erase(test_server_timetraps); + Timers -> put(test_server_timetraps, + lists:keydelete(Handle, 1, Timers)) end, test_server_sup:timetrap_cancel(Handle). +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% timetrap_cancel() -> ok +%% +%% Cancels timetrap for current test case. +timetrap_cancel() -> + case get(test_server_timetraps) of + undefined -> + ok; + Timers -> + case lists:keysearch(self(), 2, Timers) of + {value,{Handle,_}} -> + timetrap_cancel(Handle); + _ -> + ok + end + end. + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% hours(N) -> Milliseconds %% minutes(N) -> Milliseconds diff --git a/lib/test_server/src/test_server_ctrl.erl b/lib/test_server/src/test_server_ctrl.erl index 30d7314058..de9b962dfc 100644 --- a/lib/test_server/src/test_server_ctrl.erl +++ b/lib/test_server/src/test_server_ctrl.erl @@ -1812,6 +1812,9 @@ start_log_file() -> ok = file:make_dir(PrivDir), put(test_server_priv_dir,PrivDir++"/"), print_timestamp(13,"Suite started at "), + + LogInfo = [{topdir,Dir},{rundir,lists:flatten(TestDir)}], + test_server_sup:framework_call(report, [loginfo,LogInfo]), ok. make_html_link(LinkName, Target, Explanation) -> @@ -1925,7 +1928,6 @@ html_convert_modules(TestSpec, _Config) -> copy_html_files(get(test_server_dir), get(test_server_log_dir_base)). %% Retrieve a list of modules out of the test spec. - html_isolate_modules(List) -> html_isolate_modules(List, sets:new()). html_isolate_modules([], Set) -> sets:to_list(Set); @@ -1939,37 +1941,56 @@ html_isolate_modules([{Mod,_Case,_Args}|Cases], Set) -> html_isolate_modules(Cases, sets:add_element(Mod, Set)). %% Given a list of modules, convert each module's source code to HTML. - html_convert_modules([Mod|Mods]) -> case code:which(Mod) of Path when is_list(Path) -> SrcFile = filename:rootname(Path) ++ ".erl", - DestDir = get(test_server_dir), - Name = atom_to_list(Mod), - DestFile = filename:join(DestDir, downcase(Name) ++ ?src_listing_ext), - html_possibly_convert(SrcFile, DestFile), - html_convert_modules(Mods); - _Other -> ok + FoundSrcFile = + case file:read_file_info(SrcFile) of + {ok,SInfo} -> + {SrcFile,SInfo}; + {error,_} -> + ModInfo = Mod:module_info(compile), + case proplists:get_value(source, ModInfo) of + undefined -> + undefined; + OtherSrcFile -> + case file:read_file_info(OtherSrcFile) of + {ok,SInfo} -> + {OtherSrcFile,SInfo}; + {error,_} -> + undefined + end + end + end, + case FoundSrcFile of + undefined -> + html_convert_modules(Mods); + {SrcFile1,SrcFileInfo} -> + DestDir = get(test_server_dir), + Name = atom_to_list(Mod), + DestFile = filename:join(DestDir, + downcase(Name)++?src_listing_ext), + html_possibly_convert(SrcFile1, SrcFileInfo, DestFile), + html_convert_modules(Mods) + end; + _Other -> + html_convert_modules(Mods) end; html_convert_modules([]) -> ok. %% Convert source code to HTML if possible and needed. - -html_possibly_convert(Src, Dest) -> - case file:read_file_info(Src) of - {ok,SInfo} -> - case file:read_file_info(Dest) of - {error,_Reason} -> % no dest file - erl2html2:convert(Src, Dest); - {ok,DInfo} when DInfo#file_info.mtime < SInfo#file_info.mtime -> - erl2html2:convert(Src, Dest); - {ok,_DInfo} -> ok % dest file up to date - end; - {error,_Reason} -> ok % no source code found +html_possibly_convert(Src, SrcInfo, Dest) -> + case file:read_file_info(Dest) of + {error,_Reason} -> % no dest file + erl2html2:convert(Src, Dest); + {ok,DestInfo} when DestInfo#file_info.mtime < SrcInfo#file_info.mtime -> + erl2html2:convert(Src, Dest); + {ok,_DestInfo} -> + ok % dest file up to date end. %% Copy all HTML files in InDir to OutDir. - copy_html_files(InDir, OutDir) -> Files = filelib:wildcard(filename:join(InDir, "*" ++ ?src_listing_ext)), lists:foreach(fun (Src) -> copy_html_file(Src, OutDir) end, Files). diff --git a/lib/test_server/src/test_server_sup.erl b/lib/test_server/src/test_server_sup.erl index 1a614d74d5..53dfb45e3a 100644 --- a/lib/test_server/src/test_server_sup.erl +++ b/lib/test_server/src/test_server_sup.erl @@ -83,13 +83,13 @@ timetrap(Timeout0, Scale, Pid) -> %% Handle = term() %% %% Cancels a time trap. - timetrap_cancel(Handle) -> unlink(Handle), MonRef = erlang:monitor(process, Handle), exit(Handle, kill), receive {'DOWN',MonRef,_,_,_} -> ok after 2000 -> ok end. + capture_get(Msgs) -> receive {captured,Msg} -> diff --git a/lib/test_server/src/ts_install.erl b/lib/test_server/src/ts_install.erl index 2ddffccf5b..8332ccfb40 100644 --- a/lib/test_server/src/ts_install.erl +++ b/lib/test_server/src/ts_install.erl @@ -22,6 +22,7 @@ -export([install/2, platform_id/1]). -include("ts.hrl"). +-include_lib("kernel/include/file.hrl"). install(install_local, Options) -> install(os:type(), Options); @@ -150,11 +151,17 @@ add_vars(Vars0, Opts0) -> end, {PlatformId, PlatformLabel, PlatformFilename, Version} = platform([{longnames, LongNames}|Vars0]), + NetDir = lists:concat(["/net", hostname()]), + Mounted = case file:read_file_info(NetDir) of + {ok, #file_info{type = directory}} -> NetDir; + _ -> "" + end, {Opts, [{longnames, LongNames}, {platform_id, PlatformId}, {platform_filename, PlatformFilename}, {rsh_name, get_rsh_name()}, {platform_label, PlatformLabel}, + {ts_net_dir, Mounted}, {erl_flags, []}, {erl_release, Version}, {ts_testcase_callback, get_testcase_callback()} | Vars0]}. diff --git a/lib/test_server/src/ts_run.erl b/lib/test_server/src/ts_run.erl index 067961a216..d145290820 100644 --- a/lib/test_server/src/ts_run.erl +++ b/lib/test_server/src/ts_run.erl @@ -212,6 +212,12 @@ make_command(Vars, Spec, State) -> false -> ok end, + + %% If Common Test specific variables are needed, add them here + %% on form: "{key1,value1}" "{key2,value2}" ... + NetDir = ts_lib:var(ts_net_dir, Vars), + TestVars = [ "\"{net_dir,\\\"",NetDir,"\\\"}\"" ], + %% NOTE: Do not use ' in these commands as it wont work on windows Cmd = [Erl, Naming, "test_server" " -rsh ", ts_lib:var(rsh_name, Vars), @@ -224,6 +230,7 @@ make_command(Vars, Spec, State) -> %% " -test_server_format_exception false", " -boot start_sasl -sasl errlog_type error", " -pz ",Cwd, + " -ct_test_vars ",TestVars, " -eval \"file:set_cwd(\\\"",TestDir,"\\\")\" " " -eval \"ct:run_test(", backslashify(lists:flatten(State#state.test_server_args)),")\"" @@ -369,7 +376,6 @@ make_common_test_args(Args0, Options, _Vars) -> end, ConfigFiles = [{config,[filename:join(ConfigPath,File) || File <- get_config_files()]}], - io_lib:format("~100000p",[Args0++Trace++Cover++Logdir++ ConfigFiles++Options]). diff --git a/lib/test_server/test/Makefile b/lib/test_server/test/Makefile index 34c55c595d..ab72a9d579 100644 --- a/lib/test_server/test/Makefile +++ b/lib/test_server/test/Makefile @@ -86,7 +86,7 @@ release_tests_spec: make_emakefile $(INSTALL_DIR) $(RELSYSDIR) $(INSTALL_DATA) $(EMAKEFILE) $(ERL_FILES) $(COVERFILE) $(RELSYSDIR) $(INSTALL_DATA) test_server.spec test_server.cover $(RELSYSDIR) - chmod -f -R u+w $(RELSYSDIR) + chmod -R u+w $(RELSYSDIR) @tar cf - *_SUITE_data | (cd $(RELSYSDIR); tar xf -) release_docs_spec: diff --git a/lib/tools/emacs/erlang.el b/lib/tools/emacs/erlang.el index e1c0d31371..6728bef2a4 100644 --- a/lib/tools/emacs/erlang.el +++ b/lib/tools/emacs/erlang.el @@ -386,7 +386,8 @@ then no prototype is inserted. The test is performed by the function `erlang-test-criteria-list'.") (defvar erlang-electric-arrow-criteria - '(erlang-next-lines-empty-p + '(erlang-stop-when-in-type-spec + erlang-next-lines-empty-p erlang-at-end-of-function-p) "*List of functions controlling the arrow aspect of `erlang-electric-gt'. The functions in this list are called, in order, whenever a `>' @@ -4045,6 +4046,16 @@ This function is designed to be a member of a criteria list." nil))) +(defun erlang-stop-when-in-type-spec () + "Return `stop' when in a type spec line. + +This function is designed to be a member of a criteria list." + (save-excursion + (beginning-of-line) + (when (save-match-data (looking-at "-\\(spec\\|type\\)")) + 'stop))) + + (defun erlang-next-lines-empty-p () "Return non-nil if next lines are empty. diff --git a/lib/tools/src/cover.erl b/lib/tools/src/cover.erl index 230f0e9428..73a736f0e8 100644 --- a/lib/tools/src/cover.erl +++ b/lib/tools/src/cover.erl @@ -253,6 +253,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, @@ -625,7 +626,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}]), @@ -1258,13 +1259,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), @@ -1284,7 +1285,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} -> 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) -> diff --git a/lib/tools/test/Makefile b/lib/tools/test/Makefile index 63f96520fd..8019b7269f 100644 --- a/lib/tools/test/Makefile +++ b/lib/tools/test/Makefile @@ -87,7 +87,7 @@ release_tests_spec: make_emakefile $(INSTALL_DIR) $(RELSYSDIR) $(INSTALL_DATA) $(SPEC_FILES) $(COVER_FILE) $(EMAKEFILE) \ $(ERL_FILES) $(RELSYSDIR) - chmod -f -R u+w $(RELSYSDIR) + chmod -R u+w $(RELSYSDIR) @tar cf - *_SUITE_data | (cd $(RELSYSDIR); tar xf -) release_docs_spec: diff --git a/lib/tv/src/tv_io_lib.erl b/lib/tv/src/tv_io_lib.erl index f693ff796d..5457575b7d 100644 --- a/lib/tv/src/tv_io_lib.erl +++ b/lib/tv/src/tv_io_lib.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1998-2009. All Rights Reserved. +%% Copyright Ericsson AB 1998-2010. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -52,10 +52,11 @@ write(_Term, 0) -> "..."; write(Term, _D) when is_integer(Term) -> integer_to_list(Term); write(Term, _D) when is_float(Term) -> tv_io_lib_format:fwrite_g(Term); write(Atom, _D) when is_atom(Atom) -> write_atom(Atom); -write(Term, _D) when is_port(Term) -> "#Port"; +write(Term, _D) when is_port(Term) -> lists:flatten(io_lib:write(Term)); write(Term, _D) when is_pid(Term) -> pid_to_list(Term); -write(Term, _D) when is_reference(Term) -> "#Ref"; -write(Term, _D) when is_binary(Term) -> "#Bin"; +write(Term, _D) when is_reference(Term) -> io_lib:write(Term); +write(Term, _D) when is_binary(Term), byte_size(Term) > 100 -> "#Bin"; +write(Term, _D) when is_binary(Term) -> "<<\"" ++ binary_to_list(Term) ++ "\">>"; write(Term, _D) when is_bitstring(Term) -> "#Bitstr"; write([], _D) -> "[]"; write({}, _D) -> "{}"; diff --git a/lib/typer/src/typer.erl b/lib/typer/src/typer.erl index fc8caa4f21..e40c4f39cd 100644 --- a/lib/typer/src/typer.erl +++ b/lib/typer/src/typer.erl @@ -628,6 +628,8 @@ cl(["-T"|Opts]) -> cl(["-r"|Opts]) -> {Files, RestOpts} = dialyzer_cl_parse:collect_args(Opts), {{files_r, Files}, RestOpts}; +cl(["-pa",Dir|Opts]) -> {{pa,Dir}, Opts}; +cl(["-pz",Dir|Opts]) -> {{pz,Dir}, Opts}; cl(["-"++H|_]) -> fatal_error("unknown option -"++H); cl(Opts) -> {Files, RestOpts} = dialyzer_cl_parse:collect_args(Opts), @@ -672,7 +674,13 @@ analyze_result({plt, Plt}, Args, Analysis) -> analyze_result(show_succ, Args, Analysis) -> {Args, Analysis#analysis{show_succ = true}}; analyze_result(no_spec, Args, Analysis) -> - {Args, Analysis#analysis{no_spec = true}}. + {Args, Analysis#analysis{no_spec = true}}; +analyze_result({pa, Dir}, Args, Analysis) -> + code:add_patha(Dir), + {Args, Analysis}; +analyze_result({pz, Dir}, Args, Analysis) -> + code:add_pathz(Dir), + {Args, Analysis}. %%-------------------------------------------------------------------- %% File processing. @@ -1009,7 +1017,8 @@ version_message() -> help_message() -> S = <<" Usage: typer [--help] [--version] [--plt PLT] [--edoc] [--show | --show-exported | --annotate | --annotate-inc-files] - [-Ddefine]* [-I include_dir]* [-T application]* [-r] file* + [-Ddefine]* [-I include_dir]* [-pa dir]* [-pz dir]* + [-T application]* [-r] file* Options: -r dir* @@ -1039,6 +1048,10 @@ help_message() -> -I include_dir pass the include_dir to TypEr (The syntax of includes is the same as that used by \"erlc\".) + -pa dir + -pz dir + Set code path options to TypEr + (This is useful for files that use parse tranforms.) --version (or -v) prints the Typer version and exits --help (or -h) 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<?QueryString> ]]></code> <p>An <c>alias</c> parameter in the configuration function can be an ErlScriptAlias as used in the above URL. The definition of - an ErlScripAlias shall be like this:</p> + an ErlScriptAlias shall be like this:</p> <p><c>{alias,{erl_alias,Path,[Modules]}}</c>, e.g.</p> <p><c>{alias,{erl_alias,"/testtool",[helloworld]}}</c></p> <p>The following URL will then cause a call to the function @@ -184,7 +184,7 @@ http://Servername:Port/ErlScriptAlias/Mod/Func<?QueryString> ]]></code> directory <c>/usr/local/otp/lib/myapp-1.0/priv</c>:</p> <p><c>{alias,{"/mytool_home","/usr/local/otp/lib/myapp-1.0/priv"}}</c></p> <p>See the INETS documentation, especially the module - <c>mod_esi</c>, for a more in depht coverage of Erl Scheme.</p> + <c>mod_esi</c>, for a more in depth coverage of the Erl Scheme.</p> </section> <section> 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 <code>xmerl_xpath_parse.yrl</code>. % The core functions are defined in <code>xmerl_xpath_pred.erl</code>. diff --git a/system/doc/design_principles/sup_princ.xml b/system/doc/design_principles/sup_princ.xml index 067fd31961..2748f21bbe 100644 --- a/system/doc/design_principles/sup_princ.xml +++ b/system/doc/design_principles/sup_princ.xml @@ -4,7 +4,7 @@ <chapter> <header> <copyright> - <year>1997</year><year>2009</year> + <year>1997</year><year>2011</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> @@ -335,6 +335,12 @@ supervisor:start_child(Pid, [id1])</code> <c>apply(call, start_link, []++[id1])</c>, or actually:</p> <code type="none"> call:start_link(id1)</code> + <p>A child under a <c>simple_one_for_one</c> supervisor can be terminated + with</p> + <code type="none"> +supervisor:terminate_child(Sup, Pid)</code> + <p>where <c>Sup</c> is the pid, or name, of the supervisor and + <c>Pid</c> is the pid of the child.</p> </section> <section> diff --git a/system/doc/efficiency_guide/advanced.xml b/system/doc/efficiency_guide/advanced.xml index 8126b93a2d..821175bb09 100644 --- a/system/doc/efficiency_guide/advanced.xml +++ b/system/doc/efficiency_guide/advanced.xml @@ -34,7 +34,7 @@ <p>A good start when programming efficiently is to have knowledge about how much memory different data types and operations require. It is implementation-dependent how much memory the Erlang data types and - other items consume, but here are some figures for + other items consume, but here are some figures for the erts-5.2 system (OTP release R9B). (There have been no significant changes in R13.)</p> diff --git a/system/doc/efficiency_guide/binaryhandling.xml b/system/doc/efficiency_guide/binaryhandling.xml index 3628d7a232..425d6308cf 100644 --- a/system/doc/efficiency_guide/binaryhandling.xml +++ b/system/doc/efficiency_guide/binaryhandling.xml @@ -114,7 +114,7 @@ my_binary_to_list(<<>>) -> [].]]></code> data. For each field that is matched out of a binary, the position in the match context will be incremented.</p> - <p>In R11B, a match context was only using during a binary matching + <p>In R11B, a match context was only used during a binary matching operation.</p> <p>In R12B, the compiler tries to avoid generating code that @@ -205,7 +205,7 @@ Bin4 = <<Bin1/binary,17>>, %% 5 !!! ProcBin for the binary. The reason is that the binary object can be moved (reallocated) during an append operation, and when that happens the pointer in the ProcBin must be updated. If there would be more than - on ProcBin pointing to the binary object, it would not be possible to + one ProcBin pointing to the binary object, it would not be possible to find and update all of them.</p> <p>Therefore, certain operations on a binary will mark it so that @@ -291,7 +291,7 @@ my_binary_to_list(<<>>) -> [].]]></code> that initializes the matching operation will basically do nothing when it sees that it was passed a match context instead of a binary.</p> - <p>When the end of the binary is reached and second clause matches, + <p>When the end of the binary is reached and the second clause matches, the match context will simply be discarded (removed in the next garbage collection, since there is no longer any reference to it).</p> diff --git a/system/doc/efficiency_guide/drivers.xml b/system/doc/efficiency_guide/drivers.xml index 9fe54fb19a..1967fd7ada 100644 --- a/system/doc/efficiency_guide/drivers.xml +++ b/system/doc/efficiency_guide/drivers.xml @@ -40,7 +40,7 @@ any code in a driver.</p> <p>By default, that lock will be at the driver level, meaning that - if several ports has been opened to the same driver, only code for + if several ports have been opened to the same driver, only code for one port at the same time can be running.</p> <p>A driver can be configured to instead have one lock for each port.</p> diff --git a/system/doc/efficiency_guide/functions.xml b/system/doc/efficiency_guide/functions.xml index fe14a4f000..6be49dd7c9 100644 --- a/system/doc/efficiency_guide/functions.xml +++ b/system/doc/efficiency_guide/functions.xml @@ -127,7 +127,7 @@ map_pairs2(_Map, [_|_]=Xs, [] ) -> map_pairs2(Map, [X|Xs], [Y|Ys]) -> [Map(X, Y)|map_pairs2(Map, Xs, Ys)].]]></code> - <p>the compiler is free rearrange the clauses. It will generate code + <p>the compiler is free to rearrange the clauses. It will generate code similar to this</p> <p><em>DO NOT (already done by the compiler)</em></p> diff --git a/system/doc/efficiency_guide/processes.xml b/system/doc/efficiency_guide/processes.xml index a25ec53370..b75be7d531 100644 --- a/system/doc/efficiency_guide/processes.xml +++ b/system/doc/efficiency_guide/processes.xml @@ -105,7 +105,7 @@ loop() -> <seealso marker="erts:erlang#spawn_opt/4">spawn_opt/4</seealso>.</p> <p>The gain is twofold: Firstly, although the garbage collector will - grow the heap, it will it grow it step by step, which will be more + grow the heap, it will grow it step by step, which will be more costly than directly establishing a larger heap when the process is spawned. Secondly, the garbage collector may also shrink the heap if it is much larger than the amount of data stored on it; @@ -172,7 +172,7 @@ days_in_month(M) -> <p>Shared sub-terms are <em>not</em> preserved when a term is sent to another process, passed as the initial process arguments in the <c>spawn</c> call, or stored in an ETS table. - That is an optimization. Most applications do not send message + That is an optimization. Most applications do not send messages with shared sub-terms.</p> <p>Here is an example of how a shared sub-term can be created:</p> @@ -237,8 +237,8 @@ true <section> <title>The SMP emulator</title> - <p>The SMP emulator (introduced in R11B) will take advantage of - multi-core or multi-CPU computer by running several Erlang schedulers + <p>The SMP emulator (introduced in R11B) will take advantage of a + multi-core or multi-CPU computer by running several Erlang scheduler threads (typically, the same as the number of cores). Each scheduler thread schedules Erlang processes in the same way as the Erlang scheduler in the non-SMP emulator.</p> diff --git a/system/doc/efficiency_guide/profiling.xml b/system/doc/efficiency_guide/profiling.xml index 65d13408bc..8be1c7175d 100644 --- a/system/doc/efficiency_guide/profiling.xml +++ b/system/doc/efficiency_guide/profiling.xml @@ -74,7 +74,7 @@ <title>What to look for</title> <p>When analyzing the result file from the profiling activity you should look for functions that are called many - times and have a long "own" execution time (time excluded calls + times and have a long "own" execution time (time excluding calls to other functions). Functions that just are called very many times can also be interesting, as even small things can add up to quite a bit if they are repeated often. Then you need to @@ -87,7 +87,7 @@ <item>Are there redundant tests that can be removed? </item> <item>Is there some expression calculated giving the same result each time? </item> - <item>Is there other ways of doing this that are equivalent and + <item>Are there other ways of doing this that are equivalent and more efficient?</item> <item>Can I use another internal data representation to make things more efficient? </item> @@ -138,7 +138,7 @@ <p><c>cprof</c> is something in between <c>fprof</c> and <c>cover</c> regarding features. It counts how many times each function is called when the program is run, on a per module - basis. <c>cprof</c> has a low performance degradation (versus + basis. <c>cprof</c> has a low performance degradation effect (versus <c>fprof</c> and <c>eprof</c>) and does not need to recompile any modules to profile (versus <c>cover</c>).</p> </section> @@ -231,7 +231,7 @@ consistent from run to run. The disadvantage is that the time spent in the operating system kernel (such as swapping and I/O) are not included. Therefore, measuring CPU time is misleading if - any I/O (file or sockets) are involved.</p> + any I/O (file or socket) is involved.</p> <p>It is probably a good idea to do both wall-clock measurements and CPU time measurements.</p> @@ -239,18 +239,18 @@ <p>Some additional advice:</p> <list type="bulleted"> - <item>The granularity of both types measurement could be quite + <item>The granularity of both types of measurement could be quite high so you should make sure that each individual measurement lasts for at least several seconds.</item> <item>To make the test fair, each new test run should run in its own, - newly created Erlang process. Otherwise, if all tests runs in the + newly created Erlang process. Otherwise, if all tests run in the same process, the later tests would start out with larger heap sizes - and therefore probably does less garbage collections. You could + and therefore probably do less garbage collections. You could also consider restarting the Erlang emulator between each test.</item> <item>Do not assume that the fastest implementation of a given algorithm - on computer architecture X also is the fast on computer architecture Y.</item> + on computer architecture X also is the fastest on computer architecture Y.</item> </list> </section> diff --git a/system/doc/efficiency_guide/tablesDatabases.xml b/system/doc/efficiency_guide/tablesDatabases.xml index 4b53348c4c..2f5103a08b 100644 --- a/system/doc/efficiency_guide/tablesDatabases.xml +++ b/system/doc/efficiency_guide/tablesDatabases.xml @@ -280,9 +280,9 @@ lists:filter(fun(X) -> X#person.name == "Bryan" end, TabList), <p>A simple solution would be to use the <c>name</c> field as the key instead of the <c>idno</c> field, but that would cause problems if the names were not unique. A more general solution - would be create a second table with name as key and idno as - data, i.e. to index (invert) the table with regards to the - <c>name</c> field. The second table would of course have to be + would be to create a second table with <c>name</c> as key and + <c>idno</c> as data, i.e. to index (invert) the table with regards + to the <c>name</c> field. The second table would of course have to be kept consistent with the master table. Mnesia could do this for you, but a home brew index table could be very efficient compared to the overhead involved in using Mnesia.</p> |