aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--erts/emulator/drivers/common/efile_drv.c98
-rw-r--r--lib/diameter/doc/src/diameter.xml2
-rw-r--r--lib/diameter/doc/src/diameter_compile.xml32
-rw-r--r--lib/diameter/doc/src/diameter_dict.xml5
-rw-r--r--lib/diameter/doc/src/diameter_make.xml38
-rw-r--r--lib/diameter/examples/code/redirect_cb.erl4
-rw-r--r--lib/diameter/src/base/diameter.erl2
-rw-r--r--lib/diameter/src/base/diameter_config.erl73
-rw-r--r--lib/diameter/src/base/diameter_lib.erl245
-rw-r--r--lib/diameter/src/base/diameter_peer_fsm.erl29
-rw-r--r--lib/diameter/src/base/diameter_watchdog.erl7
-rw-r--r--lib/diameter/test/Makefile5
-rw-r--r--lib/diameter/test/diameter_codec_test.erl6
-rw-r--r--lib/diameter/test/diameter_compiler_SUITE.erl51
-rw-r--r--lib/diameter/test/diameter_config_SUITE.erl261
-rw-r--r--lib/diameter/test/diameter_ct.erl2
-rw-r--r--lib/diameter/test/diameter_examples_SUITE.erl334
-rw-r--r--lib/diameter/test/modules.mk2
-rw-r--r--lib/hipe/cerl/erl_bif_types.erl4
-rw-r--r--lib/hipe/icode/Makefile2
-rw-r--r--lib/hipe/icode/hipe_icode.erl2
-rw-r--r--lib/hipe/icode/hipe_icode.hrl8
-rw-r--r--lib/hipe/icode/hipe_icode_callgraph.erl2
-rw-r--r--lib/hipe/icode/hipe_icode_ssa_struct_reuse.erl18
-rw-r--r--lib/hipe/regalloc/hipe_ls_regalloc.erl2
-rw-r--r--lib/hipe/rtl/Makefile2
-rw-r--r--lib/hipe/rtl/hipe_rtl_binary_match.erl166
-rw-r--r--lib/hipe/rtl/hipe_tagscheme.erl4
-rw-r--r--lib/tools/src/cover.erl11
-rw-r--r--lib/tools/test/cover_SUITE.erl26
30 files changed, 1048 insertions, 395 deletions
diff --git a/erts/emulator/drivers/common/efile_drv.c b/erts/emulator/drivers/common/efile_drv.c
index a2ef0db83c..6cc1295973 100644
--- a/erts/emulator/drivers/common/efile_drv.c
+++ b/erts/emulator/drivers/common/efile_drv.c
@@ -397,7 +397,6 @@ struct t_pwritev {
ErlDrvPort port;
ErlDrvPDL q_mtx;
size_t size;
- size_t free_size;
unsigned cnt;
unsigned n;
struct t_pbuf_spec specs[1];
@@ -462,7 +461,6 @@ struct t_data
ErlDrvPort port;
ErlDrvPDL q_mtx;
size_t size;
- size_t free_size;
size_t reply_size;
} writev;
struct t_pwritev pwritev;
@@ -1532,26 +1530,24 @@ static void invoke_writev(void *data) {
}
EF_FREE(iov);
- d->c.writev.free_size = size;
- d->c.writev.size -= size;
if (! d->result_ok) {
d->again = 0;
+ MUTEX_LOCK(d->c.writev.q_mtx);
+ driver_deq(d->c.writev.port, d->c.writev.size);
+ MUTEX_UNLOCK(d->c.writev.q_mtx);
} else {
if (! segment) {
d->again = 0;
}
+ d->c.writev.size -= size;
TRACE_F(("w%lu", (unsigned long)size));
-
+ MUTEX_LOCK(d->c.writev.q_mtx);
+ driver_deq(d->c.writev.port, size);
+ MUTEX_UNLOCK(d->c.writev.q_mtx);
}
- DTRACE_INVOKE_RETURN(FILE_WRITE);
-}
-static void free_writev(void *data) {
- struct t_data *d = data;
- MUTEX_LOCK(d->c.writev.q_mtx);
- driver_deq(d->c.writev.port, d->c.writev.size + d->c.writev.free_size);
- MUTEX_UNLOCK(d->c.writev.q_mtx);
- EF_FREE(d);
+
+ DTRACE_INVOKE_RETURN(FILE_WRITE);
}
static void invoke_pwd(void *data)
@@ -1602,7 +1598,7 @@ static void invoke_pwritev(void *data) {
struct t_pwritev *c = &d->c.pwritev;
size_t p;
int segment;
- size_t size, write_size;
+ size_t size, write_size, written;
DTRACE_INVOKE_SETUP(FILE_PWRITEV);
segment = d->again && c->size >= 2*FILE_SEGMENT_WRITE;
@@ -1622,23 +1618,19 @@ static void invoke_pwritev(void *data) {
if (iovlen < 0)
goto error; /* Port terminated */
- for (iovcnt = 0, c->free_size = 0;
- c->cnt < c->n && iovcnt < iovlen && c->free_size < size;
+ for (iovcnt = 0, written = 0;
+ c->cnt < c->n && iovcnt < iovlen && written < size;
c->cnt++) {
int chop;
write_size = c->specs[c->cnt].size;
if (iov[iovcnt].iov_len - p < write_size) {
- /* Mismatch between pos/size spec and what is queued */
- d->errInfo.posix_errno = EINVAL;
- d->result_ok = 0;
- d->again = 0;
- goto done;
+ goto error;
}
- chop = segment && c->free_size + write_size >= 2*FILE_SEGMENT_WRITE;
+ chop = segment && written + write_size >= 2*FILE_SEGMENT_WRITE;
if (chop) {
- ASSERT(c->free_size < FILE_SEGMENT_WRITE);
+ ASSERT(written < FILE_SEGMENT_WRITE);
write_size = FILE_SEGMENT_WRITE + FILE_SEGMENT_WRITE/2
- - c->free_size;
+ - written;
}
d->result_ok = efile_pwrite(&d->errInfo, (int) d->fd,
(char *)(iov[iovcnt].iov_base) + p,
@@ -1646,15 +1638,15 @@ static void invoke_pwritev(void *data) {
c->specs[c->cnt].offset);
if (! d->result_ok) {
d->again = 0;
- goto done;
+ goto deq_error;
}
- c->free_size += write_size;
+ written += write_size;
c->size -= write_size;
if (chop) {
c->specs[c->cnt].offset += write_size;
c->specs[c->cnt].size -= write_size;
/* Schedule out (d->again != 0) */
- goto done;
+ break;
}
/* Move forward in buffer */
p += write_size;
@@ -1676,25 +1668,28 @@ static void invoke_pwritev(void *data) {
d->errInfo.posix_errno = EINVAL;
d->result_ok = 0;
d->again = 0;
+ deq_error:
+ MUTEX_LOCK(d->c.writev.q_mtx);
+ driver_deq(d->c.pwritev.port, c->size);
+ MUTEX_UNLOCK(d->c.writev.q_mtx);
+
+ goto done;
} else {
- ASSERT(c->free_size == size);
+ ASSERT(written == size);
d->again = 0;
}
- }
+ } else
+ ASSERT(written == FILE_SEGMENT_WRITE);
+
+ MUTEX_LOCK(d->c.writev.q_mtx);
+ driver_deq(d->c.pwritev.port, size);
+ MUTEX_UNLOCK(d->c.writev.q_mtx);
done:
EF_FREE(iov); /* Free our copy of the vector, nothing to restore */
+
DTRACE_INVOKE_RETURN(FILE_PWRITEV);
}
-static void free_pwritev(void *data) {
- struct t_data *d = data;
-
- MUTEX_LOCK(d->c.writev.q_mtx);
- driver_deq(d->c.pwritev.port, d->c.pwritev.free_size + d->c.pwritev.size);
- MUTEX_UNLOCK(d->c.writev.q_mtx);
- EF_FREE(d);
-}
-
static void invoke_flstat(void *data)
{
struct t_data *d = (struct t_data *) data;
@@ -2008,21 +2003,8 @@ static void try_free_read_bin(file_descriptor *desc) {
static int try_again(file_descriptor *desc, struct t_data *d) {
- if (! d->again) {
+ if (! d->again)
return 0;
- }
- switch (d->command) {
- case FILE_WRITE:
- MUTEX_LOCK(d->c.writev.q_mtx);
- driver_deq(d->c.writev.port, d->c.writev.free_size);
- MUTEX_UNLOCK(d->c.writev.q_mtx);
- break;
- case FILE_PWRITEV:
- MUTEX_LOCK(d->c.writev.q_mtx);
- driver_deq(d->c.pwritev.port, d->c.pwritev.free_size);
- MUTEX_UNLOCK(d->c.writev.q_mtx);
- break;
- }
if (desc->timer_state != timer_idle) {
driver_cancel_timer(desc->port);
}
@@ -2078,10 +2060,9 @@ static struct t_data *async_write(file_descriptor *desc, int *errp,
}
#endif
d->reply = reply;
- d->c.writev.free_size = 0;
d->c.writev.reply_size = reply_size;
d->invoke = invoke_writev;
- d->free = free_writev;
+ d->free = free_data;
d->level = 1;
cq_enq(desc, d);
desc->write_buffered = 0;
@@ -2394,7 +2375,7 @@ file_async_ready(ErlDrvData e, ErlDrvThreadData data)
desc->write_errInfo = d->errInfo;
}
}
- free_writev(data);
+ free_data(data);
break;
case FILE_LSEEK:
if (d->reply) {
@@ -2524,7 +2505,7 @@ file_async_ready(ErlDrvData e, ErlDrvThreadData data)
} else {
reply_Uint(desc, d->c.pwritev.n);
}
- free_pwritev(data);
+ free_data(data);
break;
case FILE_PREADV:
if (!d->result_ok) {
@@ -2581,7 +2562,7 @@ file_async_ready(ErlDrvData e, ErlDrvThreadData data)
}
DTRACE6(efile_drv_return, sched_i1, sched_i2, sched_utag,
command, result_ok, posix_errno);
- if (desc->write_buffered != 0 && desc->timer_state == timer_idle) {
+ if (desc->write_buffered != 0 && desc->timer_state == timer_idle ) {
desc->timer_state = timer_write;
driver_set_timer(desc->port, desc->write_delay);
}
@@ -3651,7 +3632,6 @@ file_outputv(ErlDrvData e, ErlIOVec *ev) {
#ifdef USE_VM_PROBES
dt_i3 = d->c.pwritev.size;
#endif
- d->c.pwritev.free_size = 0;
if (j == 0) {
/* Trivial case - nothing to write */
EF_FREE(d);
@@ -3675,7 +3655,7 @@ file_outputv(ErlDrvData e, ErlIOVec *ev) {
MUTEX_UNLOCK(desc->q_mtx);
/* Execute the command */
d->invoke = invoke_pwritev;
- d->free = free_pwritev;
+ d->free = free_data;
d->level = 1;
cq_enq(desc, d);
}
diff --git a/lib/diameter/doc/src/diameter.xml b/lib/diameter/doc/src/diameter.xml
index eadc42536f..7ea93d480b 100644
--- a/lib/diameter/doc/src/diameter.xml
+++ b/lib/diameter/doc/src/diameter.xml
@@ -1162,7 +1162,7 @@ transport.</p>
<marker id="transport_config"/>
<tag><c>{transport_config, term()}</c></tag>
-<tag><c>{transport_config, term(), &dict_Unsigned32;}</c></tag>
+<tag><c>{transport_config, term(), &dict_Unsigned32; | infinity}</c></tag>
<item>
<p>
A term passed as the third argument to the &transport_start; function of
diff --git a/lib/diameter/doc/src/diameter_compile.xml b/lib/diameter/doc/src/diameter_compile.xml
index 0bd7ad1789..fc81e4efed 100644
--- a/lib/diameter/doc/src/diameter_compile.xml
+++ b/lib/diameter/doc/src/diameter_compile.xml
@@ -11,7 +11,7 @@
<comref>
<header>
<copyright>
-<year>2011</year><year>2012</year>
+<year>2011</year><year>2013</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -59,6 +59,7 @@ The module &man_make; provides an alternate compilation interface.</p>
Compile a single dictionary file to Erlang source.
Valid options are as follows.</p>
+<taglist>
<tag><![CDATA[-i <dir>]]></tag>
<item>
<p>
@@ -71,7 +72,6 @@ dependency, not an erl/hrl dependency.</p>
Multiple <c>-i</c> options can be specified.</p>
</item>
-<taglist>
<tag><![CDATA[-o <dir>]]></tag>
<item>
<p>
@@ -90,18 +90,30 @@ Supress erl and hrl generation, respectively.</p>
<tag><![CDATA[--prefix <prefix>]]></tag>
<item>
<p>
-Set <c>&dict_name;</c> or <c>&dict_prefix;</c> to the specified
-string.
-Overrides any setting in the file itself.</p>
+Transform the input dictionary before compilation, setting
+<c>&dict_name;</c> or <c>&dict_prefix;</c> to the specified
+string.</p>
</item>
-<tag><![CDATA[--inherits <dict>]]></tag>
+<tag><![CDATA[--inherits <arg>]]></tag>
<item>
<p>
-Append &dict_inherits; of the specified module.
-Specifying <c>"-"</c> has the effect of discarding clearing any
-previous inherits, both in the dictionary file and on the options
-list.</p>
+Transform the input dictionary before compilation, appending
+<c>&dict_inherits;</c> of the specified string.</p>
+
+<p>
+Two forms of <c>--inherits</c> have special meaning:</p>
+
+<pre>
+--inherits -
+--inherits Prev/Mod
+</pre>
+
+<p>
+The first has the effect of clearing any previous inherits, the second
+of replacing a previous inherits of <c>Prev</c> to one of <c>Mod</c>.
+This allows the semantics of the input dictionary to be changed without
+modifying the file itself.</p>
<p>
Multiple <c>--inherits</c> options can be specified.</p>
diff --git a/lib/diameter/doc/src/diameter_dict.xml b/lib/diameter/doc/src/diameter_dict.xml
index 1034781ff2..419dc143af 100644
--- a/lib/diameter/doc/src/diameter_dict.xml
+++ b/lib/diameter/doc/src/diameter_dict.xml
@@ -263,15 +263,14 @@ dictionary's definitions but the former makes for easier reuse.</p>
<p>
All dictionaries should typically inherit &the_rfc; AVPs from
-<c>diameter_gen_base_rfc3588</c>.</p>
+<c>diameter_gen_base_rfc6733</c>.</p>
<p>
Example:</p>
<pre>
-@inherits diameter_gen_base_rfc3588
+@inherits diameter_gen_base_rfc6733
</pre>
-
</item>
<marker id="avp_types"/>
diff --git a/lib/diameter/doc/src/diameter_make.xml b/lib/diameter/doc/src/diameter_make.xml
index da6124310e..ec71251be1 100644
--- a/lib/diameter/doc/src/diameter_make.xml
+++ b/lib/diameter/doc/src/diameter_make.xml
@@ -14,6 +14,7 @@
<header>
<copyright>
<year>2012</year>
+<year>2013</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -73,7 +74,7 @@ Compile a single dictionary file to Erlang source.
<taglist>
-<tag><c>{include, Dir::string()}</c></tag>
+<tag><c>{include, string()}</c></tag>
<item>
<p>
Prepend the specified directory to the code path.
@@ -85,7 +86,7 @@ dependency, not an erl/hrl dependency.</p>
Multiple <c>include</c> options can be specified.</p>
</item>
-<tag><c>{outdir, Dir::string()}</c></tag>
+<tag><c>{outdir, string()}</c></tag>
<item>
<p>
Write generated source to the specified directory.
@@ -95,18 +96,30 @@ Defaults to the current working directory.</p>
<tag><c>{name|prefix, string()}</c></tag>
<item>
<p>
-Set <c>&dict_name;</c> or <c>&dict_prefix;</c> to the specified
-string.
-Overrides any setting in the file itself.</p>
+Transform the input dictionary before compilation, setting
+<c>&dict_name;</c> or <c>&dict_prefix;</c> to the specified
+string.</p>
</item>
-<tag><c>{inherits, Mod::string()}</c></tag>
+<tag><c>{inherits, string()}</c></tag>
<item>
<p>
-Append &dict_inherits; of the specified module.
-Specifying <c>"-"</c> has the effect of discarding clearing any
-previous inherits, both in the dictionary file and on the options
-list.</p>
+Transform the input dictionary before compilation, appending
+<c>&dict_inherits;</c> of the specified string.</p>
+
+<p>
+Two forms of <c>@inherits</c> have special meaning:</p>
+
+<pre>
+{inherits, "-"}
+{inherits, "Prev/Mod"}
+</pre>
+
+<p>
+The first has the effect of clearing any previous inherits, the second
+of replacing a previous inherits of <c>Prev</c> to one of <c>Mod</c>.
+This allows the semantics of the input dictionary to be changed without
+modifying the file itself.</p>
<p>
Multiple <c>inherits</c> options can be specified.</p>
@@ -126,8 +139,9 @@ Multiple <c>inherits</c> options can be specified.</p>
<p>
All options are string-valued.
-In particular, it is not currently possible to
-an &dict_inherits; module as an atom() or a path as a &filename;</p>
+In particular, it is not currently possible to specify
+an &dict_inherits; module as an atom(), or a path as an arbitrary
+&filename;</p>
</section>
diff --git a/lib/diameter/examples/code/redirect_cb.erl b/lib/diameter/examples/code/redirect_cb.erl
index da31add70d..69836774a1 100644
--- a/lib/diameter/examples/code/redirect_cb.erl
+++ b/lib/diameter/examples/code/redirect_cb.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2010-2012. All Rights Reserved.
+%% Copyright Ericsson AB 2010-2013. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -20,7 +20,7 @@
-module(redirect_cb).
-include_lib("diameter/include/diameter.hrl").
--include_lib("diameter/src/app/diameter_gen_base_rfc3588.hrl").
+-include_lib("diameter/include/diameter_gen_base_rfc3588.hrl").
%% diameter callbacks
-export([peer_up/3,
diff --git a/lib/diameter/src/base/diameter.erl b/lib/diameter/src/base/diameter.erl
index 490a1fa8aa..57730cad61 100644
--- a/lib/diameter/src/base/diameter.erl
+++ b/lib/diameter/src/base/diameter.erl
@@ -335,7 +335,7 @@ call(SvcName, App, Message) ->
-type transport_opt()
:: {transport_module, atom()}
| {transport_config, any()}
- | {transport_config, any(), non_neg_integer() | infinity}
+ | {transport_config, any(), 'Unsigned32'() | infinity}
| {applications, [app_alias()]}
| {capabilities, [capability()]}
| {capabilities_cb, evaluable()}
diff --git a/lib/diameter/src/base/diameter_config.erl b/lib/diameter/src/base/diameter_config.erl
index 3a2e0d2140..1282930145 100644
--- a/lib/diameter/src/base/diameter_config.erl
+++ b/lib/diameter/src/base/diameter_config.erl
@@ -103,6 +103,10 @@
%% Time to lay low before restarting a dead service.
-define(RESTART_SLEEP, 2000).
+%% Test for a valid timeout.
+-define(IS_UINT32(N),
+ is_integer(N) andalso 0 =< N andalso 0 == N bsr 32).
+
%% A minimal diameter_caps for checking for valid capabilities values.
-define(EXAMPLE_CAPS,
#diameter_caps{origin_host = "TheHost",
@@ -490,13 +494,11 @@ stop(SvcName) ->
%% has many.
add(SvcName, Type, Opts) ->
- %% Ensure usable capabilities. diameter_service:merge_service/2
- %% depends on this.
- lists:foreach(fun(Os) ->
- is_list(Os) orelse ?THROW({capabilities, Os}),
- ok = encode_CER(Os)
- end,
- [Os || {capabilities, Os} <- Opts, is_list(Os)]),
+ %% Ensure acceptable transport options. This won't catch all
+ %% possible errors (faulty callbacks for example) but it catches
+ %% many. diameter_service:merge_service/2 depends on usable
+ %% capabilities for example.
+ ok = transport_opts(Opts),
Ref = make_ref(),
T = {Ref, Type, Opts},
@@ -514,6 +516,61 @@ add(SvcName, Type, Opts) ->
No
end.
+transport_opts(Opts) ->
+ lists:foreach(fun(T) -> opt(T) orelse ?THROW({invalid, T}) end, Opts).
+
+opt({transport_module, M}) ->
+ is_atom(M);
+
+opt({transport_config, _, Tmo}) ->
+ ?IS_UINT32(Tmo) orelse Tmo == infinity;
+
+opt({applications, As}) ->
+ is_list(As);
+
+opt({capabilities, Os}) ->
+ is_list(Os) andalso ok == encode_CER(Os);
+
+opt({capx_timeout, Tmo}) ->
+ ?IS_UINT32(Tmo);
+
+opt({length_errors, T}) ->
+ lists:member(T, [exit, handle, discard]);
+
+opt({reconnect_timer, Tmo}) ->
+ ?IS_UINT32(Tmo);
+
+opt({watchdog_timer, {M,F,A}})
+ when is_atom(M), is_atom(F), is_list(A) ->
+ true;
+opt({watchdog_timer, Tmo}) ->
+ ?IS_UINT32(Tmo);
+
+opt({watchdog_config, L}) ->
+ is_list(L) andalso lists:all(fun wdopt/1, L);
+
+%% Options that we can't validate.
+opt({K, _})
+ when K == transport_config;
+ K == capabilities_cb;
+ K == disconnect_cb;
+ K == private ->
+ true;
+
+%% Anything else, which is ignored by us. This makes options sensitive
+%% to spelling mistakes but arbitrary options are passed by some users
+%% as a way to identify transports. (That is, can't just do away with
+%% it.)
+opt(_) ->
+ true.
+
+wdopt({K,N}) ->
+ (K == okay orelse K == suspect) andalso is_integer(N) andalso 0 =< N;
+wdopt(_) ->
+ false.
+
+%% start_transport/2
+
start_transport(SvcName, T) ->
case diameter_service:start_transport(SvcName, T) of
{ok, _Pid} ->
@@ -636,7 +693,7 @@ opt(K, _) ->
?THROW({value, K}).
sequence({H,N} = T)
- when 0 =< N, N =< 32, 0 =< H, 0 == H bsr N ->
+ when 0 =< N, N =< 32, 0 =< H, 0 == H bsr (32-N) ->
T;
sequence(_) ->
diff --git a/lib/diameter/src/base/diameter_lib.erl b/lib/diameter/src/base/diameter_lib.erl
index 362d593b24..44d81e2778 100644
--- a/lib/diameter/src/base/diameter_lib.erl
+++ b/lib/diameter/src/base/diameter_lib.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2010-2011. All Rights Reserved.
+%% Copyright Ericsson AB 2010-2013. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -19,77 +19,86 @@
-module(diameter_lib).
--export([report/2, info_report/2,
+-export([info_report/2,
error_report/2,
warning_report/2,
now_diff/1,
time/1,
eval/1,
- ip4address/1,
- ip6address/1,
ipaddr/1,
spawn_opts/2,
wait/1,
fold_tuple/3,
log/4]).
--include("diameter_internal.hrl").
-
%% ---------------------------------------------------------------------------
-%% # info_report(Reason, MFA)
-%%
-%% Input: Reason = Arbitrary term indicating the reason for the report.
-%% MFA = {Module, Function, Args} to report.
-%%
-%% Output: true
+%% # info_report/2
%% ---------------------------------------------------------------------------
-report(Reason, MFA) ->
- info_report(Reason, MFA).
+-spec info_report(Reason :: term(), T :: term())
+ -> true.
-info_report(Reason, MFA) ->
- report(fun error_logger:info_report/1, Reason, MFA),
+info_report(Reason, T) ->
+ report(fun error_logger:info_report/1, Reason, T),
true.
-%%% ---------------------------------------------------------------------------
-%%% # error_report(Reason, MFA)
-%%% # warning_report(Reason, MFA)
-%%%
-%%% Output: false
-%%% ---------------------------------------------------------------------------
+%% ---------------------------------------------------------------------------
+%% # error_report/2
+%% # warning_report/2
+%% ---------------------------------------------------------------------------
+
+-spec error_report(Reason :: term(), T :: term())
+ -> false.
+
+error_report(Reason, T) ->
+ report(fun error_logger:error_report/1, Reason, T).
-error_report(Reason, MFA) ->
- report(fun error_logger:error_report/1, Reason, MFA).
+-spec warning_report(Reason :: term(), T :: term())
+ -> false.
-warning_report(Reason, MFA) ->
- report(fun error_logger:warning_report/1, Reason, MFA).
+warning_report(Reason, T) ->
+ report(fun error_logger:warning_report/1, Reason, T).
-report(Fun, Reason, MFA) ->
- Fun([{why, Reason}, {who, self()}, {what, MFA}]),
+report(Fun, Reason, T) ->
+ Fun([{why, Reason}, {who, self()}, {what, T}]),
false.
-%%% ---------------------------------------------------------------------------
-%%% # now_diff(Time)
-%%%
-%%% Description: Return timer:now_diff(now(), Time) as an {H, M, S, MicroS}
-%%% tuple instead of as integer microseconds.
-%%% ---------------------------------------------------------------------------
+%% ---------------------------------------------------------------------------
+%% # now_diff/1
+%% ---------------------------------------------------------------------------
+
+-spec now_diff(NowT)
+ -> {Hours, Mins, Secs, MicroSecs}
+ when NowT :: {non_neg_integer(), 0..999999, 0..999999},
+ Hours :: non_neg_integer(),
+ Mins :: 0..59,
+ Secs :: 0..59,
+ MicroSecs :: 0..999999.
+
+%% Return timer:now_diff(now(), NowT) as an {H, M, S, MicroS} tuple
+%% instead of as integer microseconds.
now_diff({_,_,_} = Time) ->
- time(timer:now_diff(erlang:now(), Time)).
-
-%%% ---------------------------------------------------------------------------
-%%% # time(Time)
-%%%
-%%% Input: Time = {MegaSec, Sec, MicroSec}
-%%% | MicroSec
-%%%
-%%% Output: {H, M, S, MicroS}
-%%% ---------------------------------------------------------------------------
-
-time({_,_,_} = Time) -> %% time of day
+ time(timer:now_diff(now(), Time)).
+
+%% ---------------------------------------------------------------------------
+%% # time/1
+%%
+%% Return an elapsed time as an {H, M, S, MicroS} tuple.
+%% ---------------------------------------------------------------------------
+
+-spec time(NowT | Diff)
+ -> {Hours, Mins, Secs, MicroSecs}
+ when NowT :: {non_neg_integer(), 0..999999, 0..999999},
+ Diff :: non_neg_integer(),
+ Hours :: non_neg_integer(),
+ Mins :: 0..59,
+ Secs :: 0..59,
+ MicroSecs :: 0..999999.
+
+time({_,_,_} = NowT) -> %% time of day
%% 24 hours = 24*60*60*1000000 = 86400000000 microsec
- time(timer:now_diff(Time, {0,0,0}) rem 86400000000);
+ time(timer:now_diff(NowT, {0,0,0}) rem 86400000000);
time(Micro) -> %% elapsed time
Seconds = Micro div 1000000,
@@ -98,9 +107,21 @@ time(Micro) -> %% elapsed time
S = Seconds rem 60,
{H, M, S, Micro rem 1000000}.
-%%% ---------------------------------------------------------------------------
-%%% # eval(Func)
-%%% ---------------------------------------------------------------------------
+%% ---------------------------------------------------------------------------
+%% # eval/1
+%%
+%% Evaluate a function in various forms.
+%% ---------------------------------------------------------------------------
+
+-type f() :: {module(), atom(), list()}
+ | nonempty_maybe_improper_list(fun(), list())
+ | fun().
+
+-spec eval(Fun)
+ -> term()
+ when Fun :: f()
+ | {f()}
+ | nonempty_maybe_improper_list(f(), list()).
eval({M,F,A}) ->
apply(M,F,A);
@@ -120,66 +141,15 @@ eval({F}) ->
eval(F) ->
F().
-%%% ---------------------------------------------------------------------------
-%%% # ip4address(Addr)
-%%%
-%%% Input: string() (eg. "10.0.0.1")
-%%% | list of integer()
-%%% | tuple of integer()
-%%%
-%%% Output: {_,_,_,_} of integer
-%%%
-%%% Exceptions: error: {invalid_address, Addr, erlang:get_stacktrace()}
-%%% ---------------------------------------------------------------------------
-
-ip4address([_,_,_,_] = Addr) -> %% Length 4 string can't be an address.
- ipaddr(list_to_tuple(Addr));
-
-%% Be brutal.
-ip4address(Addr) ->
- try
- {_,_,_,_} = ipaddr(Addr)
- catch
- error: _ ->
- erlang:error({invalid_address, Addr, ?STACK})
- end.
-
-%%% ---------------------------------------------------------------------------
-%%% # ip6address(Addr)
-%%%
-%%% Input: string() (eg. "1080::8:800:200C:417A")
-%%% | list of integer()
-%%% | tuple of integer()
-%%%
-%%% Output: {_,_,_,_,_,_,_,_} of integer
-%%%
-%%% Exceptions: error: {invalid_address, Addr, erlang:get_stacktrace()}
-%%% ---------------------------------------------------------------------------
-
-ip6address([_,_,_,_,_,_,_,_] = Addr) -> %% Length 8 string can't be an address.
- ipaddr(list_to_tuple(Addr));
-
-%% Be brutal.
-ip6address(Addr) ->
- try
- {_,_,_,_,_,_,_,_} = ipaddr(Addr)
- catch
- error: _ ->
- erlang:error({invalid_address, Addr, ?STACK})
- end.
-
-%%% ---------------------------------------------------------------------------
-%%% # ipaddr(Addr)
-%%%
-%%% Input: string() | tuple of integer()
-%%%
-%%% Output: {_,_,_,_} | {_,_,_,_,_,_,_,_}
-%%%
-%%% Exceptions: error: {invalid_address, erlang:get_stacktrace()}
-%%% ---------------------------------------------------------------------------
+%% ---------------------------------------------------------------------------
+%% # ipaddr/1
+%%
+%% Parse an IP address.
+%% ---------------------------------------------------------------------------
--spec ipaddr(string() | tuple())
- -> inet:ip_address().
+-spec ipaddr([byte()] | tuple())
+ -> inet:ip_address()
+ | none().
%% Don't convert lists of integers since a length 8 list like
%% [$1,$0,$.,$0,$.,$0,$.,$1] is ambiguous: is it "10.0.0.1" or
@@ -193,7 +163,7 @@ ipaddr(Addr) ->
ip(Addr)
catch
error: _ ->
- erlang:error({invalid_address, ?STACK})
+ erlang:error({invalid_address, erlang:get_stacktrace()})
end.
%% Already a tuple: ensure non-negative integers of the right size.
@@ -210,11 +180,12 @@ ip(Addr) ->
{ok, A} = inet_parse:address(Addr), %% documented in inet(3)
A.
-%%% ---------------------------------------------------------------------------
-%%% # spawn_opts(Type, Opts)
-%%% ---------------------------------------------------------------------------
+%% ---------------------------------------------------------------------------
+%% # spawn_opts/2
+%% ---------------------------------------------------------------------------
-%% TODO: config variables.
+-spec spawn_opts(server|worker, list())
+ -> list().
spawn_opts(server, Opts) ->
opts(75000, Opts);
@@ -224,24 +195,32 @@ spawn_opts(worker, Opts) ->
opts(HeapSize, Opts) ->
[{min_heap_size, HeapSize} | lists:keydelete(min_heap_size, 1, Opts)].
-%%% ---------------------------------------------------------------------------
-%%% # wait(MRefs)
-%%% ---------------------------------------------------------------------------
+%% ---------------------------------------------------------------------------
+%% # wait/1
+%% ---------------------------------------------------------------------------
+
+-spec wait([pid()])
+ -> ok.
wait(L) ->
- w([erlang:monitor(process, P) || P <- L]).
+ down([erlang:monitor(process, P) || P <- L]).
-w([]) ->
+down([]) ->
ok;
-w(L) ->
- receive
- {'DOWN', MRef, process, _, _} ->
- w(lists:delete(MRef, L))
- end.
+down([MRef|T]) ->
+ receive {'DOWN', MRef, process, _, _} -> ok end,
+ down(T).
-%%% ---------------------------------------------------------------------------
-%%% # fold_tuple(N, T0, T)
-%%% ---------------------------------------------------------------------------
+%% ---------------------------------------------------------------------------
+%% # fold_tuple/3
+%% ---------------------------------------------------------------------------
+
+-spec fold_tuple(N, T0, T)
+ -> tuple()
+ when N :: pos_integer(),
+ T0 :: tuple(),
+ T :: tuple()
+ | undefined.
%% Replace fields in T0 by those of T starting at index N, unless the
%% new value is 'undefined'.
@@ -262,11 +241,11 @@ ft(undefined, {_, T}) ->
ft(Value, {Idx, T}) ->
setelement(Idx, T, Value).
-%%% ----------------------------------------------------------
-%%% # log(Slogan, Mod, Line, Details)
-%%%
-%%% Called to have something to trace on for happenings of interest.
-%%% ----------------------------------------------------------
+%% ---------------------------------------------------------------------------
+%% # log/4
+%%
+%% Called to have something to trace on for happenings of interest.
+%% ---------------------------------------------------------------------------
-log(_, _, _, _) ->
+log(_Slogan, _Mod, _Line, _Details) ->
ok.
diff --git a/lib/diameter/src/base/diameter_peer_fsm.erl b/lib/diameter/src/base/diameter_peer_fsm.erl
index 66342f7b62..bee3e507fd 100644
--- a/lib/diameter/src/base/diameter_peer_fsm.erl
+++ b/lib/diameter/src/base/diameter_peer_fsm.erl
@@ -198,6 +198,7 @@ i({Ack, WPid, {M, Ref} = T, Opts, {Mask,
OnLengthErr = proplists:get_value(length_errors, Opts, exit),
lists:member(OnLengthErr, [exit, handle, discard])
orelse ?ERROR({invalid, {length_errors, OnLengthErr}}),
+ %% Error checking is for configuration added in old code.
{TPid, Addrs} = start_transport(T, Rest, Svc),
@@ -212,9 +213,6 @@ i({Ack, WPid, {M, Ref} = T, Opts, {Mask,
%% transports on the same service can use different local addresses.
%% The local addresses are put into Host-IP-Address avps here when
%% sending capabilities exchange messages.
-%%
-%% Invalid transport config may cause us to crash but note that the
-%% watchdog start (start/2) succeeds regardless.
%% Wait for the caller to have a monitor to avoid a race with our
%% death. (Since the exit reason is used in diameter_service.)
@@ -846,8 +844,12 @@ a('DPR', #diameter_caps{origin_host = {Host, _},
%% recv_CER/2
recv_CER(CER, #state{service = Svc, dictionary = Dict}) ->
- {ok, T} = diameter_capx:recv_CER(CER, Svc, Dict),
- T.
+ case diameter_capx:recv_CER(CER, Svc, Dict) of
+ {ok, T} ->
+ T;
+ {error, Reason} ->
+ close({'CER', CER, Svc, Dict, Reason})
+ end.
%% handle_CEA/1
@@ -907,8 +909,12 @@ recv_CEA(#diameter_packet{header = #diameter_header{version
errors = []},
#state{service = Svc,
dictionary = Dict}) ->
- {ok, T} = diameter_capx:recv_CEA(CEA, Svc, Dict),
- T;
+ case diameter_capx:recv_CEA(CEA, Svc, Dict) of
+ {ok, T} ->
+ T;
+ {error, Reason} ->
+ close({'CEA', CEA, Svc, Dict, Reason})
+ end;
recv_CEA(Pkt, S) ->
close({'CEA', caps(S), Pkt}).
@@ -987,8 +993,17 @@ capz(#diameter_caps{} = L, #diameter_caps{} = R) ->
%% close/1
close(Reason) ->
+ report(Reason),
throw({?MODULE, close, Reason}).
+%% Could possibly log more here.
+report({M, _, _, _, _} = T)
+ when M == 'CER';
+ M == 'CEA' ->
+ diameter_lib:error_report(failure, T);
+report(_) ->
+ ok.
+
%% dwa/1
dwa(#diameter_caps{origin_host = OH,
diff --git a/lib/diameter/src/base/diameter_watchdog.erl b/lib/diameter/src/base/diameter_watchdog.erl
index 82ca603cf3..41c493ff20 100644
--- a/lib/diameter/src/base/diameter_watchdog.erl
+++ b/lib/diameter/src/base/diameter_watchdog.erl
@@ -158,7 +158,7 @@ wait(Ref, Pid) ->
config(Opts) ->
Config = proplists:get_value(watchdog_config, Opts, []),
is_list(Config) orelse config_error({watchdog_config, Config}),
- lists:foldl(fun config/2, #config{}, Config).
+ lists:foldl(fun config/2, #config{}, Config). %% ^ added in old code
config({suspect, N}, Rec)
when ?IS_NATURAL(N) ->
@@ -168,7 +168,7 @@ config({okay, N}, Rec)
when ?IS_NATURAL(N) ->
Rec#config{okay = N};
-config(T, _) ->
+config(T, _) -> %% added in old code
config_error(T).
%% start/5
@@ -225,7 +225,8 @@ dict0(_, _, Acc) ->
Acc.
config_error(T) ->
- ?ERROR({configuration_error, T}).
+ diameter_lib:error_report(configuration_error, T),
+ exit({shutdown, {configuration_error, T}}).
%% handle_call/3
diff --git a/lib/diameter/test/Makefile b/lib/diameter/test/Makefile
index 061f0bcbef..9719c67b32 100644
--- a/lib/diameter/test/Makefile
+++ b/lib/diameter/test/Makefile
@@ -93,6 +93,11 @@ info:
@$(call list,HRL_FILES)
@echo
@$(call list,SUITES)
+ @echo
+ @echo erl = $(shell which erl)
+ @erl -noinput \
+ -eval 'io:format("diameter = ~s~n", [code:lib_dir(diameter)])' \
+ -s init stop
@echo ========================================
help:
diff --git a/lib/diameter/test/diameter_codec_test.erl b/lib/diameter/test/diameter_codec_test.erl
index dc8cbffc83..0baac59c1a 100644
--- a/lib/diameter/test/diameter_codec_test.erl
+++ b/lib/diameter/test/diameter_codec_test.erl
@@ -65,7 +65,7 @@ lib(N, {_,_} = T) ->
lib(IP, B) ->
LA = tuple_to_list(IP),
{SA,Fun} = ip(LA),
- [] = run([[fun lib/4, IP, B, Fun, A] || A <- [IP, LA, SA]]).
+ [] = run([[fun lib/4, IP, B, Fun, A] || A <- [IP, SA]]).
lib(IP, B, Fun, A) ->
try Fun(A) of
@@ -78,10 +78,10 @@ lib(IP, B, Fun, A) ->
ip([_,_,_,_] = A) ->
[$.|S] = lists:append(["." ++ integer_to_list(N) || N <- A]),
- {S, fun diameter_lib:ip4address/1};
+ {S, fun diameter_lib:ipaddr/1};
ip([_,_,_,_,_,_,_,_] = A) ->
[$:|S] = lists:flatten([":" ++ io_lib:format("~.16B", [N]) || N <- A]),
- {S, fun diameter_lib:ip6address/1}.
+ {S, fun diameter_lib:ipaddr/1}.
%% ------------------------------------------------------------------------
%% base/1
diff --git a/lib/diameter/test/diameter_compiler_SUITE.erl b/lib/diameter/test/diameter_compiler_SUITE.erl
index 79bf9d32db..81722c8dca 100644
--- a/lib/diameter/test/diameter_compiler_SUITE.erl
+++ b/lib/diameter/test/diameter_compiler_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2010-2012. All Rights Reserved.
+%% Copyright Ericsson AB 2010-2013. 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
@@ -31,8 +31,7 @@
%% testcases
-export([format/1, format/2,
replace/1, replace/2,
- generate/1, generate/4,
- examples/1]).
+ generate/1, generate/4]).
-export([dict/0]). %% fake dictionary module
@@ -328,14 +327,6 @@
"@codecs mymod "
"Origin-Host Origin-Realm\n&"}]}]).
-%% Standard dictionaries in examples/dict.
--define(EXAMPLES, [rfc4004_mip,
- rfc4005_nas,
- rfc4006_cc,
- rfc4072_eap,
- rfc4590_digest,
- rfc4740_sip]).
-
%% ===========================================================================
suite() ->
@@ -344,8 +335,7 @@ suite() ->
all() ->
[format,
replace,
- generate,
- examples].
+ generate].
%% Error handling testcases will make an erroneous dictionary out of
%% the base dictionary and check that the expected error results.
@@ -429,41 +419,6 @@ generate(Mods, Bin, N, Mode) ->
andalso ({ok, _} = compile:file(File ++ ".erl", [return_errors])).
%% ===========================================================================
-%% examples/1
-%%
-%% Compile dictionaries extracted from various standards.
-
-examples(_Config) ->
- Dir = filename:join([code:lib_dir(diameter, examples), "dict"]),
- [D || D <- ?EXAMPLES, _ <- [examples(?S(D), Dir)]].
-
-examples(Dict, Dir) ->
- {Name, Pre} = make_name(Dict),
- ok = diameter_make:codec(filename:join([Dir, Dict ++ ".dia"]),
- [{name, Name},
- {prefix, Pre},
- inherits("rfc3588_base")
- | opts(Dict)]),
- {ok, _, _} = compile:file(Name ++ ".erl", [return]).
-
-opts(M)
- when M == "rfc4006_cc";
- M == "rfc4072_eap" ->
- [inherits("rfc4005_nas")];
-opts("rfc4740_sip") ->
- [inherits("rfc4590_digest")];
-opts(_) ->
- [].
-
-inherits(File) ->
- {Name, _} = make_name(File),
- {inherits, File ++ "/" ++ Name}.
-
-make_name(File) ->
- {R, [$_|N]} = lists:splitwith(fun(C) -> C /= $_ end, File),
- {string:join(["diameter_gen", N, R], "_"), "diameter_" ++ N}.
-
-%% ===========================================================================
modify(Bin, Mods) ->
lists:foldl(fun re/2, Bin, Mods).
diff --git a/lib/diameter/test/diameter_config_SUITE.erl b/lib/diameter/test/diameter_config_SUITE.erl
new file mode 100644
index 0000000000..47def9c8c9
--- /dev/null
+++ b/lib/diameter/test/diameter_config_SUITE.erl
@@ -0,0 +1,261 @@
+%% coding: utf-8
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2013. 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%
+%%
+
+%%
+%% Test service and transport config. In particular, of the detection
+%% of config errors.
+%%
+
+-module(diameter_config_SUITE).
+
+-export([suite/0,
+ all/0]).
+
+%% testcases
+-export([start/1,
+ start_service/1,
+ add_transport/1,
+ stop/1]).
+
+-define(util, diameter_util).
+
+%% Lists of {Key, GoodConfigList, BadConfigList} with which to
+%% configure.
+
+-define(SERVICE_CONFIG,
+ [{application,
+ [[[{dictionary, diameter_gen_base_rfc6733},
+ {module, ?MODULE}]]
+ | [[[{dictionary, D},
+ {module, M},
+ {alias, A},
+ {state, S},
+ {answer_errors, AE},
+ {request_errors, RE},
+ {call_mutates_state, C}]]
+ || D <- [diameter_gen_base_rfc3588, diameter_gen_base_rfc6733],
+ M <- [?MODULE, [?MODULE, now()]],
+ A <- [0, common, make_ref()],
+ S <- [[], make_ref()],
+ AE <- [report, callback, discard],
+ RE <- [answer_3xxx, answer, callback],
+ C <- [true, false]]],
+ [[x],
+ [[]],
+ [[{dictionary, diameter_gen_base_rfc3588}]],
+ [[{module, ?MODULE}]]
+ | [[[{dictionary, diameter_gen_base_rfc6733},
+ {module, ?MODULE},
+ {K,x}]]
+ || K <- [answer_errors,
+ request_errors,
+ call_mutates_state]]]},
+ {restrict_connections,
+ [[false], [node], [nodes], [[node(), node()]]],
+ []},
+ {sequence,
+ [[{0,32}], [{1,31}]],
+ [[{2,31}]]},
+ {share_peers,
+ [[true],
+ [false],
+ [[node()]]],
+ [[x]]},
+ {use_shared_peers,
+ [[true],
+ [false],
+ [[node(), node()]]],
+ [[x]]}]).
+
+-define(TRANSPORT_CONFIG,
+ [{transport_module,
+ [[?MODULE]],
+ [[[?MODULE]]]},
+ {transport_config,
+ [[{}, 3000],
+ [{}, infinity]],
+ [[{}, x]]},
+ {applications,
+ [[[1, a, [x]]]],
+ [[x]]},
+ {capabilities,
+ [[[{'Origin-Host', "diameter.erlang.org"}]],
+ [[{'Origin-Realm', "erlang.org"}]]]
+ ++ [[[{'Host-IP-Address', L}]]
+ || L <- [[{127,0,0,1}],
+ ["127.0.0.1"],
+ ["127.0.0.1", "FFFF::1", "::1", {1,2,3,4,5,6,7,8}]]]
+ ++ [[[{'Product-Name', N}]]
+ || N <- [["Product", $-, ["Name"]],
+ "Norðurálfa",
+ "ᚠᚢᚦᚨᚱᚲ"]]
+ ++ [[[{K,V}]]
+ || K <- ['Vendor-Id',
+ 'Origin-State-Id',
+ 'Firmware-Revision'],
+ V <- [0, 256, 16#FFFF]]
+ ++ [[[{K,V}]]
+ || K <- ['Supported-Vendor-Id',
+ 'Auth-Application-Id',
+ 'Acct-Application-Id',
+ 'Inband-Security-Id'],
+ V <- [[17], [0, 256, 16#FFFF]]]
+ ++ [[[{'Vendor-Specific-Application-Id',
+ [[{'Vendor-Id', V},
+ {'Auth-Application-Id', [0]},
+ {'Acct-Application-Id', [4]}]]}]]
+ || V <- [1, [1]]],
+ [[x], [[{'Origin-Host', "ᚠᚢᚦᚨᚱᚲ"}]]]
+ ++ [[[{'Host-IP-Address', A}]]
+ || A <- [{127,0,0,1}]]
+ ++ [[[{'Product-Name', N}]]
+ || N <- [x, 1]]
+ ++ [[[{K,V}]]
+ || K <- ['Vendor-Id',
+ 'Origin-State-Id',
+ 'Firmware-Revision'],
+ V <- [x, [0], -1, 1 bsl 32]]
+ ++ [[[{K,V}]]
+ || K <- ['Supported-Vendor-Id',
+ 'Auth-Application-Id',
+ 'Acct-Application-Id',
+ 'Inband-Security-Id'],
+ V <- [x, 17, [-1], [1 bsl 32]]]
+ ++ [[[{'Vendor-Specific-Application-Id', V}]]
+ || V <- [x,
+ [[{'Vendor-Id', 1 bsl 32}]],
+ [[{'Auth-Application-Id', 1}]]]]},
+ {capabilities_cb,
+ [[x]],
+ []},
+ {capx_timeout,
+ [[3000]],
+ [[{?MODULE, tmo, []}]]},
+ {disconnect_cb,
+ [[x]],
+ []},
+ {length_errors,
+ [[exit], [handle], [discard]],
+ [[x]]},
+ {reconnect_timer,
+ [[3000]],
+ [[infinity]]},
+ {watchdog_timer,
+ [[3000],
+ [{?MODULE, tmo, []}]],
+ [[infinity],
+ [-1]]},
+ {watchdog_config,
+ [[[{okay, 0}, {suspect, 0}]],
+ [[{okay, 1}]],
+ [[{suspect, 2}]]],
+ [[x],
+ [[{open, 0}]]]}]).
+
+%% ===========================================================================
+
+suite() ->
+ [{timetrap, {seconds, 60}}].
+
+all() ->
+ [start,
+ start_service,
+ add_transport,
+ stop].
+
+%% ===========================================================================
+
+start(_) ->
+ ok = diameter:start().
+
+start_service(T)
+ when is_tuple(T) ->
+ do(fun start/3, T);
+
+start_service(_) ->
+ [] = ?util:run([{?MODULE, start_service, [T]}
+ || T <- [lists:keyfind(capabilities, 1, ?TRANSPORT_CONFIG)
+ | ?SERVICE_CONFIG]]).
+
+add_transport(T)
+ when is_tuple(T) ->
+ do(fun add/3, T);
+
+add_transport(_) ->
+ [] = ?util:run([{?MODULE, add_transport, [T]}
+ || T <- ?TRANSPORT_CONFIG]).
+
+stop(_) ->
+ ok = diameter:stop().
+
+%% ===========================================================================
+
+%% do/2
+
+do(F, {Key, Good, Bad}) ->
+ F(Key, Good, Bad).
+
+%% add/3
+
+add(Key, Good, Bad) ->
+ {[],[]} = {[{Vs,T} || Vs <- Good,
+ T <- [add(Key, Vs)],
+ [T] /= [T || {ok,_} <- [T]]],
+ [{Vs,T} || Vs <- Bad,
+ T <- [add(Key, Vs)],
+ [T] /= [T || {error,_} <- [T]]]}.
+
+add(Key, Vs) ->
+ T = list_to_tuple([Key | Vs]),
+ diameter:add_transport(make_ref(), {connect, [T]}).
+
+%% start/3
+
+start(Key, Good, Bad) ->
+ {[],[]} = {[{Vs,T} || Vs <- Good,
+ T <- [start(Key, Vs)],
+ T /= ok],
+ [{Vs,T} || Vs <- Bad,
+ T <- [start(Key, Vs)],
+ [T] /= [T || {error,_} <- [T]]]}.
+
+start(capabilities = K, [Vs]) ->
+ if is_list(Vs) ->
+ start(make_ref(), Vs ++ apps(K));
+ true ->
+ {error, Vs}
+ end;
+
+start(Key, Vs)
+ when is_atom(Key) ->
+ start(make_ref(), [list_to_tuple([Key | Vs]) | apps(Key)]);
+
+start(SvcName, Opts) ->
+ try
+ diameter:start_service(SvcName, Opts)
+ after
+ diameter:stop_service(SvcName)
+ end.
+
+apps(application) ->
+ [];
+apps(_) ->
+ [{application, [{dictionary, diameter_gen_base_rfc6733},
+ {module, ?MODULE}]}].
diff --git a/lib/diameter/test/diameter_ct.erl b/lib/diameter/test/diameter_ct.erl
index 1697287a22..ed2f884681 100644
--- a/lib/diameter/test/diameter_ct.erl
+++ b/lib/diameter/test/diameter_ct.erl
@@ -53,7 +53,7 @@ info(L0, L1) ->
L0,
L1),
Diff = [T, C, {memory, M}],
- ct:pal("INFO: ~p~n", [Diff]).
+ io:format("INFO: ~p~n", [Diff]).
diff(time, T0, T1) ->
timer:now_diff(T1, T0);
diff --git a/lib/diameter/test/diameter_examples_SUITE.erl b/lib/diameter/test/diameter_examples_SUITE.erl
new file mode 100644
index 0000000000..6d797f6911
--- /dev/null
+++ b/lib/diameter/test/diameter_examples_SUITE.erl
@@ -0,0 +1,334 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2013. 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%
+%%
+
+%%
+%% Test example code under ../examples/code.
+%%
+
+-module(diameter_examples_SUITE).
+
+-export([suite/0,
+ all/0]).
+
+%% testcases
+-export([dict/1, dict/0,
+ code/1,
+ enslave/1,
+ start/1,
+ traffic/1,
+ stop/1]).
+
+-export([install/1,
+ call/1]).
+
+-include("diameter.hrl").
+
+%% ===========================================================================
+
+-define(util, diameter_util).
+
+%% The order here is significant and causes the server to listen
+%% before the clients connect.
+-define(NODES, [compile, server, client]).
+
+%% Options to ct_slave:start/2.
+-define(TIMEOUTS, [{T, 15000} || T <- [boot_timeout,
+ init_timeout,
+ start_timeout]]).
+
+%% @inherits dependencies between example dictionaries. This is needed
+%% in order compile them in the right order. Can't compile to erl to
+%% find out since @inherits is a beam dependency.
+-define(INHERITS, [{rfc4006_cc, [rfc4005_nas]},
+ {rfc4072_eap, [rfc4005_nas]},
+ {rfc4740_sip, [rfc4590_digest]}]).
+
+%% Common dictionaries to inherit from examples.
+-define(DICT0, [rfc3588_base, rfc6733_base]).
+
+%% ===========================================================================
+
+suite() ->
+ [{timetrap, {seconds, 45}}].
+
+all() ->
+ [dict,
+ code,
+ enslave,
+ start,
+ traffic,
+ stop].
+
+%% ===========================================================================
+%% dict/1
+%%
+%% Compile example dictionaries in examples/dict.
+
+dict() ->
+ [{timetrap, {minutes, 10}}].
+
+dict(_Config) ->
+ Dirs = [filename:join(H ++ ["examples", "dict"])
+ || H <- [[code:lib_dir(diameter)], [here(), ".."]]],
+ [] = [{F,D,RC} || {_,F} <- sort(find_files(Dirs, ".*\\.dia")),
+ D <- ?DICT0,
+ RC <- [make(F,D)],
+ RC /= ok].
+
+sort([{_,_} | _] = Files) ->
+ lists:sort(fun({A,_},{B,_}) ->
+ sort([filename:rootname(F) || F <- [A,B]])
+ end,
+ Files);
+
+sort([A,B] = L) ->
+ [DA,DB] = [dep([D],[]) || D <- L],
+ case {[A] -- DB, [B] -- DA} of
+ {[], [_]} -> %% B depends on A
+ true;
+ {[_], []} -> %% A depends on B
+ false;
+ {[_],[_]} -> %% or not
+ length(DA) < length(DB)
+ end.
+
+%% Recursively accumulate inherited dictionaries.
+dep([D|Rest], Acc) ->
+ dep(dep(D), Rest, Acc);
+dep([], Acc) ->
+ Acc.
+
+dep([{Dict, _} | T], Rest, Acc) ->
+ dep(T, [Dict | Rest], [Dict | Acc]);
+dep([], Rest, Acc) ->
+ dep(Rest, Acc).
+
+make(Path, Dict0)
+ when is_atom(Dict0) ->
+ make(Path, atom_to_list(Dict0));
+
+make(Path, Dict0) ->
+ Dict = filename:rootname(filename:basename(Path)),
+ {Mod, Pre} = make_name(Dict),
+ {"diameter_gen_base" ++ Suf = Mod0, _} = make_name(Dict0),
+ Name = Mod ++ Suf,
+ try
+ ok = to_erl(Path, [{name, Name},
+ {prefix, Pre},
+ {inherits, "rfc3588_base/" ++ Mod0}
+ | [{inherits, D ++ "/" ++ M ++ Suf}
+ || {D,M} <- dep(Dict)]]),
+ ok = to_beam(Name)
+ catch
+ throw: {_,_} = E ->
+ E
+ end.
+
+to_erl(File, Opts) ->
+ case diameter_make:codec(File, Opts) of
+ ok ->
+ ok;
+ No ->
+ throw({make, No})
+ end.
+
+to_beam(Name) ->
+ case compile:file(Name ++ ".erl", [return]) of
+ {ok, _, _} ->
+ ok;
+ No ->
+ throw({compile, No})
+ end.
+
+dep(Dict) ->
+ case lists:keyfind(list_to_atom(Dict), 1, ?INHERITS) of
+ {_, Is} ->
+ lists:map(fun inherits/1, Is);
+ false ->
+ []
+ end.
+
+inherits(Dict)
+ when is_atom(Dict) ->
+ inherits(atom_to_list(Dict));
+
+inherits(Dict) ->
+ {Name, _} = make_name(Dict),
+ {Dict, Name}.
+
+make_name(Dict) ->
+ {R, [$_|N]} = lists:splitwith(fun(C) -> C /= $_ end, Dict),
+ {string:join(["diameter_gen", N, R], "_"), "diameter_" ++ N}.
+
+%% ===========================================================================
+%% code/1
+%%
+%% Compile example code under examples/code.
+
+code(Config) ->
+ Node = slave(hd(?NODES), here()),
+ [] = rpc:call(Node,
+ ?MODULE,
+ install,
+ [proplists:get_value(priv_dir, Config)]).
+
+%% Compile on another node since the code path may be modified.
+install(PrivDir) ->
+ Top = install(here(), PrivDir),
+ Src = filename:join([Top, "examples", "code"]),
+ Files = find_files([Src], ".*\\.erl"),
+ [] = [{F,E} || {_,F} <- Files,
+ {error, _, _} = E <- [compile:file(F, [warnings_as_errors,
+ return_errors])]].
+
+%% Copy include files into a temporary directory and adjust the code
+%% path in order for example code to be able to include them with
+%% include_lib. This is really only required when running in the reop
+%% since generated includes, that the example code wants to
+%% include_lib, are under src/gen and there's no way to get get the
+%% preprocessor to find these otherwise. Generated hrls are only be
+%% under include in an installation. ("Installing" them locally is
+%% anathema.)
+install(Dir, PrivDir) ->
+ %% Remove the path added by slave/1 (needed for the rpc:call/4 in
+ %% compile/1 to find ?MODULE) so the call to code:lib_dir/2 below
+ %% returns the installed path.
+ [Ebin | _] = code:get_path(),
+ true = code:del_path(Ebin),
+ Top = top(Dir, code:lib_dir(diameter)),
+
+ %% Create a new diameter/include in priv_dir. Copy all includes
+ %% there, from below ../include and ../src/gen if they exist (in
+ %% the repo).
+ Tmp = filename:join([PrivDir, "diameter"]),
+ TmpInc = filename:join([PrivDir, "diameter", "include"]),
+ TmpEbin = filename:join([PrivDir, "diameter", "ebin"]),
+ [] = [{T,E} || T <- [Tmp, TmpInc, TmpEbin],
+ {error, E} <- [file:make_dir(T)]],
+
+ Inc = filename:join([Top, "include"]),
+ Gen = filename:join([Top, "src", "gen"]),
+ Files = find_files([Inc, Gen], ".*\\.hrl"),
+ [] = [{F,E} || {_,F} <- Files,
+ B <- [filename:basename(F)],
+ D <- [filename:join([TmpInc, B])],
+ {error, E} <- [file:copy(F,D)]],
+
+ %% Prepend the created directory just so that code:lib_dir/1 finds
+ %% it when compile:file/2 tries to resolve include_lib.
+ true = code:add_patha(TmpEbin),
+ Tmp = code:lib_dir(diameter), %% assert
+ %% Return the top directory containing examples/code.
+ Top.
+
+find_files(Dirs, RE) ->
+ lists:foldl(fun(D,A) -> fold_files(D, RE, A) end,
+ orddict:new(),
+ Dirs).
+
+fold_files(Dir, RE, Acc) ->
+ filelib:fold_files(Dir, RE, false, fun store/2, Acc).
+
+store(Path, Dict) ->
+ orddict:store(filename:basename(Path), Path, Dict).
+
+%% ===========================================================================
+
+%% enslave/1
+%%
+%% Start two nodes: one for the server, one for the client.
+
+enslave(Config) ->
+ Dir = here(),
+ Nodes = [{N, slave(N, Dir)} || N <- tl(?NODES)],
+ ?util:write_priv(Config, nodes, Nodes).
+
+slave(Name, Dir) ->
+ {ok, Node} = ct_slave:start(Name, ?TIMEOUTS),
+ ok = rpc:call(Node,
+ code,
+ add_pathsa,
+ [[Dir, filename:join([Dir, "..", "ebin"])]]),
+ Node.
+
+here() ->
+ filename:dirname(code:which(?MODULE)).
+
+top(Dir, LibDir) ->
+ File = filename:join([Dir, "depend.sed"]), %% only in the repo
+ case filelib:is_regular(File) of
+ true -> filename:join([Dir, ".."]);
+ false -> LibDir
+ end.
+
+%% start/1
+
+start(server) ->
+ ok = diameter:start(),
+ ok = server:start(),
+ {ok, Ref} = server:listen(tcp),
+ [_] = ?util:lport(tcp, Ref, 20),
+ ok;
+
+start(client) ->
+ ok = diameter:start(),
+ true = diameter:subscribe(client),
+ ok = client:start(),
+ {ok, Ref} = client:connect(tcp),
+ receive #diameter_event{info = {up, Ref, _, _, _}} -> ok end;
+
+start(Config) ->
+ Nodes = ?util:read_priv(Config, nodes),
+ [] = [RC || {T,N} <- Nodes,
+ RC <- [rpc:call(N, ?MODULE, start, [T])],
+ RC /= ok].
+
+%% traffic/1
+%%
+%% Send successful messages from client to server.
+
+traffic(server) ->
+ ok;
+
+traffic(client) ->
+ {_, MRef} = spawn_monitor(fun() -> call(100) end),
+ receive {'DOWN', MRef, process, _, Reason} -> Reason end;
+
+traffic(Config) ->
+ Nodes = ?util:read_priv(Config, nodes),
+ [] = [RC || {T,N} <- Nodes,
+ RC <- [rpc:call(N, ?MODULE, traffic, [T])],
+ RC /= ok].
+
+call(0) ->
+ exit(ok);
+
+call(N) ->
+ {ok, _} = client:call(),
+ call(N-1).
+
+%% stop/1
+
+stop(Name)
+ when is_atom(Name) ->
+ {ok, _Node} = ct_slave:stop(Name),
+ ok;
+
+stop(_Config) ->
+ [] = [RC || N <- ?NODES, RC <- [stop(N)], RC /= ok].
diff --git a/lib/diameter/test/modules.mk b/lib/diameter/test/modules.mk
index beff588a02..1a829f8031 100644
--- a/lib/diameter/test/modules.mk
+++ b/lib/diameter/test/modules.mk
@@ -29,11 +29,13 @@ MODULES = \
diameter_capx_SUITE \
diameter_codec_SUITE \
diameter_codec_test \
+ diameter_config_SUITE \
diameter_compiler_SUITE \
diameter_dict_SUITE \
diameter_distribution_SUITE \
diameter_dpr_SUITE \
diameter_event_SUITE \
+ diameter_examples_SUITE \
diameter_failover_SUITE \
diameter_gen_sctp_SUITE \
diameter_length_SUITE \
diff --git a/lib/hipe/cerl/erl_bif_types.erl b/lib/hipe/cerl/erl_bif_types.erl
index 0a2c6e822f..42c7e360c1 100644
--- a/lib/hipe/cerl/erl_bif_types.erl
+++ b/lib/hipe/cerl/erl_bif_types.erl
@@ -1053,6 +1053,8 @@ type(hipe_bifs, mark_referred_from, 1, Xs) ->
fun (_) -> t_nil() end);
type(hipe_bifs, merge_term, 1, Xs) ->
strict(arg_types(hipe_bifs, merge_term, 1), Xs, fun ([X]) -> X end);
+type(hipe_bifs, nstack_used_size, 0, _) ->
+ t_non_neg_fixnum();
type(hipe_bifs, patch_call, 3, Xs) ->
strict(arg_types(hipe_bifs, patch_call, 3), Xs, fun (_) -> t_nil() end);
type(hipe_bifs, patch_insn, 3, Xs) ->
@@ -2361,6 +2363,8 @@ arg_types(hipe_bifs, mark_referred_from, 1) ->
[t_mfa()];
arg_types(hipe_bifs, merge_term, 1) ->
[t_any()];
+arg_types(hipe_bifs, nstack_used_size, 0) ->
+ [];
arg_types(hipe_bifs, patch_call, 3) ->
[t_integer(), t_integer(), t_trampoline()];
arg_types(hipe_bifs, patch_insn, 3) ->
diff --git a/lib/hipe/icode/Makefile b/lib/hipe/icode/Makefile
index 0f2d6db39b..238f70cf59 100644
--- a/lib/hipe/icode/Makefile
+++ b/lib/hipe/icode/Makefile
@@ -83,7 +83,7 @@ DOC_FILES= $(DOC_MODULES:%=$(DOCS)/%.html)
include ../native.mk
-ERL_COMPILE_FLAGS += +warn_unused_import +warn_missing_spec # +warn_untyped_record
+ERL_COMPILE_FLAGS += +warn_unused_import +warn_exported_vars +warn_missing_spec # +warn_untyped_record
# ----------------------------------------------------
# Targets
diff --git a/lib/hipe/icode/hipe_icode.erl b/lib/hipe/icode/hipe_icode.erl
index 3e211bf385..dfea092af2 100644
--- a/lib/hipe/icode/hipe_icode.erl
+++ b/lib/hipe/icode/hipe_icode.erl
@@ -261,7 +261,6 @@
%% {tuple, N}
%% atom
%% {atom, Atom}
-%% constant
%% number
%% integer
%% {integer, N}
@@ -380,7 +379,6 @@
%% | {tuple, integer()}
%% | atom
%% | {atom, atom()}
-%% | constant
%% | number
%% | integer
%% | {integer, integer()}
diff --git a/lib/hipe/icode/hipe_icode.hrl b/lib/hipe/icode/hipe_icode.hrl
index d76eebf78d..89d297ef01 100644
--- a/lib/hipe/icode/hipe_icode.hrl
+++ b/lib/hipe/icode/hipe_icode.hrl
@@ -23,12 +23,6 @@
%%=====================================================================
%%---------------------------------------------------------------------
-%% THIS DOES NOT REALLY BELONG HERE -- PLEASE REMOVE ASAP!
-%%---------------------------------------------------------------------
-
--type ordset(T) :: [T].
-
-%%---------------------------------------------------------------------
%% Include files needed for the compilation of this header file
%%---------------------------------------------------------------------
@@ -67,7 +61,7 @@
| 'op_exact_eqeq_2' | 'suspend_msg_timeout'.
-type icode_type_test() :: 'atom' | 'bignum' | 'binary' | 'bitstr' | 'boolean'
- | 'cons' | 'constant' | 'fixnum' | 'float'
+ | 'cons' | 'fixnum' | 'float'
| 'function' | 'function2' | 'integer' | 'list' | 'nil'
| 'number' | 'pid' | 'port' | 'reference' | 'tuple'
| {'atom', atom()} | {'integer', integer()}
diff --git a/lib/hipe/icode/hipe_icode_callgraph.erl b/lib/hipe/icode/hipe_icode_callgraph.erl
index ae4b5785c4..6d004823e2 100644
--- a/lib/hipe/icode/hipe_icode_callgraph.erl
+++ b/lib/hipe/icode/hipe_icode_callgraph.erl
@@ -102,7 +102,7 @@ pp(#icode_callgraph{ordered_sccs = SCCs}) ->
%%------------------------------------------------------------------------
%% Get the modules called from this module
--spec get_called_modules([mfa_icode()]) -> ordset(atom()).
+-spec get_called_modules([mfa_icode()]) -> ordsets:ordset(atom()).
get_called_modules(List) ->
get_remote_calls(List, []).
diff --git a/lib/hipe/icode/hipe_icode_ssa_struct_reuse.erl b/lib/hipe/icode/hipe_icode_ssa_struct_reuse.erl
index 675c8c1ad8..718d5d442b 100644
--- a/lib/hipe/icode/hipe_icode_ssa_struct_reuse.erl
+++ b/lib/hipe/icode/hipe_icode_ssa_struct_reuse.erl
@@ -129,8 +129,8 @@ maps_expr_key_enter(Expr, Maps) ->
key = none :: 'none' | tuple(), % illegal_icode_instr()
defs = none :: 'none' | [icode_var()],
direct_replace = false :: boolean(),
- inserts = ?SETS:new() :: ?SET(_),
- use = ?SETS:new() :: ?SET(_)}).
+ inserts = ?SETS:new() :: ?SETS:?SET(_),
+ use = ?SETS:new() :: ?SETS:?SET(_)}).
expr_id(#expr{id = Out}) -> Out.
expr_defs(#expr{defs = Out}) -> Out.
@@ -169,7 +169,7 @@ expr_create(Key, Defs) ->
%% exprid - a expression value number which is the expression that
%% the variable is defined by.
--record(varinfo, {use = ?SETS:new() :: ?SET(_),
+-record(varinfo, {use = ?SETS:new() :: ?SETS:?SET(_),
ref = none :: 'none' | {non_neg_integer(), non_neg_integer()},
elem = none :: 'none' | {icode_var(), non_neg_integer()},
exprid = none :: 'none' | non_neg_integer()}).
@@ -215,12 +215,12 @@ varinfo_use_add(#varinfo{use = UseSet} = I, Use) ->
varmap = [] :: [{icode_var(), icode_var()}],
pre_loop = false :: boolean(),
non_struct_defs = gb_sets:new() :: gb_set(),
- up_expr = none :: 'none' | ?SET(_),
- killed_expr = none :: 'none' | ?SET(_),
- sub_inserts = ?SETS:new() :: ?SET(_),
- inserts = ?SETS:new() :: ?SET(_),
- antic_in = none :: 'none' | ?SET(_),
- antic_out = none :: 'none' | ?SET(_),
+ up_expr = none :: 'none' | ?SETS:?SET(_),
+ killed_expr = none :: 'none' | ?SETS:?SET(_),
+ sub_inserts = ?SETS:new() :: ?SETS:?SET(_),
+ inserts = ?SETS:new() :: ?SETS:?SET(_),
+ antic_in = none :: 'none' | ?SETS:?SET(_),
+ antic_out = none :: 'none' | ?SETS:?SET(_),
struct_type = [] :: [struct_type()],
struct_elems = [] :: [struct_elems()]}).
diff --git a/lib/hipe/regalloc/hipe_ls_regalloc.erl b/lib/hipe/regalloc/hipe_ls_regalloc.erl
index d06b938bea..7fb65be6a0 100644
--- a/lib/hipe/regalloc/hipe_ls_regalloc.erl
+++ b/lib/hipe/regalloc/hipe_ls_regalloc.erl
@@ -72,7 +72,7 @@
%% PhysRegs = [reg()]
%% Entrypoints = [labelname()]
%% DontSpill = reg()
-%% Options = proplist:proplist()
+%% Options = proplists:proplist()
%% Target = atom()
%% Coloring = [{temp(), pos()}]
%% NumberOfSpills = integer()
diff --git a/lib/hipe/rtl/Makefile b/lib/hipe/rtl/Makefile
index 7852a2172b..0312e67822 100644
--- a/lib/hipe/rtl/Makefile
+++ b/lib/hipe/rtl/Makefile
@@ -74,7 +74,7 @@ TARGET_FILES= $(MODULES:%=$(EBIN)/%.$(EMULATOR))
include ../native.mk
-ERL_COMPILE_FLAGS += +inline
+ERL_COMPILE_FLAGS += +inline +warn_unused_import +warn_exported_vars
# ----------------------------------------------------
# Targets
diff --git a/lib/hipe/rtl/hipe_rtl_binary_match.erl b/lib/hipe/rtl/hipe_rtl_binary_match.erl
index d147bed6d8..8831199244 100644
--- a/lib/hipe/rtl/hipe_rtl_binary_match.erl
+++ b/lib/hipe/rtl/hipe_rtl_binary_match.erl
@@ -2,7 +2,7 @@
%%%
%%% %CopyrightBegin%
%%%
-%%% Copyright Ericsson AB 2007-2009. All Rights Reserved.
+%%% Copyright Ericsson AB 2007-2013. 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
@@ -42,6 +42,7 @@
%%--------------------------------------------------------------------
+%% ----- bs_start_match -----
gen_rtl({bs_start_match, 0}, [Ms], [Binary], TrueLblName, FalseLblName) ->
ReInitLbl = hipe_rtl:mk_new_label(),
BinaryLbl = hipe_rtl:mk_new_label(),
@@ -62,7 +63,7 @@ gen_rtl({bs_start_match, Max}, [Ms], [Binary], TrueLblName, FalseLblName) ->
TestCode =
[hipe_rtl:mk_move(Ms,Binary),
hipe_tagscheme:test_matchstate(Binary,
- hipe_rtl:label_name(MatchStateLbl),
+ hipe_rtl:label_name(MatchStateLbl),
hipe_rtl:label_name(BinaryLbl),
0.99)],
MatchStateTestCode =
@@ -86,7 +87,7 @@ gen_rtl({{bs_start_match, bitstr}, Max}, [Ms], [Binary],
gen_rtl({{bs_start_match, bitstr}, _Max}, [], [_Binary],
TrueLblName, _FalseLblName) ->
[hipe_rtl:mk_goto(TrueLblName)];
-gen_rtl({{bs_start_match,ok_matchstate}, Max}, [Ms], [Binary],
+gen_rtl({{bs_start_match, ok_matchstate}, Max}, [Ms], [Binary],
TrueLblName, FalseLblName) ->
MatchStateLbl = hipe_rtl:mk_new_label(),
BinaryLbl = hipe_rtl:mk_new_label(),
@@ -106,12 +107,13 @@ gen_rtl({{bs_start_match, ok_matchstate}, _Max}, [], [Binary],
hipe_rtl:label_name(MatchStateLbl), 0.99),
MatchStateLbl,
hipe_tagscheme:test_matchstate(Binary, TrueLblName, FalseLblName, 0.99)];
-gen_rtl({bs_get_integer, 0, _Flags}, [Dst, NewMs], [Ms],
+%% ----- bs_get_integer -----
+gen_rtl({bs_get_integer, 0, _Flags}, [Dst, NewMs], [Ms],
TrueLblName, _FalseLblName) ->
update_ms(NewMs, Ms) ++
[hipe_rtl:mk_move(Dst, hipe_rtl:mk_imm(15)),
hipe_rtl:mk_goto(TrueLblName)];
-gen_rtl({bs_get_integer,Size,Flags}, [Dst,NewMs], Args,
+gen_rtl({bs_get_integer, Size, Flags}, [Dst, NewMs], Args,
TrueLblName, FalseLblName) ->
case is_illegal_const(Size) of
true ->
@@ -123,15 +125,14 @@ gen_rtl({bs_get_integer,Size,Flags}, [Dst,NewMs], Args,
UnSafe = unsafe(Flags),
case Args of
[Ms] ->
- CCode= int_get_c_code(Dst, Ms, hipe_rtl:mk_imm(Size),
- Flags, TrueLblName, FalseLblName),
+ CCode = int_get_c_code(Dst, Ms, hipe_rtl:mk_imm(Size),
+ Flags, TrueLblName, FalseLblName),
update_ms(NewMs, Ms) ++
get_static_int(Dst, Ms, Size, CCode,
Signed, LittleEndian, Aligned, UnSafe,
TrueLblName, FalseLblName);
[Ms, Arg] ->
- {SizeCode1, SizeReg1} =
- make_size(Size, Arg, FalseLblName),
+ {SizeCode1, SizeReg1} = make_size(Size, Arg, FalseLblName),
CCode = int_get_c_code(Dst, Ms, SizeReg1, Flags,
TrueLblName, FalseLblName),
InCode = get_dynamic_int(Dst, Ms, SizeReg1, CCode,
@@ -140,7 +141,8 @@ gen_rtl({bs_get_integer,Size,Flags}, [Dst,NewMs], Args,
update_ms(NewMs, Ms) ++ SizeCode1 ++ InCode
end
end;
-gen_rtl({bs_get_float,Size,Flags}, [Dst1,NewMs], Args,
+%% ----- bs_get_float -----
+gen_rtl({bs_get_float,Size,Flags}, [Dst1, NewMs], Args,
TrueLblName, FalseLblName) ->
case is_illegal_const(Size) of
true ->
@@ -152,24 +154,26 @@ gen_rtl({bs_get_float,Size,Flags}, [Dst1,NewMs], Args,
CCode = float_get_c_code(Dst1, Ms, hipe_rtl:mk_imm(Size), Flags,
TrueLblName, FalseLblName),
update_ms(NewMs, Ms) ++ CCode;
- [Ms,Arg] ->
- {SizeCode, SizeReg} = make_size(Size, Arg,
- FalseLblName),
+ [Ms, Arg] ->
+ {SizeCode, SizeReg} = make_size(Size, Arg, FalseLblName),
CCode = float_get_c_code(Dst1, Ms, SizeReg, Flags,
TrueLblName, FalseLblName),
update_ms(NewMs, Ms) ++ SizeCode ++ CCode
end
end;
+%% ----- bs_get_binary_all -----
gen_rtl({bs_get_binary_all, Unit, _Flags}, [Dst], [Ms],
TrueLblName, FalseLblName) ->
[hipe_rtl:mk_gctest(?SUB_BIN_WORDSIZE)] ++
get_binary_all(Dst, Unit, Ms, TrueLblName,FalseLblName);
-gen_rtl({bs_get_binary_all_2, Unit, _Flags}, [Dst,NewMs], [Ms],
+%% ----- bs_get_binary_all_2 -----
+gen_rtl({bs_get_binary_all_2, Unit, _Flags}, [Dst, NewMs], [Ms],
TrueLblName, FalseLblName) ->
[hipe_rtl:mk_gctest(?SUB_BIN_WORDSIZE)] ++
update_ms(NewMs, Ms) ++
get_binary_all(Dst, Unit, Ms, TrueLblName, FalseLblName);
-gen_rtl({bs_get_binary,Size,Flags}, [Dst,NewMs], Args,
+%% ----- bs_get_binary -----
+gen_rtl({bs_get_binary, Size, Flags}, [Dst, NewMs], Args,
TrueLblName, FalseLblName) ->
case is_illegal_const(Size) of
true ->
@@ -188,65 +192,78 @@ gen_rtl({bs_get_binary,Size,Flags}, [Dst,NewMs], Args,
[hipe_rtl:mk_gctest(?SUB_BIN_WORDSIZE)] ++
update_ms(NewMs, Ms) ++ SizeCode ++ InCode
end;
-gen_rtl(bs_get_utf8, [Dst,NewMs], [Ms], TrueLblName, FalseLblName) ->
+%% ----- bs_get_utf8 -----
+gen_rtl(bs_get_utf8, [Dst, NewMs], [Ms], TrueLblName, FalseLblName) ->
update_ms(NewMs, Ms) ++ utf8_get_c_code(Dst, Ms, TrueLblName, FalseLblName);
-gen_rtl({bs_get_utf16,Flags}, [Dst,NewMs], [Ms], TrueLblName, FalseLblName) ->
- update_ms(NewMs, Ms) ++ utf16_get_c_code(Flags, Dst, Ms, TrueLblName, FalseLblName);
-gen_rtl(bs_validate_unicode_retract, [NewMs], [Src,Ms], TrueLblName, FalseLblName) ->
- update_ms(NewMs, Ms) ++ validate_unicode_retract_c_code(Src, Ms, TrueLblName, FalseLblName);
+%% ----- bs_get_utf16 -----
+gen_rtl({bs_get_utf16, Flags}, [Dst, NewMs], [Ms], TrueLblName, FalseLblName) ->
+ update_ms(NewMs, Ms) ++
+ utf16_get_c_code(Flags, Dst, Ms, TrueLblName, FalseLblName);
+%% ----- bs_validate_unicode_retract -----
+gen_rtl(bs_validate_unicode_retract, [NewMs], [Src, Ms],
+ TrueLblName, FalseLblName) ->
+ update_ms(NewMs, Ms) ++
+ validate_unicode_retract_c_code(Src, Ms, TrueLblName, FalseLblName);
+%% ----- bs_test_tail -----
gen_rtl({bs_test_tail, NumBits}, [NewMs], [Ms], TrueLblName, FalseLblName) ->
{[Offset,BinSize], ExCode} = extract_matchstate_vars([offset,binsize], Ms),
update_ms(NewMs, Ms) ++ ExCode ++
[add_to_offset(Offset, Offset, hipe_rtl:mk_imm(NumBits), FalseLblName),
hipe_rtl:mk_branch(Offset, eq, BinSize, TrueLblName, FalseLblName)];
+%% ----- bs_test_unit -----
gen_rtl({bs_test_unit, Unit}, [], [Ms], TrueLblName, FalseLblName) ->
- {[Offset,BinSize], ExCode} = extract_matchstate_vars([offset,binsize], Ms),
+ {[Offset, BinSize], ExCode} = extract_matchstate_vars([offset, binsize], Ms),
SizeReg = hipe_rtl:mk_new_reg(),
ExCode ++
[hipe_rtl:mk_alu(SizeReg, BinSize, sub, Offset)|
test_alignment_code(SizeReg, Unit, TrueLblName, FalseLblName)];
gen_rtl({bs_test_tail, NumBits}, [], [Ms], TrueLblName, FalseLblName) ->
- {[Offset,BinSize], ExCode} = extract_matchstate_vars([offset,binsize], Ms),
+ {[Offset, BinSize], ExCode} = extract_matchstate_vars([offset, binsize], Ms),
ExCode ++
[add_to_offset(Offset, Offset, hipe_rtl:mk_imm(NumBits), FalseLblName),
hipe_rtl:mk_branch(Offset, eq, BinSize, TrueLblName, FalseLblName)];
-gen_rtl({bs_skip_bits_all, Unit, _Flags}, Dst, [Ms],
+%% ----- bs_skip_bits_all -----
+gen_rtl({bs_skip_bits_all, Unit, _Flags}, Dst, [Ms],
TrueLblName, FalseLblName) ->
opt_update_ms(Dst, Ms) ++
skip_bits_all(Unit, Ms, TrueLblName, FalseLblName);
+%% ----- bs_skip_bits -----
gen_rtl({bs_skip_bits, Bits}, Dst, [Ms|Args], TrueLblName, FalseLblName) ->
- opt_update_ms(Dst,Ms) ++
- case Args of
- [] ->
- skip_bits2(Ms, hipe_rtl:mk_imm(Bits), TrueLblName, FalseLblName);
- [Arg] ->
- {SizeCode, SizeReg} = make_size(Bits, Arg, FalseLblName),
- InCode = skip_bits2(Ms, SizeReg, TrueLblName, FalseLblName),
- SizeCode ++ InCode
- end;
+ opt_update_ms(Dst, Ms) ++
+ case Args of
+ [] ->
+ skip_bits2(Ms, hipe_rtl:mk_imm(Bits), TrueLblName, FalseLblName);
+ [Arg] ->
+ {SizeCode, SizeReg} = make_size(Bits, Arg, FalseLblName),
+ InCode = skip_bits2(Ms, SizeReg, TrueLblName, FalseLblName),
+ SizeCode ++ InCode
+ end;
+%% ----- bs_restore -----
gen_rtl({bs_restore, Slot}, [NewMs], [Ms], TrueLblName, _FalseLblName) ->
Tmp1 = hipe_rtl:mk_new_reg_gcsafe(),
update_ms(NewMs, Ms) ++
[get_field_from_term({matchstate, {saveoffset, Slot}}, Ms, Tmp1),
set_field_from_term({matchstate, {matchbuffer, offset}}, Ms, Tmp1),
hipe_rtl:mk_goto(TrueLblName)];
+%% ----- bs_save -----
gen_rtl({bs_save, Slot}, [NewMs], [Ms], TrueLblName, _FalseLblName) ->
{Offset, Instr} = extract_matchstate_var(offset, Ms),
update_ms(NewMs, Ms) ++
[Instr,
set_field_from_term({matchstate, {saveoffset, Slot}}, Ms, Offset),
hipe_rtl:mk_goto(TrueLblName)];
-gen_rtl({bs_match_string, String, ByteSize}, [NewMs],
- [Ms], TrueLblName, FalseLblName) ->
+%% ----- bs_match_string -----
+gen_rtl({bs_match_string, String, ByteSize}, Dst, [Ms],
+ TrueLblName, FalseLblName) ->
{[Offset, BinSize, Base], Instrs} =
extract_matchstate_vars([offset, binsize, base], Ms),
[SuccessLbl, ALbl, ULbl] = create_lbls(3),
- [NewOffset,BitOffset] = create_gcsafe_regs(2),
+ [NewOffset, BitOffset] = create_gcsafe_regs(2),
Unit = hipe_rtl_arch:word_size() - 1,
Loops = ByteSize div Unit,
Init =
[Instrs,
- update_ms(NewMs,Ms),
+ opt_update_ms(Dst, Ms),
check_size(Offset, hipe_rtl:mk_imm(ByteSize*?BYTE_SIZE), BinSize,
NewOffset, hipe_rtl:label_name(SuccessLbl), FalseLblName),
SuccessLbl],
@@ -255,10 +272,10 @@ gen_rtl({bs_match_string, String, ByteSize}, [NewMs],
hipe_rtl:label_name(ALbl), hipe_rtl:label_name(ULbl))],
Loops = ByteSize div Unit,
SkipSize = Loops * Unit,
- {ACode1,UCode1} =
+ {ACode1, UCode1} =
case Loops of
0 ->
- {[],[]};
+ {[], []};
_ ->
create_loops(Loops, Unit, String, Base,
Offset, BitOffset, FalseLblName)
@@ -267,12 +284,17 @@ gen_rtl({bs_match_string, String, ByteSize}, [NewMs],
{ACode2, UCode2} =
case ByteSize rem Unit of
0 ->
- {[],[]};
+ {[], []};
Rem ->
create_rests(Rem, RestString, Base, Offset, BitOffset, FalseLblName)
end,
- End = [update_offset(NewOffset, NewMs), hipe_rtl:mk_goto(TrueLblName)],
- [Init, SplitCode, ALbl, ACode1, ACode2, End, ULbl, UCode1, UCode2,End];
+ GoTo = hipe_rtl:mk_goto(TrueLblName),
+ End = case Dst of
+ [] -> [GoTo];
+ [NewMs] -> [update_offset(NewOffset, NewMs), GoTo]
+ end,
+ [Init, SplitCode, ALbl, ACode1, ACode2, End, ULbl, UCode1, UCode2, End];
+%% ----- bs_context_to_binary -----
gen_rtl(bs_context_to_binary, [Bin], [Var], TrueLblName, _FalseLblName) ->
MSLabel = hipe_rtl:mk_new_label(),
[hipe_rtl:mk_move(Bin, Var),
@@ -304,9 +326,7 @@ get_c_code(Func, Dst1, Ms, Size, Flags, TrueLblName, FalseLblName) ->
hipe_rtl_arch:call_bif([Dst1], Func, [SizeReg, FlagsReg, MatchBuf],
hipe_rtl:label_name(RetLabel), FalseLblName),
RetLabel,
- hipe_rtl:mk_branch(Dst1, eq, NonVal,
- FalseLblName,
- TrueLblName, 0.01)].
+ hipe_rtl:mk_branch(Dst1, eq, NonVal, FalseLblName, TrueLblName, 0.01)].
utf8_get_c_code(Dst, Ms, TrueLblName, FalseLblName) ->
MatchBuf = hipe_rtl:mk_new_reg(),
@@ -330,7 +350,7 @@ validate_unicode_retract_c_code(Src, Ms, TrueLblName, FalseLblName) ->
Tmp = hipe_rtl:mk_new_reg(),
[hipe_tagscheme:extract_matchbuffer(MatchBuf, Ms),
hipe_rtl_arch:call_bif([Tmp], bs_validate_unicode_retract,
- [MatchBuf,Src], [], []),
+ [MatchBuf, Src], [], []),
hipe_rtl:mk_branch(Tmp, eq, Zero, FalseLblName, TrueLblName, 0.01)].
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% Int Code %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@@ -464,9 +484,9 @@ get_int_from_unaligned_bin(Ms, Size, Dst1, Signed,
{[Base,Offset,BinSize], ExCode} =
extract_matchstate_vars([base,offset,binsize], Ms),
ExCode ++
- [check_size(Offset, hipe_rtl:mk_imm(Size), BinSize, NewOffset,
- UnSafe, hipe_rtl:label_name(SuccessLbl), FalseLblName),
- SuccessLbl] ++
+ [check_size(Offset, hipe_rtl:mk_imm(Size), BinSize, NewOffset,
+ UnSafe, hipe_rtl:label_name(SuccessLbl), FalseLblName),
+ SuccessLbl] ++
[update_offset(NewOffset, Ms)] ++
get_unaligned_int(Dst1, Size, Base, Offset, Shiftr, Type, TrueLblName).
@@ -499,7 +519,7 @@ make_matchstate(Binary, Max, Ms, TrueLblName, FalseLblName) ->
Offset = hipe_rtl:mk_new_reg_gcsafe(),
Lbl = hipe_rtl:mk_new_label(),
[hipe_rtl:mk_gctest(?MS_MIN_SIZE+Max),
- get_binary_bytes(Binary, BinSize, Base, Offset,
+ get_binary_bytes(Binary, BinSize, Base, Offset,
Orig, hipe_rtl:label_name(Lbl), FalseLblName),
Lbl,
hipe_tagscheme:create_matchstate(Max, BinSize, Base, Offset, Orig, Ms),
@@ -551,24 +571,22 @@ get_binary_all(Dst1, Unit, Ms, TrueLblName, FalseLblName) ->
hipe_rtl:mk_goto(TrueLblName)],
ExCode ++ MakeCode.
-get_binary(Dst1, Ms, SizeReg,
- UnSafe, TrueLblName, FalseLblName) ->
+get_binary(Dst1, Ms, SizeReg, UnSafe, TrueLblName, FalseLblName) ->
[SuccessLbl] = create_lbls(1),
[EndOffset] = create_gcsafe_regs(1),
{[Offset,BinSize,Orig], ExCode} =
extract_matchstate_vars([offset,binsize,orig], Ms),
CheckCode =
- [check_size(Offset, SizeReg, BinSize, EndOffset,
- UnSafe, hipe_rtl:label_name(SuccessLbl),
- FalseLblName),
+ [check_size(Offset, SizeReg, BinSize, EndOffset, UnSafe,
+ hipe_rtl:label_name(SuccessLbl), FalseLblName),
SuccessLbl],
MakeCode =
- construct_subbin(Dst1,SizeReg,Offset,Orig)
+ construct_subbin(Dst1, SizeReg, Offset, Orig)
++ [update_offset(EndOffset, Ms),
hipe_rtl:mk_goto(TrueLblName)],
ExCode ++ CheckCode ++ MakeCode.
-construct_subbin(Dst,Size,Offset,Orig) ->
+construct_subbin(Dst, Size, Offset, Orig) ->
[BitOffset, ByteOffset, BitSize, ByteSize] = create_gcsafe_regs(4),
[hipe_rtl:mk_alu(ByteSize, Size, srl, hipe_rtl:mk_imm(?BYTE_SHIFT)),
hipe_rtl:mk_alu(BitSize, Size, 'and', hipe_rtl:mk_imm(?LOW_BITS)),
@@ -579,12 +597,10 @@ construct_subbin(Dst,Size,Offset,Orig) ->
%%%%%%%%%%%%%%%%%%%%%%%%% Skip Bits %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-skip_bits_all(1, Ms, TrueLblName,_FalseLblName) ->
+skip_bits_all(1, Ms, TrueLblName, _FalseLblName) ->
{[BinSize], ExCode} = extract_matchstate_vars([binsize], Ms),
- ExCode ++
- [update_offset(BinSize,Ms),
- hipe_rtl:mk_goto(TrueLblName)];
-skip_bits_all(Unit,Ms, TrueLblName,FalseLblName) ->
+ ExCode ++ [update_offset(BinSize,Ms), hipe_rtl:mk_goto(TrueLblName)];
+skip_bits_all(Unit,Ms, TrueLblName, FalseLblName) ->
[Size] = create_gcsafe_regs(1),
[SuccessLbl] = create_lbls(1),
SLblName = hipe_rtl:label_name(SuccessLbl),
@@ -597,7 +613,7 @@ skip_bits_all(Unit,Ms, TrueLblName,FalseLblName) ->
update_offset(BinSize,Ms),
hipe_rtl:mk_goto(TrueLblName)].
-test_alignment_code(Size,Unit,SLblName,FalseLblName) ->
+test_alignment_code(Size, Unit, SLblName, FalseLblName) ->
case Unit of
1 -> [hipe_rtl:mk_goto(SLblName)];
2 -> get_fast_test_code(Size,1,SLblName,FalseLblName);
@@ -608,13 +624,13 @@ test_alignment_code(Size,Unit,SLblName,FalseLblName) ->
_ -> get_slow_test_code(Size,Unit,SLblName,FalseLblName)
end.
-get_fast_test_code(Size,AndTest,SLblName,FalseLblName) ->
+get_fast_test_code(Size, AndTest, SLblName, FalseLblName) ->
[Tmp] = create_gcsafe_regs(1),
- [hipe_rtl:mk_alub(Tmp,Size,'and',hipe_rtl:mk_imm(AndTest),
- eq,SLblName,FalseLblName)].
+ [hipe_rtl:mk_alub(Tmp, Size, 'and', hipe_rtl:mk_imm(AndTest),
+ 'eq', SLblName, FalseLblName)].
%% This is really slow
-get_slow_test_code(Size,Unit,SLblName,FalseLblName) ->
+get_slow_test_code(Size, Unit, SLblName, FalseLblName) ->
[Tmp] = create_gcsafe_regs(1),
[LoopLbl,Lbl1,Lbl2] = create_lbls(3),
LoopLblName = hipe_rtl:label_name(LoopLbl),
@@ -638,7 +654,7 @@ skip_bits2(Ms, NoOfBits, TrueLblName, FalseLblName) ->
[hipe_rtl:mk_branch(BinSize, 'ltu', NewOffset, FalseLblName,
hipe_rtl:label_name(TempLbl), 0.01),
TempLbl,
- update_offset(NewOffset,Ms),
+ update_offset(NewOffset, Ms),
hipe_rtl:mk_goto(TrueLblName)].
add_to_offset(Result, Extra, Original, FalseLblName) ->
@@ -685,7 +701,7 @@ get_base(Orig,Base) ->
[hipe_tagscheme:test_heap_binary(Orig, hipe_rtl:label_name(HeapLbl),
hipe_rtl:label_name(REFCLbl)),
HeapLbl,
- hipe_rtl:mk_alu(Base, Orig, add, hipe_rtl:mk_imm(?HEAP_BIN_DATA-2)),
+ hipe_rtl:mk_alu(Base, Orig, 'add', hipe_rtl:mk_imm(?HEAP_BIN_DATA-2)),
hipe_rtl:mk_goto(hipe_rtl:label_name(EndLbl)),
REFCLbl,
hipe_rtl:mk_load(Base, Orig, hipe_rtl:mk_imm(?PROC_BIN_BYTES-2)),
@@ -761,8 +777,7 @@ unsafe(Flags) ->
end.
update_offset(NewOffset, Ms) ->
- set_field_from_term({matchstate,{matchbuffer,offset}},
- Ms, NewOffset).
+ set_field_from_term({matchstate, {matchbuffer, offset}}, Ms, NewOffset).
opt_update_ms([NewMs], OldMs) ->
[hipe_rtl:mk_move(NewMs, OldMs)];
@@ -774,7 +789,7 @@ update_ms(NewMs, OldMs) ->
create_lbls(0) ->
[];
-create_lbls(X) when X > 0->
+create_lbls(X) when X > 0 ->
[hipe_rtl:mk_new_label()|create_lbls(X-1)].
make_dyn_prep(SizeReg, CCode) ->
@@ -1101,9 +1116,12 @@ multiply_code(List=[Head|_Tail], Variable, Result, FalseLblName) ->
multiply_code([ShiftSize|Rest], Register, Result, FalseLblName, Tmp1, OldCode) ->
SuccessLbl = hipe_rtl:mk_new_label(),
- Code = OldCode ++ [hipe_rtl:mk_alu(Tmp1, Register, sll, hipe_rtl:mk_imm(ShiftSize)),
- hipe_rtl:mk_alub(Result, Tmp1, 'add', Result, not_overflow, hipe_rtl:label_name(SuccessLbl), FalseLblName, 0.99),
- SuccessLbl],
+ Code =
+ OldCode ++
+ [hipe_rtl:mk_alu(Tmp1, Register, sll, hipe_rtl:mk_imm(ShiftSize)),
+ hipe_rtl:mk_alub(Result, Tmp1, 'add', Result, not_overflow,
+ hipe_rtl:label_name(SuccessLbl), FalseLblName, 0.99),
+ SuccessLbl],
multiply_code(Rest, Register, Result, FalseLblName, Tmp1, Code);
multiply_code([], _Register, _Result, _FalseLblName, _Tmp1, Code) ->
Code.
diff --git a/lib/hipe/rtl/hipe_tagscheme.erl b/lib/hipe/rtl/hipe_tagscheme.erl
index 0cc6c2deec..f1e8d1ef41 100644
--- a/lib/hipe/rtl/hipe_tagscheme.erl
+++ b/lib/hipe/rtl/hipe_tagscheme.erl
@@ -2,7 +2,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2001-2011. All Rights Reserved.
+%% Copyright Ericsson AB 2001-2013. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -20,7 +20,7 @@
%%========================================================================
%%
%% Filename : hipe_tagscheme.erl
-%% Note : This is specific to Erlang 5.* (i.e. R9 to R13).
+%% Note : This is specific to Erlang 5.* (i.e. starting with R9).
%%
%% Modifications:
%% 020904: Happi - added support for external pids and ports.
diff --git a/lib/tools/src/cover.erl b/lib/tools/src/cover.erl
index dfcfc3675f..c2c627abe0 100644
--- a/lib/tools/src/cover.erl
+++ b/lib/tools/src/cover.erl
@@ -1139,9 +1139,14 @@ remote_collect(Module,Nodes,Stop) ->
do_collection(Node, Module, Stop) ->
CollectorPid = spawn(fun collector_proc/0),
- remote_call(Node,{remote,collect,Module,CollectorPid, self()}),
- if Stop -> remote_call(Node,{remote,stop});
- true -> ok
+ case remote_call(Node,{remote,collect,Module,CollectorPid, self()}) of
+ {error,node_dead} ->
+ CollectorPid ! done,
+ ok;
+ ok when Stop ->
+ remote_call(Node,{remote,stop});
+ ok ->
+ ok
end.
%% Process which receives chunks of data from remote nodes - either when
diff --git a/lib/tools/test/cover_SUITE.erl b/lib/tools/test/cover_SUITE.erl
index 5abc5c41b1..c033be98a3 100644
--- a/lib/tools/test/cover_SUITE.erl
+++ b/lib/tools/test/cover_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2001-2012. All Rights Reserved.
+%% Copyright Ericsson AB 2001-2013. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -27,7 +27,8 @@
dont_reconnect_after_stop/1, stop_node_after_disconnect/1,
export_import/1,
otp_5031/1, eif/1, otp_5305/1, otp_5418/1, otp_6115/1, otp_7095/1,
- otp_8188/1, otp_8270/1, otp_8273/1, otp_8340/1]).
+ otp_8188/1, otp_8270/1, otp_8273/1, otp_8340/1,
+ otp_10979_hanging_node/1]).
-include_lib("test_server/include/test_server.hrl").
@@ -52,7 +53,7 @@ all() ->
dont_reconnect_after_stop, stop_node_after_disconnect,
export_import, otp_5031, eif, otp_5305, otp_5418,
otp_6115, otp_7095, otp_8188, otp_8270, otp_8273,
- otp_8340];
+ otp_8340, otp_10979_hanging_node];
_pid ->
{skip,
"It looks like the test server is running "
@@ -1381,6 +1382,25 @@ comprehension_8188(Cf) ->
ok.
+otp_10979_hanging_node(_Config) ->
+
+ P1 = processes(),
+
+ cover:stop(non_existing_node),
+ cover:stop(),
+
+ P2 = processes(),
+
+ case P2--P1 of
+ [] ->
+ ok;
+ New ->
+ [io:format("New: ~p, ~p~n",[P,process_info(P)]) || P<-New],
+ ct:fail(hanging_process)
+ end,
+
+ ok.
+
%%--Auxiliary------------------------------------------------------------
analyse_expr(Expr, Config) ->