diff options
60 files changed, 1644 insertions, 485 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/erts/test/nt_SUITE.erl b/erts/test/nt_SUITE.erl index f9bd15a0ce..7580a7b364 100644 --- a/erts/test/nt_SUITE.erl +++ b/erts/test/nt_SUITE.erl @@ -270,8 +270,11 @@ service_prio(Config) when is_list(Config) -> ?line {ok, OldProcs} = get_current_procs(Config), ?line start_service(Name), ?line {ok, NewProcs} = get_current_procs(Config), + timer:sleep(2000), + ?line {ok, NewProcs2} = get_current_procs(Config), ?line remove_service(Name), ?line Diff = arrived_procs(OldProcs,NewProcs), + io:format("NewProcs ~p~n after sleep~n ~p~n",[Diff, arrived_procs(OldProcs,NewProcs2)]), %% Not really correct, could fail if another heart is %% started at the same time... ?line {value, {"heart.exe",_,"high"}} = diff --git a/lib/common_test/src/unix_telnet.erl b/lib/common_test/src/unix_telnet.erl index 99ce92e9f1..71df2ab44e 100644 --- a/lib/common_test/src/unix_telnet.erl +++ b/lib/common_test/src/unix_telnet.erl @@ -94,11 +94,16 @@ connect(Ip,Port,Timeout,KeepAlive,Extra) -> {Username,Password} -> connect1(Ip,Port,Timeout,KeepAlive,Username,Password); Name -> - case get_username_and_password(Name) of - {ok,{Username,Password}} -> - connect1(Ip,Port,Timeout,KeepAlive,Username,Password); - Error -> - Error + case not_require_user_and_pass(Name) of + true -> + connect_without_username_and_pass(Ip,Port,Timeout,KeepAlive); + _ -> + case get_username_and_password(Name) of + {ok,{Username,Password}} -> + connect1(Ip,Port,Timeout,KeepAlive,Username,Password); + Error -> + Error + end end end. @@ -144,6 +149,27 @@ connect1(Ip,Port,Timeout,KeepAlive,Username,Password) -> end_log(), Result. +connect_without_username_and_pass(Ip,Port,Timeout,KeepAlive) -> + start_log("unix_telnet:connect"), + Result = + case ct_telnet_client:open(Ip,Port,Timeout,KeepAlive) of + {ok,Pid} -> + {ok, Pid}; + Error -> + cont_log("Could not open telnet connection\n~p\n",[Error]), + Error + end, + end_log(), + Result. + +not_require_user_and_pass(Name) -> + case ct:get_config({Name, not_require_user_and_pass}) of + undefined -> + false; + _ -> + true + end. + get_username_and_password(Name) -> case ct:get_config({Name,username}) of undefined -> diff --git a/lib/common_test/test/Makefile b/lib/common_test/test/Makefile index bd746f87a7..a9ebd8f1d3 100644 --- a/lib/common_test/test/Makefile +++ b/lib/common_test/test/Makefile @@ -58,7 +58,8 @@ MODULES= \ ct_group_leader_SUITE \ ct_cover_SUITE \ ct_groups_search_SUITE \ - ct_surefire_SUITE + ct_surefire_SUITE \ + ct_telnet_SUITE ERL_FILES= $(MODULES:%=%.erl) diff --git a/lib/common_test/test/ct_telnet_SUITE.erl b/lib/common_test/test/ct_telnet_SUITE.erl new file mode 100644 index 0000000000..b4f24baa0c --- /dev/null +++ b/lib/common_test/test/ct_telnet_SUITE.erl @@ -0,0 +1,122 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2009-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% +%% + +%%%------------------------------------------------------------------- +%%% File: ct_telnet_SUITE +%%% +%%% Description: +%%% Edit your ts.unix.config or ts.win32.config before runnings these tests +%%% Test ct_telnet_SUITE module +%%% +%%%------------------------------------------------------------------- +-module(ct_telnet_SUITE). +-compile(export_all). + +-include_lib("common_test/include/ct.hrl"). +-include_lib("common_test/include/ct_event.hrl"). + +-define(eh, ct_test_support_eh). + +%%-------------------------------------------------------------------- +%% TEST SERVER CALLBACK FUNCTIONS +%%-------------------------------------------------------------------- + +%%-------------------------------------------------------------------- +%% Description: Since Common Test starts another Test Server +%% instance, the tests need to be performed on a separate node (or +%% there will be clashes with logging processes etc). +%%-------------------------------------------------------------------- +init_per_suite(Config) -> + ct_test_support:init_per_suite(Config). + +end_per_suite(Config) -> + ct_test_support:end_per_suite(Config). + +init_per_testcase(TestCase, Config) -> + ct_test_support:init_per_testcase(TestCase, Config). + +end_per_testcase(TestCase, Config) -> + ct_test_support:end_per_testcase(TestCase, Config). + +suite() -> [{ct_hooks,[ts_install_cth]}]. + +all() -> + [ + default + ]. + +%%-------------------------------------------------------------------- +%% TEST CASES +%%-------------------------------------------------------------------- + +%%%----------------------------------------------------------------- +%%% +default(Config) when is_list(Config) -> + DataDir = ?config(data_dir, Config), + Suite = filename:join(DataDir, "ct_telnet_basic_SUITE"), + Cfg = {unix, ct:get_config(unix)}, + ok = file:write_file(filename:join(DataDir, "telnet.cfg"), io_lib:write(Cfg) ++ "."), + CfgFile = filename:join(DataDir, "telnet.cfg"), + {Opts,ERPid} = setup([{suite,Suite},{label,default}, {config, CfgFile}], Config), + ok = execute(default, Opts, ERPid, Config). + +%%%----------------------------------------------------------------- +%%% HELP FUNCTIONS +%%%----------------------------------------------------------------- + +setup(Test, Config) -> + Opts0 = ct_test_support:get_opts(Config), + Level = ?config(trace_level, Config), + EvHArgs = [{cbm,ct_test_support},{trace_level,Level}], + Opts = Opts0 ++ [{event_handler,{?eh,EvHArgs}}|Test], + ERPid = ct_test_support:start_event_receiver(Config), + {Opts,ERPid}. + +execute(Name, Opts, ERPid, Config) -> + ok = ct_test_support:run(Opts, Config), + Events = ct_test_support:get_events(ERPid, Config), + + ct_test_support:log_events(Name, + reformat(Events, ?eh), + ?config(priv_dir, Config), + Opts), + + TestEvents = events_to_check(Name,Config), + ct_test_support:verify_events(TestEvents, Events, Config). + +reformat(Events, EH) -> + ct_test_support:reformat(Events, EH). + +%%%----------------------------------------------------------------- +%%% TEST EVENTS +%%%----------------------------------------------------------------- +events_to_check(default,Config) -> + {module,_} = code:load_abs(filename:join(?config(data_dir,Config), + ct_telnet_basic_SUITE)), + TCs = ct_telnet_basic_SUITE:all(), + code:purge(ct_telnet_basic_SUITE), + code:delete(ct_telnet_basic_SUITE), + + OneTest = + [{?eh,start_logging,{'DEF','RUNDIR'}}] ++ + [{?eh,tc_done,{ct_telnet_basic_SUITE,TC,ok}} || TC <- TCs] ++ + [{?eh,stop_logging,[]}], + + %% 2 tests (ct:run_test + script_start) is default + OneTest ++ OneTest. diff --git a/lib/common_test/test/ct_telnet_SUITE_data/ct_telnet_basic_SUITE.erl b/lib/common_test/test/ct_telnet_SUITE_data/ct_telnet_basic_SUITE.erl new file mode 100644 index 0000000000..914b95f9cf --- /dev/null +++ b/lib/common_test/test/ct_telnet_SUITE_data/ct_telnet_basic_SUITE.erl @@ -0,0 +1,78 @@ +%% Modify your ts.unix.config or ts.win32.config file before running these tests +-module(ct_telnet_basic_SUITE). + +-compile(export_all). + +-include_lib("common_test/include/ct.hrl"). + +%%-------------------------------------------------------------------- +%% TEST SERVER CALLBACK FUNCTIONS +%%-------------------------------------------------------------------- + +init_per_suite(Config) -> + Config. + +end_per_suite(_Config) -> + ok. + + +suite() -> [{require,telnet_temp,{unix,[telnet]}}]. + +all() -> + [start_stop, send_and_get, expect, already_closed, + cmd, sendf, close_wrong_type]. + +groups() -> + []. + +init_per_group(_GroupName, Config) -> + Config. + +end_per_group(_GroupName, Config) -> + Config. + +start_stop(_Config) -> + {ok, Handle} = ct_telnet:open(telnet_temp), + ok = ct_telnet:close(Handle), + ok. +send_and_get(_) -> + {ok, Handle} = ct_telnet:open(telnet_temp), + ok = ct_telnet:send(Handle, "ayt"), + {ok, _Data} = ct_telnet:get_data(Handle), + ok = ct_telnet:close(Handle), + ok. + +expect(_) -> + {ok, Handle} = ct_telnet:open(telnet_temp), + ok = ct_telnet:send(Handle, "echo ayt"), + ok = case ct_telnet:expect(Handle, ["ayt"]) of + {ok, _} -> + ok; + {error, {prompt, _}} -> + ok + end, + ok = ct_telnet:close(Handle), + ok. + +already_closed(_) -> + {ok, Handle} = ct_telnet:open(telnet_temp), + ok = ct_telnet:close(Handle), + {error, already_closed} = ct_telnet:close(Handle), + ok. + +cmd(_) -> + {ok, Handle} = ct_telnet:open(telnet_temp), + {ok, _} = ct_telnet:cmd(Handle, "display"), + {ok, _} = ct_telnet:cmdf(Handle, "~s ~s", ["set", "bsasdel"]), + ok = ct_telnet:close(Handle), + ok. + +sendf(_) -> + {ok, Handle} = ct_telnet:open(telnet_temp), + ok = ct_telnet:sendf(Handle, "~s", ["ayt"]), + ok = ct_telnet:close(Handle), + ok. + +close_wrong_type(_) -> + {error, _} = ct_telnet:close(whatever), + ok. 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/mnesia/test/mnesia.spec b/lib/mnesia/test/mnesia.spec index 653e515317..e4746fe14c 100644 --- a/lib/mnesia/test/mnesia.spec +++ b/lib/mnesia/test/mnesia.spec @@ -1,4 +1,4 @@ -{suites,"../mnesia_test",all}. +{suites,"../mnesia_test",[mnesia_SUITE]}. {skip_cases,"../mnesia_test",mnesia_measure_test, [ram_meter], "Takes to long time"}. diff --git a/lib/mnesia/test/mnesia_config_test.erl b/lib/mnesia/test/mnesia_config_test.erl index f0f3053ebf..6baf86a4a5 100644 --- a/lib/mnesia/test/mnesia_config_test.erl +++ b/lib/mnesia/test/mnesia_config_test.erl @@ -596,8 +596,8 @@ dump_log_load_regulation(Config) when is_list(Config) -> {n_branches, length(Nodes) * 10}, {n_accounts_per_branch, 5}, {replica_type, disc_copies}, - {stop_after, timer:seconds(30)}, - {report_interval, timer:seconds(10)}, + {stop_after, timer:seconds(15)}, + {report_interval, timer:seconds(3)}, {use_running_mnesia, true}, {reuse_history_id, true}], diff --git a/lib/mnesia/test/mnesia_durability_test.erl b/lib/mnesia/test/mnesia_durability_test.erl index 2fee72f066..1de62a7d25 100644 --- a/lib/mnesia/test/mnesia_durability_test.erl +++ b/lib/mnesia/test/mnesia_durability_test.erl @@ -100,14 +100,14 @@ load_latest_data(Config) when is_list(Config) -> ?match([], mnesia_test_lib:start_mnesia([N1], [])), %% Should wait for N2 - ?match({timeout, [t1]}, rpc:call(N1, mnesia, wait_for_tables, [[t1], 3000])), + ?match({timeout, [t1]}, rpc:call(N1, mnesia, wait_for_tables, [[t1], 1000])), ?match([], mnesia_test_lib:start_mnesia([N3], [])), - ?match({timeout, [t1]}, rpc:call(N1, mnesia, wait_for_tables, [[t1], 3000])), + ?match({timeout, [t1]}, rpc:call(N1, mnesia, wait_for_tables, [[t1], 1000])), ?match([], mnesia_test_lib:start_mnesia([N2], [])), - ?match(ok, rpc:call(N2, mnesia, wait_for_tables, [[t1], 3000])), - ?match(ok, rpc:call(N1, mnesia, wait_for_tables, [[t1], 3000])), + ?match(ok, rpc:call(N2, mnesia, wait_for_tables, [[t1], 10000])), + ?match(ok, rpc:call(N1, mnesia, wait_for_tables, [[t1], 10000])), %% We should find the record ?match([Rec2], rpc:call(N1, mnesia, dirty_read, [t1, test])), ?match([Rec2], rpc:call(N2, mnesia, dirty_read, [t1, test])), @@ -124,12 +124,12 @@ load_latest_data(Config) when is_list(Config) -> ?match([], mnesia_test_lib:start_mnesia([N2], [])), %% Should wait for N1 - ?match({timeout, [t1]}, rpc:call(N2, mnesia, wait_for_tables, [[t1], 2000])), + ?match({timeout, [t1]}, rpc:call(N2, mnesia, wait_for_tables, [[t1], 1000])), ?match([], mnesia_test_lib:start_mnesia([N3], [])), - ?match({timeout, [t1]}, rpc:call(N2, mnesia, wait_for_tables, [[t1], 2000])), + ?match({timeout, [t1]}, rpc:call(N2, mnesia, wait_for_tables, [[t1], 1000])), ?match([], mnesia_test_lib:start_mnesia([N1], [])), - ?match(ok, rpc:call(N2, mnesia, wait_for_tables, [[t1], 1000])), - ?match(ok, rpc:call(N1, mnesia, wait_for_tables, [[t1], 1000])), + ?match(ok, rpc:call(N2, mnesia, wait_for_tables, [[t1], 10000])), + ?match(ok, rpc:call(N1, mnesia, wait_for_tables, [[t1], 10000])), %% We should find the record ?match([Rec1], rpc:call(N1, mnesia, dirty_read, [t1, test])), ?match([Rec1], rpc:call(N2, mnesia, dirty_read, [t1, test])), diff --git a/lib/mnesia/test/mnesia_examples_test.erl b/lib/mnesia/test/mnesia_examples_test.erl index 373d47a05a..219f358fdb 100644 --- a/lib/mnesia/test/mnesia_examples_test.erl +++ b/lib/mnesia/test/mnesia_examples_test.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1997-2010. All Rights Reserved. +%% Copyright Ericsson AB 1997-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 @@ -34,32 +34,6 @@ end_per_testcase(Func, Conf) -> delete_schema], N, Config, ?FILE, ?LINE)). -opt_net_load(ExampleMod) -> - opt_net_load([node() | nodes()], ExampleMod, ok). - -opt_net_load([Node | Nodes], ExampleMod, Res) -> - case rpc:call(Node, ?MODULE, opt_load, [ExampleMod]) of - {module, ExampleMod} -> - opt_net_load(Nodes, ExampleMod, Res); - {error, Reason} -> - Error = {opt_net_load, ExampleMod, Node, Reason}, - opt_net_load(Nodes, ExampleMod, {error, Error}); - {badrpc, Reason} -> - Error = {opt_net_load, ExampleMod, Node, Reason}, - opt_net_load(Nodes, ExampleMod, {error, Error}) - end; -opt_net_load([], _ExampleMod, Res) -> - Res. - -opt_load(Mod) -> - case code:is_loaded(Mod) of - {file, _} -> - {module, Mod}; - false -> - Abs = filename:join([code:lib_dir(mnesia), examples, Mod]), - code:load_abs(Abs) - end. - %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% all() -> [bup, company, meter, {group, tpcb}]. @@ -95,49 +69,49 @@ replica_test(suite) -> []; replica_test(Config) when is_list(Config) -> ?init(3, Config), opt_net_load(mnesia_tpcb), - ?match({ok, _}, mnesia_tpcb:start(mnesia_tpcb:config(replica_test, ram_copies))). + ?match({ok, _}, mnesia_tpcb:start(config(replica_test, ram_copies))). sticky_replica_test(suite) -> []; sticky_replica_test(Config) when is_list(Config) -> ?init(3, Config), opt_net_load(mnesia_tpcb), - ?match({ok, _}, mnesia_tpcb:start(mnesia_tpcb:config(sticky_replica_test, ram_copies))). + ?match({ok, _}, mnesia_tpcb:start(config(sticky_replica_test, ram_copies))). dist_test(suite) -> []; dist_test(Config) when is_list(Config) -> ?init(3, [{tc_timeout, timer:minutes(10)} | Config]), opt_net_load(mnesia_tpcb), - ?match({ok, _}, mnesia_tpcb:start(mnesia_tpcb:config(dist_test, ram_copies))). + ?match({ok, _}, mnesia_tpcb:start(config(dist_test, ram_copies))). conflict_test(suite) -> []; conflict_test(Config) when is_list(Config) -> ?init(3, Config), opt_net_load(mnesia_tpcb), - ?match({ok, _}, mnesia_tpcb:start(mnesia_tpcb:config(conflict_test, ram_copies))). + ?match({ok, _}, mnesia_tpcb:start(config(conflict_test, ram_copies))). frag_test(suite) -> []; frag_test(Config) when is_list(Config) -> ?init(3, Config), opt_net_load(mnesia_tpcb), - ?match({ok, _}, mnesia_tpcb:start(mnesia_tpcb:config(frag_test, ram_copies))). + ?match({ok, _}, mnesia_tpcb:start(config(frag_test, ram_copies))). frag2_test(suite) -> []; frag2_test(Config) when is_list(Config) -> ?init(3, Config), opt_net_load(mnesia_tpcb), - ?match({ok, _}, mnesia_tpcb:start(mnesia_tpcb:config(frag2_test, ram_copies))). + ?match({ok, _}, mnesia_tpcb:start(config(frag2_test, ram_copies))). remote_test(suite) -> []; remote_test(Config) when is_list(Config) -> ?init(3, Config), opt_net_load(mnesia_tpcb), - ?match({ok, _}, mnesia_tpcb:start(mnesia_tpcb:config(remote_test, ram_copies))). + ?match({ok, _}, mnesia_tpcb:start(config(remote_test, ram_copies))). remote_frag2_test(suite) -> []; remote_frag2_test(Config) when is_list(Config) -> ?init(3, Config), opt_net_load(mnesia_tpcb), - ?match({ok, _}, mnesia_tpcb:start(mnesia_tpcb:config(remote_frag2_test, ram_copies))). + ?match({ok, _}, mnesia_tpcb:start(config(remote_frag2_test, ram_copies))). %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% meter(doc) -> @@ -149,4 +123,37 @@ meter(Config) when is_list(Config) -> opt_net_load(mnesia_meter), ?match(ok, mnesia_meter:go(ram_copies, [N])). +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +config(Test, Type) -> + Config0 = mnesia_tpcb:config(Test, Type), + %% Cut the times, the idea is to test the example and configuration + %% not running the test a long time + Config1 = lists:keyreplace(stop_after, 1, Config0, {stop_after, 6000}), + lists:keyreplace(report_interval, 1, Config1, {report_interval, 1000}). + +opt_net_load(ExampleMod) -> + opt_net_load([node() | nodes()], ExampleMod, ok). + +opt_net_load([Node | Nodes], ExampleMod, Res) -> + case rpc:call(Node, ?MODULE, opt_load, [ExampleMod]) of + {module, ExampleMod} -> + opt_net_load(Nodes, ExampleMod, Res); + {error, Reason} -> + Error = {opt_net_load, ExampleMod, Node, Reason}, + opt_net_load(Nodes, ExampleMod, {error, Error}); + {badrpc, Reason} -> + Error = {opt_net_load, ExampleMod, Node, Reason}, + opt_net_load(Nodes, ExampleMod, {error, Error}) + end; +opt_net_load([], _ExampleMod, Res) -> + Res. +opt_load(Mod) -> + case code:is_loaded(Mod) of + {file, _} -> + {module, Mod}; + false -> + Abs = filename:join([code:lib_dir(mnesia), examples, Mod]), + code:load_abs(Abs) + end. diff --git a/lib/mnesia/test/mnesia_recovery_test.erl b/lib/mnesia/test/mnesia_recovery_test.erl index c4910a4b11..0d0ad32fb0 100644 --- a/lib/mnesia/test/mnesia_recovery_test.erl +++ b/lib/mnesia/test/mnesia_recovery_test.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2012. All Rights Reserved. +%% Copyright Ericsson AB 1996-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 @@ -607,7 +607,7 @@ explicit_stop_during_snmp(Config) when is_list(Config) -> Do_trans_Pid1 = spawn_link(Node2, ?MODULE, do_trans_loop, [Tab, self()]), Do_trans_Pid2 = spawn_link(?MODULE, do_trans_loop, [Tab, self()]), - Start_stop_Pid = spawn_link(?MODULE, start_stop, [Node1, 10, self()]), + Start_stop_Pid = spawn_link(?MODULE, start_stop, [Node1, 5, self()]), receive test_done -> ok @@ -631,13 +631,13 @@ do_trans_loop2(Tab, Father) -> end, case mnesia:transaction(Trans) of {atomic, ok} -> - timer:sleep(200), + timer:sleep(100), do_trans_loop2(Tab, Father); {aborted, {node_not_running, N}} when N == node() -> - timer:sleep(200), + timer:sleep(100), do_trans_loop2(Tab, Father); {aborted, {no_exists, Tab}} -> - timer:sleep(200), + timer:sleep(100), do_trans_loop2(Tab, Father); Else -> ?error("Transaction failed: ~p ~n", [Else]), @@ -649,9 +649,9 @@ start_stop(_Node1, 0, Father) -> Father ! test_done, exit(shutdown); start_stop(Node1, N, Father) when N > 0-> - timer:sleep(timer:seconds(5)), - ?match(stopped, rpc:call(Node1, mnesia, stop, [])), timer:sleep(timer:seconds(2)), + ?match(stopped, rpc:call(Node1, mnesia, stop, [])), + timer:sleep(timer:seconds(1)), ?match([], mnesia_test_lib:start_mnesia([Node1])), start_stop(Node1, N-1, Father). diff --git a/lib/odbc/c_src/odbcserver.c b/lib/odbc/c_src/odbcserver.c index a6b3de6e48..5730e20774 100644 --- a/lib/odbc/c_src/odbcserver.c +++ b/lib/odbc/c_src/odbcserver.c @@ -1222,7 +1222,7 @@ static db_result_msg encode_out_params(db_state *state, (column.type.strlen_or_indptr_array[j])); break; case SQL_C_SLONG: - ei_x_encode_long(&dynamic_buffer(state), ((long*)values)[j]); + ei_x_encode_long(&dynamic_buffer(state), ((SQLINTEGER*)values)[j]); break; case SQL_C_DOUBLE: ei_x_encode_double(&dynamic_buffer(state), diff --git a/lib/odbc/test/odbc_query_SUITE.erl b/lib/odbc/test/odbc_query_SUITE.erl index 062373afa0..56550bfaa6 100644 --- a/lib/odbc/test/odbc_query_SUITE.erl +++ b/lib/odbc/test/odbc_query_SUITE.erl @@ -43,7 +43,7 @@ suite() -> [{ct_hooks,[ts_install_cth]}]. all() -> case odbc_test_lib:odbc_check() of ok -> - [sql_query, next, {group, scrollable_cursors}, select_count, + [stored_proc, sql_query, next, {group, scrollable_cursors}, select_count, select_next, select_relative, select_absolute, create_table_twice, delete_table_twice, duplicate_key, not_connection_owner, no_result_set, query_error, @@ -172,6 +172,26 @@ end_per_testcase(_Case, Config) -> %%------------------------------------------------------------------------- %% Test cases starts here. %%------------------------------------------------------------------------- +stored_proc(doc)-> + ["Test stored proc with OUT param"]; +stored_proc(suite) -> []; +stored_proc(Config) when is_list(Config) -> + case ?RDBMS of + X when X == oracle; X == postgres-> + Ref = ?config(connection_ref, Config), + {updated, _} = + odbc:sql_query(Ref, + ?RDBMS:stored_proc_integer_out()), + Result = ?RDBMS:query_result(), + Result = + ?RDBMS:param_query(Ref), + {updated, _} = + odbc:sql_query(Ref, ?RDBMS:drop_proc()), + ok; + _ -> + {skip, "stored proc not yet supported"} + end. + sql_query(doc)-> ["Test the common cases"]; sql_query(suite) -> []; diff --git a/lib/odbc/test/oracle.erl b/lib/odbc/test/oracle.erl index d74863d8c1..95cf7155dc 100644 --- a/lib/odbc/test/oracle.erl +++ b/lib/odbc/test/oracle.erl @@ -240,3 +240,30 @@ describe_floating() -> {ok,[{"F",sql_double},{"R",sql_double},{"D",sql_double}]}. describe_dec_num() -> {ok,[{"MYDEC",{sql_decimal,9,3}},{"MYNUM",{sql_decimal,9,2}}]}. + +%------------------------------------------------------------------------- +drop_proc() -> + "drop procedure test_proc1;". + +stored_proc_integer_out() -> + "create or replace PROCEDURE test_proc1(" ++ + "int_a OUT NUMBER, " ++ + "int_b OUT NUMBER) " ++ + "is " ++ + "begin " ++ + " int_a := 123; " ++ + " int_b := 456; " ++ + "exception " ++ + "WHEN NO_DATA_FOUND THEN " ++ + " int_a := 0; " ++ + " int_b := 0; " ++ + "end;". + +param_query(Ref) -> + odbc:param_query(Ref, "call test_proc1(?,?)", + [{sql_integer, out, [0]}, + {sql_integer, out, [0]}]). + + +query_result() -> + {executed, 2, [{123, 456}]}. diff --git a/lib/odbc/test/postgres.erl b/lib/odbc/test/postgres.erl index d564dbd5ff..0c1761b835 100644 --- a/lib/odbc/test/postgres.erl +++ b/lib/odbc/test/postgres.erl @@ -293,3 +293,42 @@ describe_dec_num() -> describe_timestamp() -> {ok, [{"field", sql_timestamp}]}. + +%------------------------------------------------------------------------- +drop_proc() -> + "drop function test_proc1(OUT integer, OUT integer);". + +stored_proc_integer_out() -> + "create or replace FUNCTION test_proc1(" ++ + "OUT int_a INTEGER, " ++ + "OUT int_b INTEGER) " ++ + "AS $$ " ++ + "BEGIN " ++ + " int_a := 123; " ++ + " int_b := 456; " ++ + "END " ++ + "$$ LANGUAGE plpgsql ". + +%% This does not test what you might think it is supposed to test. +%% Since the stored procedure has got 2 out parameters and no +%% in parameters it is of arity 0 as called below. +%% +%% The port program odbcserver.c will marshal these out parameters +%% and hand them to ODBC. The ODBC driver for postgres will +%% apparently not give a hoot about these out parameters and instead +%% return the result in a regular result select set. The port program +%% will assume it has the result in the out parameters and marshal +%% these as they are i.e as it itself had packed them, so they +%% come back unchanged. +%% +%% The real function result goes into the void but the code in odbcserver.c +%% that marshals out parameters returned from ODBC will be run +%% so that is what this test tests... +%% +param_query(Ref) -> + odbc:param_query(Ref, "select * from test_proc1()", + [{sql_integer, out, [111]}, + {sql_integer, out, [444]}]). + +query_result() -> + {executed, 2, [{111, 444}]}. diff --git a/lib/orber/COSS/CosNaming/orber_cosnaming_utils.erl b/lib/orber/COSS/CosNaming/orber_cosnaming_utils.erl index 768653c898..aa582d1d4e 100644 --- a/lib/orber/COSS/CosNaming/orber_cosnaming_utils.erl +++ b/lib/orber/COSS/CosNaming/orber_cosnaming_utils.erl @@ -30,7 +30,7 @@ -include("CosNaming_NamingContext.hrl"). -include("CosNaming_NamingContextExt.hrl"). -include_lib("orber/include/corba.hrl"). - +-include_lib("orber/src/orber_iiop.hrl"). %%----------------------------------------------------------------- %% External exports @@ -182,6 +182,8 @@ address(protocol, [$:|T], [], []) -> address(version, T, [], [iiop]); address(protocol, [$i, $i, $o, $p, $:|T], [], []) -> address(version, T, [], [iiop]); +address(protocol, [$s,$s,$l, $i, $o, $p, $:|T], [], []) -> + address(version, T, [], [ssliop]); address(protocol, [$r, $i, $r, $:|T], [], []) -> {false, rir, T}; address(protocol, What, _, _) -> @@ -465,6 +467,20 @@ lookup({corbaname, [[iiop, Vers, Host, Port]|Addresses], Key, Name}, Ctx) -> Obj -> Obj end; +%%% Corbaname via SSL +lookup({corbaname, [[ssliop, Vers, Host, Port]|Addresses], Key, Name}, Ctx) -> + SSLComponent = + #'IOP_TaggedComponent'{tag=?TAG_SSL_SEC_TRANS, + component_data=#'SSLIOP_SSL'{target_supports = 2, + target_requires = 2, + port = Port}}, + NS = iop_ior:create_external(Vers, key2id(Key), Host, Port, Key, [SSLComponent]), + case catch 'CosNaming_NamingContext':resolve(NS, Ctx, Name) of + {'EXCEPTION', _} -> + lookup({corbaname, Addresses, Key, Name}, Ctx); + Obj -> + Obj + end; lookup({corbaname, [_|Addresses], Key, Name}, Ctx) -> lookup({corbaname, Addresses, Key, Name}, Ctx); @@ -498,7 +514,43 @@ lookup({corbaloc, [[iiop, Vers, Host, Port]|Addresses], Key}, Ctx) -> lookup({corbaloc, Addresses, Key}, Ctx) end end; - + +%%% Corbaloc via SSL +lookup({corbaloc, [[ssliop, Vers, Host, Port]|Addresses], Key}, Ctx) -> + SSLComponent = + #'IOP_TaggedComponent'{tag=?TAG_SSL_SEC_TRANS, + component_data=#'SSLIOP_SSL'{target_supports = 2, + target_requires = 2, + port = Port}}, + ObjRef = iop_ior:create_external(Vers, key2id(Key), Host, Port, Key, [SSLComponent]), + OldVal = put(orber_forward_notify, true), + + case catch corba_object:non_existent(ObjRef, Ctx) of + {location_forward, Result} -> + put(orber_forward_notify, OldVal), + Result; + false -> + put(orber_forward_notify, OldVal), + ObjRef; + true -> + put(orber_forward_notify, OldVal), + lookup({corbaloc, Addresses, Key}, Ctx); + _ -> + %% May be located on a version using '_not_existent' + %% see CORBA2.3.1 page 15-34 try again. + case catch corba_object:not_existent(ObjRef, Ctx) of + {location_forward, Result} -> + put(orber_forward_notify, OldVal), + Result; + false -> + put(orber_forward_notify, OldVal), + ObjRef; + _ -> + put(orber_forward_notify, OldVal), + lookup({corbaloc, Addresses, Key}, Ctx) + end + end; + lookup({corbaloc, [_|Addresses], Key}, Ctx) -> lookup({corbaloc, Addresses, Key}, Ctx); diff --git a/lib/orber/doc/src/notes.xml b/lib/orber/doc/src/notes.xml index d43ab3ac24..9e896f03c8 100644 --- a/lib/orber/doc/src/notes.xml +++ b/lib/orber/doc/src/notes.xml @@ -32,6 +32,22 @@ <file>notes.xml</file> </header> + + <section><title>Orber 3.6.26</title> + + <section><title>Fixed Bugs and Malfunctions</title> + <list> + <item> + <p> + Fix bug in corbaloc/corbaname over ssl.</p> + <p> + Own Id: OTP-10675</p> + </item> + </list> + </section> + + </section> + <section><title>Orber 3.6.25</title> <section><title>Improvements and New Features</title> @@ -45,7 +61,6 @@ </list> </section> - <section><title>Known Bugs and Problems</title> <list> <item> @@ -57,7 +72,6 @@ </item> </list> </section> - </section> <section><title>Orber 3.6.24</title> diff --git a/lib/orber/src/orber_env.erl b/lib/orber/src/orber_env.erl index 8758450104..67d31018ff 100644 --- a/lib/orber/src/orber_env.erl +++ b/lib/orber/src/orber_env.erl @@ -302,6 +302,7 @@ create_security_info(ssl, Info) -> "SSL IIOP accept timeout.......: ~p~n" "SSL IIOP backlog..............: ~p~n" "SSL IIOP Local Interface......: ~p~n" + "SSL server options............: ~p~n" "SSL server certfile...........: ~p~n" "SSL server verification type..: ~p~n" "SSL server verification depth.: ~p~n" @@ -310,6 +311,7 @@ create_security_info(ssl, Info) -> "SSL server password...........: ~p~n" "SSL server ciphers............: ~p~n" "SSL server cachetimeout.......: ~p~n" + "SSL client options............: ~p~n" "SSL client certfile...........: ~p~n" "SSL client verification type..: ~p~n" "SSL client verification depth.: ~p~n" @@ -323,10 +325,12 @@ create_security_info(ssl, Info) -> iiop_ssl_in_keepalive(), iiop_ssl_out_keepalive(), nat_iiop_ssl_port(), iiop_ssl_accept_timeout(), iiop_ssl_backlog(), iiop_ssl_ip_address_local(), + ssl_server_options(), ssl_server_certfile(), ssl_server_verify(), ssl_server_depth(), ssl_server_cacertfile(), ssl_server_keyfile(), ssl_server_password(), ssl_server_ciphers(), ssl_server_cachetimeout(), + ssl_client_options(), ssl_client_certfile(), ssl_client_verify(), ssl_client_depth(), ssl_client_cacertfile(), ssl_client_keyfile(), ssl_client_password(), diff --git a/lib/orber/vsn.mk b/lib/orber/vsn.mk index 10b19477e0..4e09532f88 100644 --- a/lib/orber/vsn.mk +++ b/lib/orber/vsn.mk @@ -1,3 +1,2 @@ - -ORBER_VSN = 3.6.25 +ORBER_VSN = 3.6.26 diff --git a/lib/reltool/src/reltool_server.erl b/lib/reltool/src/reltool_server.erl index 5e25f22a6f..97785ca7f8 100644 --- a/lib/reltool/src/reltool_server.erl +++ b/lib/reltool/src/reltool_server.erl @@ -973,7 +973,8 @@ refresh_app(#app{name = AppName, is_escript = IsEscript, active_dir = ActiveDir, label = OptLabel, - mods = Mods} = App, + mods = Mods, + status = AppStatus} = App, Force, Status) -> if @@ -993,6 +994,8 @@ refresh_app(#app{name = AppName, read_app_info(AppFile, AppFile, AppName, + ActiveDir, + AppStatus, DefaultVsn, Status), @@ -1064,9 +1067,11 @@ refresh_app(#app{name = AppName, missing_app_info(Vsn) -> #app_info{vsn = Vsn}. -read_app_info(_AppFileOrBin, _AppFile, erts, DefaultVsn, Status) -> +read_app_info(_AppFileOrBin, _AppFile, erts, _ActiveDir, _AppStatus, DefaultVsn, Status) -> {missing_app_info(DefaultVsn), Status}; -read_app_info(AppFileOrBin, AppFile, AppName, DefaultVsn, Status) -> +read_app_info(_AppFileOrBin, _AppFile, _AppName, undefined, missing, DefaultVsn, Status) -> + {missing_app_info(DefaultVsn), Status}; +read_app_info(AppFileOrBin, AppFile, AppName, _ActiveDir, _AppStatus, DefaultVsn, Status) -> EnoentText = file:format_error(enoent), case reltool_utils:prim_consult(AppFileOrBin) of {ok, [{application, AppName, Info}]} -> @@ -1080,9 +1085,9 @@ read_app_info(AppFileOrBin, AppFile, AppName, DefaultVsn, Status) -> Status)}; {error, Text} when Text =:= EnoentText -> {missing_app_info(DefaultVsn), - reltool_utils:add_warning("~w: Missing app file ~tp.", - [AppName,AppFile], - Status)}; + reltool_utils:add_warning("~w: Missing app file ~tp.", + [AppName,AppFile], + Status)}; {error, Text} -> {missing_app_info(DefaultVsn), reltool_utils:add_warning("~w: Cannot parse app file ~tp (~tp).", @@ -1773,13 +1778,15 @@ escripts_to_apps([Escript | Escripts], Apps, Status) -> get_vsn_from_dir(AppName,AppLabel), AppFileName = filename:join([Escript, FullName]), + Dir = filename:join([Escript, AppName]), {Info, StatusAcc2} = read_app_info(GetBin(), AppFileName, AppName, + Dir, + ok, DefaultVsn, Status), - Dir = filename:join([Escript, AppName]), {[{AppName, app, Dir, Info} | FileAcc], StatusAcc2}; E when E =:= Ext -> @@ -1979,20 +1986,27 @@ refresh_apps(ConfigApps, [New | NewApps], Acc, Force, Status) -> refresh_apps(_ConfigApps, [], Acc, _Force, Status) -> {lists:reverse(Acc), Status}. - ensure_app_info(#app{is_escript = IsEscript, active_dir = Dir, info = Info}, Status) when IsEscript=/=false -> %% Escript or application which is inlined in an escript {Info, Dir, Status}; -ensure_app_info(#app{name = Name, sorted_dirs = []}, _Status) -> - reltool_utils:throw_error("~w: : Missing application directory.",[Name]); +ensure_app_info(#app{name = Name, sorted_dirs = []} = App, Status) -> + Reason = "~w: Missing application directory.", + case App of + #app{incl_cond = exclude, status = missing, active_dir = Dir} -> + Status2 = reltool_utils:add_warning(Reason, [Name], Status), + {missing_app_info(""), Dir, Status2}; + _ -> + reltool_utils:throw_error(Reason, [Name]) + end; ensure_app_info(#app{name = Name, vsn = Vsn, use_selected_vsn = UseSelectedVsn, active_dir = ActiveDir, sorted_dirs = Dirs, - info = undefined}, + info = undefined, + status = AppStatus}, Status) -> ReadInfo = fun(Dir, StatusAcc) -> @@ -2000,7 +2014,8 @@ ensure_app_info(#app{name = Name, Ebin = filename:join([Dir, "ebin"]), DefaultVsn = get_vsn_from_dir(Name,Base), AppFile = filename:join([Ebin, atom_to_list(Name) ++ ".app"]), - read_app_info(AppFile, AppFile, Name, DefaultVsn, StatusAcc) + read_app_info(AppFile, AppFile, Name, ActiveDir, + AppStatus, DefaultVsn, StatusAcc) end, {AllInfo, Status2} = lists:mapfoldl(ReadInfo, Status, Dirs), AllVsns = [I#app_info.vsn || I <- AllInfo], diff --git a/lib/reltool/test/reltool_server_SUITE.erl b/lib/reltool/test/reltool_server_SUITE.erl index 23338d9ecd..adea716e99 100644 --- a/lib/reltool/test/reltool_server_SUITE.erl +++ b/lib/reltool/test/reltool_server_SUITE.erl @@ -80,6 +80,8 @@ all() -> otp_9229_dupl_mod_exclude_app, otp_9229_dupl_mod_exclude_mod, dupl_mod_in_app_file, + include_non_existing_app, + exclude_non_existing_app, get_apps, get_mod, get_sys, @@ -1313,7 +1315,6 @@ otp_9229_dupl_mod_exclude_mod(Config) -> ok. - %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% Test that if a module is duplicated in a .app file, then a warning %% is produced, but target can still be created. @@ -1346,6 +1347,56 @@ dupl_mod_in_app_file(Config) -> ok. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% Test that a reasonable error message is returned if an application +%% is missing +include_non_existing_app(_Config) -> + %% Configure the server + Sys = + {sys, + [ + {incl_cond,exclude}, + {app,foobar,[{incl_cond,include}]}, + {app,kernel,[{incl_cond,include}]}, + {app,stdlib,[{incl_cond,include}]}, + {app,sasl,[{incl_cond,include}]} + ]}, + + %% Generate target file + TargetDir = filename:join([?WORK_DIR, "target_include_non_existing_app"]), + ?m(ok, reltool_utils:recursive_delete(TargetDir)), + ?m(ok, file:make_dir(TargetDir)), + ?log("SPEC: ~p\n", [reltool:get_target_spec([{config, Sys}])]), + ?m({error,"foobar: Missing application directory."}, + reltool:get_status([{config, Sys}])), + + ok. + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% Test that if a missing application is explicitly excluded a warning +%% should be issued. +exclude_non_existing_app(_Config) -> + %% Configure the server + Sys = + {sys, + [ + {incl_cond,exclude}, + {app,foobar,[{incl_cond,exclude}]}, + {app,kernel,[{incl_cond,include}]}, + {app,stdlib,[{incl_cond,include}]}, + {app,sasl,[{incl_cond,include}]} + ]}, + + %% Generate target file + TargetDir = filename:join([?WORK_DIR, "target_exclude_non_existing_app"]), + ?m(ok, reltool_utils:recursive_delete(TargetDir)), + ?m(ok, file:make_dir(TargetDir)), + ?log("SPEC: ~p\n", [reltool:get_target_spec([{config, Sys}])]), + ?m({ok,["foobar: Missing application directory."]}, + reltool:get_status([{config, Sys}])), + + ok. + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% Test the interface used by the GUI: %% get_app %% get_apps diff --git a/lib/ssh/doc/html/.gitignore b/lib/ssh/doc/html/.gitignore index e69de29bb2..72e8ffc0db 100644 --- a/lib/ssh/doc/html/.gitignore +++ b/lib/ssh/doc/html/.gitignore @@ -0,0 +1 @@ +* diff --git a/lib/ssl/src/ssl_connection.erl b/lib/ssl/src/ssl_connection.erl index 4d29ecce7a..4f241ecc0a 100644 --- a/lib/ssl/src/ssl_connection.erl +++ b/lib/ssl/src/ssl_connection.erl @@ -1151,7 +1151,9 @@ init_certificates(undefined, CertDbRef, CertDbHandle, FileRefHandle, PemCacheHan init_certificates(undefined, CertDbRef, CertDbHandle, FileRefHandle, PemCacheHandle, CacheHandle, CertFile, client) -> try - [OwnCert] = ssl_certificate:file_to_certificats(CertFile, PemCacheHandle), + %% Ignoring potential proxy-certificates see: + %% http://dev.globus.org/wiki/Security/ProxyFileFormat + [OwnCert|_] = ssl_certificate:file_to_certificats(CertFile, PemCacheHandle), {ok, CertDbRef, CertDbHandle, FileRefHandle, PemCacheHandle, CacheHandle, OwnCert} catch _Error:_Reason -> {ok, CertDbRef, CertDbHandle, FileRefHandle, PemCacheHandle, CacheHandle, undefined} @@ -1159,7 +1161,7 @@ init_certificates(undefined, CertDbRef, CertDbHandle, FileRefHandle, PemCacheHan init_certificates(undefined, CertDbRef, CertDbHandle, FileRefHandle, PemCacheHandle, CacheRef, CertFile, server) -> try - [OwnCert] = ssl_certificate:file_to_certificats(CertFile, PemCacheHandle), + [OwnCert|_] = ssl_certificate:file_to_certificats(CertFile, PemCacheHandle), {ok, CertDbRef, CertDbHandle, FileRefHandle, PemCacheHandle, CacheRef, OwnCert} catch _:Reason -> diff --git a/lib/stdlib/doc/src/erl_parse.xml b/lib/stdlib/doc/src/erl_parse.xml index bafc2e0746..56a7131821 100644 --- a/lib/stdlib/doc/src/erl_parse.xml +++ b/lib/stdlib/doc/src/erl_parse.xml @@ -4,7 +4,7 @@ <erlref> <header> <copyright> - <year>1996</year><year>2011</year> + <year>1996</year><year>2013</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> @@ -167,6 +167,23 @@ <p>Converts the Erlang data structure <c><anno>Data</anno></c> into an abstract form of type <c><anno>AbsTerm</anno></c>. This is the inverse of <c>normalise/1</c>.</p> + <p><c>erl_parse:abstract(T)</c> is equivalent to + <c>erl_parse:abstract(T, 0)</c>.</p> + </desc> + </func> + <func> + <name name="abstract" arity="2"/> + <fsummary>Convert an Erlang term into an abstract form</fsummary> + <desc> + <p>Converts the Erlang data structure <c><anno>Data</anno></c> into an + abstract form of type <c><anno>AbsTerm</anno></c>.</p> + <p>The <c><anno>Line</anno></c> option is the line that will + be assigned to each node of the abstract form.</p> + <p>The <c><anno>Encoding</anno></c> option is used for + selecting which integer lists will be considered + as strings. The default is to use the encoding returned by + <seealso marker="epp#default_encoding/0"> + <c>epp:default_encoding/0</c></seealso></p> </desc> </func> </funcs> diff --git a/lib/stdlib/src/erl_parse.yrl b/lib/stdlib/src/erl_parse.yrl index 9ff25fcbc5..7145b0858f 100644 --- a/lib/stdlib/src/erl_parse.yrl +++ b/lib/stdlib/src/erl_parse.yrl @@ -887,6 +887,7 @@ abstract(T, Options) when is_list(Options) -> abstract(T, Line, Encoding). -define(UNICODE(C), + is_integer(C) andalso (C >= 0 andalso C < 16#D800 orelse C > 16#DFFF andalso C < 16#FFFE orelse C > 16#FFFF andalso C =< 16#10FFFF)). diff --git a/lib/stdlib/src/erl_scan.erl b/lib/stdlib/src/erl_scan.erl index 3651f608bc..d988a4d8c7 100644 --- a/lib/stdlib/src/erl_scan.erl +++ b/lib/stdlib/src/erl_scan.erl @@ -338,6 +338,7 @@ string_thing(_) -> "string". -define(DIGIT(C), C >= $0, C =< $9). -define(CHAR(C), is_integer(C), C >= 0). -define(UNICODE(C), + is_integer(C) andalso (C >= 0 andalso C < 16#D800 orelse C > 16#DFFF andalso C < 16#FFFE orelse C > 16#FFFF andalso C =< 16#10FFFF)). diff --git a/lib/stdlib/test/erl_scan_SUITE.erl b/lib/stdlib/test/erl_scan_SUITE.erl index ecd181e87c..361abbb771 100644 --- a/lib/stdlib/test/erl_scan_SUITE.erl +++ b/lib/stdlib/test/erl_scan_SUITE.erl @@ -21,7 +21,8 @@ -export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1, init_per_group/2,end_per_group/2]). --export([ error_1/1, error_2/1, iso88591/1, otp_7810/1, otp_10302/1]). +-export([ error_1/1, error_2/1, iso88591/1, otp_7810/1, otp_10302/1, + otp_10990/1, otp_10992/1]). -import(lists, [nth/2,flatten/1]). -import(io_lib, [print/1]). @@ -60,7 +61,7 @@ end_per_testcase(_Case, Config) -> suite() -> [{ct_hooks,[ts_install_cth]}]. all() -> - [{group, error}, iso88591, otp_7810, otp_10302]. + [{group, error}, iso88591, otp_7810, otp_10302, otp_10990, otp_10992]. groups() -> [{error, [], [error_1, error_2]}]. @@ -1121,6 +1122,29 @@ otp_10302(Config) when is_list(Config) -> erl_parse:abstract("a"++[1024]++"c", [{encoding,latin1}]), ok. +otp_10990(doc) -> + "OTP-10990. Floating point number in input string."; +otp_10990(suite) -> + []; +otp_10990(Config) when is_list(Config) -> + {'EXIT',_} = (catch {foo, erl_scan:string([$",42.0,$"],1)}), + ok. + +otp_10992(doc) -> + "OTP-10992. List of floats to abstract format."; +otp_10992(suite) -> + []; +otp_10992(Config) when is_list(Config) -> + {cons,0,{float,0,42.0},{nil,0}} = + erl_parse:abstract([42.0], [{encoding,unicode}]), + {cons,0,{float,0,42.0},{nil,0}} = + erl_parse:abstract([42.0], [{encoding,utf8}]), + {cons,0,{integer,0,65},{cons,0,{float,0,42.0},{nil,0}}} = + erl_parse:abstract([$A,42.0], [{encoding,unicode}]), + {cons,0,{integer,0,65},{cons,0,{float,0,42.0},{nil,0}}} = + erl_parse:abstract([$A,42.0], [{encoding,utf8}]), + ok. + test_string(String, Expected) -> {ok, Expected, _End} = erl_scan:string(String), test(String). diff --git a/lib/stdlib/test/escript_SUITE.erl b/lib/stdlib/test/escript_SUITE.erl index b6cdd0a9c7..eebfec3336 100644 --- a/lib/stdlib/test/escript_SUITE.erl +++ b/lib/stdlib/test/escript_SUITE.erl @@ -615,7 +615,7 @@ archive_script_file_access(Config) when is_list(Config) -> %% 3. If symlinks are supported, run one of the scripts via a symlink. %% %% This is in order to test error b) described above this test case. - case file:read_link(Symlink2) of + case element(1,os:type()) =:= win32 orelse file:read_link(Symlink2) of {ok,_} -> run(PrivDir, "./" ++ SymlinkName2 ++ " " ++ ScriptName2, [<<"ExitCode:0">>]); diff --git a/lib/stdlib/test/escript_SUITE_data/archive_script_file_access/archive_script_file_access.erl b/lib/stdlib/test/escript_SUITE_data/archive_script_file_access/archive_script_file_access.erl index b03c8ba70d..523621e4f3 100644 --- a/lib/stdlib/test/escript_SUITE_data/archive_script_file_access/archive_script_file_access.erl +++ b/lib/stdlib/test/escript_SUITE_data/archive_script_file_access/archive_script_file_access.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2012. All Rights Reserved. +%% Copyright Ericsson AB 2012-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 @@ -56,7 +56,7 @@ main([RelArchiveFile]) -> %% If symlinks are supported on this platform... RelSymlinkArchiveFile = "symlink_to_" ++ RelArchiveFile, - case file:read_link(RelSymlinkArchiveFile) of + case element(1,os:type()) =:= win32 orelse file:read_link(RelSymlinkArchiveFile) of {ok,_} -> DotSlashSymlinkArchiveFile = "./" ++ RelSymlinkArchiveFile, AbsSymlinkArchiveFile=filename:join(filename:dirname(AbsArchiveFile), 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) -> diff --git a/lib/wx/test/wx_basic_SUITE.erl b/lib/wx/test/wx_basic_SUITE.erl index cf17818a9d..d55a037599 100644 --- a/lib/wx/test/wx_basic_SUITE.erl +++ b/lib/wx/test/wx_basic_SUITE.erl @@ -2,7 +2,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2012. All Rights Reserved. +%% Copyright Ericsson AB 2008-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 @@ -100,6 +100,7 @@ several_apps(Config) -> || N <- lists:seq(1,4)], process_flag(trap_exit,true), ?m_multi_receive([{complete,Pid} || Pid <- Pids]), + [Pid ! quit || Pid <- Pids], case wx_test_lib:user_available(Config) of true -> receive {'EXIT',_,foo} -> ok end; @@ -118,6 +119,7 @@ several_apps(Parent, N, Config) -> #wx{obj=Frame, event=#wxSize{}} -> Parent ! {complete, self()} end, + receive quit -> ok end, wx_test_lib:wx_destroy(Frame, Config), exit(foo). diff --git a/lib/wx/test/wx_class_SUITE.erl b/lib/wx/test/wx_class_SUITE.erl index 4186d73c88..7c3eda0be1 100644 --- a/lib/wx/test/wx_class_SUITE.erl +++ b/lib/wx/test/wx_class_SUITE.erl @@ -140,7 +140,7 @@ treeCtrl(Config) -> ?m({true, {_,Y1,_,_}} when Y1 > Y0, wxTreeCtrl:getBoundingRect(Tree, Item2)), ?m({Item1, _}, wxTreeCtrl:hitTest(Tree, {X0+W0 div 2, Y0+H0 div 2})), ?m(true, wxTreeCtrl:isTreeItemIdOk(Item1)), - ?m({0, _}, wxTreeCtrl:hitTest(Tree, {X0+W0 div 2, Y0+H0+H0})), + ?m({0, _}, wxTreeCtrl:hitTest(Tree, {X0+W0+W0, Y0+H0+4*H0})), ?m(false, wxTreeCtrl:isTreeItemIdOk(0)), wxFrame:connect(Tree, command_tree_item_expanded), |