aboutsummaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/appmon/vsn.mk12
-rw-r--r--lib/common_test/info2
-rw-r--r--lib/compiler/src/Makefile69
-rw-r--r--lib/compiler/src/compile.erl2
-rw-r--r--lib/compiler/src/sys_pre_expand.erl60
-rw-r--r--lib/compiler/src/v3_core.erl14
-rw-r--r--lib/docbuilder/info2
-rw-r--r--lib/edoc/info2
-rw-r--r--lib/edoc/vsn.mk2
-rw-r--r--lib/erl_docgen/priv/xsl/db_man.xsl28
-rw-r--r--lib/et/doc/src/fascicules.xml18
-rw-r--r--lib/et/doc/src/files.mk3
-rw-r--r--lib/eunit/info2
-rw-r--r--lib/eunit/vsn.mk2
-rw-r--r--lib/hipe/Makefile2
-rw-r--r--lib/hipe/doc/Makefile17
-rw-r--r--lib/hipe/doc/src/Makefile21
-rw-r--r--lib/hipe/doc/src/book.xml9
-rw-r--r--lib/hipe/doc/src/hipe_app.xml58
-rw-r--r--lib/hipe/doc/src/ref_man.xml (renamed from lib/et/doc/src/part_notes.xml)21
-rw-r--r--lib/hipe/info2
-rw-r--r--lib/jinterface/vsn.mk12
-rw-r--r--lib/kernel/src/Makefile3
-rw-r--r--lib/kernel/src/hipe_unified_loader.erl42
-rw-r--r--lib/kernel/src/inet.erl147
-rw-r--r--lib/kernel/src/inet_config.erl32
-rw-r--r--lib/kernel/src/inet_db.erl107
-rw-r--r--lib/kernel/src/inet_gethost_native.erl72
-rw-r--r--lib/kernel/src/inet_parse.erl285
-rw-r--r--lib/kernel/src/user.erl16
-rw-r--r--lib/kernel/test/inet_SUITE.erl198
-rw-r--r--lib/kernel/test/inet_res_SUITE.erl88
-rw-r--r--lib/parsetools/vsn.mk2
-rw-r--r--lib/percept/src/egd_render.erl12
-rw-r--r--lib/percept/test/egd_SUITE.erl14
-rw-r--r--lib/percept/vsn.mk2
-rw-r--r--lib/reltool/doc/src/Makefile30
-rw-r--r--lib/reltool/doc/src/book.gifbin1081 -> 0 bytes
-rw-r--r--lib/reltool/doc/src/fascicules.xml17
-rw-r--r--lib/reltool/doc/src/files.mk21
-rw-r--r--lib/reltool/doc/src/note.gifbin1539 -> 0 bytes
-rw-r--r--lib/reltool/doc/src/notes.gifbin2005 -> 0 bytes
-rw-r--r--lib/reltool/doc/src/part_notes.xml41
-rw-r--r--lib/reltool/doc/src/ref_man.gifbin1530 -> 0 bytes
-rw-r--r--lib/reltool/doc/src/reltool_examples.xml32
-rw-r--r--lib/reltool/doc/src/user_guide.gifbin1581 -> 0 bytes
-rw-r--r--lib/reltool/doc/src/warning.gifbin1498 -> 0 bytes
-rw-r--r--lib/reltool/src/reltool_target.erl25
-rw-r--r--lib/runtime_tools/vsn.mk2
-rw-r--r--lib/snmp/doc/src/notes.xml13
-rw-r--r--lib/snmp/src/agent/snmpa_net_if.erl15
-rw-r--r--lib/snmp/src/app/snmp.appup.src6
-rw-r--r--lib/snmp/src/manager/snmpm_net_if.erl8
-rw-r--r--lib/snmp/src/misc/snmp_config.erl2
-rw-r--r--lib/snmp/src/misc/snmp_log.erl10
-rw-r--r--lib/snmp/vsn.mk6
-rw-r--r--lib/stdlib/doc/src/shell.xml9
-rw-r--r--lib/stdlib/src/Makefile3
-rw-r--r--lib/stdlib/src/dets_v8.erl10
-rw-r--r--lib/stdlib/src/erl_lint.erl114
-rw-r--r--lib/stdlib/src/escript.erl71
-rw-r--r--lib/stdlib/src/file_sorter.erl10
-rw-r--r--lib/stdlib/src/io_lib.erl14
-rw-r--r--lib/stdlib/src/qlc.erl10
-rw-r--r--lib/stdlib/src/qlc_pt.erl10
-rw-r--r--lib/stdlib/test/erl_lint_SUITE.erl12
-rw-r--r--lib/stdlib/test/io_proto_SUITE.erl50
-rw-r--r--lib/stdlib/test/shell_SUITE.erl16
-rw-r--r--lib/syntax_tools/vsn.mk2
-rw-r--r--lib/test_server/info2
-rw-r--r--lib/tools/doc/src/Makefile12
-rw-r--r--lib/tools/doc/src/lcnt.xml465
-rw-r--r--lib/tools/doc/src/lcnt_chapter.xml301
-rw-r--r--lib/tools/doc/src/part.xml9
-rw-r--r--lib/tools/doc/src/ref_man.xml12
-rw-r--r--lib/tools/src/Makefile14
-rw-r--r--lib/tools/src/lcnt.erl840
-rw-r--r--lib/tools/src/xref_utils.erl13
-rw-r--r--lib/tools/test/Makefile7
-rw-r--r--lib/tools/test/lcnt_SUITE.erl154
-rw-r--r--lib/tools/test/lcnt_SUITE_data/big_bang_40.lcntbin0 -> 226100 bytes
-rw-r--r--lib/tools/test/xref_SUITE.erl24
82 files changed, 3026 insertions, 766 deletions
diff --git a/lib/appmon/vsn.mk b/lib/appmon/vsn.mk
index cbf0a88737..78b95e5688 100644
--- a/lib/appmon/vsn.mk
+++ b/lib/appmon/vsn.mk
@@ -1,19 +1,19 @@
#
# %CopyrightBegin%
-#
-# Copyright Ericsson AB 1997-2009. 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
# 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%
-APPMON_VSN = 2.1.10.2
+APPMON_VSN = 2.1.11
diff --git a/lib/common_test/info b/lib/common_test/info
index 1819ca2aad..6b2778f3e6 100644
--- a/lib/common_test/info
+++ b/lib/common_test/info
@@ -1,2 +1,2 @@
-group: tools
+group: test
short: A portable framework for automatic testing
diff --git a/lib/compiler/src/Makefile b/lib/compiler/src/Makefile
index fde2b1a655..70ddd54145 100644
--- a/lib/compiler/src/Makefile
+++ b/lib/compiler/src/Makefile
@@ -1,19 +1,19 @@
#
# %CopyrightBegin%
-#
-# Copyright Ericsson AB 1996-2009. All Rights Reserved.
-#
+#
+# Copyright Ericsson AB 1996-2010. All Rights Reserved.
+#
# The contents of this file are subject to the Erlang Public License,
# Version 1.1, (the "License"); you may not use this file except in
# compliance with the License. You should have received a copy of the
# Erlang Public License along with this software. If not, it can be
# retrieved online at http://www.erlang.org/.
-#
+#
# Software distributed under the License is distributed on an "AS IS"
# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
# the License for the specific language governing rights and limitations
# under the License.
-#
+#
# %CopyrightEnd%
#
@@ -45,46 +45,46 @@ RELSYSDIR = $(RELEASE_PATH)/lib/compiler-$(VSN)
# Target Specs
# ----------------------------------------------------
MODULES = \
- compile \
- sys_pre_attributes \
- sys_pre_expand \
- sys_expand_pmod \
- v3_core \
- sys_core_fold \
- sys_core_inline \
- sys_core_dsetel \
- core_lib \
- core_scan \
- core_parse \
- core_lint \
- core_pp \
- v3_kernel \
- v3_kernel_pp \
- v3_life \
- v3_codegen \
+ beam_asm \
beam_block \
beam_bool \
- beam_dead \
- beam_jump \
- beam_type \
- beam_clean \
- beam_peep \
beam_bsm \
- beam_trim \
+ beam_clean \
+ beam_dead \
+ beam_dict \
+ beam_disasm \
beam_flatten \
+ beam_jump \
beam_listing \
- beam_asm \
- beam_dict \
beam_opcodes \
- beam_disasm \
+ beam_peep \
+ beam_trim \
+ beam_type \
beam_utils \
beam_validator \
- erl_bifs \
cerl \
cerl_clauses \
cerl_inline \
cerl_trees \
- rec_env
+ compile \
+ core_lib \
+ core_lint \
+ core_parse \
+ core_pp \
+ core_scan \
+ erl_bifs \
+ rec_env \
+ sys_core_dsetel \
+ sys_core_fold \
+ sys_core_inline \
+ sys_expand_pmod \
+ sys_pre_attributes \
+ sys_pre_expand \
+ v3_codegen \
+ v3_core \
+ v3_kernel \
+ v3_kernel_pp \
+ v3_life
BEAM_H = $(wildcard ../priv/beam_h/*.h)
@@ -114,6 +114,9 @@ APPUP_TARGET= $(EBIN)/$(APPUP_FILE)
# FLAGS
# ----------------------------------------------------
+ifeq ($(NATIVE_LIBS_ENABLED),yes)
+ERL_COMPILE_FLAGS += +native
+endif
ERL_COMPILE_FLAGS += +inline +warn_unused_import -I../../stdlib/include -I$(EGEN) -W
# ----------------------------------------------------
diff --git a/lib/compiler/src/compile.erl b/lib/compiler/src/compile.erl
index d73c9cd762..b853800d73 100644
--- a/lib/compiler/src/compile.erl
+++ b/lib/compiler/src/compile.erl
@@ -1055,7 +1055,7 @@ test_native(#compile{options=Opts}) ->
is_native_enabled([native|_]) -> true;
is_native_enabled([no_native|_]) -> false;
-is_native_enabled([H|T]) -> is_native_enabled(T);
+is_native_enabled([_|Opts]) -> is_native_enabled(Opts);
is_native_enabled([]) -> false.
native_compile(#compile{code=none}=St) -> {ok,St};
diff --git a/lib/compiler/src/sys_pre_expand.erl b/lib/compiler/src/sys_pre_expand.erl
index 78dd73e0a2..f80d03dfac 100644
--- a/lib/compiler/src/sys_pre_expand.erl
+++ b/lib/compiler/src/sys_pre_expand.erl
@@ -1,19 +1,19 @@
%%
%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1996-2009. All Rights Reserved.
-%%
+%%
+%% Copyright Ericsson AB 1996-2010. All Rights Reserved.
+%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
%% compliance with the License. You should have received a copy of the
%% Erlang Public License along with this software. If not, it can be
%% retrieved online at http://www.erlang.org/.
-%%
+%%
%% Software distributed under the License is distributed on an "AS IS"
%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
%% the License for the specific language governing rights and limitations
%% under the License.
-%%
+%%
%% %CopyrightEnd%
%%
%% Purpose : Expand some source Erlang constructions. This is part of the
@@ -114,7 +114,7 @@ expand_pmod(Fs0, St0) ->
St1 = St0#expand{exports=Xs, defined=Ds},
{Fs2,St2} = add_instance(Ps, Fs1, St1),
{Fs3,St3} = ensure_new(Base, Ps0, Fs2, St2),
- {Fs3,St3#expand{attributes = [{abstract, [true]}
+ {Fs3,St3#expand{attributes = [{abstract, 0, [true]}
| St3#expand.attributes]}}
end.
@@ -173,7 +173,7 @@ define_functions(Forms, #expand{defined=Predef}=St) ->
St#expand{defined=ordsets:from_list(Fs)}.
module_attrs(St) ->
- {[{attribute,0,Name,Val} || {Name,Val} <- St#expand.attributes],St}.
+ {[{attribute,Line,Name,Val} || {Name,Line,Val} <- St#expand.attributes],St}.
module_predef_funcs(St) ->
PreDef = [{module_info,0},{module_info,1}],
@@ -197,8 +197,8 @@ module_predef_funcs(St) ->
forms([{attribute,_,file,_File}=F|Fs0], St0) ->
{Fs,St1} = forms(Fs0, St0),
{[F|Fs],St1};
-forms([{attribute,_,Name,Val}|Fs0], St0) ->
- St1 = attribute(Name, Val, St0),
+forms([{attribute,Line,Name,Val}|Fs0], St0) ->
+ St1 = attribute(Name, Val, Line, St0),
forms(Fs0, St1);
forms([{function,L,N,A,Cs}|Fs0], St0) ->
{Ff,St1} = function(L, N, A, Cs, St0),
@@ -207,30 +207,30 @@ forms([{function,L,N,A,Cs}|Fs0], St0) ->
forms([_|Fs], St) -> forms(Fs, St);
forms([], St) -> {[],St}.
-%% attribute(Attribute, Value, State) -> State'.
+%% attribute(Attribute, Value, Line, State) -> State'.
%% Process an attribute, this just affects the state.
-attribute(module, {Module, As}, St) ->
+attribute(module, {Module, As}, _L, St) ->
M = package_to_string(Module),
St#expand{module=list_to_atom(M),
- package = packages:strip_last(M),
+ package=packages:strip_last(M),
parameters=As};
-attribute(module, Module, St) ->
+attribute(module, Module, _L, St) ->
M = package_to_string(Module),
St#expand{module=list_to_atom(M),
- package = packages:strip_last(M)};
-attribute(export, Es, St) ->
+ package=packages:strip_last(M)};
+attribute(export, Es, _L, St) ->
St#expand{exports=union(from_list(Es), St#expand.exports)};
-attribute(import, Is, St) ->
+attribute(import, Is, _L, St) ->
import(Is, St);
-attribute(compile, C, St) when is_list(C) ->
+attribute(compile, C, _L, St) when is_list(C) ->
St#expand{compile=St#expand.compile ++ C};
-attribute(compile, C, St) ->
+attribute(compile, C, _L, St) ->
St#expand{compile=St#expand.compile ++ [C]};
-attribute(Name, Val, St) when is_list(Val) ->
- St#expand{attributes=St#expand.attributes ++ [{Name,Val}]};
-attribute(Name, Val, St) ->
- St#expand{attributes=St#expand.attributes ++ [{Name,[Val]}]}.
+attribute(Name, Val, Line, St) when is_list(Val) ->
+ St#expand{attributes=St#expand.attributes ++ [{Name,Line,Val}]};
+attribute(Name, Val, Line, St) ->
+ St#expand{attributes=St#expand.attributes ++ [{Name,Line,[Val]}]}.
function(L, N, A, Cs0, St0) ->
{Cs,St} = clauses(Cs0, St0#expand{func=N,arity=A,fcount=0}),
@@ -299,10 +299,10 @@ pattern({match,Line,Pat1, Pat2}, St0) ->
{TT,St2} = pattern(Pat1, St1),
{{match,Line,TT,TH},St2};
%% Compile-time pattern expressions, including unary operators.
-pattern({op,Line,Op,A}, St) ->
- {erl_eval:partial_eval({op,Line,Op,A}),St};
-pattern({op,Line,Op,L,R}, St) ->
- {erl_eval:partial_eval({op,Line,Op,L,R}),St}.
+pattern({op,_Line,_Op,_A}=Op, St) ->
+ {erl_eval:partial_eval(Op),St};
+pattern({op,_Line,_Op,_L,_R}=Op, St) ->
+ {erl_eval:partial_eval(Op),St}.
pattern_list([P0|Ps0], St0) ->
{P,St1} = pattern(P0, St0),
@@ -400,18 +400,18 @@ expr({'receive',Line,Cs0,To0,ToEs0}, St0) ->
{{'receive',Line,Cs,To,ToEs},St3};
expr({'fun',Line,Body}, St) ->
fun_tq(Line, Body, St);
-expr({call,Line,{atom,La,N},As0}, St0) ->
+expr({call,Line,{atom,La,N}=Atom,As0}, St0) ->
{As,St1} = expr_list(As0, St0),
Ar = length(As),
case erl_internal:bif(N, Ar) of
true ->
- {{call,Line,{remote,La,{atom,La,erlang},{atom,La,N}},As},St1};
+ {{call,Line,{remote,La,{atom,La,erlang},Atom},As},St1};
false ->
case imported(N, Ar, St1) of
{yes,Mod} ->
- {{call,Line,{remote,La,{atom,La,Mod},{atom,La,N}},As},St1};
+ {{call,Line,{remote,La,{atom,La,Mod},Atom},As},St1};
no ->
- {{call,Line,{atom,La,N},As},St1}
+ {{call,Line,Atom,As},St1}
end
end;
expr({call,Line,{record_field,_,_,_}=M,As0}, St0) ->
diff --git a/lib/compiler/src/v3_core.erl b/lib/compiler/src/v3_core.erl
index a39a3c538f..dfe15de4ff 100644
--- a/lib/compiler/src/v3_core.erl
+++ b/lib/compiler/src/v3_core.erl
@@ -1,19 +1,19 @@
%%
%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1999-2009. All Rights Reserved.
-%%
+%%
+%% Copyright Ericsson AB 1999-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%
%%
%% Purpose : Transform normal Erlang to Core Erlang
@@ -164,8 +164,8 @@ form({attribute,_,file,{File,_Line}}, {Fs,As,Es,Ws,_}, _Opts) ->
form({attribute,_,_,_}=F, {Fs,As,Es,Ws,File}, _Opts) ->
{Fs,[attribute(F)|As],Es,Ws,File}.
-attribute({attribute,_,Name,Val}) ->
- {#c_literal{val=Name},#c_literal{val=Val}}.
+attribute({attribute,Line,Name,Val}) ->
+ {#c_literal{val=Name, anno=[Line]}, #c_literal{val=Val, anno=[Line]}}.
function({function,_,Name,Arity,Cs0}, Es0, Ws0, File, Opts) ->
%%ok = io:fwrite("~p - ", [{Name,Arity}]),
diff --git a/lib/docbuilder/info b/lib/docbuilder/info
index 33ce19fb4b..60daa212c8 100644
--- a/lib/docbuilder/info
+++ b/lib/docbuilder/info
@@ -1,2 +1,2 @@
-group: tools
+group: doc
short: Tool for generating HTML documentation for applications.
diff --git a/lib/edoc/info b/lib/edoc/info
index cb25c1e519..bc52caa78b 100644
--- a/lib/edoc/info
+++ b/lib/edoc/info
@@ -1,3 +1,3 @@
-group: tools
+group: doc Documentation Applications
short: A utility used to generate documentation out of tags in source files.
diff --git a/lib/edoc/vsn.mk b/lib/edoc/vsn.mk
index 7c7ba58cc9..2de2641b4a 100644
--- a/lib/edoc/vsn.mk
+++ b/lib/edoc/vsn.mk
@@ -1 +1 @@
-EDOC_VSN = 0.7.6.5
+EDOC_VSN = 0.7.6.6
diff --git a/lib/erl_docgen/priv/xsl/db_man.xsl b/lib/erl_docgen/priv/xsl/db_man.xsl
index a9a2781a8a..a2b1e755e2 100644
--- a/lib/erl_docgen/priv/xsl/db_man.xsl
+++ b/lib/erl_docgen/priv/xsl/db_man.xsl
@@ -176,10 +176,12 @@
<xsl:template match="/erlref">
<xsl:variable name="companyname">
<xsl:choose>
- <xsl:when test="$company = ''"><xsl:value-of select="header/holder"/></xsl:when>
- <xsl:otherwise><xsl:value-of select="$company"/></xsl:otherwise>
+ <!-- Workaround until all of OTP's .../holder contents are correct. -->
+ <xsl:when test="starts-with(header/copyright/holder,'Ericsson AB')"><xsl:text>Ericsson AB</xsl:text></xsl:when>
+ <xsl:otherwise><xsl:value-of select="header/copyright/holder"/></xsl:otherwise>
</xsl:choose>
</xsl:variable>
+
<xsl:text>.TH </xsl:text><xsl:value-of select="module"/><xsl:text> 3 "</xsl:text><xsl:value-of select="$appname"/><xsl:text> </xsl:text><xsl:value-of select="$appver"/><xsl:text>" "</xsl:text><xsl:value-of select="$companyname"/><xsl:text>" "Erlang Module Definition"&#10;</xsl:text>
<xsl:text>.SH NAME&#10;</xsl:text>
<xsl:value-of select="module"/><xsl:text> \- </xsl:text><xsl:value-of select="modulesummary"/><xsl:text>&#10;</xsl:text>
@@ -190,11 +192,12 @@
<xsl:template match="/comref">
<xsl:variable name="companyname">
<xsl:choose>
- <xsl:when test="$company = ''"><xsl:value-of select="header/holder"/></xsl:when>
- <xsl:otherwise><xsl:value-of select="$company"/></xsl:otherwise>
+ <!-- Workaround until all of OTP's .../holder contents are correct. -->
+ <xsl:when test="starts-with(header/copyright/holder,'Ericsson AB')"><xsl:text>Ericsson AB</xsl:text></xsl:when>
+ <xsl:otherwise><xsl:value-of select="header/copyright/holder"/></xsl:otherwise>
</xsl:choose>
</xsl:variable>
- <xsl:text>.TH </xsl:text><xsl:value-of select="com"/><xsl:text> 1 "</xsl:text><xsl:value-of select="$appname"/><xsl:text> </xsl:text><xsl:value-of select="$appver"/><xsl:text>" "</xsl:text><xsl:value-of select="$companyname"/><xsl:text>" "User Commands"&#10;</xsl:text>
+ <xsl:text>.TH </xsl:text><xsl:value-of select="com"/><xsl:text> 1 "</xsl:text><xsl:value-of select="$appname"/><xsl:text> </xsl:text><xsl:value-of select="$appver"/><xsl:text>" "</xsl:text><xsl:value-of select="$companyname"/><xsl:text>" "User Commands"&#10;</xsl:text>
<xsl:text>.SH NAME&#10;</xsl:text>
<xsl:value-of select="com"/><xsl:text> \- </xsl:text><xsl:value-of select="comsummary"/><xsl:text>&#10;</xsl:text>
<xsl:apply-templates/>
@@ -204,8 +207,9 @@
<xsl:template match="/cref">
<xsl:variable name="companyname">
<xsl:choose>
- <xsl:when test="$company = ''"><xsl:value-of select="header/holder"/></xsl:when>
- <xsl:otherwise><xsl:value-of select="$company"/></xsl:otherwise>
+ <!-- Workaround until all of OTP's .../holder contents are correct. -->
+ <xsl:when test="starts-with(header/copyright/holder,'Ericsson AB')"><xsl:text>Ericsson AB</xsl:text></xsl:when>
+ <xsl:otherwise><xsl:value-of select="header/copyright/holder"/></xsl:otherwise>
</xsl:choose>
</xsl:variable>
<xsl:text>.TH </xsl:text><xsl:value-of select="lib"/><xsl:text> 3 "</xsl:text><xsl:value-of select="$appname"/><xsl:text> </xsl:text><xsl:value-of select="$appver"/><xsl:text>" "</xsl:text><xsl:value-of select="$companyname"/><xsl:text>" "C Library Functions"&#10;</xsl:text>
@@ -218,8 +222,9 @@
<xsl:template match="/fileref">
<xsl:variable name="companyname">
<xsl:choose>
- <xsl:when test="$company = ''"><xsl:value-of select="header/holder"/></xsl:when>
- <xsl:otherwise><xsl:value-of select="$company"/></xsl:otherwise>
+ <!-- Workaround until all of OTP's .../holder contents are correct. -->
+ <xsl:when test="starts-with(header/copyright/holder,'Ericsson AB')"><xsl:text>Ericsson AB</xsl:text></xsl:when>
+ <xsl:otherwise><xsl:value-of select="header/copyright/holder"/></xsl:otherwise>
</xsl:choose>
</xsl:variable>
<xsl:text>.TH </xsl:text><xsl:value-of select="file"/><xsl:text> 5 "</xsl:text><xsl:value-of select="$appname"/><xsl:text> </xsl:text><xsl:value-of select="$appver"/><xsl:text>" "</xsl:text><xsl:value-of select="$companyname"/><xsl:text>" "Files"&#10;</xsl:text>
@@ -232,8 +237,9 @@
<xsl:template match="/appref">
<xsl:variable name="companyname">
<xsl:choose>
- <xsl:when test="$company = ''"><xsl:value-of select="header/holder"/></xsl:when>
- <xsl:otherwise><xsl:value-of select="$company"/></xsl:otherwise>
+ <!-- Workaround until all of OTP's .../holder contents are correct. -->
+ <xsl:when test="starts-with(header/copyright/holder,'Ericsson AB')"><xsl:text>Ericsson AB</xsl:text></xsl:when>
+ <xsl:otherwise><xsl:value-of select="header/copyright/holder"/></xsl:otherwise>
</xsl:choose>
</xsl:variable>
<xsl:text>.TH </xsl:text><xsl:value-of select="app"/><xsl:text> 7 "</xsl:text><xsl:value-of select="$appname"/><xsl:text> </xsl:text><xsl:value-of select="$appver"/><xsl:text>" "</xsl:text><xsl:value-of select="$companyname"/><xsl:text>" "Erlang Application Definition"&#10;</xsl:text>
diff --git a/lib/et/doc/src/fascicules.xml b/lib/et/doc/src/fascicules.xml
deleted file mode 100644
index 0678195e07..0000000000
--- a/lib/et/doc/src/fascicules.xml
+++ /dev/null
@@ -1,18 +0,0 @@
-<?xml version="1.0" encoding="latin1" ?>
-<!DOCTYPE fascicules SYSTEM "fascicules.dtd">
-
-<fascicules>
- <fascicule file="part" href="part_frame.html" entry="no">
- User's Guide
- </fascicule>
- <fascicule file="ref_man" href="ref_man_frame.html" entry="yes">
- Reference Manual
- </fascicule>
- <fascicule file="part_notes" href="part_notes_frame.html" entry="no">
- Release Notes
- </fascicule>
- <fascicule file="" href="../../../../doc/print.html" entry="no">
- Off-Print
- </fascicule>
-</fascicules>
-
diff --git a/lib/et/doc/src/files.mk b/lib/et/doc/src/files.mk
index 41964de892..41fffb83f1 100644
--- a/lib/et/doc/src/files.mk
+++ b/lib/et/doc/src/files.mk
@@ -26,8 +26,7 @@ XML_REF3_FILES = \
et_viewer.xml
XML_PART_FILES = \
- part.xml \
- part_notes.xml
+ part.xml
XML_CHAPTER_FILES = \
et_intro.xml \
diff --git a/lib/eunit/info b/lib/eunit/info
index 138f4dc040..e7e6265940 100644
--- a/lib/eunit/info
+++ b/lib/eunit/info
@@ -1,2 +1,2 @@
-group: tools
+group: test
short: Support for unit testing.
diff --git a/lib/eunit/vsn.mk b/lib/eunit/vsn.mk
index 002703b1b3..3bfa9c8000 100644
--- a/lib/eunit/vsn.mk
+++ b/lib/eunit/vsn.mk
@@ -1 +1 @@
-EUNIT_VSN = 2.1.4
+EUNIT_VSN = 2.1.5
diff --git a/lib/hipe/Makefile b/lib/hipe/Makefile
index 10bf82b2d7..54efd7fcaf 100644
--- a/lib/hipe/Makefile
+++ b/lib/hipe/Makefile
@@ -27,7 +27,7 @@ else
HIPE_SUBDIRS =
endif
-ALWAYS_SUBDIRS = misc main cerl icode flow util
+ALWAYS_SUBDIRS = misc main cerl icode flow util doc/src
ifdef HIPE_ENABLED
# "rtl" below must be the first directory so that file rtl/hipe_literals.hrl
diff --git a/lib/hipe/doc/Makefile b/lib/hipe/doc/Makefile
index 340f909aa6..cdf9c9c798 100644
--- a/lib/hipe/doc/Makefile
+++ b/lib/hipe/doc/Makefile
@@ -1,21 +1,28 @@
-# ``The contents of this file are subject to the Erlang Public License,
+#
+# %CopyrightBegin%
+#
+# Copyright Ericsson AB 2006-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 via the world wide web at http://www.erlang.org/.
-#
+# 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%
+#
SHELL=/bin/sh
include $(ERL_TOP)/make/target.mk
include $(ERL_TOP)/make/$(TARGET)/otp.mk
clean:
- -rm -f *.html edoc-info stylesheet.css
+ -rm -f *.html edoc-info stylesheet.css erlang.png
# ----------------------------------------------------
# Special Build Targets
diff --git a/lib/hipe/doc/src/Makefile b/lib/hipe/doc/src/Makefile
index 3b63e57549..d440178e4c 100644
--- a/lib/hipe/doc/src/Makefile
+++ b/lib/hipe/doc/src/Makefile
@@ -1,19 +1,20 @@
-# ``The contents of this file are subject to the Erlang Public License,
+#
+# %CopyrightBegin%
+#
+# Copyright Ericsson AB 2006-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 via the world wide web at http://www.erlang.org/.
-#
+# 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.
-#
-# The Initial Developer of the Original Code is Ericsson Utvecklings AB.
-# Portions created by Ericsson are Copyright 1999, Ericsson Utvecklings
-# AB. All Rights Reserved.''
-#
-# $Id$
+#
+# %CopyrightEnd%
#
include $(ERL_TOP)/make/target.mk
include $(ERL_TOP)/make/$(TARGET)/otp.mk
@@ -33,7 +34,7 @@ RELSYSDIR = $(RELEASE_PATH)/lib/$(APPLICATION)-$(VSN)
# ----------------------------------------------------
# Target Specs
# ----------------------------------------------------
-XML_APPLICATION_FILES =
+XML_APPLICATION_FILES = ref_man.xml
XML_REF3_FILES =
XML_PART_FILES = part_notes.xml
diff --git a/lib/hipe/doc/src/book.xml b/lib/hipe/doc/src/book.xml
index 236dfc69a1..9c95e3a827 100644
--- a/lib/hipe/doc/src/book.xml
+++ b/lib/hipe/doc/src/book.xml
@@ -4,7 +4,7 @@
<book xmlns:xi="http://www.w3.org/2001/XInclude">
<header titlestyle="normal">
<copyright>
- <year>2006</year><year>2009</year>
+ <year>2006</year><year>2010</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -13,12 +13,12 @@
compliance with the License. You should have received a copy of the
Erlang Public License along with this software. If not, it can be
retrieved online at http://www.erlang.org/.
-
+
Software distributed under the License is distributed on an "AS IS"
basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
the License for the specific language governing rights and limitations
under the License.
-
+
</legalnotice>
<title>HiPE</title>
@@ -31,6 +31,9 @@
<preamble>
</preamble>
<pagetext>HiPE</pagetext>
+ <applications>
+ <xi:include href="ref_man.xml"/>
+ </applications>
<releasenotes>
<xi:include href="notes.xml"/>
</releasenotes>
diff --git a/lib/hipe/doc/src/hipe_app.xml b/lib/hipe/doc/src/hipe_app.xml
new file mode 100644
index 0000000000..56729d4cc4
--- /dev/null
+++ b/lib/hipe/doc/src/hipe_app.xml
@@ -0,0 +1,58 @@
+<?xml version="1.0" encoding="latin1" ?>
+<!DOCTYPE appref SYSTEM "appref.dtd">
+
+<appref>
+ <header>
+ <copyright>
+ <year>1997</year><year>2010</year>
+ <holder>Ericsson AB. All Rights Reserved.</holder>
+ </copyright>
+ <legalnotice>
+ 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.
+
+ </legalnotice>
+
+ <title>snmp</title>
+ <prepared></prepared>
+ <responsible></responsible>
+ <docno></docno>
+ <approved></approved>
+ <checked></checked>
+ <date></date>
+ <rev></rev>
+ <file>hipe.xml</file>
+ </header>
+ <app>HiPE</app>
+ <appsummary>The HiPE Application</appsummary>
+ <description>
+ <p>
+ The normal way to native-compile an Erlang module using HiPE is to include the atom native
+ in the Erlang compiler options, as in:
+ <code>
+ 1> <input>c(my_module, [native]).</input></code>
+ Options to the HiPE compiler are then passed as follows:
+ <code>
+ 1> <input>c(my_module, [native,{hipe,Options}]).</input></code>
+ For on-line help in the Erlang shell, call <c>hipe:help()</c>.
+ Details on HiPE compiler options are given by <c>hipe:help_options()</c>.
+ </p>
+ </description>
+ <section>
+ <title>SEE ALSO</title>
+ <p>
+ <seealso marker="stdlib:c">c(3)</seealso>,
+ <seealso marker="compiler:compile">compile(3)</seealso>
+ </p>
+ </section>
+
+</appref>
+
diff --git a/lib/et/doc/src/part_notes.xml b/lib/hipe/doc/src/ref_man.xml
index 00b3d9df23..09d10147ee 100644
--- a/lib/et/doc/src/part_notes.xml
+++ b/lib/hipe/doc/src/ref_man.xml
@@ -1,10 +1,10 @@
<?xml version="1.0" encoding="latin1" ?>
-<!DOCTYPE part SYSTEM "part.dtd">
+<!DOCTYPE application SYSTEM "application.dtd">
-<part xmlns:xi="http://www.w3.org/2001/XInclude">
+<application xmlns:xi="http://www.w3.org/2001/XInclude">
<header>
<copyright>
- <year>2002</year><year>2009</year>
+ <year>1996</year><year>2009</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -21,16 +21,15 @@
</legalnotice>
- <title>Event Tracer (ET) Release Notes</title>
- <prepared>H&aring;kan Mattsson</prepared>
+ <title>HiPE</title>
+ <prepared></prepared>
<docno></docno>
- <date></date>
- <rev>%VSN%</rev>
+ <date>1997-06-04</date>
+ <rev>1.3.1</rev>
+ <file>ref_man.xml</file>
</header>
<description>
- <p>The Event Tracer (ET) uses the built-in trace mechanism in Erlang
- and provides tools for collection and graphical viewing of trace data.</p>
</description>
- <xi:include href="notes.xml"/>
-</part>
+ <xi:include href="hipe_app.xml"/>
+</application>
diff --git a/lib/hipe/info b/lib/hipe/info
index 51b5dfb979..fe08fc8990 100644
--- a/lib/hipe/info
+++ b/lib/hipe/info
@@ -1,2 +1,2 @@
-group: basic
+group: misc Miscellaneous Applications
short: High Performance Erlang \ No newline at end of file
diff --git a/lib/jinterface/vsn.mk b/lib/jinterface/vsn.mk
index 243547cf1f..6b5719d7c5 100644
--- a/lib/jinterface/vsn.mk
+++ b/lib/jinterface/vsn.mk
@@ -1,19 +1,19 @@
##
## %CopyrightBegin%
-##
-## Copyright Ericsson AB 2000-2009. All Rights Reserved.
-##
+##
+## Copyright Ericsson AB 2000-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%
-JINTERFACE_VSN = 1.5.2
+JINTERFACE_VSN = 1.5.3
diff --git a/lib/kernel/src/Makefile b/lib/kernel/src/Makefile
index cd011f09fe..9db6014a7d 100644
--- a/lib/kernel/src/Makefile
+++ b/lib/kernel/src/Makefile
@@ -143,6 +143,9 @@ APPUP_TARGET= $(EBIN)/$(APPUP_FILE)
# FLAGS
# ----------------------------------------------------
+ifeq ($(NATIVE_LIBS_ENABLED),yes)
+ERL_COMPILE_FLAGS += +native
+endif
ERL_COMPILE_FLAGS += -I../include
# ----------------------------------------------------
diff --git a/lib/kernel/src/hipe_unified_loader.erl b/lib/kernel/src/hipe_unified_loader.erl
index 42eab67478..f289b8110d 100644
--- a/lib/kernel/src/hipe_unified_loader.erl
+++ b/lib/kernel/src/hipe_unified_loader.erl
@@ -96,14 +96,6 @@ load_hipe_modules() ->
%% code:load_file/1) and the atom `no_native' on failure.
load_native_code(Mod, Bin) when is_atom(Mod), is_binary(Bin) ->
- erlang:system_flag(multi_scheduling, block),
- try
- load_native_code_nosmp(Mod, Bin)
- after
- erlang:system_flag(multi_scheduling, unblock)
- end.
-
-load_native_code_nosmp(Mod, Bin) ->
Architecture = erlang:system_info(hipe_architecture),
try chunk_name(Architecture) of
ChunkTag ->
@@ -111,10 +103,15 @@ load_native_code_nosmp(Mod, Bin) ->
case code:get_chunk(Bin, ChunkTag) of
undefined -> no_native;
NativeCode when is_binary(NativeCode) ->
- OldReferencesToPatch = patch_to_emu_step1(Mod),
- case load_module(Mod, NativeCode, Bin, OldReferencesToPatch) of
- bad_crc -> no_native;
- Result -> Result
+ erlang:system_flag(multi_scheduling, block),
+ try
+ OldReferencesToPatch = patch_to_emu_step1(Mod),
+ case load_module(Mod, NativeCode, Bin, OldReferencesToPatch) of
+ bad_crc -> no_native;
+ Result -> Result
+ end
+ after
+ erlang:system_flag(multi_scheduling, unblock)
end
end
catch
@@ -128,17 +125,18 @@ load_native_code_nosmp(Mod, Bin) ->
-spec post_beam_load(atom()) -> 'ok'.
post_beam_load(Mod) when is_atom(Mod) ->
- erlang:system_flag(multi_scheduling, block),
- try
- post_beam_load_nosmp(Mod)
- after
- erlang:system_flag(multi_scheduling, unblock)
- end.
-
-post_beam_load_nosmp(Mod) ->
Architecture = erlang:system_info(hipe_architecture),
- try chunk_name(Architecture) of _ChunkTag -> patch_to_emu(Mod)
- catch _:_ -> ok
+ try chunk_name(Architecture) of
+ _ChunkTag ->
+ erlang:system_flag(multi_scheduling, block),
+ try
+ patch_to_emu(Mod)
+ after
+ erlang:system_flag(multi_scheduling, unblock)
+ end
+ catch
+ _:_ ->
+ ok
end.
%%========================================================================
diff --git a/lib/kernel/src/inet.erl b/lib/kernel/src/inet.erl
index b86aa1839e..eb503235d8 100644
--- a/lib/kernel/src/inet.erl
+++ b/lib/kernel/src/inet.erl
@@ -1,19 +1,19 @@
%%
%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1997-2009. 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
%% 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(inet).
@@ -45,6 +45,7 @@
%% resolve
-export([gethostbyname/1, gethostbyname/2, gethostbyname/3,
gethostbyname_tm/3]).
+-export([gethostbyname_string/2, gethostbyname_self/2]).
-export([gethostbyaddr/1, gethostbyaddr/2,
gethostbyaddr_tm/2]).
@@ -411,7 +412,17 @@ gethostbyname(Name,Family,Timeout) ->
Res.
gethostbyname_tm(Name,Family,Timer) ->
- gethostbyname_tm(Name,Family,Timer,inet_db:res_option(lookup)).
+ Opts0 = inet_db:res_option(lookup),
+ Opts =
+ case (lists:member(native, Opts0) orelse
+ lists:member(string, Opts0) orelse
+ lists:member(nostring, Opts0)) of
+ true ->
+ Opts0;
+ false ->
+ [string|Opts0]
+ end,
+ gethostbyname_tm(Name, Family, Timer, Opts).
-spec gethostbyaddr(Address :: string() | ip_address()) ->
@@ -850,75 +861,61 @@ getaddrs_tm(Address, Family, Timer) ->
%%
%% gethostbyname with option search
%%
-gethostbyname_tm(Name, Type, Timer, [dns | Opts]) ->
- Res = inet_res:gethostbyname_tm(Name, Type, Timer),
- case Res of
- {ok,_} -> Res;
- {error,timeout} -> Res;
- {error,formerr} -> {error,einval};
- {error,_} -> gethostbyname_tm(Name,Type,Timer,Opts)
- end;
-gethostbyname_tm(Name, Type, Timer, [file | Opts]) ->
- case inet_hosts:gethostbyname(Name, Type) of
- {error,formerr} -> {error,einval};
- {error,_} -> gethostbyname_tm(Name,Type,Timer,Opts);
- Result -> Result
- end;
-gethostbyname_tm(Name, Type, Timer, [yp | Opts]) ->
+gethostbyname_tm(Name, Type, Timer, [string|_]=Opts) ->
+ Result = gethostbyname_string(Name, Type),
+ gethostbyname_tm(Name, Type, Timer, Opts, Result);
+gethostbyname_tm(Name, Type, Timer, [dns|_]=Opts) ->
+ Result = inet_res:gethostbyname_tm(Name, Type, Timer),
+ gethostbyname_tm(Name, Type, Timer, Opts, Result);
+gethostbyname_tm(Name, Type, Timer, [file|_]=Opts) ->
+ Result = inet_hosts:gethostbyname(Name, Type),
+ gethostbyname_tm(Name, Type, Timer, Opts, Result);
+gethostbyname_tm(Name, Type, Timer, [yp|_]=Opts) ->
gethostbyname_tm_native(Name, Type, Timer, Opts);
-gethostbyname_tm(Name, Type, Timer, [nis | Opts]) ->
+gethostbyname_tm(Name, Type, Timer, [nis|_]=Opts) ->
gethostbyname_tm_native(Name, Type, Timer, Opts);
-gethostbyname_tm(Name, Type, Timer, [nisplus | Opts]) ->
+gethostbyname_tm(Name, Type, Timer, [nisplus|_]=Opts) ->
gethostbyname_tm_native(Name, Type, Timer, Opts);
-gethostbyname_tm(Name, Type, Timer, [wins | Opts]) ->
+gethostbyname_tm(Name, Type, Timer, [wins|_]=Opts) ->
gethostbyname_tm_native(Name, Type, Timer, Opts);
-gethostbyname_tm(Name, Type, Timer, [native | Opts]) ->
+gethostbyname_tm(Name, Type, Timer, [native|_]=Opts) ->
gethostbyname_tm_native(Name, Type, Timer, Opts);
-gethostbyname_tm(_, _, _, [no_default|_]) ->
- %% If the native resolver has failed, we should not bother
- %% to try to be smarter and parse the IP address here.
- {error,nxdomain};
-gethostbyname_tm(Name, Type, Timer, [_ | Opts]) ->
+gethostbyname_tm(Name, Type, Timer, [_|_]=Opts) ->
gethostbyname_tm(Name, Type, Timer, Opts);
-%% Last resort - parse the hostname as address
-gethostbyname_tm(Name, inet, _Timer, []) ->
- case inet_parse:ipv4_address(Name) of
- {ok,IP4} ->
- {ok,make_hostent(Name, [IP4], [], inet)};
- _ ->
- gethostbyname_self(Name)
- end;
-gethostbyname_tm(Name, inet6, _Timer, []) ->
- case inet_parse:ipv6_address(Name) of
- {ok,IP6} ->
- {ok,make_hostent(Name, [IP6], [], inet6)};
- _ ->
- %% Even if Name is a valid IPv4 address, we can't
- %% assume it's correct to return it on a IPv6
- %% format ( {0,0,0,0,0,16#ffff,?u16(A,B),?u16(C,D)} ).
- %% This host might not support IPv6.
- gethostbyname_self(Name)
+%% Make sure we always can look up our own hostname.
+gethostbyname_tm(Name, Type, Timer, []) ->
+ Result = gethostbyname_self(Name, Type),
+ gethostbyname_tm(Name, Type, Timer, [], Result).
+
+gethostbyname_tm(Name, Type, Timer, Opts, Result) ->
+ case Result of
+ {ok,_} ->
+ Result;
+ {error,formerr} ->
+ {error,einval};
+ {error,_} when Opts =:= [] ->
+ {error,nxdomain};
+ {error,_} ->
+ gethostbyname_tm(Name, Type, Timer, tl(Opts))
end.
gethostbyname_tm_native(Name, Type, Timer, Opts) ->
%% Fixme: add (global) timeout to gethost_native
- case inet_gethost_native:gethostbyname(Name, Type) of
- {error,formerr} -> {error,einval};
- {error,timeout} -> {error,timeout};
- {error,_} -> gethostbyname_tm(Name, Type, Timer, Opts++[no_default]);
- Result -> Result
- end.
+ Result = inet_gethost_native:gethostbyname(Name, Type),
+ gethostbyname_tm(Name, Type, Timer, Opts, Result).
-%% Make sure we always can look up our own hostname.
-gethostbyname_self(Name) ->
- Type = case inet_db:res_option(inet6) of
- true -> inet6;
- false -> inet
- end,
+
+
+gethostbyname_self(Name, Type) when is_atom(Name) ->
+ gethostbyname_self(atom_to_list(Name), Type);
+gethostbyname_self(Name, Type)
+ when is_list(Name), Type =:= inet;
+ is_list(Name), Type =:= inet6 ->
case inet_db:gethostname() of
Name ->
- {ok,make_hostent(Name, [translate_ip(loopback, Type)],
- [], Type)};
+ {ok,make_hostent(Name,
+ [translate_ip(loopback, Type)],
+ [], Type)};
Self ->
case inet_db:res_option(domain) of
"" -> {error,nxdomain};
@@ -931,7 +928,31 @@ gethostbyname_self(Name) ->
_ -> {error,nxdomain}
end
end
- end.
+ end;
+gethostbyname_self(_, _) ->
+ {error,formerr}.
+
+gethostbyname_string(Name, Type) when is_atom(Name) ->
+ gethostbyname_string(atom_to_list(Name), Type);
+gethostbyname_string(Name, Type)
+ when is_list(Name), Type =:= inet;
+ is_list(Name), Type =:= inet6 ->
+ case
+ case Type of
+ inet ->
+ inet_parse:ipv4_address(Name);
+ inet6 ->
+ %% XXX should we really translate IPv4 addresses here
+ %% even if we do not know if this host can do IPv6?
+ inet_parse:ipv6_address(Name)
+ end of
+ {ok,IP} ->
+ {ok,make_hostent(Name, [IP], [], Type)};
+ {error,einval} ->
+ {error,nxdomain}
+ end;
+gethostbyname_string(_, _) ->
+ {error,formerr}.
make_hostent(Name, Addrs, Aliases, Type) ->
#hostent{h_name = Name,
diff --git a/lib/kernel/src/inet_config.erl b/lib/kernel/src/inet_config.erl
index b5317f72f5..311e6bc9f9 100644
--- a/lib/kernel/src/inet_config.erl
+++ b/lib/kernel/src/inet_config.erl
@@ -1,19 +1,19 @@
%%
%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1997-2009. 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
%% 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(inet_config).
@@ -130,21 +130,25 @@ init() ->
{unix,_} ->
%% The Etc variable enables us to run tests with other
%% configuration files than the normal ones
- Etc = case os:getenv("ERL_INET_ETC_DIR") of
- false -> ?DEFAULT_ETC;
- _EtcDir ->
- _EtcDir
- end,
+ Etc =
+ case os:getenv("ERL_INET_ETC_DIR") of
+ false ->
+ ?DEFAULT_ETC;
+ _EtcDir ->
+ _EtcDir
+ end,
case inet_db:res_option(resolv_conf) of
undefined ->
- inet_db:set_resolv_conf(filename:join(Etc,
- ?DEFAULT_RESOLV));
+ inet_db:res_option(
+ resolv_conf_name,
+ filename:join(Etc, ?DEFAULT_RESOLV));
_ -> ok
end,
case inet_db:res_option(hosts_file) of
undefined ->
- inet_db:set_hosts_file(filename:join(Etc,
- ?DEFAULT_HOSTS));
+ inet_db:res_option(
+ hosts_file_name,
+ filename:join(Etc, ?DEFAULT_HOSTS));
_ -> ok
end;
_ -> ok
diff --git a/lib/kernel/src/inet_db.erl b/lib/kernel/src/inet_db.erl
index 211847014f..a05b380855 100644
--- a/lib/kernel/src/inet_db.erl
+++ b/lib/kernel/src/inet_db.erl
@@ -1,19 +1,19 @@
%%
%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1997-2009. 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
%% 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%
%%
@@ -425,7 +425,9 @@ res_optname(usevc) -> res_usevc;
res_optname(edns) -> res_edns;
res_optname(udp_payload_size) -> res_udp_payload_size;
res_optname(resolv_conf) -> res_resolv_conf;
+res_optname(resolv_conf_name) -> res_resolv_conf;
res_optname(hosts_file) -> res_hosts_file;
+res_optname(hosts_file_name) -> res_hosts_file;
res_optname(_) -> undefined.
res_check_option(nameserver, NSs) -> %% Legacy
@@ -458,9 +460,15 @@ res_check_option(udp_payload_size, S) when is_integer(S), S >= 512 -> true;
res_check_option(resolv_conf, "") -> true;
res_check_option(resolv_conf, F) ->
res_check_option_absfile(F);
+res_check_option(resolv_conf_name, "") -> true;
+res_check_option(resolv_conf_name, F) ->
+ res_check_option_absfile(F);
res_check_option(hosts_file, "") -> true;
res_check_option(hosts_file, F) ->
res_check_option_absfile(F);
+res_check_option(hosts_file_name, "") -> true;
+res_check_option(hosts_file_name, F) ->
+ res_check_option_absfile(F);
res_check_option(_, _) -> false.
res_check_option_absfile(F) ->
@@ -503,7 +511,7 @@ res_update_hosts() ->
res_update(res_hosts_file, res_hosts_file_tm, res_hosts_file_info,
set_hosts_file_tm, fun set_hosts_file/1).
-res_update(Tag, TagTm, TagInfo, CallTag, SetFun) ->
+res_update(Tag, TagTm, TagInfo, TagSetTm, SetFun) ->
case db_get(TagTm) of
undefined -> ok;
TM ->
@@ -522,12 +530,12 @@ res_update(Tag, TagTm, TagInfo, CallTag, SetFun) ->
atime = undefined},
case db_get(TagInfo) of
Finfo ->
- call({CallTag, Now});
+ call({TagSetTm, Now});
_ ->
SetFun(File)
end;
_ ->
- call({CallTag, Now}),
+ call({TagSetTm, Now}),
error
end
end;
@@ -974,37 +982,55 @@ handle_call(Request, From, #state{db=Db}=State) ->
{reply, error, State}
end;
+ {res_set, hosts_file_name=Option, Fname} ->
+ handle_set_file(
+ Option, Fname, res_hosts_file_tm, res_hosts_file_info,
+ undefined, From, State);
+ {res_set, resolv_conf_name=Option, Fname} ->
+ handle_set_file(
+ Option, Fname, res_resolv_conf_tm, res_resolv_conf_info,
+ undefined, From, State);
+
{res_set, hosts_file=Option, Fname} ->
- handle_set_file(Option, Fname,
- res_hosts_file_tm, res_hosts_file_info,
- fun (Bin) ->
- case inet_parse:hosts(Fname,
- {chars,Bin}) of
- {ok,Opts} ->
- [{load_hosts_file,Opts}];
- _ -> error
- end
- end,
- From, State);
+ handle_set_file(
+ Option, Fname, res_hosts_file_tm, res_hosts_file_info,
+ fun (Bin) ->
+ case inet_parse:hosts(
+ Fname, {chars,Bin}) of
+ {ok,Opts} ->
+ [{load_hosts_file,Opts}];
+ _ -> error
+ end
+ end,
+ From, State);
%%
{res_set, resolv_conf=Option, Fname} ->
- handle_set_file(Option, Fname,
- res_resolv_conf_tm, res_resolv_conf_info,
- fun (Bin) ->
- case inet_parse:resolv(Fname,
- {chars,Bin}) of
- {ok,Opts} ->
- [del_ns,
- clear_search,
- clear_cache
- |[Opt ||
- {T,_}=Opt <- Opts,
- (T =:= nameserver orelse
- T =:= search)]];
- _ -> error
- end
- end,
- From, State);
+ handle_set_file(
+ Option, Fname, res_resolv_conf_tm, res_resolv_conf_info,
+ fun (Bin) ->
+ case inet_parse:resolv(
+ Fname, {chars,Bin}) of
+ {ok,Opts} ->
+ Search =
+ lists:foldl(
+ fun ({search,L}, _) ->
+ L;
+ ({domain,""}, S) ->
+ S;
+ ({domain,D}, _) ->
+ [D];
+ (_, S) ->
+ S
+ end, [], Opts),
+ [del_ns,
+ clear_search,
+ clear_cache,
+ {search,Search}
+ |[Opt || {nameserver,_}=Opt <- Opts]];
+ _ -> error
+ end
+ end,
+ From, State);
%%
{res_set, Opt, Value} ->
case res_optname(Opt) of
@@ -1156,6 +1182,12 @@ handle_set_file(Option, Fname, TagTm, TagInfo, ParseFun, From,
ets:delete(Db, TagInfo),
ets:delete(Db, TagTm),
handle_set_file(ParseFun, <<>>, From, State);
+ true when ParseFun =:= undefined ->
+ File = filename:flatten(Fname),
+ ets:insert(Db, {res_optname(Option), File}),
+ ets:insert(Db, {TagInfo, undefined}),
+ ets:insert(Db, {TagTm, 0}),
+ {reply,ok,State};
true ->
File = filename:flatten(Fname),
ets:insert(Db, {res_optname(Option), File}),
@@ -1178,7 +1210,8 @@ handle_set_file(Option, Fname, TagTm, TagInfo, ParseFun, From,
handle_set_file(ParseFun, Bin, From, State) ->
case ParseFun(Bin) of
- error -> {reply,error,State};
+ error ->
+ {reply,error,State};
Opts ->
handle_rc_list(Opts, From, State)
end.
diff --git a/lib/kernel/src/inet_gethost_native.erl b/lib/kernel/src/inet_gethost_native.erl
index abdbe2b8cf..fabe9bf8b3 100644
--- a/lib/kernel/src/inet_gethost_native.erl
+++ b/lib/kernel/src/inet_gethost_native.erl
@@ -1,19 +1,19 @@
%%
%% %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
%% 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(inet_gethost_native).
@@ -443,19 +443,23 @@ gethostbyname(Name) ->
gethostbyname(Name, inet).
gethostbyname(Name, inet) when is_list(Name) ->
- getit(?OP_GETHOSTBYNAME, ?PROTO_IPV4, Name);
+ getit(?OP_GETHOSTBYNAME, ?PROTO_IPV4, Name, Name);
gethostbyname(Name, inet6) when is_list(Name) ->
- getit(?OP_GETHOSTBYNAME, ?PROTO_IPV6, Name);
+ getit(?OP_GETHOSTBYNAME, ?PROTO_IPV6, Name, Name);
gethostbyname(Name, Type) when is_atom(Name) ->
gethostbyname(atom_to_list(Name), Type);
gethostbyname(_, _) ->
{error, formerr}.
-gethostbyaddr({A,B,C,D}) when ?VALID_V4(A), ?VALID_V4(B), ?VALID_V4(C), ?VALID_V4(D) ->
- getit(?OP_GETHOSTBYADDR, ?PROTO_IPV4, <<A,B,C,D>>);
-gethostbyaddr({A,B,C,D,E,F,G,H}) when ?VALID_V6(A), ?VALID_V6(B), ?VALID_V6(C), ?VALID_V6(D),
- ?VALID_V6(E), ?VALID_V6(F), ?VALID_V6(G), ?VALID_V6(H) ->
- getit(?OP_GETHOSTBYADDR, ?PROTO_IPV6, <<A:16,B:16,C:16,D:16,E:16,F:16,G:16,H:16>>);
+gethostbyaddr({A,B,C,D}=Addr)
+ when ?VALID_V4(A), ?VALID_V4(B), ?VALID_V4(C), ?VALID_V4(D) ->
+ getit(?OP_GETHOSTBYADDR, ?PROTO_IPV4, <<A,B,C,D>>, Addr);
+gethostbyaddr({A,B,C,D,E,F,G,H}=Addr)
+ when ?VALID_V6(A), ?VALID_V6(B), ?VALID_V6(C), ?VALID_V6(D),
+ ?VALID_V6(E), ?VALID_V6(F), ?VALID_V6(G), ?VALID_V6(H) ->
+ getit
+ (?OP_GETHOSTBYADDR, ?PROTO_IPV6,
+ <<A:16,B:16,C:16,D:16,E:16,F:16,G:16,H:16>>, Addr);
gethostbyaddr(Addr) when is_list(Addr) ->
case inet_parse:address(Addr) of
{ok, IP} -> gethostbyaddr(IP);
@@ -466,30 +470,30 @@ gethostbyaddr(Addr) when is_atom(Addr) ->
gethostbyaddr(_) -> {error, formerr}.
control({debug_level, Level}) when is_integer(Level) ->
- getit(?OP_CONTROL, ?SETOPT_DEBUG_LEVEL, <<Level:32>>);
+ getit(?OP_CONTROL, ?SETOPT_DEBUG_LEVEL, <<Level:32>>, undefined);
control(soft_restart) ->
- getit(restart_port);
+ getit(restart_port, undefined);
control(_) -> {error, formerr}.
-getit(Op, Proto, Data) ->
- getit({Op, Proto, Data}).
+getit(Op, Proto, Data, DefaultName) ->
+ getit({Op, Proto, Data}, DefaultName).
-getit(Req) ->
+getit(Req, DefaultName) ->
Pid = ensure_started(),
Ref = make_ref(),
Pid ! {{self(),Ref}, Req},
receive
{Ref, {ok,BinHostent}} ->
- parse_address(BinHostent);
- {Ref, Error} ->
- Error
+ parse_address(BinHostent, DefaultName);
+ {Ref, Result} ->
+ Result
after 5000 ->
Ref2 = erlang:monitor(process,Pid),
Res2 = receive
{Ref, {ok,BinHostent}} ->
- parse_address(BinHostent);
- {Ref, Error} ->
- Error;
+ parse_address(BinHostent, DefaultName);
+ {Ref, Result} ->
+ Result;
{'DOWN', Ref2, process,
Pid, Reason} ->
{error, Reason}
@@ -546,21 +550,23 @@ ensure_started() ->
Pid
end.
-parse_address(BinHostent) ->
+parse_address(BinHostent, DefaultName) ->
case catch
begin
case BinHostent of
<<?UNIT_ERROR, Errstring/binary>> ->
{error, list_to_atom(listify(Errstring))};
<<?UNIT_IPV4, Naddr:32, T0/binary>> ->
- {T1,Addresses} = pick_addresses_v4(Naddr, T0),
- [Name | Names] = pick_names(T1),
+ {T1, Addresses} = pick_addresses_v4(Naddr, T0),
+ {Name, Names} =
+ expand_default_name(pick_names(T1), DefaultName),
{ok, #hostent{h_addr_list = Addresses, h_addrtype = inet,
h_aliases = Names, h_length = ?UNIT_IPV4,
h_name = Name}};
<<?UNIT_IPV6, Naddr:32, T0/binary>> ->
- {T1,Addresses} = pick_addresses_v6(Naddr, T0),
- [Name | Names] = pick_names(T1),
+ {T1, Addresses} = pick_addresses_v6(Naddr, T0),
+ {Name, Names} =
+ expand_default_name(pick_names(T1), DefaultName),
{ok, #hostent{h_addr_list = Addresses, h_addrtype = inet6,
h_aliases = Names, h_length = ?UNIT_IPV6,
h_name = Name}};
@@ -573,7 +579,15 @@ parse_address(BinHostent) ->
Normal ->
Normal
end.
-
+
+expand_default_name([], DefaultName) when is_list(DefaultName) ->
+ {DefaultName, []};
+expand_default_name([], DefaultName) when is_tuple(DefaultName) ->
+ {inet_parse:ntoa(DefaultName), []};
+expand_default_name([Name|Names], DefaultName)
+ when is_list(DefaultName); is_tuple(DefaultName) ->
+ {Name, Names}.
+
listify(Bin) ->
N = byte_size(Bin) - 1,
<<Bin2:N/binary, Ch>> = Bin,
diff --git a/lib/kernel/src/inet_parse.erl b/lib/kernel/src/inet_parse.erl
index 62d44fb723..3bd5fa0958 100644
--- a/lib/kernel/src/inet_parse.erl
+++ b/lib/kernel/src/inet_parse.erl
@@ -1,19 +1,19 @@
%%
%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1997-2009. 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
%% 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(inet_parse).
@@ -34,6 +34,7 @@
-export([nsswitch_conf/1, nsswitch_conf/2]).
-export([ipv4_address/1, ipv6_address/1]).
+-export([ipv4strict_address/1, ipv6strict_address/1]).
-export([address/1]).
-export([visible_string/1, domain/1]).
-export([ntoa/1, dots/1]).
@@ -456,17 +457,15 @@ is_dom2(_) ->
%%
-%% Test ipv4 address or ipv6 address
+%% Parse ipv4 address or ipv6 address
%% Return {ok, Address} | {error, Reason}
%%
address(Cs) when is_list(Cs) ->
case ipv4_address(Cs) of
- {ok,IP} -> {ok,IP};
+ {ok,IP} ->
+ {ok,IP};
_ ->
- case ipv6_address(Cs) of
- {ok, IP} -> {ok, IP};
- Error -> Error
- end
+ ipv6strict_address(Cs)
end;
address(_) ->
{error, einval}.
@@ -477,49 +476,145 @@ address(_) ->
%% d1.d2.d4
%% d1.d4
%% d4
+%% Any d may be octal, hexadecimal or decimal by C language standards.
+%% d4 fills all LSB bytes. This is legacy behaviour from Solaris
+%% and FreeBSD. And partly Linux that behave the same except
+%% it does not accept hexadecimal.
%%
%% Return {ok, IP} | {error, einval}
%%
ipv4_address(Cs) ->
- case catch ipv4_addr(Cs) of
- {'EXIT',_} -> {error,einval};
- Addr -> {ok,Addr}
+ try ipv4_addr(Cs) of
+ Addr ->
+ {ok,Addr}
+ catch
+ error:badarg ->
+ {error,einval}
end.
-ipv4_addr(Cs) ->
- ipv4_addr(d3(Cs), []).
+ipv4_addr(Cs) ->
+ case ipv4_addr(Cs, []) of
+ [D] when D < (1 bsl 32) ->
+ <<D1,D2,D3,D4>> = <<D:32>>,
+ {D1,D2,D3,D4};
+ [D,D1] when D < (1 bsl 24), D1 < 256 ->
+ <<D2,D3,D4>> = <<D:24>>,
+ {D1,D2,D3,D4};
+ [D,D2,D1] when D < (1 bsl 16), (D2 bor D1) < 256 ->
+ <<D3,D4>> = <<D:16>>,
+ {D1,D2,D3,D4};
+ [D4,D3,D2,D1] when (D4 bor D3 bor D2 bor D1) < 256 ->
+ {D1,D2,D3,D4};
+ _ ->
+ erlang:error(badarg)
+ end.
-ipv4_addr({Cs0,[]}, A) when length(A) =< 3 ->
- case [tod(Cs0)|A] of
- [D4,D3,D2,D1] ->
+ipv4_addr([_|_], [_,_,_,_]) ->
+ %% Early bailout for extra characters
+ erlang:error(badarg);
+ipv4_addr("0x"++Cs, Ds) ->
+ ipv4_addr(strip0(Cs), Ds, [], 16, 8);
+ipv4_addr("0X"++Cs, Ds) ->
+ ipv4_addr(strip0(Cs), Ds, [], 16, 8);
+ipv4_addr("0"++Cs, Ds) ->
+ ipv4_addr(strip0(Cs), Ds, [$0], 8, 11);
+ipv4_addr(Cs, Ds) when is_list(Cs) ->
+ ipv4_addr(Cs, Ds, [], 10, 10).
+
+ipv4_addr(Cs0, Ds, Rs, Base, N) ->
+ case ipv4_field(Cs0, N, Rs, Base) of
+ {D,""} ->
+ [D|Ds];
+ {D,[$.|[_|_]=Cs]} ->
+ ipv4_addr(Cs, [D|Ds]);
+ {_,_} ->
+ erlang:error(badarg)
+ end.
+
+strip0("0"++Cs) ->
+ strip0(Cs);
+strip0(Cs) when is_list(Cs) ->
+ Cs.
+
+
+%%
+%% Parse IPv4 strict dotted decimal address, no leading zeros:
+%% d1.d2.d3.d4
+%%
+%% Return {ok, IP} | {error, einval}
+%%
+ipv4strict_address(Cs) ->
+ try ipv4strict_addr(Cs) of
+ Addr ->
+ {ok,Addr}
+ catch
+ error:badarg ->
+ {error,einval}
+ end.
+
+ipv4strict_addr(Cs) ->
+ case ipv4strict_addr(Cs, []) of
+ [D4,D3,D2,D1] when (D4 bor D3 bor D2 bor D1) < 256 ->
{D1,D2,D3,D4};
- [D4,D2,D1] ->
- {D1,D2,0,D4};
- [D4,D1] ->
- {D1,0,0,D4};
- [D4] ->
- {0,0,0,D4}
- end;
-ipv4_addr({Cs0,"."++Cs1}, A) when length(A) =< 2 ->
- ipv4_addr(d3(Cs1), [tod(Cs0)|A]).
+ _ ->
+ erlang:error(badarg)
+ end.
+
+ipv4strict_addr([_|_], [_,_,_,_]) ->
+ %% Early bailout for extra characters
+ erlang:error(badarg);
+ipv4strict_addr("0", Ds) ->
+ [0|Ds];
+ipv4strict_addr("0."++Cs, Ds) ->
+ ipv4strict_addr(Cs, [0|Ds]);
+ipv4strict_addr(Cs0, Ds) when is_list(Cs0) ->
+ case ipv4_field(Cs0, 3, [], 10) of
+ {D,""} ->
+ [D|Ds];
+ {D,[$.|[_|_]=Cs]} ->
+ ipv4strict_addr(Cs, [D|Ds]);
+ {_,_} ->
+ erlang:error(badarg)
+ end.
+
-d3(Cs) -> d3(Cs, []).
-d3([C|Cs], R) when C >= $0, C =< $9, length(R) =< 2 ->
- d3(Cs, [C|R]);
-d3(Cs, [_|_]=R) ->
- {lists:reverse(R),Cs}.
+ipv4_field("", _, Rs, Base) ->
+ {ipv4_field(Rs, Base),""};
+ipv4_field("."++_=Cs, _, Rs, Base) ->
+ {ipv4_field(Rs, Base),Cs};
+ipv4_field("0"++_, _, [], _) ->
+ erlang:error(badarg);
+ipv4_field([C|Cs], N, Rs, Base) when N > 0 ->
+ ipv4_field(Cs, N-1, [C|Rs], Base);
+ipv4_field(Cs, _, _, _) when is_list(Cs) ->
+ erlang:error(badarg).
+
+ipv4_field(Rs, Base) ->
+ V = erlang:list_to_integer(lists:reverse(Rs), Base),
+ if V < 0 ->
+ erlang:error(badarg);
+ true ->
+ V
+ end.
-tod(Cs) ->
- case erlang:list_to_integer(Cs) of
- D when D >= 0, D =< 255 ->
- D;
+
+
+%%
+%% Forgiving IPv6 address
+%%
+%% Accepts IPv4 address and returns it as a IPv4 compatible IPv6 address
+%%
+ipv6_address(Cs) ->
+ case ipv4_address(Cs) of
+ {ok,{D1,D2,D3,D4}} ->
+ {ok,{0,0,0,0,0,16#ffff,(D1 bsl 8) bor D2,(D3 bsl 8) bor D4}};
_ ->
- erlang:error(badarg, [Cs])
+ ipv6strict_address(Cs)
end.
%%
-%% Parse IPv6 address:
+%% Parse IPv6 address according to RFC 4291:
%% x1:x2:x3:x4:x5:x6:x7:x8
%% x1:x2::x7:x8
%% ::x7:x8
@@ -530,77 +625,89 @@ tod(Cs) ->
%% ::x5:x6:d7a.d7b.d8a.d8b
%% x1:x2::d7a.d7b.d8a.d8b
%% ::d7a.d7b.d8a.d8b
+%% etc
%%
%% Return {ok, IP} | {error, einval}
%%
-ipv6_address(Cs) ->
- case catch ipv6_addr(Cs) of
- {'EXIT',_} -> {error,einval};
- Addr -> {ok,Addr}
+ipv6strict_address(Cs) ->
+ try ipv6_addr(Cs) of
+ Addr ->
+ {ok,Addr}
+ catch
+ error:badarg ->
+ {error,einval}
end.
ipv6_addr("::") ->
- ipv6_addr_done([], []);
+ ipv6_addr_done([], [], 0);
ipv6_addr("::"++Cs) ->
- ipv6_addr(x4(Cs), [], []);
+ ipv6_addr(hex(Cs), [], [], 0);
ipv6_addr(Cs) ->
- ipv6_addr(x4(Cs), []).
+ ipv6_addr(hex(Cs), [], 0).
%% Before "::"
-ipv6_addr({Cs0,[]}, A) when length(A) =:= 7 ->
- ipv6_addr_done([tox(Cs0)|A]);
-ipv6_addr({Cs0,"::"}, A) when length(A) =< 6 ->
- ipv6_addr_done([tox(Cs0)|A], []);
-ipv6_addr({Cs0,"::"++Cs1}, A) when length(A) =< 5 ->
- ipv6_addr(x4(Cs1), [tox(Cs0)|A], []);
-ipv6_addr({Cs0,":"++Cs1}, A) when length(A) =< 6 ->
- ipv6_addr(x4(Cs1), [tox(Cs0)|A]);
-ipv6_addr({Cs0,"."++Cs1}, A) when length(A) =:= 6 ->
- ipv6_addr(d3(Cs1), A, [], [tod(Cs0)]).
+ipv6_addr({Cs0,[]}, A, N) when N == 7 ->
+ ipv6_addr_done([hex_to_int(Cs0)|A]);
+ipv6_addr({Cs0,"::"}, A, N) when N =< 6 ->
+ ipv6_addr_done([hex_to_int(Cs0)|A], [], N+1);
+ipv6_addr({Cs0,"::"++Cs1}, A, N) when N =< 5 ->
+ ipv6_addr(hex(Cs1), [hex_to_int(Cs0)|A], [], N+1);
+ipv6_addr({Cs0,":"++Cs1}, A, N) when N =< 6 ->
+ ipv6_addr(hex(Cs1), [hex_to_int(Cs0)|A], N+1);
+ipv6_addr({Cs0,"."++_=Cs1}, A, N) when N == 6 ->
+ ipv6_addr_done(A, [], N, ipv4strict_addr(Cs0++Cs1));
+ipv6_addr(_, _, _) ->
+ erlang:error(badarg).
%% After "::"
-ipv6_addr({Cs0,[]}, A, B) when length(A)+length(B) =< 6 ->
- ipv6_addr_done(A, [tox(Cs0)|B]);
-ipv6_addr({Cs0,":"++Cs1}, A, B) when length(A)+length(B) =< 5 ->
- ipv6_addr(x4(Cs1), A, [tox(Cs0)|B]);
-ipv6_addr({Cs0,"."++Cs1}, A, B) when length(A)+length(B) =< 5 ->
- ipv6_addr(x4(Cs1), A, B, [tod(Cs0)]).
+ipv6_addr({Cs0,[]}, A, B, N) when N =< 6 ->
+ ipv6_addr_done(A, [hex_to_int(Cs0)|B], N+1);
+ipv6_addr({Cs0,":"++Cs1}, A, B, N) when N =< 5 ->
+ ipv6_addr(hex(Cs1), A, [hex_to_int(Cs0)|B], N+1);
+ipv6_addr({Cs0,"."++_=Cs1}, A, B, N) when N =< 5 ->
+ ipv6_addr_done(A, B, N, ipv4strict_addr(Cs0++Cs1));
+ipv6_addr(_, _, _, _) ->
+ erlang:error(badarg).
-%% After "."
-ipv6_addr({Cs0,[]}, A, B, C) when length(C) =:= 3 ->
- ipv6_addr_done(A, B, [tod(Cs0)|C]);
-ipv6_addr({Cs0,"."++Cs1}, A, B, C) when length(C) =< 2 ->
- ipv6_addr(d3(Cs1), A, B, [tod(Cs0)|C]).
+ipv6_addr_done(Ar, Br, N, {D1,D2,D3,D4}) ->
+ ipv6_addr_done(Ar, [((D3 bsl 8) bor D4),((D1 bsl 8) bor D2)|Br], N+2).
-ipv6_addr_done(Ar, Br, [D4,D3,D2,D1]) ->
- ipv6_addr_done(Ar, [((D3 bsl 8) bor D4),((D1 bsl 8) bor D2)|Br]).
-
-ipv6_addr_done(Ar, Br) ->
- ipv6_addr_done(Br++dup(8-length(Ar)-length(Br), 0, Ar)).
+ipv6_addr_done(Ar, Br, N) ->
+ ipv6_addr_done(Br++dup(8-N, 0, Ar)).
ipv6_addr_done(Ar) ->
list_to_tuple(lists:reverse(Ar)).
-x4(Cs) -> x4(Cs, []).
-
-x4([C|Cs], R) when C >= $0, C =< $9, length(R) =< 3 ->
- x4(Cs, [C|R]);
-x4([C|Cs], R) when C >= $a, C =< $f, length(R) =< 3 ->
- x4(Cs, [C|R]);
-x4([C|Cs], R) when C >= $A, C =< $F, length(R) =< 3 ->
- x4(Cs, [C|R]);
-x4(Cs, [_|_]=R) ->
- {lists:reverse(R),Cs}.
-
-tox(Cs) ->
- erlang:list_to_integer(Cs, 16).
+%% Collect Hex digits
+hex(Cs) -> hex(Cs, []).
+%%
+hex([C|Cs], R) when C >= $0, C =< $9 ->
+ hex(Cs, [C|R]);
+hex([C|Cs], R) when C >= $a, C =< $f ->
+ hex(Cs, [C|R]);
+hex([C|Cs], R) when C >= $A, C =< $F ->
+ hex(Cs, [C|R]);
+hex(Cs, [_|_]=R) when is_list(Cs) ->
+ {lists:reverse(R),Cs};
+hex(_, _) ->
+ erlang:error(badarg).
+
+%% Hex string to integer
+hex_to_int(Cs0) ->
+ case strip0(Cs0) of
+ Cs when length(Cs) =< 4 ->
+ erlang:list_to_integer("0"++Cs, 16);
+ _ ->
+ erlang:error(badarg)
+ end.
+%% Dup onto head of existing list
dup(0, _, L) ->
L;
dup(N, E, L) when is_integer(N), N >= 1 ->
- dup(N-1, E, [E|L]);
-dup(N, E, L) ->
- erlang:error(badarg, [N,E,L]).
+ dup(N-1, E, [E|L]).
+
+
%% Convert IPv4 adress to ascii
%% Convert IPv6 / IPV4 adress to ascii (plain format)
@@ -674,7 +781,7 @@ separate(_E, [H], R) ->
lists:reverse(R, [H]).
%% convert to A.B decimal form
-dig_to_dec(0) -> [$0,$.,$0];
+dig_to_dec(0) -> "0.0";
dig_to_dec(X) ->
integer_to_list((X bsr 8) band 16#ff) ++ "." ++
integer_to_list(X band 16#ff).
diff --git a/lib/kernel/src/user.erl b/lib/kernel/src/user.erl
index edf650ec59..17dc5a56a2 100644
--- a/lib/kernel/src/user.erl
+++ b/lib/kernel/src/user.erl
@@ -1,19 +1,19 @@
%%
%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1996-2009. All Rights Reserved.
-%%
+%%
+%% Copyright Ericsson AB 1996-2010. All Rights Reserved.
+%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
%% compliance with the License. You should have received a copy of the
%% Erlang Public License along with this software. If not, it can be
%% retrieved online at http://www.erlang.org/.
-%%
+%%
%% Software distributed under the License is distributed on an "AS IS"
%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
%% the License for the specific language governing rights and limitations
%% under the License.
-%%
+%%
%% %CopyrightEnd%
%%
-module(user).
@@ -698,7 +698,11 @@ get_chars_more(State, M, F, Xa, Port, Q, Fmt) ->
prompt(_Port, '') -> ok;
prompt(Port, Prompt) ->
- put_port(io_lib:format_prompt(Prompt), Port).
+ put_port(wrap_characters_to_binary(io_lib:format_prompt(Prompt),unicode,
+ case get(unicode) of
+ true -> unicode;
+ _ -> latin1
+ end), Port).
%% Convert error code to make it look as before
err_func(io_lib, get_until, {_,F,_}) ->
diff --git a/lib/kernel/test/inet_SUITE.erl b/lib/kernel/test/inet_SUITE.erl
index cf33e8b27f..eb8f918491 100644
--- a/lib/kernel/test/inet_SUITE.erl
+++ b/lib/kernel/test/inet_SUITE.erl
@@ -1,19 +1,19 @@
%%
%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1997-2009. 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
%% 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(inet_SUITE).
@@ -28,7 +28,7 @@
gethostnative_parallell/1, cname_loop/1,
gethostnative_soft_restart/1,gethostnative_debug_level/1,getif/1]).
--export([get_hosts/1, get_ipv6_hosts/1, parse_hosts/1,
+-export([get_hosts/1, get_ipv6_hosts/1, parse_hosts/1, parse_address/1,
kill_gethost/0, parallell_gethost/0]).
-export([init_per_testcase/2, end_per_testcase/2]).
@@ -249,14 +249,16 @@ t_getaddr_v6(Config) when is_list(Config) ->
?line {ok,IP46} = inet:getaddr(IP46, inet6),
?line {ok,IP46} = inet:getaddr(Name, inet6),
?line {ok,IP46} = inet:getaddr(FullName, inet6),
- ?line IP4toIP6 = inet:getaddr(IPStr, inet6),
- ?line case IP4toIP6 of
- {ok,IP46} -> % only native can do this
- ?line true = lists:member(native,
- inet_db:res_option(lookup));
- {error,nxdomain} ->
- ok
- end,
+ ?line {ok,IP46} = inet:getaddr(IPStr, inet6),
+%% ?line IP4toIP6 = inet:getaddr(IPStr, inet6),
+%% ?line case IP4toIP6 of
+%% {ok,IP46} ->
+%% ?line ok;
+%% {error,nxdomain} ->
+%% ?line false =
+%% lists:member(native,
+%% inet_db:res_option(lookup))
+%% end,
?line {Name6, FullName6, IPStr6, IP6, _} =
?config(test_host_ipv6_only, Config),
?line {ok,_} = inet:getaddr(list_to_atom(Name6), inet6),
@@ -301,7 +303,6 @@ ipv4_to_ipv6(Config) when is_list(Config) ->
end,
?line case {IP4to6Res,inet:gethostbyname(IPStr, inet6)} of
{true,{ok,HEnt}} ->
- ?line true = lists:member(native, inet_db:res_option(lookup)),
?line HEnt_ = HEnt#hostent{h_addrtype = inet6,
h_length = 16,
h_addr_list = [IP_46]},
@@ -374,9 +375,10 @@ get_hosts([C|Rest], Cur, Ip, Result) ->
get_hosts([], _, _, Result) ->
Result.
-parse(suite) -> [parse_hosts];
+parse(suite) -> [parse_hosts, parse_address];
parse(doc) -> ["Test that parsing of the hosts file or equivalent works,",
"and that erroneous lines are skipped"].
+
parse_hosts(Config) when is_list(Config) ->
?line DataDir = ?config(data_dir,Config),
?line HostFile = filename:join(DataDir, "hosts"),
@@ -388,6 +390,170 @@ parse_hosts(Config) when is_list(Config) ->
?line ResolvErr1 = filename:join(DataDir,"resolv.conf.err1"),
?line inet_parse:resolv(ResolvErr1).
+parse_address(Config) when is_list(Config) ->
+ V4Strict =
+ [{{0,0,0,0},"0.0.0.0"},
+ {{1,2,3,4},"1.2.3.4"},
+ {{253,252,251,250},"253.252.251.250"},
+ {{1,2,255,254},"1.2.255.254"}],
+ V6Strict =
+ [{{0,0,0,0,0,0,0,0},"::"},
+ {{15,0,0,0,0,0,0,2},"f::2"},
+ {{15,16#f11,0,0,0,0,256,2},"f:f11::0100:2"},
+ {{0,0,0,0,0,0,0,16#17},"::17"},
+ {{16#700,0,0,0,0,0,0,0},"0700::"},
+ {{0,0,0,0,0,0,2,1},"::2:1"},
+ {{0,0,0,0,0,3,2,1},"::3:2:1"},
+ {{0,0,0,0,4,3,2,1},"::4:3:2:1"},
+ {{0,0,0,5,4,3,2,1},"::5:4:3:2:1"},
+ {{0,0,6,5,4,3,2,1},"::6:5:4:3:2:1"},
+ {{0,7,6,5,4,3,2,1},"::7:6:5:4:3:2:1"},
+ {{7,0,0,0,0,0,0,0},"7::"},
+ {{7,6,0,0,0,0,0,0},"7:6::"},
+ {{7,6,5,0,0,0,0,0},"7:6:5::"},
+ {{7,6,5,4,0,0,0,0},"7:6:5:4::"},
+ {{7,6,5,4,3,0,0,0},"7:6:5:4:3::"},
+ {{7,6,5,4,3,2,0,0},"7:6:5:4:3:2::"},
+ {{7,6,5,4,3,2,1,0},"7:6:5:4:3:2:1::"},
+ {{16#c11,16#c22,16#5c33,16#c440,16#55c0,16#c66c,16#77,16#88},
+ "c11:0c22:5c33:c440:55c0:c66c:77:0088"},
+ {{16#c11,0,16#5c33,16#c440,16#55c0,16#c66c,16#77,16#88},
+ "c11::5c33:c440:55c0:c66c:77:0088"},
+ {{16#c11,16#c22,0,16#c440,16#55c0,16#c66c,16#77,16#88},
+ "c11:0c22::c440:55c0:c66c:77:0088"},
+ {{16#c11,16#c22,16#5c33,0,16#55c0,16#c66c,16#77,16#88},
+ "c11:0c22:5c33::55c0:c66c:77:0088"},
+ {{16#c11,16#c22,16#5c33,16#c440,0,16#c66c,16#77,16#88},
+ "c11:0c22:5c33:c440::c66c:77:0088"},
+ {{16#c11,16#c22,16#5c33,16#c440,16#55c0,0,16#77,16#88},
+ "c11:0c22:5c33:c440:55c0::77:0088"},
+ {{16#c11,16#c22,16#5c33,16#c440,16#55c0,16#c66c,0,16#88},
+ "c11:0c22:5c33:c440:55c0:c66c::0088"},
+ {{16#c11,0,0,16#c440,16#55c0,16#c66c,16#77,16#88},
+ "c11::c440:55c0:c66c:77:0088"},
+ {{16#c11,16#c22,0,0,16#55c0,16#c66c,16#77,16#88},
+ "c11:0c22::55c0:c66c:77:0088"},
+ {{16#c11,16#c22,16#5c33,0,0,16#c66c,16#77,16#88},
+ "c11:0c22:5c33::c66c:77:0088"},
+ {{16#c11,16#c22,16#5c33,16#c440,0,0,16#77,16#88},
+ "c11:0c22:5c33:c440::77:0088"},
+ {{16#c11,16#c22,16#5c33,16#c440,16#55c0,0,0,16#88},
+ "c11:0c22:5c33:c440:55c0::0088"},
+ {{16#c11,0,0,0,16#55c0,16#c66c,16#77,16#88},
+ "c11::55c0:c66c:77:0088"},
+ {{16#c11,16#c22,0,0,0,16#c66c,16#77,16#88},
+ "c11:0c22::c66c:77:0088"},
+ {{16#c11,16#c22,16#5c33,0,0,0,16#77,16#88},
+ "c11:0c22:5c33::77:0088"},
+ {{16#c11,16#c22,16#5c33,16#c440,0,0,0,16#88},
+ "c11:0c22:5c33:c440::0088"},
+ {{16#c11,0,0,0,0,16#c66c,16#77,16#88},
+ "c11::c66c:77:0088"},
+ {{16#c11,16#c22,0,0,0,0,16#77,16#88},
+ "c11:0c22::77:0088"},
+ {{16#c11,16#c22,16#5c33,0,0,0,0,16#88},
+ "c11:0c22:5c33::0088"},
+ {{16#c11,0,0,0,0,0,16#77,16#88},
+ "c11::77:0088"},
+ {{16#c11,16#c22,0,0,0,0,0,16#88},
+ "c11:0c22::0088"},
+ {{0,0,0,0,0,65535,258,65534},"::FFFF:1.2.255.254"},
+ {{16#ffff,16#ffff,16#ffff,16#ffff,16#ffff,16#ffff,16#ffff,16#ffff},
+ "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff"}
+ |[{{D2,0,0,0,0,P,(D1 bsl 8) bor D2,(D3 bsl 8) bor D4},
+ erlang:integer_to_list(D2, 16)++"::"++Q++S}
+ || {{D1,D2,D3,D4},S} <- V4Strict,
+ {P,Q} <- [{0,""},{16#17,"17:"},{16#ff0,"0ff0:"}]]],
+ V4Sloppy =
+ [{{10,1,16#98,16#76},"10.0x019876"},
+ {{8#12,1,8#130,8#321},"012.01.054321"},
+ {{255,255,255,255},"255.255.255.0377"},
+ {{255,255,255,255},"0Xff.000000000377.0x0000ff.255"},
+ {{255,255,255,255},"255.255.65535"},
+ {{255,255,255,255},"255.0xFF.0177777"},
+ {{255,255,255,255},"255.16777215"},
+ {{255,255,255,255},"00377.0XFFFFFF"},
+ {{255,255,255,255},"4294967295"},
+ {{255,255,255,255},"0xffffffff"},
+ {{255,255,255,255},"00000000000037777777777"},
+ {{16#12,16#34,16#56,16#78},"0x12345678"},
+ {{16#12,16#34,16#56,16#78},"0x12.0x345678"},
+ {{16#12,16#34,16#56,16#78},"0x12.0X34.0x5678"},
+ {{16#12,16#34,16#56,16#78},"0x12.0X34.0x56.0X78"},
+ {{0,0,0,0},"0"},
+ {{0,0,0,0},"00"},
+ {{0,0,0,0},"0.0"},
+ {{0,0,0,0},"00.00.00"},
+ {{0,0,0,0},"0.00.0.0"},
+ {{0,0,0,0},"0.0.000000000000.0"}],
+ V6Sloppy =
+ [{{0,0,0,0,0,65535,(D1 bsl 8) bor D2,(D3 bsl 8) bor D4},S}
+ || {{D1,D2,D3,D4},S} <- V4Strict++V4Sloppy],
+ V4Err =
+ ["0.256.0.1",
+ "1.2.3.4.5",
+ "256.255.65535",
+ "4294967296",
+ "0x100000000",
+ "040000000000",
+ "1.2.3.-4",
+ "1.2.-3.4",
+ "1.-2.3.4",
+ "-1.2.3.4",
+ "10.",
+ "172.16.",
+ "198.168.0.",
+ "127.0.0.1."],
+ V6Err =
+ [":::",
+ "f:::2",
+ "::-1",
+ "::g",
+ "f:f11::10100:2",
+ "::17000",
+ "10000::",
+ "::8:7:6:5:4:3:2:1",
+ "8:7:6:5:4:3:2:1::",
+ "8:7:6:5:4::3:2:1",
+ "::1.2.3.4.5",
+ "::1.2.3.04",
+ "::1.256.3.4",
+ "::-5.4.3.2",
+ "::5.-4.3.2",
+ "::5.4.-3.2",
+ "::5.4.3.-2",
+ "::FFFF:1.2.3.4.5",
+ "::10.",
+ "::FFFF:172.16.",
+ "fe80::198.168.0.",
+ "fec0::fFfF:127.0.0.1."],
+ t_parse_address
+ (ipv6_address,
+ V6Strict++V6Sloppy++V6Err++V4Err),
+ t_parse_address
+ (ipv6strict_address,
+ V6Strict++V6Err++V4Err++[S || {_,S} <- V6Sloppy]),
+ t_parse_address
+ (ipv4_address,
+ V4Strict++V4Sloppy++V4Err++V6Err++[S || {_,S} <- V6Strict]),
+ t_parse_address
+ (ipv4strict_address,
+ V4Strict++V4Err++V6Err++[S || {_,S} <- V4Sloppy++V6Strict]).
+
+t_parse_address(Func, []) ->
+ io:format("~p done.~n", [Func]),
+ ok;
+t_parse_address(Func, [{Addr,String}|L]) ->
+ io:format("~p = ~p.~n", [Addr,String]),
+ {ok,Addr} = inet_parse:Func(String),
+ t_parse_address(Func, L);
+t_parse_address(Func, [String|L]) ->
+ io:format("~p.~n", [String]),
+ {error,einval} = inet_parse:Func(String),
+ t_parse_address(Func, L).
+
+
+
t_gethostnative(suite) ->[];
t_gethostnative(doc) ->[];
t_gethostnative(Config) when is_list(Config) ->
diff --git a/lib/kernel/test/inet_res_SUITE.erl b/lib/kernel/test/inet_res_SUITE.erl
index 659cfc5988..cc32d1f8f9 100644
--- a/lib/kernel/test/inet_res_SUITE.erl
+++ b/lib/kernel/test/inet_res_SUITE.erl
@@ -1,19 +1,19 @@
%%
%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2009. All Rights Reserved.
-%%
+%%
+%% Copyright Ericsson AB 2009-2010. All Rights Reserved.
+%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
%% compliance with the License. You should have received a copy of the
%% Erlang Public License along with this software. If not, it can be
%% retrieved online at http://www.erlang.org/.
-%%
+%%
%% Software distributed under the License is distributed on an "AS IS"
%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
%% the License for the specific language governing rights and limitations
%% under the License.
-%%
+%%
%% %CopyrightEnd%
%%
-module(inet_res_SUITE).
@@ -239,16 +239,37 @@ resolve(_Opts, []) -> ok;
resolve(Opts, [{Class,Type,Name,Answers,Authority}=Q|Qs]) ->
io:format("Query: ~p~nOptions: ~p~n", [Q,Opts]),
{ok,Msg} = inet_res:resolve(Name, Class, Type, Opts),
- if Answers =/= undefined ->
- AnList = lists:sort(Answers),
- AnList = lists:sort([inet_dns:rr(RR, data) ||
- RR <- inet_dns:msg(Msg, anlist)]);
- true -> ok end,
- if Authority =/= undefined ->
- NsList = lists:sort(Authority),
- NsList = lists:sort([inet_dns:rr(RR, data) ||
- RR <- inet_dns:msg(Msg, nslist)]);
- true -> ok end,
+ AnList =
+ if
+ Answers =/= undefined ->
+ lists:sort(Answers);
+ true ->
+ undefined
+ end,
+ NsList =
+ if
+ Authority =/= undefined ->
+ lists:sort(Authority);
+ true ->
+ undefined
+ end,
+ case {lists:sort
+ ([inet_dns:rr(RR, data) || RR <- inet_dns:msg(Msg, anlist)]),
+ lists:sort
+ ([inet_dns:rr(RR, data) || RR <- inet_dns:msg(Msg, nslist)])} of
+ {AnList,NsList} ->
+ ok;
+ {NsList,AnList} when Type =:= ns ->
+ %% This whole case statement is kind of inside out just
+ %% to accept this case when some legacy DNS resolvers
+ %% return the answer to a NS query in the answer section
+ %% instead of in the authority section.
+ ok;
+ {AnList,_} when NsList =:= undefined ->
+ ok;
+ {_,NsList} when AnList =:= undefined ->
+ ok
+ end,
Buf = inet_dns:encode(Msg),
{ok,Msg} = inet_dns:decode(Buf),
resolve(Opts, Qs).
@@ -292,10 +313,23 @@ edns0(Config) when is_list(Config) ->
MXs = lists:sort(inet_res_filter(inet_dns:msg(Msg2, anlist), in, mx)),
Buf2 = inet_dns:encode(Msg2),
{ok,Msg2} = inet_dns:decode(Buf2),
- [OptRR] = [RR || RR <- inet_dns:msg(Msg2, arlist),
- inet_dns:rr(RR, type) =:= opt],
- io:format("~p~n", [inet_dns:rr(OptRR)]),
- ok.
+ case [RR || RR <- inet_dns:msg(Msg2, arlist),
+ inet_dns:rr(RR, type) =:= opt] of
+ [OptRR] ->
+ io:format("~p~n", [inet_dns:rr(OptRR)]),
+ ok;
+ [] ->
+ case os:type() of
+ {unix,sunos} ->
+ case os:version() of
+ {M,V,_} when M < 5; M == 5, V =< 8 ->
+ %% In our test park only known platform
+ %% with an DNS resolver that can not do
+ %% EDNS0.
+ {comment,"No EDNS0"}
+ end
+ end
+ end.
inet_res_filter(Anlist, Class, Type) ->
[inet_dns:rr(RR, data) || RR <- Anlist,
@@ -331,11 +365,13 @@ files_monitor(suite) ->
files_monitor(doc) ->
["Tests monitoring of /etc/hosts and /etc/resolv.conf, but not them"];
files_monitor(Config) when is_list(Config) ->
+ Search = inet_db:res_option(search),
HostsFile = inet_db:res_option(hosts_file),
ResolvConf = inet_db:res_option(resolv_conf),
Inet6 = inet_db:res_option(inet6),
try do_files_monitor(Config)
after
+ inet_db:res_option(search, Search),
inet_db:res_option(resolv_conf, ResolvConf),
inet_db:res_option(hosts_file, HostsFile),
inet_db:res_option(inet6, Inet6)
@@ -344,7 +380,13 @@ files_monitor(Config) when is_list(Config) ->
do_files_monitor(Config) ->
Dir = ?config(priv_dir, Config),
{ok,Hostname} = inet:gethostname(),
- FQDN = Hostname++"."++inet_db:res_option(domain),
+ FQDN =
+ case inet_db:res_option(domain) of
+ "" ->
+ Hostname;
+ _ ->
+ Hostname++"."++inet_db:res_option(domain)
+ end,
HostsFile = filename:join(Dir, "files_monitor_hosts"),
ResolvConf = filename:join(Dir, "files_monitor_resolv.conf"),
ok = inet_db:res_option(resolv_conf, ResolvConf),
@@ -362,20 +404,20 @@ do_files_monitor(Config) ->
{error,nxdomain} = inet_res:gethostbyname(FQDN),
{ok,{127,0,0,10}} = inet:getaddr("mx.otptest", inet),
{ok,{0,0,0,0,0,0,32512,28}} = inet:getaddr("resolve.otptest", inet6),
- ok = inet_db:res_option(inet6, true),
{ok,#hostent{h_name = Hostname,
h_addrtype = inet6,
h_length = 16,
h_addr_list = [{0,0,0,0,0,0,0,1}]}} =
- inet:gethostbyname(Hostname),
+ inet:gethostbyname(Hostname, inet6),
{ok,#hostent{h_name = FQDN,
h_addrtype = inet6,
h_length = 16,
h_addr_list = [{0,0,0,0,0,0,0,1}]}} =
- inet:gethostbyname(FQDN),
+ inet:gethostbyname(FQDN, inet6),
{error,nxdomain} = inet_res:gethostbyname("resolve"),
%% XXX inet does not honour res_option inet6, might be a problem?
%% therefore inet_res is called here
+ ok = inet_db:res_option(inet6, true),
{ok,#hostent{h_name = "resolve.otptest",
h_addrtype = inet6,
h_length = 16,
diff --git a/lib/parsetools/vsn.mk b/lib/parsetools/vsn.mk
index e3db40c193..b1354e89d8 100644
--- a/lib/parsetools/vsn.mk
+++ b/lib/parsetools/vsn.mk
@@ -1 +1 @@
-PARSETOOLS_VSN = 2.0.1
+PARSETOOLS_VSN = 2.0.2
diff --git a/lib/percept/src/egd_render.erl b/lib/percept/src/egd_render.erl
index cea9d2d926..4a0247dd33 100644
--- a/lib/percept/src/egd_render.erl
+++ b/lib/percept/src/egd_render.erl
@@ -1,19 +1,19 @@
%%
%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2008-2009. All Rights Reserved.
-%%
+%%
+%% Copyright Ericsson AB 2008-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%
%%
@@ -179,7 +179,7 @@ color(Trans,Layers,Type,OldC) ->
color([],_) -> {0.0,0.0,0.0,0.0};
color([{_,C}|_],opaque) -> C;
-color(Layers,alpha) -> color1({0,0,0,0},Layers).
+color(Layers,alpha) -> color1({0.0,0.0,0.0,0.0},Layers).
color1(Color,[]) -> Color;
color1(Color,[{_,C}|Layers]) -> color1(alpha_blend(Color,C),Layers).
diff --git a/lib/percept/test/egd_SUITE.erl b/lib/percept/test/egd_SUITE.erl
index a2595400dd..fde02b47d5 100644
--- a/lib/percept/test/egd_SUITE.erl
+++ b/lib/percept/test/egd_SUITE.erl
@@ -1,19 +1,19 @@
%%
%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2007-2009. All Rights Reserved.
-%%
+%%
+%% Copyright Ericsson AB 2007-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%
%%
@@ -143,6 +143,8 @@ image_shape(Config) when is_list(Config) ->
?line ok = bitmap_point_has_color(Bitmap, {W,H}, Pt2, Fgc),
?line ok = bitmap_point_has_color(Bitmap, {W,H}, Pt1, Fgc),
+ ?line <<_/binary>> = egd:render(Im, raw_bitmap, [{render_engine, alpha}]),
+
?line ok = egd:destroy(Im),
erase(image_size),
ok.
@@ -177,6 +179,8 @@ image_primitives(Config) when is_list(Config) ->
?line ok = bitmap_point_has_color(Bitmap, {W,H}, Pt2, Fgc),
?line ok = bitmap_point_has_color(Bitmap, {W,H}, Pt1, Fgc),
+ ?line <<_/binary>> = egd_render:binary(Im2, alpha),
+
erase(image_size),
ok.
diff --git a/lib/percept/vsn.mk b/lib/percept/vsn.mk
index ef5a20f028..443d25c78f 100644
--- a/lib/percept/vsn.mk
+++ b/lib/percept/vsn.mk
@@ -1 +1 @@
-PERCEPT_VSN = 0.8.3
+PERCEPT_VSN = 0.8.4
diff --git a/lib/reltool/doc/src/Makefile b/lib/reltool/doc/src/Makefile
index 2c634bdf6c..8bc1488f77 100644
--- a/lib/reltool/doc/src/Makefile
+++ b/lib/reltool/doc/src/Makefile
@@ -1,19 +1,19 @@
#
# %CopyrightBegin%
-#
-# Copyright Ericsson AB 2009. All Rights Reserved.
-#
+#
+# Copyright Ericsson AB 2009-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%
include $(ERL_TOP)/make/target.mk
@@ -39,6 +39,10 @@ include files.mk
# ----------------------------------------------------
+XML_FILES = \
+ $(BOOK_FILES) $(XML_APPLICATION_FILES) $(XML_REF3_FILES) \
+ $(XML_PART_FILES) $(XML_CHAPTER_FILES)
+
HTML_FILES = $(XML_APPLICATION_FILES:%.xml=$(HTMLDIR)/%.html) \
$(XML_PART_FILES:%.xml=$(HTMLDIR)/%.html)
@@ -46,10 +50,6 @@ INFO_FILE = ../../info
MAN3_FILES = $(XML_REF3_FILES:%.xml=$(MAN3DIR)/%.3)
-XML_FILES = \
- $(BOOK_FILES) $(XML_CHAPTER_FILES) \
- $(XML_PART_FILES) $(XML_REF3_FILES) $(XML_APPLICATION_FILES)
-
HTML_REF_MAN_FILE = $(HTMLDIR)/index.html
TOP_PDF_FILE = $(PDFDIR)/$(APPLICATION)-$(VSN).pdf
@@ -72,15 +72,20 @@ $(TOP_PDF_FILE): $(XML_FILES)
pdf: $(TOP_PDF_FILE)
-html: gifs $(HTML_REF_MAN_FILE)
+html:images $(HTML_REF_MAN_FILE)
man: $(MAN3_FILES)
-gifs: $(GIF_FILES:%=$(HTMLDIR)/%)
+images: $(IMAGE_FILES:%=$(HTMLDIR)/%)
debug opt:
clean clean_docs:
+ for file in $(XML_FILES); do \
+ if [ -f $$file\src ]; then \
+ rm -f $$file; \
+ fi \
+ done
rm -rf $(HTMLDIR)/*
rm -f $(MAN3DIR)/*
rm -f $(TOP_PDF_FILE) $(TOP_PDF_FILE:%.pdf=%.fo)
@@ -95,8 +100,7 @@ release_docs_spec: docs
$(INSTALL_DIR) $(RELSYSDIR)/doc/pdf
$(INSTALL_DATA) $(TOP_PDF_FILE) $(RELSYSDIR)/doc/pdf
$(INSTALL_DIR) $(RELSYSDIR)/doc/html
- $(INSTALL_DATA) $(HTMLDIR)/* \
- $(RELSYSDIR)/doc/html
+ $(INSTALL_DATA) $(HTMLDIR)/* $(RELSYSDIR)/doc/html
$(INSTALL_DATA) $(INFO_FILE) $(RELSYSDIR)
$(INSTALL_DIR) $(RELEASE_PATH)/man/man3
$(INSTALL_DATA) $(MAN3DIR)/* $(RELEASE_PATH)/man/man3
diff --git a/lib/reltool/doc/src/book.gif b/lib/reltool/doc/src/book.gif
deleted file mode 100644
index 94b3868792..0000000000
--- a/lib/reltool/doc/src/book.gif
+++ /dev/null
Binary files differ
diff --git a/lib/reltool/doc/src/fascicules.xml b/lib/reltool/doc/src/fascicules.xml
deleted file mode 100644
index a57808974e..0000000000
--- a/lib/reltool/doc/src/fascicules.xml
+++ /dev/null
@@ -1,17 +0,0 @@
-<?xml version="1.0" encoding="latin1" ?>
-<!DOCTYPE fascicules SYSTEM "fascicules.dtd">
-
-<fascicules>
- <fascicule file="part" href="part_frame.html" entry="no">
- User's Guide
- </fascicule>
- <fascicule file="ref_man" href="ref_man_frame.html" entry="yes">
- Reference Manual
- </fascicule>
- <fascicule file="part_notes" href="part_notes_frame.html" entry="no">
- Release Notes
- </fascicule>
- <fascicule file="" href="../../../../doc/print.html" entry="no">
- Off-Print
- </fascicule>
-</fascicules>
diff --git a/lib/reltool/doc/src/files.mk b/lib/reltool/doc/src/files.mk
index b2dc06411d..07b52f4934 100644
--- a/lib/reltool/doc/src/files.mk
+++ b/lib/reltool/doc/src/files.mk
@@ -1,20 +1,20 @@
#-*-makefile-*- ; force emacs to enter makefile-mode
#
# %CopyrightBegin%
-#
-# Copyright Ericsson AB 2009. All Rights Reserved.
-#
+#
+# Copyright Ericsson AB 2009-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%
XML_APPLICATION_FILES = \
@@ -24,8 +24,7 @@ XML_REF3_FILES = \
reltool.xml
XML_PART_FILES = \
- part.xml \
- part_notes.xml
+ part.xml
XML_CHAPTER_FILES = \
reltool_intro.xml \
@@ -35,11 +34,5 @@ XML_CHAPTER_FILES = \
BOOK_FILES = book.xml
-GIF_FILES = \
- book.gif \
- note.gif \
- notes.gif \
- ref_man.gif \
- user_guide.gif \
- warning.gif
+IMAGE_FILES =
diff --git a/lib/reltool/doc/src/note.gif b/lib/reltool/doc/src/note.gif
deleted file mode 100644
index 6fffe30419..0000000000
--- a/lib/reltool/doc/src/note.gif
+++ /dev/null
Binary files differ
diff --git a/lib/reltool/doc/src/notes.gif b/lib/reltool/doc/src/notes.gif
deleted file mode 100644
index e000cca26a..0000000000
--- a/lib/reltool/doc/src/notes.gif
+++ /dev/null
Binary files differ
diff --git a/lib/reltool/doc/src/part_notes.xml b/lib/reltool/doc/src/part_notes.xml
deleted file mode 100644
index 5a2aeecce6..0000000000
--- a/lib/reltool/doc/src/part_notes.xml
+++ /dev/null
@@ -1,41 +0,0 @@
-<?xml version="1.0" encoding="latin1" ?>
-<!DOCTYPE part SYSTEM "part.dtd">
-
-<part xmlns:xi="http://www.w3.org/2001/XInclude">
- <header>
- <copyright>
- <year>2009</year>
- <year>2009</year>
- <holder>Ericsson AB, All Rights Reserved</holder>
- </copyright>
- <legalnotice>
- 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.
-
- The Initial Developer of the Original Code is Ericsson AB.
- </legalnotice>
-
- <title>Reltool Release Notes</title>
- <prepared>H&aring;kan Mattsson</prepared>
- <docno></docno>
- <date></date>
- <rev>%VSN%</rev>
- </header>
- <description>
- <p><c>Reltool</c> is a release management tool. It analyses a given
- Erlang/OTP installation and determines various dependencies
- between applications. The <c>graphical</c> frontend depicts the
- dependencies and enables interactive customization of a
- target system. The backend provides a <c>batch</c> interface
- for generation of customized target systems.</p>
- </description>
- <xi:include href="notes.xml"/>
-</part>
diff --git a/lib/reltool/doc/src/ref_man.gif b/lib/reltool/doc/src/ref_man.gif
deleted file mode 100644
index b13c4efd53..0000000000
--- a/lib/reltool/doc/src/ref_man.gif
+++ /dev/null
Binary files differ
diff --git a/lib/reltool/doc/src/reltool_examples.xml b/lib/reltool/doc/src/reltool_examples.xml
index 3d087862e6..d6db246f6c 100644
--- a/lib/reltool/doc/src/reltool_examples.xml
+++ b/lib/reltool/doc/src/reltool_examples.xml
@@ -45,7 +45,8 @@
its server can be obtained with <c>reltool:get_server/1</c></p>
<pre>
-Erlang R13B02 (erts-5.7.3) [source] [64-bit] [smp:4:4] [rq:4] [async-threads:0] [kernel-poll:false]
+Erlang R13B02 (erts-5.7.3) [source] [64-bit] [smp:4:4] [rq:4]
+ [async-threads:0] [kernel-poll:false]
Eshell V5.7.3 (abort with ^G)
1&gt; {ok, Win} = reltool:start([]).
@@ -72,10 +73,13 @@ ok
<title>Inspecting the configuration</title>
<pre>
-Erlang R13B02 (erts-5.7.3) [source] [64-bit] [smp:4:4] [rq:4] [async-threads:0] [kernel-poll:false]
+Erlang R13B02 (erts-5.7.3) [source] [64-bit] [smp:4:4] [rq:4]
+ [async-threads:0] [kernel-poll:false]
Eshell V5.7.3 (abort with ^G)
-1&gt; Config = {sys, [{escript, "examples/display_args", [{incl_cond, include}]},
+1&gt; Config = {sys, [{escript,
+ "examples/display_args",
+ [{incl_cond, include}]},
{app, inets, [{incl_cond, include}]},
{app, mnesia, [{incl_cond, exclude}]},
{app, ssl, [{incl_cond, exclude}]},
@@ -244,7 +248,8 @@ Eshell V5.7.3 (abort with ^G)
<title>Generate release and script files</title>
<pre>
5&gt; {ok, Server} = reltool:start_server([{config, {sys, [{boot_rel, "NAME"},
- {rel, "NAME", "VSN", [kernel, stdlib, sasl]}]}}]).
+ {rel, "NAME", "VSN",
+ [kernel, stdlib, sasl]}]}}]).
{ok,&lt;0.1288.0&gt;}
6&gt; reltool:get_config(Server).
{ok,{sys,[{boot_rel,"NAME"},
@@ -297,10 +302,13 @@ ok
<section>
<title>Create a target system</title>
<pre>
-Erlang R13B02 (erts-5.7.3) [source] [64-bit] [smp:4:4] [rq:4] [async-threads:0] [kernel-poll:false]
+Erlang R13B02 (erts-5.7.3) [source] [64-bit] [smp:4:4] [rq:4]
+ [async-threads:0] [kernel-poll:false]
Eshell V5.7.3 (abort with ^G)
-1&gt; Config = {sys, [{escript, "examples/display_args", [{incl_cond, include}]},
+1&gt; Config = {sys, [{escript,
+ "examples/display_args",
+ [{incl_cond, include}]},
{app, inets, [{incl_cond, include}]},
{app, mnesia, [{incl_cond, exclude}]},
{app, ssl, [{incl_cond, exclude}]},
@@ -320,11 +328,11 @@ Eshell V5.7.3 (abort with ^G)
[{write_file,"start_erl.data","5.7.3 1.0"},
{create_dir,"1.0",
[{write_file,"start_clean.rel",
- [37,37,32,114,101,108,32,103,101,110,101,114,97,116|...]},
+ [37,37,32,114,101,108,32,103,101,110,101|...]},
{write_file,"start_clean.script",
- [37,37,32,115,99,114,105,112,116,32,103,101,110|...]},
+ [37,37,32,115,99,114,105,112,116,32|...]},
{write_file,"start_clean.boot",
- &lt;&lt;131,104,3,100,0,6,115,99,114,105,112,116,...&gt;&gt;},
+ &lt;&lt;131,104,3,100,0,6,115,99,114,...&gt;&gt;},
{write_file,"start_sasl.rel",
[37,37,32,114,101,108,32,103,101,110,101|...]},
{write_file,"start_sasl.script",
@@ -409,11 +417,13 @@ Eshell V5.7.3 (abort with ^G)
{copy_file,...},
{...}|...]},
{create_dir,"src",
- [{copy_file,[...]},{copy_file,...},{...}|...]}]}]},
+ [{copy_file,[...]},
+ {copy_file,...},{...}|...]}]}]},
{archive,"crypto-1.6.1.ez",[],
[{create_dir,"crypto-1.6.1",
[{create_dir,"ebin",
- [{copy_file,[...]},{copy_file,...},{...}|...]},
+ [{copy_file,[...]},
+ {copy_file,...},{...}|...]},
{create_dir,"src",[{copy_file,...},{...}|...]}]}]},
{create_dir,"crypto-1.6.1",
[{create_dir,"priv",
diff --git a/lib/reltool/doc/src/user_guide.gif b/lib/reltool/doc/src/user_guide.gif
deleted file mode 100644
index e6275a803d..0000000000
--- a/lib/reltool/doc/src/user_guide.gif
+++ /dev/null
Binary files differ
diff --git a/lib/reltool/doc/src/warning.gif b/lib/reltool/doc/src/warning.gif
deleted file mode 100644
index 96af52360e..0000000000
--- a/lib/reltool/doc/src/warning.gif
+++ /dev/null
Binary files differ
diff --git a/lib/reltool/src/reltool_target.erl b/lib/reltool/src/reltool_target.erl
index 895fc6702b..6d85a98d9f 100644
--- a/lib/reltool/src/reltool_target.erl
+++ b/lib/reltool/src/reltool_target.erl
@@ -1,19 +1,19 @@
%%
%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2009. All Rights Reserved.
-%%
+%%
+%% Copyright Ericsson AB 2009-2010. All Rights Reserved.
+%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
%% compliance with the License. You should have received a copy of the
%% Erlang Public License along with this software. If not, it can be
%% retrieved online at http://www.erlang.org/.
-%%
+%%
%% Software distributed under the License is distributed on an "AS IS"
%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
%% the License for the specific language governing rights and limitations
%% under the License.
-%%
+%%
%% %CopyrightEnd%
-module(reltool_target).
@@ -966,9 +966,9 @@ do_eval_spec({create_dir, Dir, Files}, OrigSourceDir, SourceDir, TargetDir) ->
TargetDir2 = filename:join([TargetDir, Dir]),
reltool_utils:create_dir(TargetDir2),
do_eval_spec(Files, OrigSourceDir, SourceDir2, TargetDir2);
-do_eval_spec({create_dir, NewDir, OldDir, Files}, OrigSourceDir, _SourceDir, TargetDir) ->
+do_eval_spec({create_dir, Dir, OldDir, Files}, OrigSourceDir, _SourceDir, TargetDir) ->
SourceDir2 = filename:join([OrigSourceDir, OldDir]),
- TargetDir2 = filename:join([TargetDir, NewDir]),
+ TargetDir2 = filename:join([TargetDir, Dir]),
reltool_utils:create_dir(TargetDir2),
do_eval_spec(Files, SourceDir2, SourceDir2, TargetDir2);
do_eval_spec({archive, Archive, Options, Files}, OrigSourceDir, SourceDir, TargetDir) ->
@@ -992,9 +992,9 @@ do_eval_spec({copy_file, File}, _OrigSourceDir, SourceDir, TargetDir) ->
SourceFile = filename:join([SourceDir, File]),
TargetFile = filename:join([TargetDir, File]),
reltool_utils:copy_file(SourceFile, TargetFile);
-do_eval_spec({copy_file, NewFile, OldFile}, OrigSourceDir, _SourceDir, TargetDir) ->
+do_eval_spec({copy_file, File, OldFile}, OrigSourceDir, _SourceDir, TargetDir) ->
SourceFile = filename:join([OrigSourceDir, OldFile]),
- TargetFile = filename:join([TargetDir, NewFile]),
+ TargetFile = filename:join([TargetDir, File]),
reltool_utils:copy_file(SourceFile, TargetFile);
do_eval_spec({write_file, File, IoList}, _OrigSourceDir, _SourceDir, TargetDir) ->
TargetFile = filename:join([TargetDir, File]),
@@ -1014,8 +1014,8 @@ cleanup_spec({create_dir, Dir, Files}, TargetDir) ->
TargetDir2 = filename:join([TargetDir, Dir]),
cleanup_spec(Files, TargetDir2),
file:del_dir(TargetDir2);
-cleanup_spec({create_dir, NewDir, _OldDir, Files}, TargetDir) ->
- TargetDir2 = filename:join([TargetDir, NewDir]),
+cleanup_spec({create_dir, Dir, _OldDir, Files}, TargetDir) ->
+ TargetDir2 = filename:join([TargetDir, Dir]),
cleanup_spec(Files, TargetDir2),
file:del_dir(TargetDir2);
cleanup_spec({archive, Archive, _Options, Files}, TargetDir) ->
@@ -1125,6 +1125,8 @@ match(String, [#regexp{source = _, compiled = MP} | Regexps]) ->
end.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% Old style installation
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
install(RelName, TargetDir) ->
try
@@ -1220,7 +1222,6 @@ subst_var([C| Rest], Vars, Result, VarAcc) ->
subst_var(Rest, Vars, Result, [C| VarAcc]);
subst_var([], Vars, Result, VarAcc) ->
subst([], Vars, [VarAcc ++ [$% | Result]]).
-
start_scripts() ->
["erl", "start", "start_erl"].
diff --git a/lib/runtime_tools/vsn.mk b/lib/runtime_tools/vsn.mk
index 591f3e1ac4..4bbdef19de 100644
--- a/lib/runtime_tools/vsn.mk
+++ b/lib/runtime_tools/vsn.mk
@@ -1 +1 @@
-RUNTIME_TOOLS_VSN = 1.8.2
+RUNTIME_TOOLS_VSN = 1.8.3
diff --git a/lib/snmp/doc/src/notes.xml b/lib/snmp/doc/src/notes.xml
index 7984f2a536..dc2d879672 100644
--- a/lib/snmp/doc/src/notes.xml
+++ b/lib/snmp/doc/src/notes.xml
@@ -64,17 +64,22 @@
<section>
<title>Reported Fixed Bugs and Malfunctions</title>
+ <!--
<p>-</p>
+ -->
- <!--
<list type="bulleted">
<item>
- <p>TBD. </p>
- <p>Own Id: OTP-8384</p>
+ <p>The config utility
+ (<seealso marker="snmp#config">snmp:config/0</seealso>)
+ generated a default notify.conf
+ with a bad name for the starndard trap entry (was "stadard trap",
+ but should have been "standard trap"). This has been corrected. </p>
+ <p>Kenji Rikitake</p>
+ <p>Own Id: OTP-8433</p>
</item>
</list>
- -->
</section>
diff --git a/lib/snmp/src/agent/snmpa_net_if.erl b/lib/snmp/src/agent/snmpa_net_if.erl
index bc0777a7dd..3a91cf4033 100644
--- a/lib/snmp/src/agent/snmpa_net_if.erl
+++ b/lib/snmp/src/agent/snmpa_net_if.erl
@@ -945,6 +945,12 @@ system_terminate(Reason, _Parent, _Dbg, #state{log = Log}) ->
do_close_log(Log),
exit(Reason).
+system_code_change(OldState, _Module, _OldVsn, downgrade_to_pre_4_16) ->
+ {OldLog, Type} = OldState#state.log,
+ NewLog = snmp_log:downgrade(OldLog),
+ NewState = OldState#state{log = {NewLog, Type}},
+ {ok, NewState};
+
system_code_change(OldState, _Module, _OldVsn, upgrade_from_pre_4_16) ->
Initial = ?ATL_SEQNO_INITIAL,
Max = ?ATL_SEQNO_MAX,
@@ -952,12 +958,11 @@ system_code_change(OldState, _Module, _OldVsn, upgrade_from_pre_4_16) ->
Function = increment_counter,
Args = [atl_seqno, Initial, Max],
SeqNoGen = {Module, Function, Args},
- NewLog = snmp_log:upgrade(OldState#state.log, SeqNoGen),
- NewState = OldState#state{log = NewLog},
- {ok, NewState};
-system_code_change(OldState, _Module, _OldVsn, downgrade_to_pre_4_16) ->
- NewState = OldState#state{log = snmp_log:downgrade(OldState#state.log)},
+ {OldLog, Type} = OldState#state.log,
+ NewLog = snmp_log:upgrade(OldLog, SeqNoGen),
+ NewState = OldState#state{log = {NewLog, Type}},
{ok, NewState};
+
system_code_change(S, _Module, _OldVsn, _Extra) ->
{ok, S}.
diff --git a/lib/snmp/src/app/snmp.appup.src b/lib/snmp/src/app/snmp.appup.src
index 74747b2e59..05aa3d0d48 100644
--- a/lib/snmp/src/app/snmp.appup.src
+++ b/lib/snmp/src/app/snmp.appup.src
@@ -25,6 +25,7 @@
{"4.15",
[
{load_module, snmpa, soft_purge, soft_purge, [snmp_log]},
+ {load_module, snmp_config, soft_purge, soft_purge, []},
{load_module, snmp_log, soft_purge, soft_purge, []},
{update, snmpa_net_if, {advanced, upgrade_from_pre_4_16},
soft_purge, soft_purge, [snmpa_agent, snmp_log]},
@@ -34,6 +35,7 @@
{"4.14",
[
{load_module, snmpa, soft_purge, soft_purge, [snmp_log]},
+ {load_module, snmp_config, soft_purge, soft_purge, []},
{load_module, snmp_log, soft_purge, soft_purge, []},
{update, snmpa_net_if, {advanced, upgrade_from_pre_4_16},
soft_purge, soft_purge, [snmpa_agent, snmp_log]},
@@ -49,6 +51,7 @@
[
{load_module, snmpa_mib_data, soft_purge, soft_purge, []},
{load_module, snmpa, soft_purge, soft_purge, [snmp_log]},
+ {load_module, snmp_config, soft_purge, soft_purge, []},
{load_module, snmp_log, soft_purge, soft_purge, []},
{update, snmpa_net_if, {advanced, upgrade_from_pre_4_16},
soft_purge, soft_purge, [snmpa_agent, snmp_log]},
@@ -70,6 +73,7 @@
{"4.15",
[
{load_module, snmpa, soft_purge, soft_purge, [snmp_log]},
+ {load_module, snmp_config, soft_purge, soft_purge, []},
{load_module, snmp_log, soft_purge, soft_purge, []},
{update, snmpa_net_if, {advanced, downgrade_to_pre_4_16},
soft_purge, soft_purge, [snmpa_agent, snmp_log]},
@@ -79,6 +83,7 @@
{"4.14",
[
{load_module, snmpa, soft_purge, soft_purge, [snmp_log]},
+ {load_module, snmp_config, soft_purge, soft_purge, []},
{load_module, snmp_log, soft_purge, soft_purge, []},
{update, snmpa_net_if, {advanced, downgrade_to_pre_4_16},
soft_purge, soft_purge, [snmpa_agent, snmp_log]},
@@ -92,6 +97,7 @@
{"4.13.5",
[
{load_module, snmpa_mib_data, soft_purge, soft_purge, []},
+ {load_module, snmp_config, soft_purge, soft_purge, []},
{load_module, snmpa, soft_purge, soft_purge, [snmp_log]},
{load_module, snmp_log, soft_purge, soft_purge, []},
{update, snmpa_net_if, {advanced, downgrade_to_pre_4_16},
diff --git a/lib/snmp/src/manager/snmpm_net_if.erl b/lib/snmp/src/manager/snmpm_net_if.erl
index 4ec24af7f3..ad39157721 100644
--- a/lib/snmp/src/manager/snmpm_net_if.erl
+++ b/lib/snmp/src/manager/snmpm_net_if.erl
@@ -464,13 +464,17 @@ do_close_log(_) ->
code_change({down, _Vsn}, OldState, downgrade_to_pre_4_16) ->
?d("code_change(down) -> entry", []),
- State = OldState#state{log = snmp_log:downgrade(OldState#state.log)},
+ {OldLog, Type} = OldState#state.log,
+ NewLog = snmp_log:downgrade(OldLog),
+ State = OldState#state{log = {NewLog, Type}},
{ok, State};
% upgrade
code_change(_Vsn, OldState, upgrade_from_pre_4_16) ->
?d("code_change(up) -> entry", []),
- State = OldState#state{log = snmp_log:upgrade(OldState#state.log)},
+ {OldLog, Type} = OldState#state.log,
+ NewLog = snmp_log:upgrade(OldLog),
+ State = OldState#state{log = {NewLog, Type}},
{ok, State};
code_change(_Vsn, State, _Extra) ->
diff --git a/lib/snmp/src/misc/snmp_config.erl b/lib/snmp/src/misc/snmp_config.erl
index 0ee373a4d4..c066680160 100644
--- a/lib/snmp/src/misc/snmp_config.erl
+++ b/lib/snmp/src/misc/snmp_config.erl
@@ -1806,7 +1806,7 @@ write_agent_snmp_notify_conf(Dir, NotifyType) ->
"%% {\"standard inform\", \"std_inform\", inform}.\n"
"%%\n\n",
Hdr = header() ++ Comment,
- Conf = [{"stadard_trap", "std_trap", NotifyType}],
+ Conf = [{"standard trap", "std_trap", NotifyType}],
write_agent_notify_config(Dir, Hdr, Conf).
write_agent_notify_config(Dir, Hdr, Conf) ->
diff --git a/lib/snmp/src/misc/snmp_log.erl b/lib/snmp/src/misc/snmp_log.erl
index 9f4fdf97ca..f9aa911817 100644
--- a/lib/snmp/src/misc/snmp_log.erl
+++ b/lib/snmp/src/misc/snmp_log.erl
@@ -115,6 +115,11 @@ create(Name, File, SeqNoGen, Size, Repair, Notify) ->
close(#snmp_log{id = Log}) ->
?vtrace("close -> entry with"
"~n Log: ~p", [Log]),
+ do_close(Log);
+close(Log) ->
+ do_close(Log).
+
+do_close(Log) ->
disk_log:close(Log).
@@ -345,6 +350,11 @@ next_seqno(_) ->
%% -- change_size ---
change_size(#snmp_log{id = Log}, NewSize) ->
+ do_change_size(Log, NewSize);
+change_size(Log, NewSize) ->
+ do_change_size(Log, NewSize).
+
+do_change_size(Log, NewSize) ->
?vtrace("change_size -> entry with"
"~n Log: ~p"
"~n NewSize: ~p", [Log, NewSize]),
diff --git a/lib/snmp/vsn.mk b/lib/snmp/vsn.mk
index d78a2cec7a..a151f332ae 100644
--- a/lib/snmp/vsn.mk
+++ b/lib/snmp/vsn.mk
@@ -18,10 +18,12 @@
# %CopyrightEnd%
SNMP_VSN = 4.16
-PRE_VSN =-p01
+PRE_VSN =-p03
APP_VSN = "snmp-$(SNMP_VSN)$(PRE_VSN)"
-TICKETS = OTP-8395
+TICKETS = \
+ OTP-8395 \
+ OTP-8433
TICKETS_4_15 = OTP-8229 OTP-8249
diff --git a/lib/stdlib/doc/src/shell.xml b/lib/stdlib/doc/src/shell.xml
index 2a7c5b8c69..73cc1b33bd 100644
--- a/lib/stdlib/doc/src/shell.xml
+++ b/lib/stdlib/doc/src/shell.xml
@@ -755,10 +755,11 @@ loop(N) ->
created by the shell. Currently there is only one pair:
<c>{history, N}</c>, where N is the current command number. The
function should return a list of characters or an atom. This
- constraint is due to the Erlang I/O-protocol. Note that in
- restricted mode the call <c>Mod:Func(L)</c> must be allowed or
- the default shell prompt function will be called.</p>
- </section>
+ constraint is due to the Erlang I/O-protocol. Unicode characters
+ beyond codepoint 255 are allowed in the list. Note
+ that in restricted mode the call <c>Mod:Func(L)</c> must be
+ allowed or the default shell prompt function will be called.</p>
+ </section>
<funcs>
<func>
diff --git a/lib/stdlib/src/Makefile b/lib/stdlib/src/Makefile
index 37c836a254..237818c08b 100644
--- a/lib/stdlib/src/Makefile
+++ b/lib/stdlib/src/Makefile
@@ -146,6 +146,9 @@ APPUP_TARGET= $(EBIN)/$(APPUP_FILE)
# FLAGS
# ----------------------------------------------------
+ifeq ($(NATIVE_LIBS_ENABLED),yes)
+ERL_COMPILE_FLAGS += +native
+endif
ERL_COMPILE_FLAGS += -I../include -I../../kernel/include
# ----------------------------------------------------
diff --git a/lib/stdlib/src/dets_v8.erl b/lib/stdlib/src/dets_v8.erl
index ec3bad45bc..1f9f84cd27 100644
--- a/lib/stdlib/src/dets_v8.erl
+++ b/lib/stdlib/src/dets_v8.erl
@@ -1,19 +1,19 @@
%%
%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2001-2009. All Rights Reserved.
-%%
+%%
+%% Copyright Ericsson AB 2001-2010. All Rights Reserved.
+%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
%% compliance with the License. You should have received a copy of the
%% Erlang Public License along with this software. If not, it can be
%% retrieved online at http://www.erlang.org/.
-%%
+%%
%% Software distributed under the License is distributed on an "AS IS"
%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
%% the License for the specific language governing rights and limitations
%% under the License.
-%%
+%%
%% %CopyrightEnd%
%%
-module(dets_v8).
diff --git a/lib/stdlib/src/erl_lint.erl b/lib/stdlib/src/erl_lint.erl
index 156d68554e..91f7641af7 100644
--- a/lib/stdlib/src/erl_lint.erl
+++ b/lib/stdlib/src/erl_lint.erl
@@ -1,20 +1,20 @@
%% -*- erlang-indent-level: 4 -*-
%%
%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1996-2009. All Rights Reserved.
-%%
+%%
+%% Copyright Ericsson AB 1996-2010. All Rights Reserved.
+%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
%% compliance with the License. You should have received a copy of the
%% Erlang Public License along with this software. If not, it can be
%% retrieved online at http://www.erlang.org/.
-%%
+%%
%% Software distributed under the License is distributed on an "AS IS"
%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
%% the License for the specific language governing rights and limitations
%% under the License.
-%%
+%%
%% %CopyrightEnd%
%%
%% Do necessary checking of Erlang code.
@@ -78,7 +78,7 @@ value_option(Flag, Default, On, OnVal, Off, OffVal, Opts) ->
calls = dict:new(), %Who calls who
imported = [], %Actually imported functions
used_records=sets:new() :: set(), %Used record definitions
- used_types = sets:new() :: set() %Used type definitions
+ used_types = dict:new() :: dict() %Used type definitions
}).
%% Define the lint state record.
@@ -277,6 +277,8 @@ format_error({conflicting_behaviours,{Name,Arity},B,FirstL,FirstB}) ->
format_error({undefined_behaviour_func, {Func,Arity}, Behaviour}) ->
io_lib:format("undefined callback function ~w/~w (behaviour '~w')",
[Func,Arity,Behaviour]);
+format_error({undefined_behaviour_func, {Func,Arity,_Spec}, Behaviour}) ->
+ format_error({undefined_behaviour_func, {Func,Arity}, Behaviour});
format_error({undefined_behaviour,Behaviour}) ->
io_lib:format("behaviour ~w undefined", [Behaviour]);
format_error({undefined_behaviour_callbacks,Behaviour}) ->
@@ -288,7 +290,7 @@ format_error({ill_defined_behaviour_callbacks,Behaviour}) ->
%% --- types and specs ---
format_error({singleton_typevar, Name}) ->
io_lib:format("type variable ~w is only used once (is unbound)", [Name]);
-format_error({type_ref, {TypeName, Arity}}) ->
+format_error({undefined_type, {TypeName, Arity}}) ->
io_lib:format("type ~w~s undefined", [TypeName, gen_type_paren(Arity)]);
format_error({unused_type, {TypeName, Arity}}) ->
io_lib:format("type ~w~s is unused", [TypeName, gen_type_paren(Arity)]);
@@ -757,10 +759,11 @@ post_traversal_check(Forms, St0) ->
St7 = check_bif_clashes(Forms, St6),
St8 = check_specs_without_function(St7),
St9 = check_functions_without_spec(Forms, St8),
- StA = check_unused_types(Forms, St9),
- StB = check_untyped_records(Forms, StA),
- StC = check_on_load(StB),
- check_unused_records(Forms, StC).
+ StA = check_undefined_types(St9),
+ StB = check_unused_types(Forms, StA),
+ StC = check_untyped_records(Forms, StB),
+ StD = check_on_load(StC),
+ check_unused_records(Forms, StD).
%% check_behaviour(State0) -> State
%% Check that the behaviour attribute is valid.
@@ -786,13 +789,20 @@ behaviour_callbacks(Line, B, St0) ->
Funcs when is_list(Funcs) ->
All = all(fun({FuncName, Arity}) ->
is_atom(FuncName) andalso is_integer(Arity);
+ ({FuncName, Arity, Spec}) ->
+ is_atom(FuncName) andalso is_integer(Arity)
+ andalso is_list(Spec);
(_Other) ->
false
end,
Funcs),
+ MaybeRemoveSpec = fun({_F,_A}=FA) -> FA;
+ ({F,A,_S}) -> {F,A};
+ (Other) -> Other
+ end,
if
All =:= true ->
- {Funcs, St0};
+ {[MaybeRemoveSpec(F) || F <- Funcs], St0};
true ->
St1 = add_warning(Line,
{ill_defined_behaviour_callbacks,B},
@@ -970,6 +980,16 @@ check_undefined_functions(#lint{called=Called0,defined=Def0}=St0) ->
add_error(L, {undefined_function,NA}, St)
end, St0, Undef).
+%% check_undefined_types(State0) -> State
+
+check_undefined_types(#lint{usage=Usage,types=Def}=St0) ->
+ Used = Usage#usage.used_types,
+ UTAs = dict:fetch_keys(Used),
+ Undef = [{TA,dict:fetch(TA, Used)} || TA <- UTAs, not dict:is_key(TA, Def)],
+ foldl(fun ({TA,L}, St) ->
+ add_error(L, {undefined_type,TA}, St)
+ end, St0, Undef).
+
%% check_bif_clashes(Forms, State0) -> State
check_bif_clashes(Forms, St0) ->
@@ -1427,20 +1447,11 @@ is_pattern_expr_1({tuple,_Line,Es}) ->
all(fun is_pattern_expr/1, Es);
is_pattern_expr_1({nil,_Line}) -> true;
is_pattern_expr_1({cons,_Line,H,T}) ->
- case is_pattern_expr_1(H) of
- true -> is_pattern_expr_1(T);
- false -> false
- end;
+ is_pattern_expr_1(H) andalso is_pattern_expr_1(T);
is_pattern_expr_1({op,_Line,Op,A}) ->
- case erl_internal:arith_op(Op, 1) of
- true -> is_pattern_expr_1(A);
- false -> false
- end;
+ erl_internal:arith_op(Op, 1) andalso is_pattern_expr_1(A);
is_pattern_expr_1({op,_Line,Op,A1,A2}) ->
- case erl_internal:arith_op(Op, 2) of
- true -> all(fun is_pattern_expr/1, [A1,A2]);
- false -> false
- end;
+ erl_internal:arith_op(Op, 2) andalso all(fun is_pattern_expr/1, [A1,A2]);
is_pattern_expr_1(_Other) -> false.
%% pattern_bin([Element], VarTable, Old, BinVarTable, State) ->
@@ -1817,28 +1828,17 @@ is_gexpr({bin,_L,Fs}, RDs) ->
end, Fs);
is_gexpr({call,_L,{atom,_Lf,F},As}, RDs) ->
A = length(As),
- case erl_internal:guard_bif(F, A) of
- true -> is_gexpr_list(As, RDs);
- false -> false
- end;
+ erl_internal:guard_bif(F, A) andalso is_gexpr_list(As, RDs);
is_gexpr({call,_L,{remote,_Lr,{atom,_Lm,erlang},{atom,_Lf,F}},As}, RDs) ->
A = length(As),
- case erl_internal:guard_bif(F, A) orelse is_gexpr_op(F, A) of
- true -> is_gexpr_list(As, RDs);
- false -> false
- end;
+ (erl_internal:guard_bif(F, A) orelse is_gexpr_op(F, A))
+ andalso is_gexpr_list(As, RDs);
is_gexpr({call,L,{tuple,Lt,[{atom,Lm,erlang},{atom,Lf,F}]},As}, RDs) ->
is_gexpr({call,L,{remote,Lt,{atom,Lm,erlang},{atom,Lf,F}},As}, RDs);
is_gexpr({op,_L,Op,A}, RDs) ->
- case is_gexpr_op(Op, 1) of
- true -> is_gexpr(A, RDs);
- false -> false
- end;
+ is_gexpr_op(Op, 1) andalso is_gexpr(A, RDs);
is_gexpr({op,_L,Op,A1,A2}, RDs) ->
- case is_gexpr_op(Op, 2) of
- true -> is_gexpr_list([A1,A2], RDs);
- false -> false
- end;
+ is_gexpr_op(Op, 2) andalso is_gexpr_list([A1,A2], RDs);
is_gexpr(_Other, _RDs) -> false.
is_gexpr_op('andalso', 2) -> true;
@@ -2388,7 +2388,7 @@ check_type(Types, St) ->
{SeenVars, St1} = check_type(Types, dict:new(), St),
dict:fold(fun(Var, {seen_once, Line}, AccSt) ->
case atom_to_list(Var) of
- [$_|_] -> AccSt;
+ "_"++_ -> AccSt;
_ -> add_error(Line, {singleton_typevar, Var}, AccSt)
end;
(_Var, seen_multiple, AccSt) ->
@@ -2400,7 +2400,7 @@ check_type({ann_type, _L, [_Var, Type]}, SeenVars, St) ->
check_type({paren_type, _L, [Type]}, SeenVars, St) ->
check_type(Type, SeenVars, St);
check_type({remote_type, L, [{atom, _, Mod}, {atom, _, Name}, Args]},
- SeenVars, St = #lint{module=CurrentMod}) ->
+ SeenVars, #lint{module=CurrentMod} = St) ->
St1 =
case (dict:is_key({Name, length(Args)}, default_types())
orelse is_var_arity_type(Name)) of
@@ -2463,21 +2463,15 @@ check_type({type, _L, product, Args}, SeenVars, St) ->
lists:foldl(fun(T, {AccSeenVars, AccSt}) ->
check_type(T, AccSeenVars, AccSt)
end, {SeenVars, St}, Args);
-check_type({type, La, TypeName, Args}, SeenVars,
- St = #lint{types=Defs, usage=Usage}) ->
+check_type({type, La, TypeName, Args}, SeenVars, #lint{usage=Usage} = St) ->
Arity = length(Args),
- St1 =
- case dict:is_key({TypeName, Arity}, Defs) of
- true ->
- UsedTypes1 = Usage#usage.used_types,
- UsedTypes2 = sets:add_element({TypeName, Arity}, UsedTypes1),
- St#lint{usage=Usage#usage{used_types=UsedTypes2}};
- false ->
- case is_var_arity_type(TypeName) of
- true -> St;
- false -> add_error(La, {type_ref, {TypeName, Arity}}, St)
- end
- end,
+ St1 = case is_var_arity_type(TypeName) of
+ true -> St;
+ false ->
+ OldUsed = Usage#usage.used_types,
+ UsedTypes = dict:store({TypeName, Arity}, La, OldUsed),
+ St#lint{usage=Usage#usage{used_types=UsedTypes}}
+ end,
check_type({type, -1, product, Args}, SeenVars, St1).
check_record_types(Line, Name, Fields, SeenVars, St) ->
@@ -2636,7 +2630,7 @@ check_specs([FunType|Left], Arity, St0) ->
check_specs([], _Arity, St) ->
St.
-check_specs_without_function(St = #lint{module=Mod, defined=Funcs}) ->
+check_specs_without_function(#lint{module=Mod,defined=Funcs,specs=Specs}=St) ->
Fun = fun({M, F, A} = MFA, Line, AccSt) when M =:= Mod ->
case gb_sets:is_element({F, A}, Funcs) of
true -> AccSt;
@@ -2644,7 +2638,7 @@ check_specs_without_function(St = #lint{module=Mod, defined=Funcs}) ->
end;
({_M, _F, _A}, _Line, AccSt) -> AccSt
end,
- dict:fold(Fun, St, St#lint.specs).
+ dict:fold(Fun, St, Specs).
%% This generates warnings for functions without specs; if the user has
%% specified both options, we do not generate the same warnings twice.
@@ -2688,7 +2682,7 @@ check_unused_types(Forms, St = #lint{usage=Usage, types=Types}) ->
(Type, FileLine, AccSt) ->
case loc(FileLine) of
{FirstFile, _} ->
- case sets:is_element(Type, UsedTypes) of
+ case dict:is_key(Type, UsedTypes) of
true -> AccSt;
false ->
add_warning(FileLine,
@@ -3009,7 +3003,7 @@ check_old_unused_vars(Vt, Vt0, St0) ->
unused_vars(Vt, Vt0, _St0) ->
U0 = orddict:filter(fun (V, {_State,unused,_Ls}) ->
case atom_to_list(V) of
- [$_|_] -> false;
+ "_"++_ -> false;
_ -> true
end;
(_V, _How) -> false
diff --git a/lib/stdlib/src/escript.erl b/lib/stdlib/src/escript.erl
index c0f71fb3f5..b2562c6169 100644
--- a/lib/stdlib/src/escript.erl
+++ b/lib/stdlib/src/escript.erl
@@ -139,7 +139,8 @@ start(EscriptOptions) ->
parse_and_run(File, Args, Options) ->
CheckOnly = lists:member("s", Options),
- {Source, Module, FormsOrBin, Mode} = parse_file(File, CheckOnly),
+ {Source, Module, FormsOrBin, HasRecs, Mode} =
+ parse_file(File, CheckOnly),
Mode2 =
case lists:member("d", Options) of
true ->
@@ -159,7 +160,7 @@ parse_and_run(File, Args, Options) ->
is_list(FormsOrBin) ->
case Mode2 of
interpret ->
- interpret(FormsOrBin, File, Args);
+ interpret(FormsOrBin, HasRecs, File, Args);
compile ->
case compile:forms(FormsOrBin, [report]) of
{ok, Module, BeamBin} ->
@@ -246,7 +247,8 @@ parse_file(File, CheckOnly) ->
#state{mode = Mode,
source = Source,
module = Module,
- forms_or_bin = FormsOrBin} =
+ forms_or_bin = FormsOrBin,
+ has_records = HasRecs} =
case ScriptType of
archive ->
%% Archive file
@@ -260,7 +262,7 @@ parse_file(File, CheckOnly) ->
%% Source code
parse_source(S, File, Fd, StartLine, HeaderSz, CheckOnly)
end,
- {Source, Module, FormsOrBin, Mode}.
+ {Source, Module, FormsOrBin, HasRecs, Mode}.
%% Skip header and make a heuristic guess about the script type
skip_header(P, LineNo) ->
@@ -421,8 +423,7 @@ check_source(S, CheckOnly) ->
case S of
#state{n_errors = Nerrs} when Nerrs =/= 0 ->
fatal("There were compilation errors.");
- #state{exports_main = ExpMain,
- has_records = HasRecs,
+ #state{exports_main = ExpMain,
forms_or_bin = [FileForm2, ModForm2 | Forms]} ->
%% Optionally add export of main/1
Forms2 =
@@ -433,36 +434,15 @@ check_source(S, CheckOnly) ->
Forms3 = [FileForm2, ModForm2 | Forms2],
case CheckOnly of
true ->
- %% Optionally expand records
- Forms4 =
- case HasRecs of
- false -> Forms3;
- true -> erl_expand_records:module(Forms3, [])
- end,
%% Strong validation and halt
- case compile:forms(Forms4, [report,strong_validation]) of
+ case compile:forms(Forms3, [report,strong_validation]) of
{ok,_} ->
my_halt(0);
_Other ->
fatal("There were compilation errors.")
end;
false ->
- %% Basic validation before execution
- case erl_lint:module(Forms3) of
- {ok,Ws} ->
- report_warnings(Ws);
- {error,Es,Ws} ->
- report_errors(Es),
- report_warnings(Ws),
- fatal("There were compilation errors.")
- end,
- %% Optionally expand records
- Forms4 =
- case HasRecs of
- false -> Forms3;
- true -> erl_expand_records:module(Forms3, [])
- end,
- S#state{forms_or_bin = Forms4}
+ S#state{forms_or_bin = Forms3}
end
end.
@@ -495,17 +475,9 @@ epp_parse_file2(Epp, S, Forms, Parsed) ->
case Parsed of
{ok, Form} ->
case Form of
- {attribute,Ln,record,{Record,Fields}} ->
- S2 = S#state{has_records = true},
- case epp:normalize_typed_record_fields(Fields) of
- {typed, NewFields} ->
- epp_parse_file(Epp, S2,
- [{attribute, Ln, record, {Record, NewFields}},
- {attribute, Ln, type,
- {{record, Record}, Fields, []}} | Forms]);
- not_typed ->
- epp_parse_file(Epp, S2, [Form | Forms])
- end;
+ {attribute,_,record, _} ->
+ S2 = S#state{has_records = true},
+ epp_parse_file(Epp, S2, [Form | Forms]);
{attribute,Ln,mode,NewMode} ->
S2 = S#state{mode = NewMode},
if
@@ -564,8 +536,23 @@ run(Module, Args) ->
fatal(format_exception(Class, Reason))
end.
-interpret(Forms, File, Args) ->
- Dict = parse_to_dict(Forms),
+interpret(Forms, HasRecs, File, Args) ->
+ %% Basic validation before execution
+ case erl_lint:module(Forms) of
+ {ok,Ws} ->
+ report_warnings(Ws);
+ {error,Es,Ws} ->
+ report_errors(Es),
+ report_warnings(Ws),
+ fatal("There were compilation errors.")
+ end,
+ %% Optionally expand records
+ Forms2 =
+ case HasRecs of
+ false -> Forms;
+ true -> erl_expand_records:module(Forms, [])
+ end,
+ Dict = parse_to_dict(Forms2),
ArgsA = erl_parse:abstract(Args, 0),
Call = {call,0,{atom,0,main},[ArgsA]},
try
diff --git a/lib/stdlib/src/file_sorter.erl b/lib/stdlib/src/file_sorter.erl
index f253791f80..e21a0c88f3 100644
--- a/lib/stdlib/src/file_sorter.erl
+++ b/lib/stdlib/src/file_sorter.erl
@@ -1,19 +1,19 @@
%%
%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2001-2009. All Rights Reserved.
-%%
+%%
+%% Copyright Ericsson AB 2001-2010. All Rights Reserved.
+%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
%% compliance with the License. You should have received a copy of the
%% Erlang Public License along with this software. If not, it can be
%% retrieved online at http://www.erlang.org/.
-%%
+%%
%% Software distributed under the License is distributed on an "AS IS"
%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
%% the License for the specific language governing rights and limitations
%% under the License.
-%%
+%%
%% %CopyrightEnd%
%%
-module(file_sorter).
diff --git a/lib/stdlib/src/io_lib.erl b/lib/stdlib/src/io_lib.erl
index 2d3c86e4ea..26f6ec8931 100644
--- a/lib/stdlib/src/io_lib.erl
+++ b/lib/stdlib/src/io_lib.erl
@@ -1,19 +1,19 @@
%%
%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1996-2009. All Rights Reserved.
-%%
+%%
+%% Copyright Ericsson AB 1996-2010. All Rights Reserved.
+%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
%% compliance with the License. You should have received a copy of the
%% Erlang Public License along with this software. If not, it can be
%% retrieved online at http://www.erlang.org/.
-%%
+%%
%% Software distributed under the License is distributed on an "AS IS"
%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
%% the License for the specific language governing rights and limitations
%% under the License.
-%%
+%%
%% %CopyrightEnd%
%%
@@ -139,9 +139,9 @@ format_prompt({format,Format,Args}) ->
format_prompt(Format,Args);
format_prompt(Prompt)
when is_list(Prompt); is_atom(Prompt); is_binary(Prompt) ->
- format_prompt("~s", [Prompt]);
+ format_prompt("~ts", [Prompt]);
format_prompt(Prompt) ->
- format_prompt("~p", [Prompt]).
+ format_prompt("~tp", [Prompt]).
format_prompt(Format, Args) ->
case catch io_lib:format(Format, Args) of
diff --git a/lib/stdlib/src/qlc.erl b/lib/stdlib/src/qlc.erl
index bbeeb503e5..6e48d95973 100644
--- a/lib/stdlib/src/qlc.erl
+++ b/lib/stdlib/src/qlc.erl
@@ -1,19 +1,19 @@
%%
%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2004-2009. All Rights Reserved.
-%%
+%%
+%% Copyright Ericsson AB 2004-2010. All Rights Reserved.
+%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
%% compliance with the License. You should have received a copy of the
%% Erlang Public License along with this software. If not, it can be
%% retrieved online at http://www.erlang.org/.
-%%
+%%
%% Software distributed under the License is distributed on an "AS IS"
%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
%% the License for the specific language governing rights and limitations
%% under the License.
-%%
+%%
%% %CopyrightEnd%
%%
-module(qlc).
diff --git a/lib/stdlib/src/qlc_pt.erl b/lib/stdlib/src/qlc_pt.erl
index a72fe8639e..24378a0698 100644
--- a/lib/stdlib/src/qlc_pt.erl
+++ b/lib/stdlib/src/qlc_pt.erl
@@ -1,19 +1,19 @@
%%
%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2004-2009. All Rights Reserved.
-%%
+%%
+%% Copyright Ericsson AB 2004-2010. All Rights Reserved.
+%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
%% compliance with the License. You should have received a copy of the
%% Erlang Public License along with this software. If not, it can be
%% retrieved online at http://www.erlang.org/.
-%%
+%%
%% Software distributed under the License is distributed on an "AS IS"
%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
%% the License for the specific language governing rights and limitations
%% under the License.
-%%
+%%
%% %CopyrightEnd%
%%
-module(qlc_pt).
diff --git a/lib/stdlib/test/erl_lint_SUITE.erl b/lib/stdlib/test/erl_lint_SUITE.erl
index bfbd7b3dc1..8581b496aa 100644
--- a/lib/stdlib/test/erl_lint_SUITE.erl
+++ b/lib/stdlib/test/erl_lint_SUITE.erl
@@ -1,19 +1,19 @@
%%
%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1999-2009. All Rights Reserved.
-%%
+%%
+%% Copyright Ericsson AB 1999-2010. All Rights Reserved.
+%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
%% compliance with the License. You should have received a copy of the
%% Erlang Public License along with this software. If not, it can be
%% retrieved online at http://www.erlang.org/.
-%%
+%%
%% Software distributed under the License is distributed on an "AS IS"
%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
%% the License for the specific language governing rights and limitations
%% under the License.
-%%
+%%
%% %CopyrightEnd%
%%
-module(erl_lint_SUITE).
@@ -2597,7 +2597,7 @@ otp_8051(Config) when is_list(Config) ->
<<"-opaque foo() :: bar().
">>,
[],
- {error,[{1,erl_lint,{type_ref,{bar,0}}}],
+ {error,[{1,erl_lint,{undefined_type,{bar,0}}}],
[{1,erl_lint,{unused_type,{foo,0}}}]}}],
?line [] = run(Config, Ts),
ok.
diff --git a/lib/stdlib/test/io_proto_SUITE.erl b/lib/stdlib/test/io_proto_SUITE.erl
index 59aa175c73..93159fbd5b 100644
--- a/lib/stdlib/test/io_proto_SUITE.erl
+++ b/lib/stdlib/test/io_proto_SUITE.erl
@@ -23,7 +23,7 @@
-export([init_per_testcase/2, fin_per_testcase/2]).
-export([setopts_getopts/1,unicode_options/1,unicode_options_gen/1, binary_options/1, bc_with_r12/1,
- bc_with_r12_gl/1, read_modes_gl/1,bc_with_r12_ogl/1, read_modes_ogl/1, broken_unicode/1,eof_on_pipe/1]).
+ bc_with_r12_gl/1, read_modes_gl/1,bc_with_r12_ogl/1, read_modes_ogl/1, broken_unicode/1,eof_on_pipe/1,unicode_prompt/1]).
-export([io_server_proxy/1,start_io_server_proxy/0, proxy_getall/1, proxy_setnext/2, proxy_quit/1]).
@@ -31,6 +31,8 @@
-export([toerl_server/3,hold_the_line/3,answering_machine1/3,
answering_machine2/3]).
+-export([uprompt/1]).
+
%-define(without_test_server, true).
-ifdef(without_test_server).
@@ -43,7 +45,7 @@
-define(privdir(Conf), ?config(priv_dir, Conf)).
-endif.
-%-define(debug, true).
+-define(debug, true).
-ifdef(debug).
-define(format(S, A), io:format(S, A)).
@@ -82,7 +84,7 @@ all(doc) ->
all(suite) ->
[setopts_getopts, unicode_options, unicode_options_gen, binary_options, bc_with_r12,
bc_with_r12_gl,bc_with_r12_ogl, read_modes_gl, read_modes_ogl,
- broken_unicode,eof_on_pipe].
+ broken_unicode,eof_on_pipe,unicode_prompt].
-record(state, {
@@ -91,6 +93,48 @@ all(suite) ->
mode = list
}).
+uprompt(_L) ->
+ [1050,1072,1082,1074,1086,32,1077,32,85,110,105,99,111,100,101,32,63].
+
+unicode_prompt(suite) ->
+ [];
+unicode_prompt(doc) ->
+ ["Test that an Unicode prompt does not crash the shell"];
+unicode_prompt(Config) when is_list(Config) ->
+ ?line PA = filename:dirname(code:which(?MODULE)),
+ ?line rtnode([{putline,""},
+ {putline, "2."},
+ {getline, "2"},
+ {putline, "shell:prompt_func({io_proto_SUITE,uprompt})."},
+ {getline, "default"},
+ {putline, "io:get_line('')."},
+ {putline, "hej"},
+ {getline, "\"hej\\n\""},
+ {putline, "io:setopts([{binary,true}])."},
+ {getline, "ok"},
+ {putline, "io:get_line('')."},
+ {putline, "hej"},
+ {getline, "<<\"hej\\n\">>"}
+ ],[],[],"-pa "++ PA),
+ %% And one with oldshell
+ ?line rtnode([{putline,""},
+ {putline, "2."},
+ {getline_re, ".*2."},
+ {getline, "2"},
+ {putline, "shell:prompt_func({io_proto_SUITE,uprompt})."},
+ {getline_re, ".*default"},
+ {putline, "io:get_line('')."},
+ {putline, "hej"},
+ {getline_re, ".*\"hej\\\\n\""},
+ {putline, "io:setopts([{binary,true}])."},
+ {getline_re, ".*ok"},
+ {putline, "io:get_line('')."},
+ {putline, "hej"},
+ {getline_re, ".*<<\"hej\\\\n\">>"}
+ ],[],[],"-oldshell -pa "++PA),
+ ok.
+
+
setopts_getopts(suite) ->
[];
setopts_getopts(doc) ->
diff --git a/lib/stdlib/test/shell_SUITE.erl b/lib/stdlib/test/shell_SUITE.erl
index da73046c2a..588342d46a 100644
--- a/lib/stdlib/test/shell_SUITE.erl
+++ b/lib/stdlib/test/shell_SUITE.erl
@@ -34,7 +34,8 @@
start_restricted_on_command_line/1,restricted_local/1]).
%% Internal export.
--export([otp_5435_2/0, prompt1/1, prompt2/1, prompt3/1, prompt4/1]).
+-export([otp_5435_2/0, prompt1/1, prompt2/1, prompt3/1, prompt4/1,
+ prompt5/1]).
%%
%% Define to run outside of test server
@@ -2618,6 +2619,16 @@ otp_8393(Config) when is_list(Config) ->
?line "default\nl.\n" =
t(<<"shell:prompt_func({shell_SUITE,prompt3}). l.">>),
+ %%
+ %% Although this tests that you can set a unicode prompt function
+ %% it does not really test that it does work with the io-servers.
+ %% That is instead tested in the io_proto_SUITE, which has
+ %% the right infrastructure in place for such tests. /PaN
+ %%
+ ?line _ = shell:prompt_func(default),
+ ?line "default\nl.\n" =
+ t(<<"shell:prompt_func({shell_SUITE,prompt5}). l.">>),
+
%% Restricted shell.
Contents = <<"-module(test_restricted_shell).
-export([local_allowed/3, non_local_allowed/3]).
@@ -2672,6 +2683,9 @@ prompt3(L) ->
prompt4(_L) ->
erlang:apply({erlang,'/'}, [1,0]).
+prompt5(_L) ->
+ [1050,1072,1082,1074,1086,32,1077,32,85,110,105,99,111,100,101,32,63].
+
-ifdef(not_used).
exit_term(B) ->
"** exception exit:" ++ Reply = t(B),
diff --git a/lib/syntax_tools/vsn.mk b/lib/syntax_tools/vsn.mk
index 53c13440f3..2ba5eac582 100644
--- a/lib/syntax_tools/vsn.mk
+++ b/lib/syntax_tools/vsn.mk
@@ -1 +1 @@
-SYNTAX_TOOLS_VSN = 1.6.4
+SYNTAX_TOOLS_VSN = 1.6.5
diff --git a/lib/test_server/info b/lib/test_server/info
index 79ccc202d7..7a9ed6c700 100644
--- a/lib/test_server/info
+++ b/lib/test_server/info
@@ -1,2 +1,2 @@
-group: tools
+group: test Test Applications
short: The OTP Test Server
diff --git a/lib/tools/doc/src/Makefile b/lib/tools/doc/src/Makefile
index bab607c4bd..433f123ae5 100644
--- a/lib/tools/doc/src/Makefile
+++ b/lib/tools/doc/src/Makefile
@@ -1,19 +1,19 @@
#
# %CopyrightBegin%
-#
-# Copyright Ericsson AB 1997-2009. 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
# 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%
#
include $(ERL_TOP)/make/target.mk
@@ -41,6 +41,7 @@ XML_REF3_FILES = \
eprof.xml \
fprof.xml \
cprof.xml \
+ lcnt.xml \
instrument.xml \
make.xml \
tags.xml \
@@ -53,6 +54,7 @@ XML_CHAPTER_FILES = \
cover_chapter.xml \
fprof_chapter.xml \
cprof_chapter.xml \
+ lcnt_chapter.xml \
erlang_mode_chapter.xml \
xref_chapter.xml \
notes.xml \
diff --git a/lib/tools/doc/src/lcnt.xml b/lib/tools/doc/src/lcnt.xml
new file mode 100644
index 0000000000..3c55e4e422
--- /dev/null
+++ b/lib/tools/doc/src/lcnt.xml
@@ -0,0 +1,465 @@
+<?xml version="1.0" encoding="latin1" ?>
+<!DOCTYPE erlref SYSTEM "erlref.dtd">
+
+<erlref>
+ <header>
+ <copyright>
+ <year>2009</year>
+ <year>2010</year>
+ <holder>Ericsson AB, All Rights Reserved</holder>
+ </copyright>
+ <legalnotice>
+ 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.
+
+ The Initial Developer of the Original Code is Ericsson AB.
+ </legalnotice>
+
+ <title>lcnt</title>
+ <prepared>Björn-Egil Dahlberg</prepared>
+ <responsible>nobody</responsible>
+ <docno></docno>
+ <approved>nobody</approved>
+ <checked></checked>
+ <date>2009-11-26</date>
+ <rev>PA1</rev>
+ <file>lcnt.xml</file>
+ </header>
+ <module>lcnt</module>
+ <modulesummary>A runtime system Lock Profiling tool.</modulesummary>
+ <description>
+ <p>The <c>lcnt</c> module is used to profile the internal ethread locks in the
+ Erlang Runtime System. With <c>lcnt</c> enabled, Internal counters in the
+ runtime system are updated each time a lock is taken. The counters stores
+ information about the number of acquisition tries and the number of collisions
+ that has occurred during the acquisition tries. The counters also record the
+ waiting time a lock has caused for a blocked thread when a collision has occurred.
+ </p>
+ <p>
+ The data produced by the lock counters will give an estimate on how well
+ the runtime system will behave from a parallelizable view point for the
+ scenarios tested. This tool was mainly developed to help erlang runtime
+ developers iron out potential and generic bottlenecks.
+ </p>
+ <p>Locks in the emulator are named after what type of resource they protect and where
+ in the emulator they are initialized, those are lock 'classes'. Most of those
+ locks are also instantiated several times, and given unique identifiers, to increase
+ locking granularity. Typically an instantiated lock protects a disjunct set of
+ the resource, i.e ets-tables, processes or ports. In other cases it protects a
+ specific range of a resource, e.g. <c>pix_lock</c> which protects index to process
+ mappings, and is given a unique number within the class. A unique lock in <c>lcnt</c>
+ is referenced by a name (class) and an identifier, <c>{Name, Id}</c>.
+ </p>
+ <p>Some locks in the system are static and protects global resources, for example
+ <c>bif_timers</c> and the <c>run_queue</c> locks. Other locks are dynamic and not
+ necessarily long lived, for example process locks and ets-table locks. The
+ statistics data from short lived locks can be stored separately when the locks
+ are deleted. This behavior is by default turned off to save memory but can be
+ turned on via <c>lcnt:rt_opt({copy_save, true})</c>. The <c>lcnt:apply/1,2,3</c>
+ functions enables this behavior during profiling.
+ </p>
+ </description>
+ <funcs>
+
+ <func>
+ <name>start() -> {ok, Pid} | {error, {already_started, Pid}} </name>
+ <fsummary>Starts the lock profiler server.</fsummary>
+ <type>
+ <v>Pid = pid()</v>
+ </type>
+ <desc>
+ <p>Starts the lock profiler server. The server only act as a medium for the
+ user and performs filtering and printing of data collected by <c>lcnt:collect/1</c>.
+ </p>
+ </desc>
+ </func>
+
+ <func>
+ <name>stop() -> ok</name>
+ <fsummary>Stops the lock profiler server.</fsummary>
+ <desc>
+ <p>Stops the lock profiler server.</p>
+ </desc>
+ </func>
+
+ <func>
+ <name>collect() -> ok</name>
+ <fsummary>Same as <c>collect(node())</c>.</fsummary>
+ <desc><p>Same as <c>collect(node())</c>.</p></desc>
+ </func>
+
+ <func>
+ <name>collect(Node) -> ok</name>
+ <fsummary>Collects lock statistics from the runtime system.</fsummary>
+ <type>
+ <v>Node = node()</v>
+ </type>
+ <desc>
+ <p>Collects lock statistics from the runtime system. The function starts a
+ server if it is not already started. It then populates the server with lock
+ statistics. If the server held any lock statistics data before the collect then
+ that data is lost.
+ </p>
+ <note>
+ <p>
+ When collection occurs the runtime system transitions to a single thread,
+ blocking all other threads. No other tasks will be scheduled during this
+ operation. Depending on the size of the data this might take a long time
+ (several seconds) and cause timeouts in the system.
+ </p>
+ </note>
+ </desc>
+ </func>
+
+ <func>
+ <name>clear() -> ok</name>
+ <fsummary>Same as <c>clear(node())</c>.</fsummary>
+ <desc><p>Same as <c>clear(node())</c>.</p></desc>
+ </func>
+
+ <func>
+ <name>clear(Node) -> ok</name>
+ <fsummary>Clears the internal lock statistics from runtime system.</fsummary>
+ <type>
+ <v>Node = node()</v>
+ </type>
+ <desc>
+ <p>Clears the internal lock statistics from the runtime system. This does not clear the
+ data on the server only on runtime system. All counters for static locks are zeroed,
+ all dynamic locks currently alive are zeroed and all saved locks now destroyed are removed.
+ It also resets the duration timer.
+ </p>
+ </desc>
+ </func>
+ <func>
+ <name>conflicts() -> ok</name>
+ <fsummary>Same as <c>conflicts([])</c>.</fsummary>
+ <desc><p>Same as <c>conflicts([])</c>.</p></desc>
+ </func>
+ <func>
+ <name>conflicts([Option]) -> ok</name>
+ <fsummary>Prints a list of internal lock counters.</fsummary>
+ <type>
+ <v>Option = {sort, Sort} | {reverse, bool()} | {thresholds, [Thresholds]} | {print, [Print | {Print, integer()}]} | {max_locks, MaxLocks} | {combine, bool()}</v>
+ <v>Sort = name | id | type | tries | colls | ratio | time | entry</v>
+ <v>Thresholds = {tries, integer()} | {colls, integer()} | {time, integer()}</v>
+ <v>Print = name | id | type | entry | tries | colls | ratio | time | duration</v>
+ <v>MaxLocks = integer() | none</v>
+ </type>
+ <desc>
+ <p>Prints a list of internal locks and its statistics.</p>
+ <p>For option description, see <seealso marker="#inspect/2">lcnt:inspect/2</seealso>.</p>
+ </desc>
+ </func>
+
+ <func>
+ <name>locations() -> ok</name>
+ <fsummary>Same as <c>locations([])</c>.</fsummary>
+ <desc>
+ <p>Same as <c>locations([])</c>.</p>
+ </desc>
+ </func>
+ <func>
+ <name>locations([Option]) -> ok</name>
+ <fsummary>Prints a list of internal lock counters by source code locations.</fsummary>
+ <type>
+ <v>Option = {sort, Sort} | {thresholds, [Thresholds]} | {print, [Print | {Print, integer()}]} | {max_locks, MaxLocks} | {combine, bool()}</v>
+ <v>Sort = name | id | type | tries | colls | ratio | time | entry</v>
+ <v>Thresholds = {tries, integer()} | {colls, integer()} | {time, integer()}</v>
+ <v>Print = name | id | type | entry | tries | colls | ratio | time | duration</v>
+ <v>MaxLocks = integer() | none</v>
+ </type>
+ <desc>
+ <p>Prints a list of internal lock counters by source code locations.</p>
+ <p>For option description, see <seealso marker="#inspect/2">lcnt:inspect/2</seealso>.</p>
+ </desc>
+ </func>
+
+ <func>
+ <name>inspect(Lock) -> ok</name>
+ <fsummary>Same as <c>inspect(Lock, [])</c>.</fsummary>
+ <desc><p>Same as <c>inspect(Lock, [])</c>.</p></desc>
+ </func>
+ <func>
+ <name>inspect(Lock, [Option]) -> ok</name>
+ <fsummary>Prints a list of internal lock counters for a specific lock.</fsummary>
+ <type>
+ <v>Lock = Name | {Name, Id | [Id]}</v>
+ <v>Name = atom() | pid() | port()</v>
+ <v>Id = atom() | integer() | pid() | port()</v>
+ <v>Option = {sort, Sort} | {thresholds, [Thresholds]} | {print, [Print | {Print, integer()}]} | {max_locks, MaxLocks} | {combine, bool()} | {locations, bool()}</v>
+ <v>Sort = name | id | type | tries | colls | ratio | time</v>
+ <v>Thresholds = {tries, integer()} | {colls, integer()} | {time, integer()}</v>
+ <v>Print = name | id | type | entry | tries | colls | ratio | time | duration</v>
+ <v>MaxLocks = integer() | none</v>
+ </type>
+ <desc>
+ <p>Prints a list of internal lock counters for a specific lock.</p>
+ <p>Lock <c>Name</c> and <c>Id</c> for ports and processes are interchangeable with the use of <c>lcnt:swap_pid_keys/0</c> and is the reason why <c>pid()</c> and <c>port()</c> options can be used in both <c>Name</c> and <c>Id</c> space. Both pids and ports are special identifiers with stripped creation and can be recreated with <seealso marker="#pid/3">lcnt:pid/2,3</seealso> and <seealso marker="#port/2">lcnt:port/1,2</seealso>. </p>
+ <p>Option description:</p>
+ <taglist>
+ <tag><c>{combine, bool()}</c></tag>
+ <item>Combine the statistics from different instances of a lock class.
+ <br/>Default: <c>true</c>
+ </item>
+
+ <tag><c>{locations, bool()}</c></tag>
+ <item>Print the statistics by source file and line numbers.
+ <br/>Default: <c>false</c>
+ </item>
+
+ <tag><c>{max_locks, MaxLocks}</c></tag>
+ <item>Maximum number of locks printed or no limit with <c>none</c>.
+ <br/>Default: <c>20</c>
+ </item>
+
+ <tag><c>{print, PrintOptions}</c></tag>
+ <item>Printing options:
+ <taglist>
+ <tag><c>name</c></tag>
+ <item>Named lock or named set of locks (classes). The same name used for initializing the lock in the VM.</item>
+
+ <tag><c>id</c></tag>
+ <item>Internal id for set of locks, not always unique. This could be table name for ets tables (db_tab), port id for ports, integer identifiers for allocators, etc.</item>
+
+ <tag><c>type</c></tag>
+ <item>Type of lock: <c>rw_mutex</c>, <c>mutex</c>, <c>spinlock</c>, <c>rw_spinlock</c> or <c>proclock</c>.</item>
+
+ <tag><c>entry</c></tag>
+ <item>In combination with <c>{locations, true}</c> this option prints the lock operations source file and line number entry-points along with statistics for each entry. </item>
+
+ <tag><c>tries</c></tag>
+ <item>Number of acquisitions of this lock.</item>
+
+ <tag><c>colls</c></tag>
+ <item>Number of collisions when a thread tried to acquire this lock. This is when a trylock is EBUSY, a write try on read held rw_lock, a try read on write held rw_lock, a thread tries to lock an already locked lock. (Internal states supervises this).</item>
+
+ <tag><c>ratio</c></tag>
+ <item>The ratio between the number of collisions and the number of tries (acquisitions) in percentage.</item>
+
+ <tag><c>time</c></tag>
+ <item>Accumulated waiting time for this lock. This could be greater than actual wall clock time, it is accumulated for all threads. Trylock conflicts does not accumulate time.</item>
+
+ <tag><c>duration</c></tag>
+ <item>Percentage of accumulated waiting time of wall clock time. This percentage can be higher than 100% since accumulated time is from all threads.</item>
+ </taglist>
+ <br/>Default: <c>[name,id,tries,colls,ratio,time,duration]</c>
+ </item>
+
+ <tag><c>{reverse, bool()}</c></tag>
+ <item>Reverses the order of sorting.
+ <br/>Default: <c>false</c>
+ </item>
+
+ <tag><c>{sort, Sort}</c></tag>
+ <item>Column sorting orders.
+ <br/>Default: <c>time</c>
+ </item>
+
+ <tag><c>{thresholds, Thresholds}</c></tag>
+ <item>Filtering thresholds. Anything values above the threshold value are passed through.
+ <br/>Default: <c>[{tries, 0}, {colls, 0}, {time, 0}]</c>
+ </item>
+
+ </taglist>
+
+ </desc>
+ </func>
+
+ <func>
+ <name>information() -> ok</name>
+ <fsummary>Prints lcnt server state and generic information about collected lock statistics.</fsummary>
+ <desc>
+ <p>Prints lcnt server state and generic information about collected lock statistics.</p>
+ </desc>
+ </func>
+
+ <func>
+ <name>swap_pid_keys() -> ok</name>
+ <fsummary>Swaps places on <c>Name</c> and <c>Id</c> space for ports and processes.</fsummary>
+ <desc>
+ <p>Swaps places on <c>Name</c> and <c>Id</c> space for ports and processes.</p>
+ </desc>
+ </func>
+
+ <func>
+ <name>load(Filename) -> ok</name>
+ <fsummary>Restores previously saved data to the server.</fsummary>
+ <type>
+ <v>Filename = filename()</v>
+ </type>
+ <desc>
+ <p>Restores previously saved data to the server.</p>
+ </desc>
+ </func>
+
+ <func>
+ <name>save(Filename) -> ok</name>
+ <fsummary>Saves the collected data to file.</fsummary>
+ <type>
+ <v>Filename = filename()</v>
+ </type>
+ <desc>
+ <p>Saves the collected data to file.</p>
+ </desc>
+ </func>
+ </funcs>
+
+ <section>
+ <title>Convenience functions</title>
+ <p>The following functions are used for convenience.</p>
+ </section>
+ <funcs>
+ <func>
+ <name>apply(Fun) -> term()</name>
+ <fsummary>Same as <c>apply(Fun, [])</c>.</fsummary>
+ <desc>
+ <p>Same as <c>apply(Fun, [])</c>.</p>
+ </desc>
+ </func>
+ <func>
+ <name>apply(Fun, Args) -> term()</name>
+ <fsummary>Clears counters, applies function and collects the profiling results.</fsummary>
+ <type>
+ <v>Fun = fun()</v>
+ <v>Args = [term()]</v>
+ </type>
+ <desc>
+ <p> Clears the lock counters and then setups the instrumentation to save all destroyed locks.
+ After setup the fun is called, passing the elements in <c>Args</c> as arguments.
+ When the fun returns the statistics are immediately collected to the server. After the
+ collection the instrumentation is returned to its previous behavior.
+ The result of the applied fun is returned.
+ </p>
+ </desc>
+ </func>
+ <func>
+ <name>apply(Module, Function, Args) -> term()</name>
+ <fsummary>Clears counters, applies function and collects the profiling results.</fsummary>
+ <type>
+ <v>Module = atom()</v>
+ <v>Function = atom()</v>
+ <v>Args = [term()]</v>
+ </type>
+ <desc>
+ <p> Clears the lock counters and then setups the instrumentation to save all destroyed locks.
+ After setup the function is called, passing the elements in <c>Args</c> as arguments.
+ When the function returns the statistics are immediately collected to the server. After the
+ collection the instrumentation is returned to its previous behavior.
+ The result of the applied function is returned.
+ </p>
+ </desc>
+ </func>
+
+ <func>
+ <name>pid(Id, Serial) -> pid()</name>
+ <fsummary>Same as <c>pid(node(), Id, Serial)</c>.</fsummary>
+ <desc><p>Same as <c>pid(node(), Id, Serial)</c>.</p></desc>
+ </func>
+ <func>
+ <name>pid(Node, Id, Serial) -> pid()</name>
+ <fsummary>Creates a process id with creation 0.</fsummary>
+ <type>
+ <v>Node = node()</v>
+ <v>Id = integer()</v>
+ <v>Serial = integer()</v>
+ </type>
+ <desc>
+ <p>Creates a process id with creation 0. Example:</p>
+ </desc>
+ </func>
+
+ <func>
+ <name>port(Id) -> port()</name>
+ <fsummary>Same as <c>port(node(), Id)</c>.</fsummary>
+ <desc><p>Same as <c>port(node(), Id)</c>.</p></desc>
+ </func>
+ <func>
+ <name>port(Node, Id) -> port()</name>
+ <fsummary>Creates a port id with creation 0.</fsummary>
+ <type>
+ <v>Node = node()</v>
+ <v>Id = integer()</v>
+ </type>
+ <desc><p>Creates a port id with creation 0.</p></desc>
+ </func>
+
+ </funcs>
+
+ <section>
+ <title>Internal runtime lock counter controllers</title>
+ <p> The following functions control the behavior of the internal counters. </p>
+ </section>
+
+ <funcs>
+ <func>
+ <name>rt_collect() -> [lock_counter_data()]</name>
+ <fsummary>Same as <c>rt_collect(node())</c>.</fsummary>
+ <desc> <p>Same as <c>rt_collect(node())</c>.</p> </desc>
+ </func>
+ <func>
+ <name>rt_collect(Node) -> [lock_counter_data()]</name>
+ <fsummary>Returns a list of raw lock counter data.</fsummary>
+ <type>
+ <v>Node = node()</v>
+ </type>
+ <desc> <p>Returns a list of raw lock counter data.</p> </desc>
+ </func>
+
+ <func>
+ <name>rt_clear() -> ok</name>
+ <fsummary>Same as <c>rt_clear(node())</c>.</fsummary>
+ <desc> <p>Same as <c>rt_clear(node())</c>.</p> </desc>
+ </func>
+ <func>
+ <name>rt_clear(Node) -> ok</name>
+ <fsummary>Clears the internal counters.</fsummary>
+ <type>
+ <v>Node = node()</v>
+ </type>
+ <desc> <p>Clear the internal counters. Same as <c>lcnt:clear(Node)</c>.</p></desc>
+ </func>
+
+ <func>
+ <name>rt_opt({Type, bool()}) -> bool()</name>
+ <fsummary>Same as <c>rt_opt(node(), {Type, Opt})</c>.</fsummary>
+ <desc> <p>Same as <c>rt_opt(node(), {Type, Opt})</c>.</p> </desc>
+ </func>
+ <func>
+ <name>rt_opt(Node, {Type, bool()}) -> bool()</name>
+ <fsummary>Changes the lock counter behavior and returns the previous behaviour.</fsummary>
+ <type>
+ <v>Node = node()</v>
+ <v>Type = copy_save | process_locks</v>
+ </type>
+ <desc>
+ <p>Changes the lock counter behavior and returns the previous behaviour.</p>
+ <p>Option description:</p>
+ <taglist>
+ <tag><c>{copy_save, bool()}</c></tag>
+ <item>Enable statistics saving from destroyed locks by copying. This might consume a lot of memory.
+ <br/>Default: <c>false</c>
+ </item>
+
+ <tag><c>{process_locks, bool()}</c></tag>
+ <item>Profile process locks.
+ <br/>Default: <c>true</c>
+ </item>
+ </taglist>
+ </desc>
+ </func>
+ </funcs>
+
+ <section>
+ <title>See Also</title>
+ <p> <seealso marker="lcnt_chapter">LCNT User's Guide</seealso></p>
+ </section>
+</erlref>
diff --git a/lib/tools/doc/src/lcnt_chapter.xml b/lib/tools/doc/src/lcnt_chapter.xml
new file mode 100644
index 0000000000..8f44b23f59
--- /dev/null
+++ b/lib/tools/doc/src/lcnt_chapter.xml
@@ -0,0 +1,301 @@
+<?xml version="1.0" encoding="latin1" ?>
+<!DOCTYPE chapter SYSTEM "chapter.dtd">
+
+<chapter>
+ <header>
+ <copyright>
+ <year>2009</year><year>2010</year>
+ <holder>Ericsson AB. All Rights Reserved.</holder>
+ </copyright>
+ <legalnotice>
+ 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.
+
+ </legalnotice>
+
+ <title>lcnt - The Lock Profiler</title>
+ <prepared>Björn-Egil Dahlberg</prepared>
+ <responsible>nobody</responsible>
+ <docno></docno>
+ <approved>nobody</approved>
+ <checked>no</checked>
+ <date>2009-11-26</date>
+ <rev>PA1</rev>
+ <file>lcnt_chapter.xml</file>
+ </header>
+ <p>
+ Internally in the Erlang runtime system locks are used to protect resources from being updated from multiple threads in a fatal way. Locks are necessary
+ to ensure that the runtime system works properly but it also introduces a couple of limitations. Lock contention and locking overhead.
+ </p>
+ <p>
+ With lock contention we mean when one thread locks a resource and another thread, or threads, tries to acquire the same resource at the same time. The lock will deny
+ the other thread access to the resource and the thread will be blocked from continuing its execution. The second thread has to wait until the first thread has
+ completed its access to the resource and unlocked it. The <c>lcnt</c> tool measures these lock conflicts.
+ </p>
+ <p>
+ Locks has an inherent cost in execution time and memory space. It takes time initialize, destroy, aquiring or releasing locks. To decrease lock contention it
+ some times necessary to use finer grained locking strategies. This will usually also increase the locking overhead and hence there is a tradeoff
+ between lock contention and overhead. In general, lock contention increases with the number of threads running concurrently. The <c>lcnt</c> tool does not measure locking overhead.
+ </p>
+ <section>
+ <title> Enabling lock-counting </title>
+ <p>For investigation of locks in the emulator we use an internal tool called <c>lcnt</c> (short for lock-count). The VM needs to be compiled with this option enabled. To enable this, use:</p>
+
+ <pre>
+cd $ERL_TOP
+./configure --enable-lock-counter
+ </pre>
+
+ <p>
+ Another way to enable this alongside a normal VM is to compile it at emulator directory level, much like a debug build. To compile it this way do the following,
+ </p>
+ <pre>
+cd $ERL_TOP/erts/emulator
+make lcnt FLAVOR=smp
+ </pre>
+ <p> and then starting Erlang with,</p>
+ <pre>
+$ERL_TOP/bin/cerl -lcnt
+ </pre>
+ <p>To verify that you lock-counting enabled check that <c>[lock-counting]</c> appears in the status text when the VM is started.</p>
+ <pre>
+Erlang R13B03 (erts-5.7.4) [source] [64-bit] [smp:8:8] [rq:8] [async-threads:0] [hipe]
+ [kernel-poll:false] [lock-counting]
+ </pre>
+ </section>
+ <section>
+ <title>Getting started</title>
+ <p>Once you have a lock counting enabled VM the module <c>lcnt</c> can be used. The module is intended to be used from the current running nodes shell. To access remote nodes use <c>lcnt:clear(Node)</c> and <c>lcnt:collect(Node)</c>. </p>
+
+ <p>All locks are continuously monitored and its statistics updated. Use <c>lcnt:clear/0</c> to initially clear all counters before running any specific tests. This command will also reset the duration timer internally.</p>
+ <p>To retrieve lock statistics information use, <c>lcnt:collect/0,1</c>. The collect operation will start a <c>lcnt</c> server if it not already started. All collected data will be built into an erlang term and uploaded to the server and a duration time will also be uploaded. This duration is the time between <c>lcnt:clear/0,1</c> and <c>lcnt:collect/0,1</c>.</p>
+
+ <p>Once the data is collected to the server it can be filtered, sorted and printed in many different ways.</p>
+ <p>See the <seealso marker="lcnt">reference manual</seealso> for a description of each function.</p>
+ </section>
+ <section>
+ <title> Example of usage </title>
+ <p>From the Erlang shell:</p>
+ <pre>
+Erlang R13B03 (erts-5.7.4) [source] [smp:8:8] [rq:8] [async-threads:0] [hipe]
+ [kernel-poll:false] [lock-counting]
+1> lcnt:rt_opt({copy_save, true}).
+false
+2> lcnt:clear(), big:bang(1000), lcnt:collect().
+ok
+3> lcnt:conflicts().
+ lock id #tries #collisions collisions [%] time [us] duration [%]
+ ----- --- ------- ------------ --------------- ---------- -------------
+ alcu_allocator 50 4113692 158921 3.8632 215464 4.4962
+ pix_lock 256 4007140 4882 0.1218 12221 0.2550
+ run_queue 8 2287246 6949 0.3038 9825 0.2050
+ proc_main 1029 3115778 25755 0.8266 1199 0.0250
+ proc_msgq 1029 2467022 1910 0.0774 1048 0.0219
+ proc_status 1029 5708439 2435 0.0427 706 0.0147
+ message_pre_alloc_lock 8 2008569 134 0.0067 90 0.0019
+ timeofday 1 54065 8 0.0148 22 0.0005
+ gc_info 1 7071 7 0.0990 5 0.0001
+ok
+</pre>
+<p>
+ Another way to to profile a specific function is to use <c>lcnt:apply/3</c> or <c>lcnt:apply/1</c> which does <c>lcnt:clear/0</c> before the function and <c>lcnt:collect/0</c> after its invocation.
+ It also sets <c>copy_save</c> to <c>true</c> for the duration of the function call
+</p>
+<pre>
+Erlang R13B03 (erts-5.7.4) [source] [smp:8:8] [rq:8] [async-threads:0] [hipe]
+ [kernel-poll:false] [lock-counting]
+1> lcnt:apply(fun() -> big:bang(1000) end).
+4384.338
+2> lcnt:conflicts().
+ lock id #tries #collisions collisions [%] time [us] duration [%]
+ ----- --- ------- ------------ --------------- ---------- -------------
+ alcu_allocator 50 4117913 183091 4.4462 234232 5.1490
+ run_queue 8 2050398 3801 0.1854 6700 0.1473
+ pix_lock 256 4007080 4943 0.1234 2847 0.0626
+ proc_main 1028 3000178 28247 0.9415 1022 0.0225
+ proc_msgq 1028 2293677 1352 0.0589 545 0.0120
+ proc_status 1028 5258029 1744 0.0332 442 0.0097
+ message_pre_alloc_lock 8 2009322 147 0.0073 82 0.0018
+ timeofday 1 48616 9 0.0185 13 0.0003
+ gc_info 1 7455 12 0.1610 9 0.0002
+ok
+</pre>
+<p> The process locks are sorted after its class like all other locks. It is convenient to look at specific processes and ports as classes. We can do this by swapping class and class identifiers with <c>lcnt:swap_pid_keys/0</c>. </p>
+<pre>
+3> lcnt:swap_pid_keys().
+ok
+4> lcnt:conflicts([{print, [name, tries, ratio, time]}]).
+ lock #tries collisions [%] time [us]
+ ----- ------- --------------- ----------
+ alcu_allocator 4117913 4.4462 234232
+ run_queue 2050398 0.1854 6700
+ pix_lock 4007080 0.1234 2847
+ message_pre_alloc_lock 2009322 0.0073 82
+ &lt;[email protected]&gt; 13493 1.4452 41
+ &lt;[email protected]&gt; 13504 1.1404 36
+ &lt;[email protected]&gt; 13181 1.6235 35
+ &lt;[email protected]&gt; 13534 0.8202 22
+ &lt;[email protected]&gt; 8744 5.8326 22
+ &lt;[email protected]&gt; 13335 1.1174 19
+ &lt;[email protected]&gt; 13452 1.3678 19
+ &lt;[email protected]&gt; 13497 1.8745 18
+ &lt;[email protected]&gt; 11009 2.5343 18
+ &lt;[email protected]&gt; 13131 1.2566 16
+ &lt;[email protected]&gt; 13216 1.7327 15
+ &lt;[email protected]&gt; 13156 1.1098 15
+ &lt;[email protected]&gt; 13420 0.7303 14
+ &lt;[email protected]&gt; 13141 1.6437 14
+ &lt;[email protected]&gt; 13346 1.2064 13
+ &lt;[email protected]&gt; 13076 1.1701 13
+ok
+</pre>
+ </section>
+ <section>
+ <title> Example with Mnesia Transaction Benchmark </title>
+ <p>From the Erlang shell:</p>
+<pre>
+Erlang R13B03 (erts-5.7.4) [source] [smp:8:8] [rq:8] [async-threads:0] [hipe]
+ [kernel-poll:false] [lock-counting]
+
+Eshell V5.7.4 (abort with ^G)
+1> Conf=[{db_nodes, [node()]}, {driver_nodes, [node()]}, {replica_nodes, [node()]},
+ {n_drivers_per_node, 10}, {n_branches, 1000}, {n_accounts_per_branch, 10},
+ {replica_type, ram_copies}, {stop_after, 60000}, {reuse_history_id, true}].
+[{db_nodes,[nonode@nohost]},
+ {driver_nodes,[nonode@nohost]},
+ {replica_nodes,[nonode@nohost]},
+ {n_drivers_per_node,10},
+ {n_branches,1000},
+ {n_accounts_per_branch,10},
+ {replica_type,ram_copies},
+ {stop_after,60000},
+ {reuse_history_id,true}]
+2> mnesia_tpcb:init([{use_running_mnesia, false}|Conf]).
+ignore
+</pre>
+<p>Initial configuring of the benchmark is done. It is time to profile the actual benchmark and Mnesia</p>
+<pre>
+3> lcnt:apply(fun() -> {ok,{time, Tps,_,_,_,_}} = mnesia_tpcb:run([{use_running_mnesia,
+ true}|Conf]), Tps/60 end).
+12037.483333333334
+ok
+4> lcnt:swap_pid_keys().
+ok
+</pre>
+<p>The <c>id</c> header represents the number of unique identifiers under a class when the option <c>{combine, true}</c> is used (which is on by default). It will otherwise show the specific identifier.
+The <c>db_tab</c> listing shows 722287 unique locks, it is one for each ets-table created and Mnesia creates one for each transaction.
+</p>
+<pre>
+5> lcnt:conflicts().
+ lock id #tries #collisions collisions [%] time [us] duration [%]
+ ----- --- ------- ------------ --------------- ---------- -------------
+ alcu_allocator 50 56355118 732662 1.3001 2934747 4.8862
+ db_tab 722287 94513441 63203 0.0669 1958797 3.2613
+ timeofday 1 2701048 175854 6.5106 1746079 2.9071
+ pix_lock 256 24306168 163214 0.6715 918309 1.5289
+ run_queue 8 11813811 152637 1.2920 357040 0.5945
+ message_pre_alloc_lock 8 17671449 57203 0.3237 263043 0.4380
+ mnesia_locker 4 17477633 1618548 9.2607 97092 0.1617
+ mnesia_tm 4 9891408 463788 4.6888 86353 0.1438
+ gc_info 1 823460 628 0.0763 24826 0.0413
+ meta_main_tab_slot 16 41393400 7193 0.0174 11393 0.0190
+ &lt;[email protected]&gt; 4 4331412 333 0.0077 7148 0.0119
+ timer_wheel 1 203185 30 0.0148 3108 0.0052
+ &lt;[email protected]&gt; 4 4291098 210 0.0049 885 0.0015
+ &lt;[email protected]&gt; 4 4294702 288 0.0067 442 0.0007
+ &lt;[email protected]&gt; 4 4346066 235 0.0054 390 0.0006
+ &lt;[email protected]&gt; 4 4348159 287 0.0066 379 0.0006
+ &lt;[email protected]&gt; 4 4279309 290 0.0068 325 0.0005
+ &lt;[email protected]&gt; 4 4292190 302 0.0070 315 0.0005
+ &lt;[email protected]&gt; 4 4208858 265 0.0063 276 0.0005
+ &lt;[email protected]&gt; 4 4377502 267 0.0061 276 0.0005
+ok
+</pre>
+<p>The listing shows <c>mnesia_locker</c>, a process, has highly contended locks.</p>
+<pre>
+6> lcnt:inspect(mnesia_locker).
+ lock id #tries #collisions collisions [%] time [us] duration [%]
+ ----- --- ------- ------------ --------------- ---------- -------------
+ mnesia_locker proc_msgq 5449930 59374 1.0894 69781 0.1162
+ mnesia_locker proc_main 4462782 1487374 33.3284 14398 0.0240
+ mnesia_locker proc_status 7564921 71800 0.9491 12913 0.0215
+ mnesia_locker proc_link 0 0 0.0000 0 0.0000
+ok
+</pre>
+<p>Listing without class combiner.</p>
+
+<pre>
+7> lcnt:conflicts([{combine, false}, {print, [name, id, tries, ratio, time]}]).
+ lock id #tries collisions [%] time [us]
+ ----- --- ------- --------------- ----------
+ db_tab mnesia_transient_decision 722250 3.9463 1856852
+ timeofday undefined 2701048 6.5106 1746079
+ alcu_allocator ets_alloc 7490696 2.2737 692655
+ alcu_allocator ets_alloc 7081771 2.3294 664522
+ alcu_allocator ets_alloc 7047750 2.2520 658495
+ alcu_allocator ets_alloc 5883537 2.3177 610869
+ pix_lock 58 11011355 1.1924 564808
+ pix_lock 60 4426484 0.7120 262490
+ alcu_allocator ets_alloc 1897004 2.4248 219543
+ message_pre_alloc_lock undefined 4211267 0.3242 128299
+ run_queue 3 2801555 1.3003 116792
+ run_queue 2 2799988 1.2700 100091
+ run_queue 1 2966183 1.2712 78834
+ mnesia_locker proc_msgq 5449930 1.0894 69781
+ message_pre_alloc_lock undefined 3495672 0.3262 65773
+ message_pre_alloc_lock undefined 4189752 0.3174 58607
+ mnesia_tm proc_msgq 2094144 1.7184 56361
+ run_queue 4 2343585 1.3115 44300
+ db_tab branch 1446529 0.5229 38244
+ gc_info undefined 823460 0.0763 24826
+ok
+</pre>
+<p>
+In this scenario the lock that protects ets-table <c>mnesia_transient_decision</c> has spent most of its waiting for. That is 1.8 seconds in a test that run for 60 seconds. The time is also spread on eight different scheduler threads.
+</p>
+<pre>
+8> lcnt:inspect(db_tab, [{print, [name, id, tries, colls, ratio, duration]}]).
+ lock id #tries #collisions collisions [%] duration [%]
+ ----- --- ------- ------------ --------------- -------------
+ db_tab mnesia_transient_decision 722250 28502 3.9463 3.0916
+ db_tab branch 1446529 7564 0.5229 0.0637
+ db_tab account 1464500 8203 0.5601 0.0357
+ db_tab teller 1464529 8110 0.5538 0.0291
+ db_tab history 722250 3767 0.5216 0.0232
+ db_tab mnesia_stats 750332 7057 0.9405 0.0180
+ db_tab mnesia_trans_store 61 0 0.0000 0.0000
+ db_tab mnesia_trans_store 61 0 0.0000 0.0000
+ db_tab mnesia_trans_store 53 0 0.0000 0.0000
+ db_tab mnesia_trans_store 53 0 0.0000 0.0000
+ db_tab mnesia_trans_store 53 0 0.0000 0.0000
+ db_tab mnesia_trans_store 53 0 0.0000 0.0000
+ db_tab mnesia_trans_store 53 0 0.0000 0.0000
+ db_tab mnesia_trans_store 53 0 0.0000 0.0000
+ db_tab mnesia_trans_store 53 0 0.0000 0.0000
+ db_tab mnesia_trans_store 53 0 0.0000 0.0000
+ db_tab mnesia_trans_store 53 0 0.0000 0.0000
+ db_tab mnesia_trans_store 53 0 0.0000 0.0000
+ db_tab mnesia_trans_store 53 0 0.0000 0.0000
+ db_tab mnesia_trans_store 53 0 0.0000 0.0000
+ok
+</pre>
+
+ </section>
+ <section>
+ <title> Deciphering the output </title>
+ <p> Typically high <c>time</c> values are bad and this is often the thing to look for. However, one should also look for high lock acquisition frequencies (#tries) since locks generate overhead and because high frequency could become problematic if they begin to have conflicts even if it is not shown in a particular test. </p>
+ </section>
+
+ <section>
+ <title>See Also</title>
+ <p> <seealso marker="lcnt">LCNT Reference Manual</seealso></p>
+ </section>
+</chapter>
diff --git a/lib/tools/doc/src/part.xml b/lib/tools/doc/src/part.xml
index 3e02086b80..bf9e1ebbec 100644
--- a/lib/tools/doc/src/part.xml
+++ b/lib/tools/doc/src/part.xml
@@ -4,7 +4,7 @@
<part xmlns:xi="http://www.w3.org/2001/XInclude">
<header>
<copyright>
- <year>1996</year><year>2009</year>
+ <year>1996</year><year>2010</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -13,12 +13,12 @@
compliance with the License. You should have received a copy of the
Erlang Public License along with this software. If not, it can be
retrieved online at http://www.erlang.org/.
-
+
Software distributed under the License is distributed on an "AS IS"
basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
the License for the specific language governing rights and limitations
under the License.
-
+
</legalnotice>
<title>Tools User's Guide</title>
@@ -55,6 +55,8 @@
<tag><em>instrument</em></tag>
<item>Utility functions for obtaining and analysing resource usage
in an instrumented Erlang runtime system.</item>
+ <tag><em>lcnt</em></tag>
+ <item>A lock profiling tool for the Erlang runtime system.</item>
<tag><em>make</em></tag>
<item>A make utility for Erlang similar to UNIX make.</item>
<tag><em>tags</em></tag>
@@ -69,6 +71,7 @@
<xi:include href="cprof_chapter.xml"/>
<xi:include href="erlang_mode_chapter.xml"/>
<xi:include href="fprof_chapter.xml"/>
+ <xi:include href="lcnt_chapter.xml"/>
<xi:include href="xref_chapter.xml"/>
</part>
diff --git a/lib/tools/doc/src/ref_man.xml b/lib/tools/doc/src/ref_man.xml
index aea74e3746..d4861af9f3 100644
--- a/lib/tools/doc/src/ref_man.xml
+++ b/lib/tools/doc/src/ref_man.xml
@@ -4,7 +4,7 @@
<application xmlns:xi="http://www.w3.org/2001/XInclude">
<header>
<copyright>
- <year>1996</year><year>2009</year>
+ <year>1996</year><year>2010</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -13,12 +13,12 @@
compliance with the License. You should have received a copy of the
Erlang Public License along with this software. If not, it can be
retrieved online at http://www.erlang.org/.
-
+
Software distributed under the License is distributed on an "AS IS"
basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
the License for the specific language governing rights and limitations
under the License.
-
+
</legalnotice>
<title>Tools Reference Manual</title>
@@ -51,9 +51,14 @@
Erlang programs. Uses trace to file to minimize runtime
performance impact, and displays time for calling and called
functions.</item>
+
<tag><em>instrument</em></tag>
<item>Utility functions for obtaining and analysing resource usage
in an instrumented Erlang runtime system.</item>
+
+ <tag><em>lcnt</em></tag>
+ <item>A lock profiling tool for the Erlang runtime system.</item>
+
<tag><em>make</em></tag>
<item>A make utility for Erlang similar to UNIX make.</item>
<tag><em>tags</em></tag>
@@ -70,6 +75,7 @@
<xi:include href="erlang_mode.xml"/>
<xi:include href="fprof.xml"/>
<xi:include href="instrument.xml"/>
+ <xi:include href="lcnt.xml"/>
<xi:include href="make.xml"/>
<xi:include href="tags.xml"/>
<xi:include href="xref.xml"/>
diff --git a/lib/tools/src/Makefile b/lib/tools/src/Makefile
index 81933cda14..360f4f8f29 100644
--- a/lib/tools/src/Makefile
+++ b/lib/tools/src/Makefile
@@ -1,19 +1,19 @@
#
# %CopyrightBegin%
-#
-# Copyright Ericsson AB 1996-2009. All Rights Reserved.
-#
+#
+# Copyright Ericsson AB 1996-2010. All Rights Reserved.
+#
# The contents of this file are subject to the Erlang Public License,
# Version 1.1, (the "License"); you may not use this file except in
# compliance with the License. You should have received a copy of the
# Erlang Public License along with this software. If not, it can be
# retrieved online at http://www.erlang.org/.
-#
+#
# Software distributed under the License is distributed on an "AS IS"
# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
# the License for the specific language governing rights and limitations
# under the License.
-#
+#
# %CopyrightEnd%
#
include $(ERL_TOP)/make/target.mk
@@ -34,11 +34,13 @@ RELSYSDIR = $(RELEASE_PATH)/lib/tools-$(VSN)
# Common Macros
# ----------------------------------------------------
-MODULES= cover \
+MODULES= \
+ cover \
cover_web \
eprof \
fprof \
cprof \
+ lcnt \
instrument \
make \
tags \
diff --git a/lib/tools/src/lcnt.erl b/lib/tools/src/lcnt.erl
new file mode 100644
index 0000000000..989a661b75
--- /dev/null
+++ b/lib/tools/src/lcnt.erl
@@ -0,0 +1,840 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2010. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+-module(lcnt).
+-behaviour(gen_server).
+-author("Björn-Egil Dahlberg").
+
+%% gen_server callbacks
+-export([
+ init/1,
+ handle_call/3,
+ handle_cast/2,
+ handle_info/2,
+ terminate/2,
+ code_change/3
+ ]).
+
+%% start/stop
+-export([
+ start/0,
+ stop/0
+ ]).
+
+%% erts_debug:lock_counters api
+-export([
+ rt_collect/0,
+ rt_collect/1,
+ rt_clear/0,
+ rt_clear/1,
+ rt_opt/1,
+ rt_opt/2
+ ]).
+
+
+%% gen_server call api
+-export([
+ raw/0,
+ collect/0,
+ collect/1,
+ clear/0,
+ clear/1,
+ conflicts/0,
+ conflicts/1,
+ locations/0,
+ locations/1,
+ inspect/1,
+ inspect/2,
+ information/0,
+ swap_pid_keys/0,
+ % set options
+ set/1,
+ set/2,
+
+ load/1,
+ save/1
+ ]).
+
+%% convenience
+-export([
+ apply/3,
+ apply/2,
+ apply/1,
+ all_conflicts/0,
+ all_conflicts/1,
+ pid/2, pid/3,
+ port/1, port/2
+ ]).
+
+-define(version, "1.0").
+
+-record(state, {
+ locks = [],
+ duration = 0
+ }).
+
+
+-record(stats, {
+ file,
+ line,
+ tries,
+ colls,
+ time, % us
+ nt % #timings collected
+ }).
+
+-record(lock, {
+ name,
+ id,
+ type,
+ stats = []
+ }).
+
+-record(print, {
+ name,
+ id,
+ type,
+ entry,
+ tries,
+ colls,
+ cr, % collision ratio
+ time,
+ dtr % time duration ratio
+ }).
+
+
+
+%% -------------------------------------------------------------------- %%
+%%
+%% start/stop/init
+%%
+%% -------------------------------------------------------------------- %%
+
+start() -> gen_server:start({local, ?MODULE}, ?MODULE, [], []).
+stop() -> gen_server:cast(?MODULE, stop).
+init([]) -> {ok, #state{ locks = [], duration = 0 } }.
+
+%% -------------------------------------------------------------------- %%
+%%
+%% API erts_debug:lock_counters
+%%
+%% -------------------------------------------------------------------- %%
+
+rt_collect() ->
+ erts_debug:lock_counters(info).
+
+rt_collect(Node) ->
+ rpc:call(Node, erts_debug, lock_counters, [info]).
+
+rt_clear() ->
+ erts_debug:lock_counters(clear).
+
+rt_clear(Node) ->
+ rpc:call(Node, erts_debug, lock_counters, [clear]).
+
+rt_opt({Type, Opt}) ->
+ erts_debug:lock_counters({Type, Opt}).
+
+rt_opt(Node, {Type, Opt}) ->
+ rpc:call(Node, erts_debug, lock_counters, [{Type, Opt}]).
+
+%% -------------------------------------------------------------------- %%
+%%
+%% API implementation
+%%
+%% -------------------------------------------------------------------- %%
+
+clear() -> rt_clear().
+clear(Node) -> rt_clear(Node).
+collect() -> call({collect, rt_collect()}).
+collect(Node) -> call({collect, rt_collect(Node)}).
+
+locations() -> call({locations,[]}).
+locations(Opts) -> call({locations, Opts}).
+conflicts() -> call({conflicts, []}).
+conflicts(Opts) -> call({conflicts, Opts}).
+inspect(Lock) -> call({inspect, Lock, []}).
+inspect(Lock, Opts) -> call({inspect, Lock, Opts}).
+information() -> call(information).
+swap_pid_keys() -> call(swap_pid_keys).
+raw() -> call(raw).
+set(Option, Value) -> call({set, Option, Value}).
+set({Option, Value}) -> call({set, Option, Value}).
+save(Filename) -> call({save, Filename}).
+load(Filename) -> start(), call({load, Filename}).
+
+call(Msg) -> gen_server:call(?MODULE, Msg, infinity).
+
+%% -------------------------------------------------------------------- %%
+%%
+%% convenience implementation
+%%
+%% -------------------------------------------------------------------- %%
+
+apply(M,F,As) when is_atom(M), is_atom(F), is_list(As) ->
+ lcnt:start(),
+ Opt = lcnt:rt_opt({copy_save, true}),
+ lcnt:clear(),
+ Res = erlang:apply(M,F,As),
+ lcnt:collect(),
+ lcnt:rt_opt({copy_save, Opt}),
+ Res.
+
+apply(Fun) when is_function(Fun) ->
+ lcnt:apply(Fun, []).
+
+apply(Fun, As) when is_function(Fun) ->
+ lcnt:start(),
+ Opt = lcnt:rt_opt({copy_save, true}),
+ lcnt:clear(),
+ Res = erlang:apply(Fun, As),
+ lcnt:collect(),
+ lcnt:rt_opt({copy_save, Opt}),
+ Res.
+
+all_conflicts() -> all_conflicts(time).
+all_conflicts(Sort) ->
+ conflicts([{max_locks, none}, {thresholds, []},{combine,false}, {sort, Sort}, {reverse, true}]).
+
+pid(Id, Serial) -> pid(node(), Id, Serial).
+pid(Node, Id, Serial) when is_atom(Node) ->
+ Header = <<131,103,100>>,
+ String = atom_to_list(Node),
+ L = length(String),
+ binary_to_term(list_to_binary([Header, bytes16(L), String, bytes32(Id), bytes32(Serial),0])).
+
+port(Id) -> port(node(), Id).
+port(Node, Id ) when is_atom(Node) ->
+ Header = <<131,102,100>>,
+ String = atom_to_list(Node),
+ L = length(String),
+ binary_to_term(list_to_binary([Header, bytes16(L), String, bytes32(Id), 0])).
+
+%% -------------------------------------------------------------------- %%
+%%
+%% handle_call
+%%
+%% -------------------------------------------------------------------- %%
+
+% printing
+
+handle_call({conflicts, InOpts}, _From, #state{ locks = Locks } = State) when is_list(InOpts) ->
+ Default = [
+ {sort, time},
+ {reverse, false},
+ {print, [name,id,tries,colls,ratio,time,duration]},
+ {max_locks, 20},
+ {combine, true},
+ {thresholds, [{tries, 0}, {colls, 0}, {time, 0}] },
+ {locations, false}],
+
+ Opts = options(InOpts, Default),
+ Flocks = filter_locks_type(Locks, proplists:get_value(type, Opts)),
+ Combos = combine_classes(Flocks, proplists:get_value(combine, Opts)),
+ Printables = locks2print(Combos, State#state.duration),
+ Filtered = filter_print(Printables, Opts),
+
+ print_lock_information(Filtered, proplists:get_value(print, Opts)),
+
+ {reply, ok, State};
+
+handle_call(information, _From, State) ->
+ print_state_information(State),
+ {reply, ok, State};
+
+handle_call({locations, InOpts}, _From, #state{ locks = Locks } = State) when is_list(InOpts) ->
+ Default = [
+ {sort, time},
+ {reverse, false},
+ {print, [name,entry,tries,colls,ratio,time,duration]},
+ {max_locks, 20},
+ {combine, true},
+ {thresholds, [{tries, 0}, {colls, 0}, {time, 0}] },
+ {locations, true}],
+
+ Opts = options(InOpts, Default),
+ Printables = filter_print([#print{
+ name = string_names(Names),
+ entry = term2string("~p:~p", [Stats#stats.file, Stats#stats.line]),
+ colls = Stats#stats.colls,
+ tries = Stats#stats.tries,
+ cr = percent(Stats#stats.colls, Stats#stats.tries),
+ time = Stats#stats.time,
+ dtr = percent(Stats#stats.time, State#state.duration)
+ } || {Stats, Names} <- combine_locations(Locks) ], Opts),
+
+ print_lock_information(Printables, proplists:get_value(print, Opts)),
+
+ {reply, ok, State};
+
+handle_call({inspect, Lockname, InOpts}, _From, #state{ duration = Duration, locks = Locks } = State) when is_list(InOpts) ->
+ Default = [
+ {sort, time},
+ {reverse, false},
+ {print, [name,id,tries,colls,ratio,time,duration]},
+ {max_locks, 20},
+ {combine, false},
+ {thresholds, [] },
+ {locations, false}],
+
+ Opts = options(InOpts, Default),
+ Filtered = filter_locks(Locks, Lockname),
+ IDs = case {proplists:get_value(full_id, Opts), proplists:get_value(combine, Opts)} of
+ {true, true} -> locks_ids(Filtered);
+ _ -> []
+ end,
+ Combos = combine_classes(Filtered, proplists:get_value(combine, Opts)),
+ case proplists:get_value(locations, Opts) of
+ true ->
+ lists:foreach(fun
+ (#lock{ name = Name, id = Id, type = Type, stats = Stats }) ->
+ IdString = case proplists:get_value(full_id, Opts) of
+ true -> term2string(proplists:get_value(Name, IDs, Id));
+ _ -> term2string(Id)
+ end,
+ Combined = [CStats || {CStats,_} <- combine_locations(Stats)],
+ case Combined of
+ [] ->
+ ok;
+ _ ->
+ %io:format("Combined ~p~n", [Combined]),
+ print("lock: " ++ term2string(Name)),
+ print("id: " ++ IdString),
+ print("type: " ++ term2string(Type)),
+ Ps = stats2print(Combined, Duration),
+ Opts1 = options([{print, [entry, tries,colls,ratio,time,duration]},
+ {thresholds, [{tries, -1}, {colls, -1}, {time, -1}]}], Opts),
+ print_lock_information(filter_print(Ps, Opts1), proplists:get_value(print, Opts1))
+ end
+ % (#lock{ name = Name, id = Id}) ->
+ % io:format("Empty lock ~p ~p~n", [Name, Id])
+ end, Combos);
+ _ ->
+ Print1 = locks2print(Combos, Duration),
+ Print2 = filter_print(Print1, Opts),
+ print_lock_information(Print2, proplists:get_value(print, Opts))
+ end,
+ {reply, ok, State};
+
+handle_call(raw, _From, #state{ locks = Locks} = State)->
+ {reply, Locks, State};
+
+% collecting
+handle_call({collect, Data}, _From, State)->
+ {reply, ok, data2state(Data, State)};
+
+% manipulate
+handle_call(swap_pid_keys, _From, #state{ locks = Locks } = State)->
+ SwappedLocks = lists:map(fun
+ (L) when L#lock.name =:= port_lock; L#lock.type =:= proclock ->
+ L#lock{ id = L#lock.name, name = L#lock.id };
+ (L) ->
+ L
+ end, Locks),
+
+ {reply, ok, State#state{ locks = SwappedLocks}};
+
+% settings
+handle_call({set, data, Data}, _From, State)->
+ {reply, ok, data2state(Data, State)};
+
+handle_call({set, duration, Duration}, _From, State)->
+ {reply, ok, State#state{ duration = Duration}};
+
+% file operations
+handle_call({load, Filename}, _From, State) ->
+ case file:read_file(Filename) of
+ {ok, Binary} ->
+ case binary_to_term(Binary) of
+ {?version, Statelist} ->
+ {reply, ok, list2state(Statelist)};
+ {Version, _} ->
+ {reply, {error, {mismatch, Version, ?version}}, State}
+ end;
+ Error ->
+ {reply, {error, Error}, State}
+ end;
+
+handle_call({save, Filename}, _From, State) ->
+ Binary = term_to_binary({?version, state2list(State)}),
+ case file:write_file(Filename, Binary) of
+ ok ->
+ {reply, ok, State};
+ Error ->
+ {reply, {error, Error}, State}
+ end;
+
+
+handle_call(Command, _From, State) ->
+ {reply, {error, {undefined, Command}}, State}.
+
+%% -------------------------------------------------------------------- %%
+%%
+%% handle_cast
+%%
+%% -------------------------------------------------------------------- %%
+
+handle_cast(stop, State) ->
+ {stop, normal, State};
+handle_cast(_, State) ->
+ {noreply, State}.
+
+%% -------------------------------------------------------------------- %%
+%%
+%% handle_info
+%%
+%% -------------------------------------------------------------------- %%
+
+handle_info(_Info, State) ->
+ {noreply, State}.
+
+%% -------------------------------------------------------------------- %%
+%%
+%% termination
+%%
+%% -------------------------------------------------------------------- %%
+
+terminate(_Reason, _State) ->
+ ok.
+
+%% -------------------------------------------------------------------- %%
+%%
+%% code_change
+%%
+%% -------------------------------------------------------------------- %%
+
+code_change(_OldVsn, State, _Extra) ->
+ {ok, State}.
+
+%% -------------------------------------------------------------------- %%
+%%
+%% AUX
+%%
+%% -------------------------------------------------------------------- %%
+
+% summate
+
+summate_locks(Locks) -> summate_locks(Locks, #stats{ tries = 0, colls = 0, time = 0, nt = 0}).
+summate_locks([], Stats) -> Stats;
+summate_locks([L|Ls], #stats{ tries = Tries, colls = Colls, time = Time, nt = Nt}) ->
+ S = summate_stats(L#lock.stats),
+ summate_locks(Ls, #stats{ tries = Tries + S#stats.tries, colls = Colls + S#stats.colls, time = Time + S#stats.time, nt = Nt + S#stats.nt}).
+
+summate_stats(Stats) -> summate_stats(Stats, #stats{ tries = 0, colls = 0, time = 0, nt = 0}).
+summate_stats([], Stats) -> Stats;
+summate_stats([S|Ss], #stats{ tries = Tries, colls = Colls, time = Time, nt = Nt}) ->
+ summate_stats(Ss, #stats{ tries = Tries + S#stats.tries, colls = Colls + S#stats.colls, time = Time + S#stats.time, nt = Nt + S#stats.nt}).
+
+
+%% manipulators
+filter_locks_type(Locks, undefined) -> Locks;
+filter_locks_type(Locks, all) -> Locks;
+filter_locks_type(Locks, Types) when is_list(Types) ->
+ [ L || L <- Locks, lists:member(L#lock.type, Types)];
+filter_locks_type(Locks, Type) ->
+ [ L || L <- Locks, L#lock.type =:= Type].
+
+filter_locks(Locks, {Lockname, Ids}) when is_list(Ids) ->
+ [ L || L <- Locks, L#lock.name =:= Lockname, lists:member(L#lock.id, Ids)];
+filter_locks(Locks, {Lockname, Id}) ->
+ [ L || L <- Locks, L#lock.name =:= Lockname, L#lock.id =:= Id ];
+filter_locks(Locks, Lockname) ->
+ [ L || L <- Locks, L#lock.name =:= Lockname ].
+% order of processing
+% 2. cut thresholds
+% 3. sort locks
+% 4. max length of locks
+
+filter_print(PLs, Opts) ->
+ TLs = threshold_locks(PLs, proplists:get_value(thresholds, Opts, [])),
+ SLs = sort_locks(TLs, proplists:get_value(sort, Opts, time)),
+ CLs = cut_locks(SLs, proplists:get_value(max_locks, Opts, none)),
+ reverse_locks(CLs, proplists:get_value(reverse, Opts, false)).
+
+sort_locks(Locks, Type) -> lists:reverse(sort_locks0(Locks, Type)).
+sort_locks0(Locks, name) -> lists:keysort(#print.name, Locks);
+sort_locks0(Locks, id) -> lists:keysort(#print.id, Locks);
+sort_locks0(Locks, type) -> lists:keysort(#print.type, Locks);
+sort_locks0(Locks, tries) -> lists:keysort(#print.tries, Locks);
+sort_locks0(Locks, colls) -> lists:keysort(#print.colls, Locks);
+sort_locks0(Locks, ratio) -> lists:keysort(#print.cr, Locks);
+sort_locks0(Locks, time) -> lists:keysort(#print.time, Locks);
+sort_locks0(Locks, _) -> sort_locks0(Locks, time).
+
+% cut locks not above certain thresholds
+threshold_locks(Locks, Thresholds) ->
+ Tries = proplists:get_value(tries, Thresholds, -1),
+ Colls = proplists:get_value(colls, Thresholds, -1),
+ Time = proplists:get_value(time, Thresholds, -1),
+ [ L || L <- Locks, L#print.tries > Tries, L#print.colls > Colls, L#print.time > Time].
+
+cut_locks(Locks, N) when is_integer(N), N > 0 -> lists:sublist(Locks, N);
+cut_locks(Locks, _) -> Locks.
+
+%% reversal
+reverse_locks(Locks, true) -> lists:reverse(Locks);
+reverse_locks(Locks, _) -> Locks.
+
+
+%%
+string_names([]) -> "";
+string_names(Names) -> string_names(Names, []).
+string_names([Name], Strings) -> strings(lists:reverse([term2string(Name) | Strings]));
+string_names([Name|Names],Strings) -> string_names(Names, [term2string(Name) ++ ","|Strings]).
+
+%% combine_locations
+%% In:
+%% Locations :: [#lock{}] | [#stats{}]
+%% Out:
+%% [{{File,Line}, #stats{}, [Lockname]}]
+
+
+combine_locations(Locations) -> gb_trees:values(combine_locations(Locations, gb_trees:empty())).
+combine_locations([], Tree) -> Tree;
+combine_locations([S|_] = Stats, Tree) when is_record(S, stats) ->
+ combine_locations(Stats, undefined, Tree);
+combine_locations([#lock{ stats = Stats, name = Name}|Ls], Tree) ->
+ combine_locations(Ls, combine_locations(Stats, Name, Tree)).
+
+combine_locations([], _, Tree) -> Tree;
+combine_locations([S|Ss], Name, Tree) when is_record(S, stats)->
+ Key = {S#stats.file, S#stats.line},
+ Tree1 = case gb_trees:lookup(Key, Tree) of
+ none ->
+ gb_trees:insert(Key, {S, [Name]}, Tree);
+ {value, {C, Names}} ->
+ NewNames = case lists:member(Name, Names) of
+ true -> Names;
+ _ -> [Name | Names]
+ end,
+ gb_trees:update(Key, {
+ C#stats{
+ tries = C#stats.tries + S#stats.tries,
+ colls = C#stats.colls + S#stats.colls,
+ time = C#stats.time + S#stats.time,
+ nt = C#stats.nt + S#stats.nt
+ }, NewNames}, Tree)
+ end,
+ combine_locations(Ss, Name, Tree1).
+
+%% combines all statistics for a class (name) lock
+%% id's are translated to #id's.
+
+combine_classes(Locks, true) -> combine_classes1(Locks, gb_trees:empty());
+combine_classes(Locks, _) -> Locks.
+
+combine_classes1([], Tree) -> gb_trees:values(Tree);
+combine_classes1([L|Ls], Tree) ->
+ Key = L#lock.name,
+ case gb_trees:lookup(Key, Tree) of
+ none ->
+ combine_classes1(Ls, gb_trees:insert(Key, L#lock{ id = 1 }, Tree));
+ {value, C} ->
+ combine_classes1(Ls, gb_trees:update(Key, C#lock{
+ id = C#lock.id + 1,
+ stats = L#lock.stats ++ C#lock.stats
+ }, Tree))
+ end.
+
+locks_ids(Locks) -> locks_ids(Locks, []).
+locks_ids([], Out) -> Out;
+locks_ids([#lock{ name = Key } = L|Ls], Out) ->
+ case proplists:get_value(Key, Out) of
+ undefined ->
+ locks_ids(Ls, [{Key, [L#lock.id] } | Out]);
+ Ids ->
+ locks_ids(Ls, [{Key, [L#lock.id | Ids] } | proplists:delete(Key,Out)])
+ end.
+
+stats2print(Stats, Duration) ->
+ lists:map(fun
+ (S) ->
+ #print{
+ entry = term2string("~p:~p", [S#stats.file, S#stats.line]),
+ colls = S#stats.colls,
+ tries = S#stats.tries,
+ cr = percent(S#stats.colls, S#stats.tries),
+ time = S#stats.time,
+ dtr = percent(S#stats.time, Duration)
+ }
+ end, Stats).
+
+locks2print(Locks, Duration) ->
+ lists:map( fun
+ (L) ->
+ Tries = lists:sum([T || #stats{ tries = T} <- L#lock.stats]),
+ Colls = lists:sum([C || #stats{ colls = C} <- L#lock.stats]),
+ Time = lists:sum([T || #stats{ time = T} <- L#lock.stats]),
+ Cr = percent(Colls, Tries),
+ Dtr = percent(Time, Duration),
+ #print{
+ name = L#lock.name,
+ id = L#lock.id,
+ type = L#lock.type,
+ tries = Tries,
+ colls = Colls,
+ cr = Cr,
+ time = Time,
+ dtr = Dtr
+ }
+ end, Locks).
+
+%% state making
+
+data2state(Data, State) ->
+ Duration = time2us(proplists:get_value(duration, Data)),
+ Rawlocks = proplists:get_value(locks, Data),
+ Locks = locks2records(Rawlocks),
+ State#state{
+ duration = Duration,
+ locks = Locks
+ }.
+
+locks2records(Locks) -> locks2records(Locks, []).
+locks2records([], Out) -> Out;
+locks2records([{Name, Id, Type, Stats}|Locks], Out) ->
+ Lock = #lock{
+ name = Name,
+ id = clean_id_creation(Id),
+ type = Type,
+ stats = [ #stats{
+ file = File,
+ line = Line,
+ tries = Tries,
+ colls = Colls,
+ time = time2us({S, Ns}),
+ nt = N
+ } || {{File, Line}, {Tries, Colls, {S, Ns, N}}} <- Stats] },
+ locks2records(Locks, [Lock|Out]).
+
+clean_id_creation(Id) when is_pid(Id) ->
+ Bin = term_to_binary(Id),
+ <<H:3/binary, L:16, Node:L/binary, Ids:8/binary, _Creation/binary>> = Bin,
+ Bin2 = list_to_binary([H, bytes16(L), Node, Ids, 0]),
+ binary_to_term(Bin2);
+clean_id_creation(Id) when is_port(Id) ->
+ Bin = term_to_binary(Id),
+ <<H:3/binary, L:16, Node:L/binary, Ids:4/binary, _Creation/binary>> = Bin,
+ Bin2 = list_to_binary([H, bytes16(L), Node, Ids, 0]),
+ binary_to_term(Bin2);
+clean_id_creation(Id) ->
+ Id.
+
+%% serializer
+
+state_default(Field) -> proplists:get_value(Field, state2list(#state{})).
+
+state2list(State) ->
+ [_|Values] = tuple_to_list(State),
+ lists:zipwith(fun
+ (locks, Locks) -> {locks, [lock2list(Lock) || Lock <- Locks]};
+ (X, Y) -> {X,Y}
+ end, record_info(fields, state), Values).
+
+list2state(List) -> list2state(record_info(fields, state), List, [state]).
+list2state([], _, Out) -> list_to_tuple(lists:reverse(Out));
+list2state([locks|Fs], List, Out) ->
+ Locks = [ list2lock(Lock) || Lock <- proplists:get_value(locks, List, [])],
+ list2state(Fs, List, [Locks|Out]);
+list2state([F|Fs], List, Out) -> list2state(Fs, List, [proplists:get_value(F, List, state_default(F))|Out]).
+
+lock_default(Field) -> proplists:get_value(Field, lock2list(#lock{})).
+
+lock2list(Lock) ->
+ [_|Values] = tuple_to_list(Lock),
+ lists:zip(record_info(fields, lock), Values).
+
+list2lock(List) -> list2lock(record_info(fields, lock), List, [lock]).
+list2lock([], _, Out) -> list_to_tuple(lists:reverse(Out));
+list2lock([F|Fs], List, Out) -> list2lock(Fs, List, [proplists:get_value(F, List, lock_default(F))|Out]).
+
+%% printing
+
+%% print_lock_information
+%% In:
+%% Locks :: [#lock{}]
+%% Print :: [Type | {Type, integer()}]
+%%
+%% Out:
+%% ok
+
+auto_print_width(Locks, Print) ->
+ % iterate all lock entries to save all max length values
+ % these are records, so we do a little tuple <-> list smashing
+ R = lists:foldl(fun
+ (L, Max) ->
+ list_to_tuple(lists:reverse(lists:foldl(fun
+ ({print,print}, Out) -> [print|Out];
+ ({Str, Len}, Out) -> [erlang:min(erlang:max(length(s(Str))+1,Len),80)|Out]
+ end, [], lists:zip(tuple_to_list(L), tuple_to_list(Max)))))
+ end, #print{ id = 4, type = 5, entry = 5, name = 6, tries = 8, colls = 13, cr = 16, time = 11, dtr = 14 },
+ Locks),
+ % Setup the offsets for later pruning
+ Offsets = [
+ {id, R#print.id},
+ {name, R#print.name},
+ {type, R#print.type},
+ {entry, R#print.entry},
+ {tries, R#print.tries},
+ {colls, R#print.colls},
+ {ratio, R#print.cr},
+ {time, R#print.time},
+ {duration, R#print.dtr}],
+ % Prune offsets to only allow specified print options
+ lists:foldr(fun
+ ({Type, W}, Out) -> [{Type, W}|Out];
+ (Type, Out) -> [proplists:lookup(Type, Offsets)|Out]
+ end, [], Print).
+
+print_lock_information(Locks, Print) ->
+ % remake Print to autosize entries
+ AutoPrint = auto_print_width(Locks, Print),
+
+ print_header(AutoPrint),
+
+ lists:foreach(fun
+ (L) ->
+ print_lock(L, AutoPrint)
+ end, Locks),
+ ok.
+
+print_header(Opts) ->
+ Header = #print{
+ name = "lock",
+ id = "id",
+ type = "type",
+ entry = "location",
+ tries = "#tries",
+ colls = "#collisions",
+ cr = "collisions [%]",
+ time = "time [us]",
+ dtr = "duration [%]"
+ },
+ Divider = #print{
+ name = lists:duplicate(1 + length(Header#print.name), 45),
+ id = lists:duplicate(1 + length(Header#print.id), 45),
+ type = lists:duplicate(1 + length(Header#print.type), 45),
+ entry = lists:duplicate(1 + length(Header#print.entry), 45),
+ tries = lists:duplicate(1 + length(Header#print.tries), 45),
+ colls = lists:duplicate(1 + length(Header#print.colls), 45),
+ cr = lists:duplicate(1 + length(Header#print.cr), 45),
+ time = lists:duplicate(1 + length(Header#print.time), 45),
+ dtr = lists:duplicate(1 + length(Header#print.dtr), 45)
+ },
+ print_lock(Header, Opts),
+ print_lock(Divider, Opts),
+ ok.
+
+
+print_lock(L, Opts) -> print_lock(L, Opts, []).
+print_lock(_, [], Formats) -> print(strings(lists:reverse(Formats)));
+print_lock(L, [Opt|Opts], Formats) ->
+ case Opt of
+ id -> print_lock(L, Opts, [{space, 25, s(L#print.id) } | Formats]);
+ {id, W} -> print_lock(L, Opts, [{space, W, s(L#print.id) } | Formats]);
+ type -> print_lock(L, Opts, [{space, 18, s(L#print.type) } | Formats]);
+ {type, W} -> print_lock(L, Opts, [{space, W, s(L#print.type) } | Formats]);
+ entry -> print_lock(L, Opts, [{space, 30, s(L#print.entry)} | Formats]);
+ {entry, W} -> print_lock(L, Opts, [{space, W, s(L#print.entry)} | Formats]);
+ name -> print_lock(L, Opts, [{space, 22, s(L#print.name) } | Formats]);
+ {name, W} -> print_lock(L, Opts, [{space, W, s(L#print.name) } | Formats]);
+ tries -> print_lock(L, Opts, [{space, 12, s(L#print.tries)} | Formats]);
+ {tries, W} -> print_lock(L, Opts, [{space, W, s(L#print.tries)} | Formats]);
+ colls -> print_lock(L, Opts, [{space, 14, s(L#print.colls)} | Formats]);
+ {colls, W} -> print_lock(L, Opts, [{space, W, s(L#print.colls)} | Formats]);
+ ratio -> print_lock(L, Opts, [{space, 20, s(L#print.cr) } | Formats]);
+ {ratio, W} -> print_lock(L, Opts, [{space, W, s(L#print.cr) } | Formats]);
+ time -> print_lock(L, Opts, [{space, 15, s(L#print.time) } | Formats]);
+ {time, W} -> print_lock(L, Opts, [{space, W, s(L#print.time) } | Formats]);
+ duration -> print_lock(L, Opts, [{space, 20, s(L#print.dtr) } | Formats]);
+ {duration, W} -> print_lock(L, Opts, [{space, W, s(L#print.dtr) } | Formats]);
+ _ -> print_lock(L, Opts, Formats)
+ end.
+
+print_state_information(#state{ locks = Locks} = State) ->
+ Stats = summate_locks(Locks),
+ print("information:"),
+ print(kv("#locks", s(length(Locks)))),
+ print(kv("duration", s(State#state.duration) ++ " us" ++ " (" ++ s(State#state.duration/1000000) ++ " s)")),
+ print("\nsummated stats:"),
+ print(kv("#tries", s(Stats#stats.tries))),
+ print(kv("#colls", s(Stats#stats.colls))),
+ print(kv("wait time", s(Stats#stats.time) ++ " us" ++ " ( " ++ s(Stats#stats.time/1000000) ++ " s)")),
+ print(kv("percent of duration", s(Stats#stats.time/State#state.duration*100) ++ " %")),
+ ok.
+
+%% AUX
+
+time2us({S, Ns}) -> round(S*1000000 + Ns/1000).
+
+percent(_,0) -> 0.0;
+percent(T,N) -> T/N*100.
+
+options(Opts, Default) when is_list(Default) ->
+ options1(proplists:unfold(Opts), Default).
+options1([], Defaults) -> Defaults;
+options1([{Key, Value}|Opts], Defaults) ->
+ case proplists:get_value(Key, Defaults) of
+ undefined -> options1(Opts, [{Key, Value} | Defaults]);
+ _ -> options1(Opts, [{Key, Value} | proplists:delete(Key, Defaults)])
+ end.
+
+%%% AUX STRING FORMATTING
+
+print(String) -> io:format("~s~n", [String]).
+
+kv(Key, Value) -> kv(Key, Value, 20).
+kv(Key, Value, Offset) -> term2string(term2string("~~~ps : ~~s", [Offset]),[Key, Value]).
+
+s(T) when is_float(T) -> term2string("~.4f", [T]);
+s(T) when is_list(T) -> term2string("~s", [T]);
+s(T) -> term2string(T).
+
+strings(Strings) -> strings(Strings, []).
+strings([], Out) -> Out;
+strings([{space, N, S} | Ss], Out) -> strings(Ss, Out ++ term2string(term2string("~~~ps", [N]), [S]));
+strings([{format, Format, S} | Ss], Out) -> strings(Ss, Out ++ term2string(Format, [S]));
+strings([S|Ss], Out) -> strings(Ss, Out ++ term2string("~s", [S])).
+
+
+term2string({M,F,A}) when is_atom(M), is_atom(F), is_integer(A) -> term2string("~p:~p/~p", [M,F,A]);
+term2string(Term) when is_port(Term) ->
+ % ex #Port<6442.816>
+ <<_:3/binary, L:16, Node:L/binary, Ids:32, _/binary>> = term_to_binary(Term),
+ term2string("#Port<~s.~w>", [Node, Ids]);
+term2string(Term) when is_pid(Term) ->
+ % ex <0.80.0>
+ <<_:3/binary, L:16, Node:L/binary, Ids:32, Serial:32, _/binary>> = term_to_binary(Term),
+ term2string("<~s.~w.~w>", [Node, Ids, Serial]);
+term2string(Term) -> term2string("~w", [Term]).
+term2string(Format, Terms) -> lists:flatten(io_lib:format(Format, Terms)).
+
+%%% AUD id binary
+
+bytes16(Value) ->
+ B0 = Value band 255,
+ B1 = (Value bsr 8) band 255,
+ <<B1, B0>>.
+
+bytes32(Value) ->
+ B0 = Value band 255,
+ B1 = (Value bsr 8) band 255,
+ B2 = (Value bsr 16) band 255,
+ B3 = (Value bsr 24) band 255,
+ <<B3, B2, B1, B0>>.
diff --git a/lib/tools/src/xref_utils.erl b/lib/tools/src/xref_utils.erl
index aeb7bf9f1c..680b7e8aac 100644
--- a/lib/tools/src/xref_utils.erl
+++ b/lib/tools/src/xref_utils.erl
@@ -1,19 +1,19 @@
%%
%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2000-2009. All Rights Reserved.
-%%
+%%
+%% Copyright Ericsson AB 2000-2010. All Rights Reserved.
+%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
%% compliance with the License. You should have received a copy of the
%% Erlang Public License along with this software. If not, it can be
%% retrieved online at http://www.erlang.org/.
-%%
+%%
%% Software distributed under the License is distributed on an "AS IS"
%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
%% the License for the specific language governing rights and limitations
%% under the License.
-%%
+%%
%% %CopyrightEnd%
%%
-module(xref_utils).
@@ -453,7 +453,8 @@ find_beam(Module) when is_atom(Module) ->
non_existing ->
error({no_such_module, Module});
preloaded ->
- {_M, _Bin, File} = code:get_object_code(Module),
+ {Module, {_M, _Bin, File}} =
+ {Module, code:get_object_code(Module)},
{ok, File};
cover_compiled ->
error({cover_compiled, Module});
diff --git a/lib/tools/test/Makefile b/lib/tools/test/Makefile
index a846a3a6f4..3a59be758a 100644
--- a/lib/tools/test/Makefile
+++ b/lib/tools/test/Makefile
@@ -26,6 +26,7 @@ MODULES = \
fprof_SUITE \
cprof_SUITE \
instrument_SUITE \
+ lcnt_SUITE \
make_SUITE \
tools_SUITE \
xref_SUITE \
@@ -49,7 +50,8 @@ RELSYSDIR = $(RELEASE_PATH)/tools_test
# FLAGS
# ----------------------------------------------------
ERL_MAKE_FLAGS +=
-ERL_COMPILE_FLAGS += -I$(ERL_TOP)/lib/test_server/include
+ERL_COMPILE_FLAGS += -I$(ERL_TOP)/lib/test_server/include \
+ -I$(ERL_TOP)/lib/percept/include
EBIN = .
@@ -68,10 +70,11 @@ tests debug opt: make_emakefile
clean:
rm -f $(EMAKEFILE)
rm -f $(TARGET_FILES)
- rm -f core
+ rm -f core *~
docs:
+
# ----------------------------------------------------
# Release Target
# ----------------------------------------------------
diff --git a/lib/tools/test/lcnt_SUITE.erl b/lib/tools/test/lcnt_SUITE.erl
new file mode 100644
index 0000000000..e6866f721d
--- /dev/null
+++ b/lib/tools/test/lcnt_SUITE.erl
@@ -0,0 +1,154 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2010. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+-module(lcnt_SUITE).
+-include("test_server.hrl").
+
+%% Test server specific exports
+-export([all/1]).
+-export([init_per_suite/1, end_per_suite/1]).
+-export([init_per_testcase/2, end_per_testcase/2]).
+
+%% Test cases
+-export([
+ load_v1/1,
+ conflicts/1,
+ locations/1,
+ swap_keys/1
+ ]).
+
+%% Default timetrap timeout (set in init_per_testcase)
+-define(default_timeout, ?t:minutes(2)).
+
+init_per_suite(Config) when is_list(Config) ->
+ Config.
+
+end_per_suite(Config) when is_list(Config) ->
+ Config.
+
+init_per_testcase(_Case, Config) ->
+ Dog = ?t:timetrap(?default_timeout),
+ [{watchdog,Dog} | Config].
+
+end_per_testcase(_Case, Config) ->
+ Dog = ?config(watchdog, Config),
+ ?t:timetrap_cancel(Dog),
+ ok.
+
+all(suite) ->
+ % Test cases
+ [load_v1, conflicts, locations, swap_keys].
+
+%%----------------------------------------------------------------------
+%% Tests
+%%----------------------------------------------------------------------
+
+load_v1(suite) ->
+ [];
+load_v1(doc) ->
+ ["Load data from file."];
+load_v1(Config) when is_list(Config) ->
+ ?line {ok, _} = lcnt:start(),
+ ?line Path = ?config(data_dir, Config),
+ ?line File = filename:join([Path,"big_bang_40.lcnt"]),
+ ?line ok = lcnt:load(File),
+ ?line ok = lcnt:stop(),
+ ok.
+
+conflicts(suite) ->
+ [];
+conflicts(doc) ->
+ ["API: conflicts"];
+conflicts(Config) when is_list(Config) ->
+ ?line {ok, _} = lcnt:start(),
+ ?line Path = ?config(data_dir, Config),
+ ?line File = filename:join([Path,"big_bang_40.lcnt"]),
+ ?line ok = lcnt:load(File),
+ ?line ok = lcnt:conflicts(),
+ THs = [-1, 0, 100, 1000],
+ Print = [name , id , type , entry , tries , colls , ratio , time , duration],
+ Opts = [
+ [{sort, Sort}, {reverse, Rev}, {max_locks, ML}, {combine, Combine}, {thresholds, [TH]}, {print, [Print]}] ||
+ Sort <- [name , id , type , tries , colls , ratio , time , entry],
+ ML <- [none, 1 , 32, 4096],
+ Combine <- [true, false],
+ TH <- [{tries, Tries} || Tries <- THs] ++ [{colls, Colls} || Colls <- THs] ++ [{time, Time} || Time <- THs],
+ Rev <- [true, false]
+ ],
+ ?line ok = test_conflicts_opts(Opts),
+ ?line ok = lcnt:stop(),
+ ok.
+
+test_conflicts_opts([]) -> ok;
+test_conflicts_opts([Opt|Opts]) ->
+ ?line ok = lcnt:conflicts(Opt),
+ test_conflicts_opts(Opts).
+
+locations(suite) ->
+ [];
+locations(doc) ->
+ ["API: locations"];
+locations(Config) when is_list(Config) ->
+ ?line {ok, _} = lcnt:start(),
+ ?line Path = ?config(data_dir, Config),
+ ?line File = filename:join([Path,"big_bang_40.lcnt"]),
+ ?line ok = lcnt:load(File),
+ ?line ok = lcnt:locations(),
+ THs = [-1, 0, 100, 1000],
+ Print = [name , id , type , entry , tries , colls , ratio , time , duration],
+ Opts = [
+ [{full_id, Id}, {sort, Sort}, {max_locks, ML}, {combine, Combine}, {thresholds, [TH]}, {print, Print}] ||
+ Sort <- [name , id , type , tries , colls , ratio , time , entry],
+ ML <- [none, 1 , 64],
+ Combine <- [true, false],
+ TH <- [{tries, Tries} || Tries <- THs] ++ [{colls, Colls} || Colls <- THs] ++ [{time, Time} || Time <- THs],
+ Id <- [true, false]
+ ],
+ ?line ok = test_locations_opts(Opts),
+ ?line ok = lcnt:stop(),
+ ok.
+
+test_locations_opts([]) -> ok;
+test_locations_opts([Opt|Opts]) ->
+ ?line ok = lcnt:locations(Opt),
+ test_locations_opts(Opts).
+
+swap_keys(suite) ->
+ [];
+swap_keys(doc) ->
+ ["Test interchanging port/process id with class"];
+swap_keys(Config) when is_list(Config) ->
+ ?line {ok, _} = lcnt:start(),
+ ?line Path = ?config(data_dir, Config),
+ ?line File = filename:join([Path,"big_bang_40.lcnt"]),
+ ?line ok = lcnt:load(File),
+ ?line ok = lcnt:conflicts(),
+ ?line ok = lcnt:swap_pid_keys(),
+ ?line ok = lcnt:conflicts(),
+ ?line ok = lcnt:stop(),
+ ok.
+
+
+%%----------------------------------------------------------------------
+%% Auxiliary tests
+%%----------------------------------------------------------------------
+
+%%----------------------------------------------------------------------
+%% Auxiliary
+%%----------------------------------------------------------------------
diff --git a/lib/tools/test/lcnt_SUITE_data/big_bang_40.lcnt b/lib/tools/test/lcnt_SUITE_data/big_bang_40.lcnt
new file mode 100644
index 0000000000..6087f6f37e
--- /dev/null
+++ b/lib/tools/test/lcnt_SUITE_data/big_bang_40.lcnt
Binary files differ
diff --git a/lib/tools/test/xref_SUITE.erl b/lib/tools/test/xref_SUITE.erl
index 0bbb3ba0f1..b4684140ca 100644
--- a/lib/tools/test/xref_SUITE.erl
+++ b/lib/tools/test/xref_SUITE.erl
@@ -1,19 +1,19 @@
%%
%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2000-2009. All Rights Reserved.
-%%
+%%
+%% Copyright Ericsson AB 2000-2010. All Rights Reserved.
+%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
%% compliance with the License. You should have received a copy of the
%% Erlang Public License along with this software. If not, it can be
%% retrieved online at http://www.erlang.org/.
-%%
+%%
%% Software distributed under the License is distributed on an "AS IS"
%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
%% the License for the specific language governing rights and limitations
%% under the License.
-%%
+%%
%% %CopyrightEnd%
-module(xref_SUITE).
@@ -1067,9 +1067,7 @@ read_expected(Version) ->
{POS13+3,{FF,{'$M_EXPR','$F_EXPR',-1}}},
{POS14+8,{{read,bi,0},{'$M_EXPR','$F_EXPR',1}}}],
- O1 = [{0,{FF,{modul,'$F_EXPR',179}}},
- {0,{FF,{read,'$F_EXPR',178}}},
- {20,{{read,lc,0},{ets,new,0}}},
+ O1 = [{20,{{read,lc,0},{ets,new,0}}},
{21,{{read,lc,0},{ets,tab2list,1}}},
{POS1+1,{FF,{erlang,spawn,1}}},
{POS1+1,{FF,{mod17,fun17,0}}},
@@ -1168,13 +1166,19 @@ read_expected(Version) ->
[{POS8+3, {FF,{erlang,apply,3}}},
{POS10+1, {FF,{erlang,apply,3}}},
{POS10+6, {FF,{erlang,apply,3}}}]
- ++ O1;
+ ++
+ [{0,{FF,{read,'$F_EXPR',178}}},
+ {0,{FF,{modul,'$F_EXPR',179}}}]
+ ++ O1;
_ ->
% [{POS15+2,{{read,bi,0},{foo,t,0}}},
% {POS15+3,{{read,bi,0},{bar,t,0}}},
% {POS15+6,{{read,bi,0},{read,local,0}}},
% {POS15+8,{{read,bi,0},{foo,t,0}}},
% {POS15+10,{{read,bi,0},{bar,t,0}}}] ++
+ [{16,{FF,{read,'$F_EXPR',178}}},
+ {17,{FF,{modul,'$F_EXPR',179}}}]
+ ++
O1
end,
@@ -1649,7 +1653,7 @@ abstract_modules(Conf) when is_list(Conf) ->
%% The compiler will no longer allow us to have a mismatch between
%% the module name and the output file, so we must use a trick.
?line {ok, param, BeamCode} = compile:file(File, [binary,debug_info]),
- ?line ok = file:write_file(filename:join(Dir, Beam), BeamCode),
+ ?line ok = file:write_file(Beam, BeamCode),
?line {ok, _} = xref:start(s),
?line {ok, param} = xref:add_module(s, MFile, {warnings,false}),