diff options
Diffstat (limited to 'erts')
-rw-r--r-- | erts/Makefile.in | 5 | ||||
-rw-r--r-- | erts/doc/src/erl_driver.xml | 7 | ||||
-rw-r--r-- | erts/doc/src/erl_nif.xml | 26 | ||||
-rw-r--r-- | erts/doc/src/erlang.xml | 4 | ||||
-rw-r--r-- | erts/doc/src/time_correction.xml | 4 | ||||
-rw-r--r-- | erts/emulator/beam/beam_bp.c | 5 | ||||
-rw-r--r-- | erts/emulator/beam/erl_alloc.h | 2 | ||||
-rw-r--r-- | erts/emulator/beam/erl_bif_ddll.c | 6 | ||||
-rw-r--r-- | erts/emulator/beam/erl_db_tree.c | 4 | ||||
-rw-r--r-- | erts/emulator/beam/erl_driver.h | 16 | ||||
-rw-r--r-- | erts/emulator/beam/erl_nif.c | 6 | ||||
-rw-r--r-- | erts/emulator/beam/erl_nif.h | 12 | ||||
-rw-r--r-- | erts/emulator/beam/erl_trace.c | 19 | ||||
-rw-r--r-- | erts/emulator/beam/erl_trace.h | 1 | ||||
-rw-r--r-- | erts/emulator/beam/ops.tab | 3 | ||||
-rw-r--r-- | erts/emulator/test/driver_SUITE_data/smaller_major_vsn_drv.c | 4 | ||||
-rw-r--r-- | erts/emulator/test/nif_SUITE.erl | 23 | ||||
-rw-r--r-- | erts/emulator/test/nif_SUITE_data/nif_SUITE.c | 32 | ||||
-rw-r--r-- | erts/emulator/test/trace_call_time_SUITE.erl | 96 | ||||
-rw-r--r-- | erts/etc/win32/nsis/erlang.nsi | 1 | ||||
-rw-r--r-- | erts/etc/win32/nsis/erlang20.nsi | 1 | ||||
-rw-r--r-- | erts/preloaded/src/erts.app.src | 3 | ||||
-rw-r--r-- | erts/test/otp_SUITE.erl | 62 |
23 files changed, 313 insertions, 29 deletions
diff --git a/erts/Makefile.in b/erts/Makefile.in index e3db37d3fd..47298cccba 100644 --- a/erts/Makefile.in +++ b/erts/Makefile.in @@ -48,6 +48,7 @@ debug opt clean: ( cd $$d && $(MAKE) $@ FLAVOR=$(FLAVOR) ) || exit $$? ; \ fi ; \ done + (cd preloaded/src && $(MAKE) ../ebin/erts.app) # ---------------------------------------------------------------------- # These are "convenience targets", provided as shortcuts for developers @@ -135,6 +136,10 @@ release: ( cd $$d && $(MAKE) $@ ) || exit $$? ; \ fi ; \ done + ( $(MAKE) -f "$(ERL_TOP)/make/otp_released_app.mk" \ + APP_PWD="$(ERL_TOP)/erts" APP_VSN=VSN APP=erts \ + TESTROOT="$(TESTROOT)" update) \ + || exit $$? .PHONY: release_docs release_docs: diff --git a/erts/doc/src/erl_driver.xml b/erts/doc/src/erl_driver.xml index 8da1836da7..ad37813ac0 100644 --- a/erts/doc/src/erl_driver.xml +++ b/erts/doc/src/erl_driver.xml @@ -315,10 +315,13 @@ <c>ERL_DRV_EXTENDED_MINOR_VERSION</c> will be incremented when new features are added. The runtime system uses the minor version of the driver to determine what features to use. - The runtime system will refuse to load a driver if the major + The runtime system will normally refuse to load a driver if the major versions differ, or if the major versions are equal and the minor version used by the driver is greater than the one used - by the runtime system.</p> + by the runtime system. Old drivers with lower major versions + will however be allowed after a bump of the major version during + a transition period of two major releases. Such old drivers might + however fail if deprecated features are used.</p> <p>The emulator will refuse to load a driver that does not use the extended driver interface, to allow for 64-bit capable drivers, diff --git a/erts/doc/src/erl_nif.xml b/erts/doc/src/erl_nif.xml index 8b19725c02..6b1f4cccf8 100644 --- a/erts/doc/src/erl_nif.xml +++ b/erts/doc/src/erl_nif.xml @@ -316,6 +316,32 @@ ok <p>The library initialization callbacks <c>load</c>, <c>reload</c> and <c>upgrade</c> are all thread-safe even for shared state data.</p> </item> + + <tag><marker id="version_management"/>Version Management</tag> + <item><p> + When a NIF library is built, information about NIF API version + is compiled into the library. When a NIF library is loaded the + runtime system verifies that the library is of a compatible version. + <c>erl_nif.h</c> defines <c>ERL_NIF_MAJOR_VERSION</c>, and + <c>ERL_NIF_MINOR_VERSION</c>. <c>ERL_NIF_MAJOR_VERSION</c> will be + incremented when NIF library incompatible changes are made to the + Erlang runtime system. Normally it will suffice to recompile the NIF + library when the <c>ERL_NIF_MAJOR_VERSION</c> has changed, but it + could, under rare circumstances, mean that NIF libraries have to + be slightly modified. If so, this will of course be documented. + <c>ERL_NIF_MINOR_VERSION</c> will be incremented when + new features are added. The runtime system uses the minor version + to determine what features to use. + </p><p> + The runtime system will normally refuse to load a NIF library if + the major versions differ, or if the major versions are equal and + the minor version used by the NIF library is greater than the one + used by the runtime system. Old NIF libraries with lower major + versions will however be allowed after a bump of the major version + during a transition period of two major releases. Such old NIF + libraries might however fail if deprecated features are used. + </p></item> + <tag>Dirty NIFs</tag> <item><p><marker id="dirty_nifs"/><em>Note that the dirty NIF functionality is experimental</em> and that you have to enable support for dirty diff --git a/erts/doc/src/erlang.xml b/erts/doc/src/erlang.xml index aeded7c719..b06d5aeb12 100644 --- a/erts/doc/src/erlang.xml +++ b/erts/doc/src/erlang.xml @@ -6121,8 +6121,8 @@ ok <c>erlang:system_info()</c> argument giving the exact OTP version. This since the exact OTP version in the general case is hard to determine. For more information see - <seealso marker="doc/installation_guide:otp_version">the - documentation of the OTP version in the installation + <seealso marker="doc/system_principles:versions">the + documentation of versions in the system principles guide</seealso>.</p> </item> <tag><marker id="system_info_port_parallelism"><c>port_parallelism</c></marker></tag> diff --git a/erts/doc/src/time_correction.xml b/erts/doc/src/time_correction.xml index d52cc7f3e2..7f7c28fc30 100644 --- a/erts/doc/src/time_correction.xml +++ b/erts/doc/src/time_correction.xml @@ -1,10 +1,10 @@ -<?xml version="1.0" encoding="utf8" ?> +<?xml version="1.0" encoding="utf-8" ?> <!DOCTYPE chapter SYSTEM "chapter.dtd"> <chapter> <header> <copyright> - <year>1999</year><year>2013</year> + <year>1999</year><year>2014</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> diff --git a/erts/emulator/beam/beam_bp.c b/erts/emulator/beam/beam_bp.c index 49a34ab4ad..4e711c89e0 100644 --- a/erts/emulator/beam/beam_bp.c +++ b/erts/emulator/beam/beam_bp.c @@ -642,7 +642,7 @@ erts_generic_breakpoint(Process* c_p, BeamInstr* I, Eterm* reg) erts_smp_atomic_inc_nob(&bp->count->acount); } - if (bp_flags & ERTS_BPF_TIME_TRACE_ACTIVE) { + if (bp_flags & ERTS_BPF_TIME_TRACE_ACTIVE && erts_is_tracer_proc_valid(c_p)) { Eterm w; erts_trace_time_call(c_p, I, bp->time); w = (BeamInstr) *c_p->cp; @@ -730,7 +730,8 @@ erts_bif_trace(int bif_index, Process* p, Eterm* args, BeamInstr* I) } } if (bp_flags & ERTS_BPF_TIME_TRACE_ACTIVE && - IS_TRACED_FL(p, F_TRACE_CALLS)) { + IS_TRACED_FL(p, F_TRACE_CALLS) && + erts_is_tracer_proc_valid(p)) { BeamInstr *pc = (BeamInstr *)ep->code+3; erts_trace_time_call(p, pc, bp->time); } diff --git a/erts/emulator/beam/erl_alloc.h b/erts/emulator/beam/erl_alloc.h index 942eaa47d0..d3109b9432 100644 --- a/erts/emulator/beam/erl_alloc.h +++ b/erts/emulator/beam/erl_alloc.h @@ -492,7 +492,7 @@ static TYPE * \ NAME##_alloc(void) \ { \ ErtsSchedulerData *esdp = erts_get_scheduler_data(); \ - if (!esdp) \ + if (!esdp || ERTS_SCHEDULER_IS_DIRTY(esdp)) \ return NULL; \ return (TYPE *) erts_sspa_alloc(sspa_data_##NAME##__, \ (int) esdp->no - 1); \ diff --git a/erts/emulator/beam/erl_bif_ddll.c b/erts/emulator/beam/erl_bif_ddll.c index 1728b200f7..56cd2ba04f 100644 --- a/erts/emulator/beam/erl_bif_ddll.c +++ b/erts/emulator/beam/erl_bif_ddll.c @@ -1548,8 +1548,10 @@ static int do_load_driver_entry(DE_Handle *dh, char *path, char *name) switch (dp->extended_marker) { case ERL_DRV_EXTENDED_MARKER: - if (ERL_DRV_EXTENDED_MAJOR_VERSION != dp->major_version - || ERL_DRV_EXTENDED_MINOR_VERSION < dp->minor_version) { + if (dp->major_version < ERL_DRV_MIN_REQUIRED_MAJOR_VERSION_ON_LOAD + || (ERL_DRV_EXTENDED_MAJOR_VERSION < dp->major_version + || (ERL_DRV_EXTENDED_MAJOR_VERSION == dp->major_version + && ERL_DRV_EXTENDED_MINOR_VERSION < dp->minor_version))) { /* Incompatible driver version */ res = ERL_DE_LOAD_ERROR_INCORRECT_VERSION; goto error; diff --git a/erts/emulator/beam/erl_db_tree.c b/erts/emulator/beam/erl_db_tree.c index 25029ba90f..a62a83a928 100644 --- a/erts/emulator/beam/erl_db_tree.c +++ b/erts/emulator/beam/erl_db_tree.c @@ -485,7 +485,7 @@ static int db_first_tree(Process *p, DbTable *tbl, Eterm *ret) *ret = am_EOT; return DB_ERROR_NONE; } - /* Walk down to the tree to the left */ + /* Walk down the tree to the left */ if ((stack = get_static_stack(tb)) != NULL) { stack->pos = stack->slot = 0; } @@ -531,7 +531,7 @@ static int db_last_tree(Process *p, DbTable *tbl, Eterm *ret) *ret = am_EOT; return DB_ERROR_NONE; } - /* Walk down to the tree to the left */ + /* Walk down the tree to the right */ if ((stack = get_static_stack(tb)) != NULL) { stack->pos = stack->slot = 0; } diff --git a/erts/emulator/beam/erl_driver.h b/erts/emulator/beam/erl_driver.h index 5517c26ba4..3ecb379326 100644 --- a/erts/emulator/beam/erl_driver.h +++ b/erts/emulator/beam/erl_driver.h @@ -136,6 +136,22 @@ typedef struct { #define ERL_DRV_EXTENDED_MINOR_VERSION 0 /* + * The emulator will refuse to load a driver with a major version + * lower than ERL_DRV_MIN_REQUIRED_MAJOR_VERSION_ON_LOAD. The load + * may however fail if user have not removed use of deprecated + * symbols. + * + * The ERL_DRV_MIN_REQUIRED_MAJOR_VERSION_ON_LOAD have to allow + * loading of drivers built at least two major OTP releases + * ago. + * + * Bump of major version to 3 happened in OTP 17. That is, in + * OTP 19 we can increase ERL_DRV_MIN_REQUIRED_MAJOR_VERSION_ON_LOAD + * to 3. + */ +#define ERL_DRV_MIN_REQUIRED_MAJOR_VERSION_ON_LOAD 2 + +/* * The emulator will refuse to load a driver with different major * version than the one used by the emulator. */ diff --git a/erts/emulator/beam/erl_nif.c b/erts/emulator/beam/erl_nif.c index 40860e141c..063dba056e 100644 --- a/erts/emulator/beam/erl_nif.c +++ b/erts/emulator/beam/erl_nif.c @@ -2049,8 +2049,10 @@ BIF_RETTYPE load_nif_2(BIF_ALIST_2) (entry = erts_sys_ddll_call_nif_init(init_func)) == NULL)) { ret = load_nif_error(BIF_P, bad_lib, "Library init-call unsuccessful"); } - else if (entry->major != ERL_NIF_MAJOR_VERSION - || entry->minor > ERL_NIF_MINOR_VERSION + else if (entry->major < ERL_NIF_MIN_REQUIRED_MAJOR_VERSION_ON_LOAD + || (ERL_NIF_MAJOR_VERSION < entry->major + || (ERL_NIF_MAJOR_VERSION == entry->major + && ERL_NIF_MINOR_VERSION < entry->minor)) || (entry->major==2 && entry->minor == 5)) { /* experimental maps */ ret = load_nif_error(BIF_P, bad_lib, "Library version (%d.%d) not compatible (with %d.%d).", diff --git a/erts/emulator/beam/erl_nif.h b/erts/emulator/beam/erl_nif.h index c12ba4d554..5b93c2398e 100644 --- a/erts/emulator/beam/erl_nif.h +++ b/erts/emulator/beam/erl_nif.h @@ -46,6 +46,18 @@ #define ERL_NIF_MAJOR_VERSION 2 #define ERL_NIF_MINOR_VERSION 6 +/* + * The emulator will refuse to load a nif-lib with a major version + * lower than ERL_NIF_MIN_REQUIRED_MAJOR_VERSION_ON_LOAD. The load + * may however fail if user have not removed use of deprecated + * symbols. + * + * The ERL_NIF_MIN_REQUIRED_MAJOR_VERSION_ON_LOAD have to allow + * loading of nif-libs built at least two major OTP releases + * ago. + */ +#define ERL_NIF_MIN_REQUIRED_MAJOR_VERSION_ON_LOAD 2 + #include <stdlib.h> #ifdef SIZEOF_CHAR diff --git a/erts/emulator/beam/erl_trace.c b/erts/emulator/beam/erl_trace.c index 6978a5f11a..305058ceff 100644 --- a/erts/emulator/beam/erl_trace.c +++ b/erts/emulator/beam/erl_trace.c @@ -151,6 +151,11 @@ do { \ message dispatcher thread takes care of that). */ #define ERTS_GET_TRACER_REF(RES, TPID, TRACEE_FLGS) \ do { (RES) = (TPID); } while(0) +int +erts_is_tracer_proc_valid(Process* p) +{ + return 1; +} #else #define ERTS_NULL_TRACER_REF NULL #define ERTS_TRACER_REF_TYPE Process * @@ -163,6 +168,20 @@ do { \ return; \ } \ } while (0) +int +erts_is_tracer_proc_valid(Process* p) +{ + Process* tracer; + + tracer = erts_proc_lookup(ERTS_TRACER_PROC(p)); + if (tracer && ERTS_TRACE_FLAGS(tracer) & F_TRACER) { + return 1; + } else { + ERTS_TRACER_PROC(p) = NIL; + ERTS_TRACE_FLAGS(p) = ~TRACEE_FLAGS; + return 0; + } +} #endif static Uint active_sched; diff --git a/erts/emulator/beam/erl_trace.h b/erts/emulator/beam/erl_trace.h index 853c6cb0d8..4f2c70d6e7 100644 --- a/erts/emulator/beam/erl_trace.h +++ b/erts/emulator/beam/erl_trace.h @@ -39,6 +39,7 @@ void erts_change_default_tracing(int setflags, Uint *flagsp, Eterm *tracerp); void erts_get_default_tracing(Uint *flagsp, Eterm *tracerp); void erts_set_system_monitor(Eterm monitor); Eterm erts_get_system_monitor(void); +int erts_is_tracer_proc_valid(Process* p); #ifdef ERTS_SMP void erts_check_my_tracer_proc(Process *); diff --git a/erts/emulator/beam/ops.tab b/erts/emulator/beam/ops.tab index 73630fda8e..68fcc177ae 100644 --- a/erts/emulator/beam/ops.tab +++ b/erts/emulator/beam/ops.tab @@ -1484,7 +1484,8 @@ new_map j d I I update_map_assoc j s d I I update_map_exact j s d I I -is_map Fail cq => jump Fail +is_map Fail Literal=q => move Literal x | is_map Fail x +is_map Fail c => jump Fail %macro: is_map IsMap -fail_action is_map f r diff --git a/erts/emulator/test/driver_SUITE_data/smaller_major_vsn_drv.c b/erts/emulator/test/driver_SUITE_data/smaller_major_vsn_drv.c index a1299fe807..6b9d4745ba 100644 --- a/erts/emulator/test/driver_SUITE_data/smaller_major_vsn_drv.c +++ b/erts/emulator/test/driver_SUITE_data/smaller_major_vsn_drv.c @@ -20,12 +20,12 @@ * Author: Rickard Green * * Description: Implementation of a driver with a smaller major - * driver version than the current system. + * driver version than allowed on load. */ #define VSN_MISMATCH_DRV_NAME_STR "smaller_major_vsn_drv" #define VSN_MISMATCH_DRV_NAME smaller_major_vsn_drv -#define VSN_MISMATCH_DRV_MAJOR_VSN_DIFF (-1) +#define VSN_MISMATCH_DRV_MAJOR_VSN_DIFF (ERL_DRV_MIN_REQUIRED_MAJOR_VERSION_ON_LOAD - ERL_DRV_EXTENDED_MAJOR_VERSION - 1) #define VSN_MISMATCH_DRV_MINOR_VSN_DIFF 0 #include "vsn_mismatch_drv_impl.c" diff --git a/erts/emulator/test/nif_SUITE.erl b/erts/emulator/test/nif_SUITE.erl index a854d3f05b..b2da6f58af 100644 --- a/erts/emulator/test/nif_SUITE.erl +++ b/erts/emulator/test/nif_SUITE.erl @@ -37,7 +37,7 @@ threading/1, send/1, send2/1, send3/1, send_threaded/1, neg/1, is_checks/1, get_length/1, make_atom/1, make_string/1, reverse_list_test/1, - otp_9668/1, consume_timeslice/1, dirty_nif/1 + otp_9668/1, consume_timeslice/1, dirty_nif/1, dirty_nif_send/1 ]). -export([many_args_100/100]). @@ -64,7 +64,7 @@ all() -> resource_takeover, threading, send, send2, send3, send_threaded, neg, is_checks, get_length, make_atom, make_string,reverse_list_test, - otp_9668, consume_timeslice, dirty_nif + otp_9668, consume_timeslice, dirty_nif, dirty_nif_send ]. groups() -> @@ -1538,6 +1538,24 @@ dirty_nif(Config) when is_list(Config) -> {skipped,"No dirty scheduler support"} end. +dirty_nif_send(Config) when is_list(Config) -> + try erlang:system_info(dirty_cpu_schedulers) of + N when is_integer(N) -> + ensure_lib_loaded(Config), + Parent = self(), + Pid = spawn_link(fun() -> + Self = self(), + {ok, Self} = receive_any(), + Parent ! {ok, Self} + end), + {ok, Pid} = send_from_dirty_nif(Pid), + {ok, Pid} = receive_any(), + ok + catch + error:badarg -> + {skipped,"No dirty scheduler support"} + end. + next_msg(_Pid) -> receive M -> M @@ -1668,6 +1686,7 @@ type_sizes() -> ?nif_stub. otp_9668_nif(_) -> ?nif_stub. consume_timeslice_nif(_,_) -> ?nif_stub. call_dirty_nif(_,_,_) -> ?nif_stub. +send_from_dirty_nif(_) -> ?nif_stub. %% maps is_map_nif(_) -> ?nif_stub. diff --git a/erts/emulator/test/nif_SUITE_data/nif_SUITE.c b/erts/emulator/test/nif_SUITE_data/nif_SUITE.c index 160f4843ad..955dc64189 100644 --- a/erts/emulator/test/nif_SUITE_data/nif_SUITE.c +++ b/erts/emulator/test/nif_SUITE_data/nif_SUITE.c @@ -1533,6 +1533,37 @@ static ERL_NIF_TERM call_dirty_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM return dirty_nif(env, argc, argv); } } + +static ERL_NIF_TERM dirty_sender(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) +{ + ERL_NIF_TERM result; + ErlNifPid pid; + ErlNifEnv* menv; + int res; + + enif_get_local_pid(env, argv[0], &pid); + result = enif_make_tuple2(env, enif_make_atom(env, "ok"), enif_make_pid(env, &pid)); + menv = enif_alloc_env(); + res = enif_send(env, &pid, menv, result); + enif_free_env(menv); + if (!res) + /* Note the next line will crash, since dirty nifs can't return exceptions. + * This is intentional, since enif_send should not fail if the test succeeds. + */ + return enif_schedule_dirty_nif_finalizer(env, enif_make_badarg(env), enif_dirty_nif_finalizer); + else + return enif_schedule_dirty_nif_finalizer(env, result, enif_dirty_nif_finalizer); +} + +static ERL_NIF_TERM send_from_dirty_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) +{ + ERL_NIF_TERM result; + ErlNifPid pid; + + if (!enif_get_local_pid(env, argv[0], &pid)) + return enif_make_badarg(env); + return enif_schedule_dirty_nif(env, ERL_NIF_DIRTY_JOB_CPU_BOUND, dirty_sender, argc, argv); +} #endif static ERL_NIF_TERM is_map_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) @@ -1713,6 +1744,7 @@ static ErlNifFunc nif_funcs[] = {"consume_timeslice_nif", 2, consume_timeslice_nif}, #ifdef ERL_NIF_DIRTY_SCHEDULER_SUPPORT {"call_dirty_nif", 3, call_dirty_nif}, + {"send_from_dirty_nif", 1, send_from_dirty_nif}, #endif {"is_map_nif", 1, is_map_nif}, {"get_map_size_nif", 1, get_map_size_nif}, diff --git a/erts/emulator/test/trace_call_time_SUITE.erl b/erts/emulator/test/trace_call_time_SUITE.erl index 5dfa87bbee..3036d2957b 100644 --- a/erts/emulator/test/trace_call_time_SUITE.erl +++ b/erts/emulator/test/trace_call_time_SUITE.erl @@ -33,7 +33,7 @@ %% Exported end user tests -export([seq/3, seq_r/3]). --export([loaded/1, a_function/1, a_called_function/1, dec/1, nif_dec/1]). +-export([loaded/1, a_function/1, a_called_function/1, dec/1, nif_dec/1, dead_tracer/1]). -define(US_ERROR, 10000). -define(R_ERROR, 0.8). @@ -89,7 +89,7 @@ all() -> true -> [not_run]; false -> [basic, on_and_off, info, pause_and_restart, scheduling, - combo, bif, nif, called_function] + combo, bif, nif, called_function, dead_tracer] end. groups() -> @@ -470,6 +470,92 @@ called_function(Config) when is_list(Config) -> ?line P = erlang:trace_pattern({'_','_','_'}, false, [call_time]), ok. +%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +dead_tracer(Config) when is_list(Config) -> + Self = self(), + FirstTracer = tracer(), + StartTracing = fun() -> turn_on_tracing(Self) end, + tell_tracer(FirstTracer, StartTracing), + [1,2,3,4,5,6,7,8] = seq(1, 8, fun(I) -> I + 1 end), + Ref = erlang:monitor(process, FirstTracer), + FirstTracer ! quit, + receive + {'DOWN',Ref,process,FirstTracer,normal} -> + ok + end, + erlang:yield(), + + %% Collect and check that we only get call_time info for the current process. + Info1 = collect_all_info(), + [] = other_than_self(Info1), + io:format("~p\n", [Info1]), + + %% Note that we have not turned off tracing for the current process, + %% but that the tracer has terminated. No more call_time information should be recorded. + [1,2,3] = seq(1, 3, fun(I) -> I + 1 end), + [] = collect_all_info(), + + %% When we start a second tracer process, that tracer process must + %% not inherit the tracing flags and the dead tracer (even though + %% we used set_on_spawn). + SecondTracer = tracer(), + tell_tracer(SecondTracer, StartTracing), + Seq20 = lists:seq(1, 20), + Seq20 = seq(1, 20, fun(I) -> I + 1 end), + Info2 = collect_all_info(), + io:format("~p\n", [Info2]), + [] = other_than_self(Info2), + SecondTracer ! quit, + + ok. + +other_than_self(Info) -> + [{Pid,MFA} || {MFA,[{Pid,_,_,_}]} <- Info, + Pid =/= self()]. + +tell_tracer(Tracer, Fun) -> + Tracer ! {execute,self(),Fun}, + receive + {Tracer,executed} -> + ok + end. + +tracer() -> + spawn_link(fun Loop() -> + receive + quit -> + ok; + {execute,From,Fun} -> + Fun(), + From ! {self(),executed}, + Loop() + end + end). + +turn_on_tracing(Pid) -> + _ = erlang:trace(Pid, true, [call,set_on_spawn]), + _ = erlang:trace_pattern({?MODULE,'_','_'}, true, [call_time]), + _ = now(), + ok. + +collect_all_info() -> + collect_all_info([{?MODULE,F,A} || {F,A} <- module_info(functions)] ++ + erlang:system_info(snifs)). + +collect_all_info([MFA|T]) -> + CallTime = erlang:trace_info(MFA, call_time), + erlang:trace_pattern(MFA, restart, [call_time]), + case CallTime of + {call_time,false} -> + collect_all_info(T); + {call_time,[]} -> + collect_all_info(T); + {call_time,[_|_]=List} -> + [{MFA,List}|collect_all_info(T)] + end; +collect_all_info([]) -> []. + %%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%% The Tests %%% @@ -478,7 +564,6 @@ called_function(Config) when is_list(Config) -> %% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% Local helpers - load_nif(Config) -> ?line Path = ?config(data_dir, Config), ?line ok = erlang:load_nif(filename:join(Path,"trace_nif"), 0). @@ -602,8 +687,11 @@ collect(A, Ref) -> end. setup() -> + setup([]). + +setup(Opts) -> Pid = spawn_link(fun() -> loop() end), - ?line 1 = erlang:trace(Pid, true, [call]), + 1 = erlang:trace(Pid, true, [call|Opts]), Pid. execute(Pids, Mfa) when is_list(Pids) -> diff --git a/erts/etc/win32/nsis/erlang.nsi b/erts/etc/win32/nsis/erlang.nsi index 162e634148..f4fd2b4cdb 100644 --- a/erts/etc/win32/nsis/erlang.nsi +++ b/erts/etc/win32/nsis/erlang.nsi @@ -93,7 +93,6 @@ SectionIn 1 RO skip_silent_mode: SetOutPath "$INSTDIR" - File "${TESTROOT}\OTP_VERSION" File "${TESTROOT}\Install.ini" File "${TESTROOT}\Install.exe" File /r "${TESTROOT}\releases" diff --git a/erts/etc/win32/nsis/erlang20.nsi b/erts/etc/win32/nsis/erlang20.nsi index 3ee33e8121..3333c4a9aa 100644 --- a/erts/etc/win32/nsis/erlang20.nsi +++ b/erts/etc/win32/nsis/erlang20.nsi @@ -144,7 +144,6 @@ Section "Development" SecErlangDev SectionIn 1 RO
SetOutPath "$INSTDIR"
- File "${TESTROOT}\OTP_VERSION"
File "${TESTROOT}\Install.ini"
File "${TESTROOT}\Install.exe"
SetOutPath "$INSTDIR\releases"
diff --git a/erts/preloaded/src/erts.app.src b/erts/preloaded/src/erts.app.src index fd3e8cb692..a15da3a421 100644 --- a/erts/preloaded/src/erts.app.src +++ b/erts/preloaded/src/erts.app.src @@ -35,7 +35,8 @@ {registered, []}, {applications, []}, {env, []}, - {mod, {erts, []}} + {mod, {erts, []}}, + {runtime_dependencies, ["stdlib-2.0", "kernel-3.0", "sasl-2.4"]} ]}. %% vim: ft=erlang diff --git a/erts/test/otp_SUITE.erl b/erts/test/otp_SUITE.erl index 8e4a1a4b1c..1fb452501f 100644 --- a/erts/test/otp_SUITE.erl +++ b/erts/test/otp_SUITE.erl @@ -24,7 +24,7 @@ -export([undefined_functions/1,deprecated_not_in_obsolete/1, obsolete_but_not_deprecated/1,call_to_deprecated/1, call_to_size_1/1,strong_components/1, - erl_file_encoding/1,xml_file_encoding/1]). + erl_file_encoding/1,xml_file_encoding/1,runtime_dependencies/1]). -include_lib("test_server/include/test_server.hrl"). @@ -36,7 +36,8 @@ all() -> [undefined_functions, deprecated_not_in_obsolete, obsolete_but_not_deprecated, call_to_deprecated, call_to_size_1, strong_components, - erl_file_encoding, xml_file_encoding]. + erl_file_encoding, xml_file_encoding, + runtime_dependencies]. groups() -> []. @@ -380,6 +381,63 @@ is_bad_encoding(File) -> true end. +runtime_dependencies(Config) -> + %% Verify that (at least) OTP application runtime dependencies found + %% by xref are listed in the runtime_dependencies field of the .app file + %% of each application. + Server = ?config(xref_server, Config), + {ok, AE} = xref:q(Server, "AE"), + SAE = lists:keysort(1, AE), + {AppDep, AppDeps} = lists:foldl(fun ({App, App}, Acc) -> + Acc; + ({App, Dep}, {undefined, []}) -> + {{App, [Dep]}, []}; + ({App, Dep}, {{App, Deps}, AppDeps}) -> + {{App, [Dep|Deps]}, AppDeps}; + ({App, Dep}, {AppDep, AppDeps}) -> + {{App, [Dep]}, [AppDep | AppDeps]} + end, + {undefined, []}, + SAE), + [] = check_apps_deps([AppDep|AppDeps]), + ok. + +have_rdep(_App, [], _Dep) -> + false; +have_rdep(App, [RDep | RDeps], Dep) -> + [AppStr, _VsnStr] = string:tokens(RDep, "-"), + case Dep == list_to_atom(AppStr) of + true -> + io:format("~p -> ~s~n", [App, RDep]), + true; + false -> + have_rdep(App, RDeps, Dep) + end. + +check_app_deps(_App, _AppFile, _AFDeps, []) -> + []; +check_app_deps(App, AppFile, AFDeps, [XRDep | XRDeps]) -> + ResOtherDeps = check_app_deps(App, AppFile, AFDeps, XRDeps), + case have_rdep(App, AFDeps, XRDep) of + true -> + ResOtherDeps; + false -> + [{missing_runtime_dependency, AppFile, XRDep} | ResOtherDeps] + end. + +check_apps_deps([]) -> + []; +check_apps_deps([{App, Deps}|AppDeps]) -> + ResOtherApps = check_apps_deps(AppDeps), + AppFile = code:where_is_file(atom_to_list(App) ++ ".app"), + {ok,[{application, App, Info}]} = file:consult(AppFile), + case lists:keyfind(runtime_dependencies, 1, Info) of + {runtime_dependencies, RDeps} -> + check_app_deps(App, AppFile, RDeps, Deps) ++ ResOtherApps; + false -> + [{missing_runtime_dependencies_key, AppFile} | ResOtherApps] + end. + %%% %%% Common help functions. %%% |