aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--erts/Makefile.in2
-rw-r--r--erts/doc/src/erlang.xml42
-rw-r--r--erts/emulator/beam/atom.names3
-rw-r--r--erts/emulator/beam/bif.c18
-rw-r--r--erts/emulator/beam/erl_alloc.types2
-rw-r--r--erts/emulator/beam/erl_bif_info.c11
-rw-r--r--erts/emulator/beam/erl_process.c252
-rw-r--r--erts/emulator/beam/erl_process.h14
-rw-r--r--erts/emulator/test/call_trace_SUITE.erl57
-rw-r--r--erts/emulator/test/statistics_SUITE.erl98
-rw-r--r--erts/emulator/test/trace_port_SUITE.erl6
-rw-r--r--erts/etc/common/Makefile.in232
-rw-r--r--erts/preloaded/ebin/erlang.beambin41136 -> 42416 bytes
-rw-r--r--erts/preloaded/src/erlang.erl34
-rw-r--r--erts/vsn.mk2
-rw-r--r--lib/debugger/test/bs_construct_SUITE.erl2
-rw-r--r--lib/debugger/test/bs_match_misc_SUITE.erl2
-rw-r--r--lib/erl_docgen/priv/xsl/db_html.xsl66
-rw-r--r--lib/inviso/test/inviso_tool_SUITE.erl7
-rw-r--r--lib/kernel/test/erl_prim_loader_SUITE.erl8
-rw-r--r--lib/observer/test/etop_SUITE.erl13
-rw-r--r--lib/runtime_tools/test/inviso_SUITE.erl17
-rw-r--r--lib/snmp/doc/src/notes.xml58
-rw-r--r--lib/snmp/doc/src/snmpa.xml22
-rw-r--r--lib/snmp/src/agent/snmpa_agent.erl9
-rw-r--r--lib/snmp/src/agent/snmpa_local_db.erl10
-rw-r--r--lib/snmp/src/agent/snmpa_mib.erl14
-rw-r--r--lib/snmp/src/agent/snmpa_mpd.erl2
-rw-r--r--lib/snmp/src/app/snmp.appup.src88
-rw-r--r--lib/snmp/test/snmp_agent_test.erl246
-rw-r--r--lib/snmp/vsn.mk3
-rw-r--r--lib/stdlib/test/erl_eval_SUITE.erl25
-rw-r--r--lib/stdlib/test/re_SUITE.erl54
-rw-r--r--lib/stdlib/test/shell_SUITE.erl29
-rw-r--r--lib/stdlib/test/sofs_SUITE.erl27
-rw-r--r--lib/tools/test/fprof_SUITE.erl16
36 files changed, 1180 insertions, 311 deletions
diff --git a/erts/Makefile.in b/erts/Makefile.in
index 2b4f562c06..1979c50781 100644
--- a/erts/Makefile.in
+++ b/erts/Makefile.in
@@ -156,4 +156,4 @@ release:
.PHONY: release_docs
release_docs:
- ( cd emulator && $(MAKE) $@ )
+ ( cd doc/src && $(MAKE) $@ )
diff --git a/erts/doc/src/erlang.xml b/erts/doc/src/erlang.xml
index 8c01d77721..fbe7b36163 100644
--- a/erts/doc/src/erlang.xml
+++ b/erts/doc/src/erlang.xml
@@ -4,7 +4,7 @@
<erlref>
<header>
<copyright>
- <year>1996</year><year>2011</year>
+ <year>1996</year><year>2012</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -215,9 +215,9 @@
representation of <c>Atom</c>. If <c>Encoding</c>
is <c>latin1</c>, there will be one byte for each character
in the text representation. If <c>Encoding</c> is <c>utf8</c> or
- <c>unicode</c>, the characters will encoded using UTF-8
+ <c>unicode</c>, the characters will be encoded using UTF-8
(meaning that characters from 16#80 up to 0xFF will be
- encode in two bytes).</p>
+ encoded in two bytes).</p>
<note><p>Currently, <c>atom_to_binary(Atom, latin1)</c> can
never fail because the text representation of an atom can only contain
@@ -268,7 +268,7 @@
<p>If <c>PosLen</c> in any way references outside the binary, a <c>badarg</c> exception is raised.</p>
- <p><c>Start</c> is zero-based, i.e:</p>
+ <p><c>Start</c> is zero-based, i.e.:</p>
<code>
1> Bin = &lt;&lt;1,2,3&gt;&gt;
2> binary_part(Bin,{0,2}).
@@ -773,9 +773,9 @@ false</pre>
turned off, nothing happens.</p>
<p>Once <c>demonitor(MonitorRef)</c> has returned it is
guaranteed that no <c>{'DOWN', MonitorRef, _, _, _}</c> message
- due to the monitor will be placed in the callers message queue
+ due to the monitor will be placed in the caller's message queue
in the future. A <c>{'DOWN', MonitorRef, _, _, _}</c> message
- might have been placed in the callers message queue prior to
+ might have been placed in the caller's message queue prior to
the call, though. Therefore, in most cases, it is advisable
to remove such a <c>'DOWN'</c> message from the message queue
after monitoring has been stopped.
@@ -818,7 +818,7 @@ false</pre>
<tag><c>flush</c></tag>
<item>
<p>Remove (one) <c>{_, MonitorRef, _, _, _}</c> message,
- if there is one, from the callers message queue after
+ if there is one, from the caller's message queue after
monitoring has been stopped.</p>
<p>Calling <c>demonitor(MonitorRef, [flush])</c>
is equivalent to the following, but more efficient:</p>
@@ -847,7 +847,7 @@ false</pre>
<item><p>The monitor was not found and could not be removed.
This probably because someone already has placed a
<c>'DOWN'</c> message corresponding to this monitor
- in the callers message queue.
+ in the caller's message queue.
</p>
</item>
</taglist>
@@ -4933,6 +4933,21 @@ true</pre>
threads in the Erlang run-time system and may therefore be greater
than the wall-clock time.</p>
</item>
+ <tag><marker id="statistics_scheduler_wall_time"><c>scheduler_wall_time</c></marker></tag>
+ <item>
+ <p>Returns
+ <c>[{Scheduler_Id, Scheduler_Worked_Time, Scheduler_Total_Time}]</c>, time lapses are since the
+ the system flag <seealso marker="#system_flag_scheduler_wall_time">scheduler_wall_time</seealso>
+ was set to true.
+ Returns <c>undefined</c> if the system flag <seealso marker="#system_flag_scheduler_wall_time">
+ scheduler_wall_time</seealso> is set to false.
+ </p>
+ <p>The list of scheduler information is unsorted and may come in different order
+ between calls. The time unit is undefined and may be changed and should only be used
+ to calculate relative utilization.
+ </p>
+ </item>
+
<tag><c>wall_clock</c></tag>
<item>
<p>Returns
@@ -5305,6 +5320,14 @@ true</pre>
flags.
</p>
</item>
+ <tag><marker id="system_flag_scheduler_wall_time"><c>erlang:system_flag(scheduler_wall_time, Boolean)</c></marker></tag>
+ <item>
+ <p>Turns on/off scheduler wall time measurements. </p>
+ <p>For more information see,
+ <seealso marker="#statistics_scheduler_wall_time">erlang:statistics(scheduler_wall_time)</seealso>.
+ </p>
+ </item>
+
<tag><marker id="system_flag_schedulers_online"><c>erlang:system_flag(schedulers_online, SchedulersOnline)</c></marker></tag>
<item>
<p>Sets the amount of schedulers online. Valid range is
@@ -5316,6 +5339,7 @@ true</pre>
<seealso marker="#system_info_schedulers_online">erlang:system_info(schedulers_online)</seealso>.
</p>
</item>
+
<tag><c>erlang:system_flag(trace_control_word, TCW)</c></tag>
<item>
<p>Sets the value of the node's trace control word to
@@ -7090,7 +7114,7 @@ true</pre>
<c>Id</c> has no effect on the caller in the future (unless
the link is setup again). If caller is trapping exits, an
<c>{'EXIT', Id, _}</c> message due to the link might have
- been placed in the callers message queue prior to the call,
+ been placed in the caller's message queue prior to the call,
though. Note, the <c>{'EXIT', Id, _}</c> message can be the
result of the link, but can also be the result of <c>Id</c>
calling <c>exit/2</c>. Therefore, it <em>may</em> be
diff --git a/erts/emulator/beam/atom.names b/erts/emulator/beam/atom.names
index 71454b3e57..7be40976f6 100644
--- a/erts/emulator/beam/atom.names
+++ b/erts/emulator/beam/atom.names
@@ -95,6 +95,7 @@ atom atom
atom atom_used
atom attributes
atom await_proc_exit
+atom await_sched_wall_time_modifications
atom awaiting_load
atom awaiting_unload
atom backtrace backtrace_depth
@@ -239,6 +240,7 @@ atom generational
atom get_seq_token
atom get_tcw
atom getenv
+atom gather_sched_wall_time_result
atom getting_linked
atom getting_unlinked
atom global
@@ -554,6 +556,7 @@ atom waiting
atom wall_clock
atom warning
atom warning_msg
+atom scheduler_wall_time
atom wordsize
atom write_concurrency
atom xor
diff --git a/erts/emulator/beam/bif.c b/erts/emulator/beam/bif.c
index 55f4798892..f8305944a4 100644
--- a/erts/emulator/beam/bif.c
+++ b/erts/emulator/beam/bif.c
@@ -43,6 +43,9 @@ static Export* set_cpu_topology_trap = NULL;
static Export* await_proc_exit_trap = NULL;
Export* erts_format_cpu_topology_trap = NULL;
+static Export *await_sched_wall_time_mod_trap;
+static erts_smp_atomic32_t sched_wall_time;
+
#define DECL_AM(S) Eterm AM_ ## S = am_atom_put(#S, sizeof(#S) - 1)
/*
@@ -4160,6 +4163,18 @@ BIF_RETTYPE system_flag_2(BIF_ALIST_2)
erts_smp_proc_lock(BIF_P, ERTS_PROC_LOCK_MAIN);
BIF_RET(am_true);
+ } else if (BIF_ARG_1 == am_scheduler_wall_time) {
+ if (BIF_ARG_2 == am_true || BIF_ARG_2 == am_false) {
+ erts_aint32_t new = BIF_ARG_2 == am_true ? 1 : 0;
+ erts_aint32_t old = erts_smp_atomic32_xchg_nob(&sched_wall_time,
+ new);
+ Eterm ref = erts_sched_wall_time_request(BIF_P, 1, new);
+ ASSERT(is_value(ref));
+ BIF_TRAP2(await_sched_wall_time_mod_trap,
+ BIF_P,
+ ref,
+ old ? am_true : am_false);
+ }
} else if (ERTS_IS_ATOM_STR("scheduling_statistics", BIF_ARG_1)) {
int what;
if (ERTS_IS_ATOM_STR("disable", BIF_ARG_2))
@@ -4457,6 +4472,9 @@ void erts_init_bif(void)
am_format_cpu_topology,
1);
await_proc_exit_trap = erts_export_put(am_erlang,am_await_proc_exit,3);
+ await_sched_wall_time_mod_trap
+ = erts_export_put(am_erlang, am_await_sched_wall_time_modifications, 2);
+ erts_smp_atomic32_init_nob(&sched_wall_time, 0);
}
#ifdef HARDDEBUG
diff --git a/erts/emulator/beam/erl_alloc.types b/erts/emulator/beam/erl_alloc.types
index 962db8b831..90a6c0cbee 100644
--- a/erts/emulator/beam/erl_alloc.types
+++ b/erts/emulator/beam/erl_alloc.types
@@ -367,6 +367,7 @@ type EXPORT LONG_LIVED_LOW CODE export_entry
type MONITOR_SH STANDARD_LOW PROCESSES monitor_sh
type NLINK_SH STANDARD_LOW PROCESSES nlink_sh
type AINFO_REQ STANDARD_LOW SYSTEM alloc_info_request
+type SCHED_WTIME_REQ STANDARD_LOW SYSTEM sched_wall_time_request
+else # "fullword"
@@ -383,6 +384,7 @@ type EXPORT LONG_LIVED CODE export_entry
type MONITOR_SH FIXED_SIZE PROCESSES monitor_sh
type NLINK_SH FIXED_SIZE PROCESSES nlink_sh
type AINFO_REQ SHORT_LIVED SYSTEM alloc_info_request
+type SCHED_WTIME_REQ SHORT_LIVED SYSTEM sched_wall_time_request
+endif
diff --git a/erts/emulator/beam/erl_bif_info.c b/erts/emulator/beam/erl_bif_info.c
index 5a806777fe..ebd475f73a 100644
--- a/erts/emulator/beam/erl_bif_info.c
+++ b/erts/emulator/beam/erl_bif_info.c
@@ -57,6 +57,8 @@
static Export* alloc_info_trap = NULL;
static Export* alloc_sizes_trap = NULL;
+static Export *gather_sched_wall_time_res_trap;
+
#define DECL_AM(S) Eterm AM_ ## S = am_atom_put(#S, sizeof(#S) - 1)
/* Keep erts_system_version as a global variable for easy access from a core */
@@ -3180,7 +3182,12 @@ BIF_RETTYPE statistics_1(BIF_ALIST_1)
Eterm res;
Eterm* hp;
- if (BIF_ARG_1 == am_context_switches) {
+ if (BIF_ARG_1 == am_scheduler_wall_time) {
+ res = erts_sched_wall_time_request(BIF_P, 0, 0);
+ if (is_non_value(res))
+ BIF_RET(am_undefined);
+ BIF_TRAP1(gather_sched_wall_time_res_trap, BIF_P, res);
+ } else if (BIF_ARG_1 == am_context_switches) {
Eterm cs = erts_make_integer(erts_get_total_context_switches(), BIF_P);
hp = HAlloc(BIF_P, 3);
res = TUPLE2(hp, cs, SMALL_ZERO);
@@ -4160,6 +4167,8 @@ erts_bif_info_init(void)
alloc_info_trap = erts_export_put(am_erlang, am_alloc_info, 1);
alloc_sizes_trap = erts_export_put(am_erlang, am_alloc_sizes, 1);
+ gather_sched_wall_time_res_trap
+ = erts_export_put(am_erlang, am_gather_sched_wall_time_result, 1);
process_info_init();
os_info_init();
}
diff --git a/erts/emulator/beam/erl_process.c b/erts/emulator/beam/erl_process.c
index 5469a59d8c..30c91af630 100644
--- a/erts/emulator/beam/erl_process.c
+++ b/erts/emulator/beam/erl_process.c
@@ -537,6 +537,209 @@ erts_late_init_process(void)
}
+static void
+init_sched_wall_time(ErtsSchedWallTime *swtp)
+{
+ swtp->enabled = 0;
+ swtp->start = 0;
+ swtp->working.total = 0;
+ swtp->working.start = 0;
+ swtp->working.currently = 0;
+}
+
+static ERTS_INLINE Uint64
+sched_wall_time_ts(void)
+{
+#ifdef HAVE_GETHRTIME
+ return (Uint64) sys_gethrtime();
+#else
+ Uint64 res;
+ SysTimeval tv;
+ sys_gettimeofday(&tv);
+ res = (Uint64) tv.tv_sec*1000000;
+ res += (Uint64) tv.tv_usec;
+ return res;
+#endif
+}
+
+static ERTS_INLINE void
+sched_wall_time_change(ErtsSchedulerData *esdp, int working)
+{
+ if (esdp->sched_wall_time.enabled) {
+ Uint64 ts = sched_wall_time_ts();
+ if (working) {
+#ifdef DEBUG
+ ASSERT(!esdp->sched_wall_time.working.currently);
+ esdp->sched_wall_time.working.currently = 1;
+#endif
+ ts -= esdp->sched_wall_time.start;
+ esdp->sched_wall_time.working.start = ts;
+ }
+ else {
+#ifdef DEBUG
+ ASSERT(esdp->sched_wall_time.working.currently);
+ esdp->sched_wall_time.working.currently = 0;
+#endif
+ ts -= esdp->sched_wall_time.start;
+ ts -= esdp->sched_wall_time.working.start;
+ esdp->sched_wall_time.working.total += ts;
+ }
+ }
+}
+
+typedef struct {
+ int set;
+ int enable;
+ Process *proc;
+ Eterm ref;
+ Eterm ref_heap[REF_THING_SIZE];
+ Uint req_sched;
+ erts_smp_atomic32_t refc;
+} ErtsSchedWallTimeReq;
+
+#if !HALFWORD_HEAP
+ERTS_SCHED_PREF_QUICK_ALLOC_IMPL(swtreq,
+ ErtsSchedWallTimeReq,
+ 5,
+ ERTS_ALC_T_SCHED_WTIME_REQ)
+#else
+static ERTS_INLINE ErtsSchedWallTimeReq *
+swtreq_alloc(void)
+{
+ return erts_alloc(ERTS_ALC_T_SCHED_WTIME_REQ,
+ sizeof(ErtsSchedWallTimeReq));
+}
+
+static ERTS_INLINE void
+swtreq_free(ErtsSchedWallTimeReq *ptr)
+{
+ erts_free(ERTS_ALC_T_SCHED_WTIME_REQ, ptr);
+}
+#endif
+
+static void
+reply_sched_wall_time(void *vswtrp)
+{
+ Uint64 working = 0, total = 0;
+ ErtsSchedulerData *esdp = erts_get_scheduler_data();
+ ErtsSchedWallTimeReq *swtrp = (ErtsSchedWallTimeReq *) vswtrp;
+ ErtsProcLocks rp_locks = (swtrp->req_sched == esdp->no
+ ? ERTS_PROC_LOCK_MAIN
+ : 0);
+ Process *rp = swtrp->proc;
+ Eterm ref_copy = NIL, msg;
+ Eterm *hp = NULL;
+ Eterm **hpp;
+ Uint sz, *szp;
+ ErlOffHeap *ohp = NULL;
+ ErlHeapFragment *bp = NULL;
+
+ ASSERT(esdp);
+
+ if (swtrp->set) {
+ if (!swtrp->enable && esdp->sched_wall_time.enabled)
+ esdp->sched_wall_time.enabled = 0;
+ else if (swtrp->enable && !esdp->sched_wall_time.enabled) {
+ Uint64 ts = sched_wall_time_ts();
+ esdp->sched_wall_time.enabled = 1;
+ esdp->sched_wall_time.start = ts;
+ esdp->sched_wall_time.working.total = 0;
+ esdp->sched_wall_time.working.start = 0;
+ esdp->sched_wall_time.working.currently = 1;
+ }
+ }
+
+ if (esdp->sched_wall_time.enabled) {
+ Uint64 ts = sched_wall_time_ts();
+ ASSERT(esdp->sched_wall_time.working.currently);
+ ts -= esdp->sched_wall_time.start;
+ total = ts;
+ ts -= esdp->sched_wall_time.working.start;
+ working = esdp->sched_wall_time.working.total + ts;
+ }
+
+ sz = 0;
+ hpp = NULL;
+ szp = &sz;
+
+ while (1) {
+ if (hpp)
+ ref_copy = STORE_NC(hpp, ohp, swtrp->ref);
+ else
+ *szp += REF_THING_SIZE;
+
+ if (swtrp->set)
+ msg = ref_copy;
+ else {
+ msg = (!esdp->sched_wall_time.enabled
+ ? am_notsup
+ : erts_bld_tuple(hpp, szp, 3,
+ make_small(esdp->no),
+ erts_bld_uint64(hpp, szp, working),
+ erts_bld_uint64(hpp, szp, total)));
+
+ msg = erts_bld_tuple(hpp, szp, 2, ref_copy, msg);
+ }
+ if (hpp)
+ break;
+
+ hp = erts_alloc_message_heap(sz, &bp, &ohp, rp, &rp_locks);
+ szp = NULL;
+ hpp = &hp;
+ }
+
+ erts_queue_message(rp, &rp_locks, bp, msg, NIL);
+
+ if (swtrp->req_sched == esdp->no)
+ rp_locks &= ~ERTS_PROC_LOCK_MAIN;
+
+ if (rp_locks)
+ erts_smp_proc_unlock(rp, rp_locks);
+
+ erts_smp_proc_dec_refc(rp);
+
+ if (erts_smp_atomic32_dec_read_nob(&swtrp->refc) == 0)
+ swtreq_free(vswtrp);
+}
+
+Eterm
+erts_sched_wall_time_request(Process *c_p, int set, int enable)
+{
+ ErtsSchedulerData *esdp = ERTS_PROC_GET_SCHDATA(c_p);
+ Eterm ref;
+ ErtsSchedWallTimeReq *swtrp;
+ Eterm *hp;
+
+ if (!set && !esdp->sched_wall_time.enabled)
+ return THE_NON_VALUE;
+
+ swtrp = swtreq_alloc();
+ ref = erts_make_ref(c_p);
+ hp = &swtrp->ref_heap[0];
+
+ swtrp->set = set;
+ swtrp->enable = enable;
+ swtrp->proc = c_p;
+ swtrp->ref = STORE_NC(&hp, NULL, ref);
+ swtrp->req_sched = esdp->no;
+ erts_smp_atomic32_init_nob(&swtrp->refc,
+ (erts_aint32_t) erts_no_schedulers);
+
+ erts_smp_proc_add_refc(c_p, (Sint32) erts_no_schedulers);
+
+#ifdef ERTS_SMP
+ if (erts_no_schedulers > 1)
+ erts_schedule_multi_misc_aux_work(1,
+ erts_no_schedulers,
+ reply_sched_wall_time,
+ (void *) swtrp);
+#endif
+
+ reply_sched_wall_time((void *) swtrp);
+
+ return ref;
+}
+
static ERTS_INLINE ErtsProcList *
proclist_create(Process *p)
{
@@ -1707,6 +1910,7 @@ aux_thread(void *unused)
static void
scheduler_wait(int *fcalls, ErtsSchedulerData *esdp, ErtsRunQueue *rq)
{
+ int working = 1;
ErtsSchedulerSleepInfo *ssi = esdp->ssi;
int spincount;
erts_aint32_t aux_work = 0;
@@ -1737,12 +1941,17 @@ scheduler_wait(int *fcalls, ErtsSchedulerData *esdp, ErtsRunQueue *rq)
tse_wait:
+ if (thr_prgr_active != working)
+ sched_wall_time_change(esdp, thr_prgr_active);
+
while (1) {
aux_work = erts_atomic32_read_acqb(&ssi->aux_work);
if (aux_work) {
- if (!thr_prgr_active)
+ if (!thr_prgr_active) {
erts_thr_progress_active(esdp, thr_prgr_active = 1);
+ sched_wall_time_change(esdp, 1);
+ }
aux_work = handle_aux_work(&esdp->aux_work_data, aux_work);
if (aux_work && erts_thr_progress_update(esdp))
erts_thr_progress_leader_update(esdp);
@@ -1751,8 +1960,10 @@ scheduler_wait(int *fcalls, ErtsSchedulerData *esdp, ErtsRunQueue *rq)
if (aux_work)
flgs = erts_smp_atomic32_read_acqb(&ssi->flags);
else {
- if (thr_prgr_active)
+ if (thr_prgr_active) {
erts_thr_progress_active(esdp, thr_prgr_active = 0);
+ sched_wall_time_change(esdp, 0);
+ }
erts_thr_progress_prepare_wait(esdp);
flgs = sched_spin_wait(ssi, spincount);
@@ -1789,8 +2000,10 @@ scheduler_wait(int *fcalls, ErtsSchedulerData *esdp, ErtsRunQueue *rq)
if (flgs & ~ERTS_SSI_FLG_SUSPENDED)
erts_smp_atomic32_read_band_nob(&ssi->flags, ERTS_SSI_FLG_SUSPENDED);
- if (!thr_prgr_active)
+ if (!thr_prgr_active) {
erts_thr_progress_active(esdp, thr_prgr_active = 1);
+ sched_wall_time_change(esdp, 1);
+ }
erts_smp_runq_lock(rq);
sched_active(esdp->no, rq);
@@ -1806,14 +2019,21 @@ scheduler_wait(int *fcalls, ErtsSchedulerData *esdp, ErtsRunQueue *rq)
sched_waiting_sys(esdp->no, rq);
+
erts_smp_runq_unlock(rq);
+ ASSERT(working);
+ sched_wall_time_change(esdp, working = 0);
+
spincount = ERTS_SCHED_SYS_SLEEP_SPINCOUNT;
while (spincount-- > 0) {
sys_poll_aux_work:
+ if (working)
+ sched_wall_time_change(esdp, working = 0);
+
ASSERT(!erts_port_task_have_outstanding_io_tasks());
erl_sys_schedule(1); /* Might give us something to do */
@@ -1828,6 +2048,8 @@ scheduler_wait(int *fcalls, ErtsSchedulerData *esdp, ErtsRunQueue *rq)
aux_work = erts_atomic32_read_acqb(&ssi->aux_work);
if (aux_work) {
+ if (!working)
+ sched_wall_time_change(esdp, working = 1);
#ifdef ERTS_SMP
if (!thr_prgr_active)
erts_thr_progress_active(esdp, thr_prgr_active = 1);
@@ -1920,6 +2142,9 @@ scheduler_wait(int *fcalls, ErtsSchedulerData *esdp, ErtsRunQueue *rq)
erts_smp_runq_unlock(rq);
+ if (working)
+ sched_wall_time_change(esdp, working = 0);
+
#ifdef ERTS_SMP
if (thr_prgr_active)
erts_thr_progress_active(esdp, thr_prgr_active = 0);
@@ -1955,6 +2180,8 @@ scheduler_wait(int *fcalls, ErtsSchedulerData *esdp, ErtsRunQueue *rq)
if (flgs & ~ERTS_SSI_FLG_SUSPENDED)
erts_smp_atomic32_read_band_nob(&ssi->flags, ERTS_SSI_FLG_SUSPENDED);
#endif
+ if (!working)
+ sched_wall_time_change(esdp, working = 1);
sched_active_sys(esdp->no, rq);
}
@@ -3430,9 +3657,14 @@ erts_init_scheduling(int no_schedulers, int no_schedulers_online)
esdp->run_queue->scheduler = esdp;
init_aux_work_data(&esdp->aux_work_data, esdp);
+ init_sched_wall_time(&esdp->sched_wall_time);
}
init_misc_aux_work();
+#if !HALFWORD_HEAP
+ init_swtreq_alloc();
+#endif
+
#ifdef ERTS_SMP
@@ -3755,6 +3987,8 @@ suspend_scheduler(ErtsSchedulerData *esdp)
if (erts_system_profile_flags.scheduler)
profile_scheduler(make_small(esdp->no), am_inactive);
+ sched_wall_time_change(esdp, 0);
+
erts_smp_mtx_lock(&schdlr_sspnd.mtx);
flgs = sched_prep_spin_suspended(ssi, ERTS_SSI_FLG_SUSPENDED);
@@ -3813,16 +4047,20 @@ suspend_scheduler(ErtsSchedulerData *esdp)
aux_work = erts_atomic32_read_acqb(&ssi->aux_work);
if (aux_work) {
- if (!thr_prgr_active)
+ if (!thr_prgr_active) {
erts_thr_progress_active(esdp, thr_prgr_active = 1);
+ sched_wall_time_change(esdp, 1);
+ }
aux_work = handle_aux_work(&esdp->aux_work_data, aux_work);
if (aux_work && erts_thr_progress_update(esdp))
erts_thr_progress_leader_update(esdp);
}
if (!aux_work) {
- if (thr_prgr_active)
+ if (thr_prgr_active) {
erts_thr_progress_active(esdp, thr_prgr_active = 0);
+ sched_wall_time_change(esdp, 0);
+ }
erts_thr_progress_prepare_wait(esdp);
flgs = sched_spin_suspended(ssi,
ERTS_SCHED_SUSPEND_SLEEP_SPINCOUNT);
@@ -3877,8 +4115,10 @@ suspend_scheduler(ErtsSchedulerData *esdp)
if (erts_system_profile_flags.scheduler)
profile_scheduler(make_small(esdp->no), am_active);
- if (!thr_prgr_active)
+ if (!thr_prgr_active) {
erts_thr_progress_active(esdp, thr_prgr_active = 1);
+ sched_wall_time_change(esdp, 1);
+ }
erts_smp_runq_lock(esdp->run_queue);
non_empty_runq(esdp->run_queue);
diff --git a/erts/emulator/beam/erl_process.h b/erts/emulator/beam/erl_process.h
index a51b380bb0..173b7df69d 100644
--- a/erts/emulator/beam/erl_process.h
+++ b/erts/emulator/beam/erl_process.h
@@ -394,6 +394,16 @@ do { \
} while (0)
typedef struct {
+ int enabled;
+ Uint64 start;
+ struct {
+ Uint64 total;
+ Uint64 start;
+ int currently;
+ } working;
+} ErtsSchedWallTime;
+
+typedef struct {
int sched_id;
ErtsSchedulerData *esdp;
ErtsSchedulerSleepInfo *ssi;
@@ -457,6 +467,8 @@ struct ErtsSchedulerData_ {
ErtsSchedAllocData alloc_data;
+ ErtsSchedWallTime sched_wall_time;
+
#ifdef ERTS_DO_VERIFY_UNUSED_TEMP_ALLOC
erts_alloc_verify_func_t verify_unused_temp_alloc;
Allctr_t *verify_unused_temp_alloc_data;
@@ -1064,6 +1076,8 @@ void erts_late_init_process(void);
void erts_early_init_scheduling(int);
void erts_init_scheduling(int, int);
+Eterm erts_sched_wall_time_request(Process *c_p, int set, int enable);
+
ErtsProcList *erts_proclist_create(Process *);
void erts_proclist_destroy(ErtsProcList *);
int erts_proclist_same(ErtsProcList *, Process *);
diff --git a/erts/emulator/test/call_trace_SUITE.erl b/erts/emulator/test/call_trace_SUITE.erl
index 3e2bee06d1..7030ebed3f 100644
--- a/erts/emulator/test/call_trace_SUITE.erl
+++ b/erts/emulator/test/call_trace_SUITE.erl
@@ -165,10 +165,14 @@ worker_loop() ->
worker_foo(_Arg) ->
ok.
-basic(doc) ->
- "Basic test of the call tracing (we trace one process).";
-basic(suite) -> [];
-basic(Config) when is_list(Config) ->
+%% Basic test of the call tracing (we trace one process).
+basic(_Config) ->
+ case test_server:is_native(lists) of
+ true -> {skip,"lists is native"};
+ false -> basic()
+ end.
+
+basic() ->
?line start_tracer(),
?line trace_info(self(), flags),
?line trace_info(self(), tracer),
@@ -263,9 +267,15 @@ foo() -> foo0.
foo(X) -> X+1.
foo(X, Y) -> X+Y.
-flags(doc) -> "Test flags (arity, timestamp) for call_trace/3. "
- "Also, test the '{tracer,Pid}' option.";
-flags(Config) when is_list(Config) ->
+%% Test flags (arity, timestamp) for call_trace/3.
+%% Also, test the '{tracer,Pid}' option.
+flags(_Config) ->
+ case test_server:is_native(filename) of
+ true -> {skip,"filename is native"};
+ false -> flags()
+ end.
+
+flags() ->
?line Tracer = start_tracer_loop(),
?line trace_pid(self(), true, [call,{tracer,Tracer}]),
@@ -428,9 +438,14 @@ pam_foo(A, B) ->
{ok,A,B}.
-change_pam(doc) -> "Test changing PAM programs for a function.";
-change_pam(suite) -> [];
-change_pam(Config) when is_list(Config) ->
+%% Test changing PAM programs for a function.
+change_pam(_Config) ->
+ case test_server:is_native(lists) of
+ true -> {skip,"lists is native"};
+ false -> change_pam()
+ end.
+
+change_pam() ->
?line start_tracer(),
?line Self = self(),
@@ -468,10 +483,11 @@ change_pam_trace(Prog) ->
{match_spec,Prog} = trace_info({erlang,process_info,2}, match_spec),
ok.
-return_trace(doc) -> "Test the new return trace.";
-return_trace(suite) -> [];
-return_trace(Config) when is_list(Config) ->
- return_trace().
+return_trace(_Config) ->
+ case test_server:is_native(lists) of
+ true -> {skip,"lists is native"};
+ false -> return_trace()
+ end.
return_trace() ->
X = {save,me},
@@ -521,7 +537,7 @@ return_trace() ->
?line {match_spec,Prog2} = trace_info({erlang,atom_to_list,1}, match_spec),
?line lists:seq(2, 7),
- ?line atom_to_list(non_literal(nisse)),
+ ?line _ = atom_to_list(non_literal(nisse)),
?line expect({trace,Self,return_from,{lists,seq,2},[2,3,4,5,6,7]}),
?line expect({trace,Self,return_from,{erlang,atom_to_list,1},"nisse"}),
@@ -539,10 +555,11 @@ return_trace() ->
nasty() ->
exit(good_bye).
-exception_trace(doc) -> "Test the new exception trace.";
-exception_trace(suite) -> [];
-exception_trace(Config) when is_list(Config) ->
- exception_trace().
+exception_trace(_Config) ->
+ case test_server:is_native(lists) of
+ true -> {skip,"lists is native"};
+ false -> exception_trace()
+ end.
exception_trace() ->
X = {save,me},
@@ -600,7 +617,7 @@ exception_trace() ->
trace_info({erlang,atom_to_list,1}, match_spec),
?line lists:seq(2, 7),
- ?line atom_to_list(non_literal(nisse)),
+ ?line _ = atom_to_list(non_literal(nisse)),
?line expect({trace,Self,return_from,{lists,seq,2},[2,3,4,5,6,7]}),
?line expect({trace,Self,return_from,{erlang,atom_to_list,1},"nisse"}),
diff --git a/erts/emulator/test/statistics_SUITE.erl b/erts/emulator/test/statistics_SUITE.erl
index 0392312a6f..a93dd309c1 100644
--- a/erts/emulator/test/statistics_SUITE.erl
+++ b/erts/emulator/test/statistics_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2011. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2012. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -29,6 +29,7 @@
runtime_zero_diff/1,
runtime_update/1, runtime_diff/1,
run_queue_one/1,
+ scheduler_wall_time/1,
reductions/1, reductions_big/1, garbage_collection/1, io/1,
badarg/1]).
@@ -51,8 +52,8 @@ suite() -> [{ct_hooks,[ts_install_cth]}].
all() ->
[{group, wall_clock}, {group, runtime}, reductions,
- reductions_big, {group, run_queue}, garbage_collection,
- io, badarg].
+ reductions_big, {group, run_queue}, scheduler_wall_time,
+ garbage_collection, io, badarg].
groups() ->
[{wall_clock, [],
@@ -266,11 +267,10 @@ run_queue_one(Config) when is_list(Config) ->
run_queue_one_test(Config) when is_list(Config) ->
- ?line Hog = spawn_link(?MODULE, hog, [self()]),
+ ?line _Hog = spawn_link(?MODULE, hog, [self()]),
?line receive
- hog_started ->
- Hog ! go
- end,
+ hog_started -> ok
+ end,
?line receive after 100 -> ok end, % Give hog a head start.
?line case statistics(run_queue) of
N when N >= 1 -> ok;
@@ -280,18 +280,88 @@ run_queue_one_test(Config) when is_list(Config) ->
%% CPU-bound process, going at low priority. It will always be ready
%% to run.
-
+
hog(Pid) ->
?line process_flag(priority, low),
?line Pid ! hog_started,
- ?line receive
- go -> hog_iter(0)
+ ?line Mon = erlang:monitor(process, Pid),
+ ?line hog_iter(0, Mon).
+
+hog_iter(N, Mon) when N > 0 ->
+ receive
+ {'DOWN', Mon, _, _, _} -> ok
+ after 0 ->
+ ?line hog_iter(N-1, Mon)
+ end;
+hog_iter(0, Mon) ->
+ ?line hog_iter(10000, Mon).
+
+%%% Tests of statistics(scheduler_wall_time).
+
+scheduler_wall_time(doc) ->
+ "Tests that statistics(scheduler_wall_time) works as intended";
+scheduler_wall_time(Config) when is_list(Config) ->
+ %% Should return undefined if system_flag is not turned on yet
+ undefined = statistics(scheduler_wall_time),
+ %% Turn on statistics
+ false = erlang:system_flag(scheduler_wall_time, true),
+ try
+ Schedulers = erlang:system_info(schedulers_online),
+ %% Let testserver and everyone else finish their work
+ timer:sleep(500),
+ %% Empty load
+ EmptyLoad = get_load(),
+ {false, _} = {lists:any(fun(Load) -> Load > 50 end, EmptyLoad),EmptyLoad},
+ MeMySelfAndI = self(),
+ StartHog = fun() ->
+ Pid = spawn(?MODULE, hog, [self()]),
+ receive hog_started -> MeMySelfAndI ! go end,
+ Pid
+ end,
+ P1 = StartHog(),
+ %% Max on one, the other schedulers empty (hopefully)
+ %% Be generous the process can jump between schedulers
+ %% which is ok and we don't want the test to fail for wrong reasons
+ _L1 = [S1Load|EmptyScheds1] = get_load(),
+ {true,_} = {S1Load > 50,S1Load},
+ {false,_} = {lists:any(fun(Load) -> Load > 50 end, EmptyScheds1),EmptyScheds1},
+ {true,_} = {lists:sum(EmptyScheds1) < 60,EmptyScheds1},
+
+ %% 50% load
+ HalfHogs = [StartHog() || _ <- lists:seq(1, (Schedulers-1) div 2)],
+ HalfLoad = lists:sum(get_load()) div Schedulers,
+ if Schedulers < 2, HalfLoad > 80 -> ok; %% Ok only one scheduler online and one hog
+ %% We want roughly 50% load
+ HalfLoad > 40, HalfLoad < 60 -> ok;
+ true -> exit({halfload, HalfLoad})
+ end,
+
+ %% 100% load
+ LastHogs = [StartHog() || _ <- lists:seq(1, Schedulers div 2)],
+ FullScheds = get_load(),
+ {false,_} = {lists:any(fun(Load) -> Load < 80 end, FullScheds),FullScheds},
+ FullLoad = lists:sum(FullScheds) div Schedulers,
+ if FullLoad > 90 -> ok;
+ true -> exit({fullload, FullLoad})
+ end,
+
+ [exit(Pid, kill) || Pid <- [P1|HalfHogs++LastHogs]],
+ AfterLoad = get_load(),
+ {false,_} = {lists:any(fun(Load) -> Load > 5 end, AfterLoad),AfterLoad},
+ true = erlang:system_flag(scheduler_wall_time, false)
+ after
+ erlang:system_flag(scheduler_wall_time, false)
end.
-hog_iter(N) when N > 0 ->
- ?line hog_iter(N-1);
-hog_iter(0) ->
- ?line hog_iter(10000).
+get_load() ->
+ Start = erlang:statistics(scheduler_wall_time),
+ timer:sleep(500),
+ End = erlang:statistics(scheduler_wall_time),
+ lists:reverse(lists:sort(load_percentage(lists:sort(Start),lists:sort(End)))).
+
+load_percentage([{Id, WN, TN}|Ss], [{Id, WP, TP}|Ps]) ->
+ [100*(WN-WP) div (TN-TP)|load_percentage(Ss, Ps)];
+load_percentage([], []) -> [].
garbage_collection(doc) ->
diff --git a/erts/emulator/test/trace_port_SUITE.erl b/erts/emulator/test/trace_port_SUITE.erl
index 0026da4979..b0ce6f81db 100644
--- a/erts/emulator/test/trace_port_SUITE.erl
+++ b/erts/emulator/test/trace_port_SUITE.erl
@@ -77,7 +77,8 @@ end_per_testcase(_Func, Config) ->
call_trace(doc) -> "Test sending call trace messages to a port.";
call_trace(Config) when is_list(Config) ->
- case test_server:is_native(?MODULE) of
+ case test_server:is_native(?MODULE) orelse
+ test_server:is_native(lists) of
true ->
{skip,"Native code"};
false ->
@@ -128,7 +129,8 @@ bs_sum_c(<<>>, Acc) -> Acc.
return_trace(doc) -> "Test the new return trace.";
return_trace(Config) when is_list(Config) ->
- case test_server:is_native(?MODULE) of
+ case test_server:is_native(?MODULE) orelse
+ test_server:is_native(lists) of
true ->
{skip,"Native code"};
false ->
diff --git a/erts/etc/common/Makefile.in b/erts/etc/common/Makefile.in
index 18f25b017b..28c5e5ccad 100644
--- a/erts/etc/common/Makefile.in
+++ b/erts/etc/common/Makefile.in
@@ -166,9 +166,8 @@ ERLSRV_OBJECTS= \
$(OBJDIR)/erlsrv_main.o \
$(OBJDIR)/erlsrv_util.o \
$(OBJDIR)/erlsrv_logmess.res
-MC_OUTPUTS= \
- $(OBJDIR)/erlsrv_logmess.h $(OBJDIR)/erlsrv_logmess.rc
- MT_FLAG="-MT"
+MC_OUTPUTS=$(OBJDIR)/erlsrv_logmess.h $(OBJDIR)/erlsrv_logmess.rc
+MT_FLAG="-MT"
else
ERLRES_OBJ=erl_res.o
ERLSRV_OBJECTS= \
@@ -178,9 +177,8 @@ ERLSRV_OBJECTS= \
$(OBJDIR)/erlsrv_main.o \
$(OBJDIR)/erlsrv_util.o \
$(OBJDIR)/erlsrv_logmess.o
-MC_OUTPUTS= \
- $(OBJDIR)/erlsrv_logmess.h $(OBJDIR)/erlsrv_logmess.res
- MT_FLAG="-MD"
+MC_OUTPUTS=$(OBJDIR)/erlsrv_logmess.h $(OBJDIR)/erlsrv_logmess.res
+MT_FLAG="-MD"
endif
INET_GETHOST = $(BINDIR)/inet_gethost.exe
INSTALL_EMBEDDED_PROGS += $(BINDIR)/typer.exe $(BINDIR)/dialyzer.exe $(BINDIR)/erlc.exe $(BINDIR)/start_erl.exe $(BINDIR)/escript.exe $(BINDIR)/ct_run.exe
@@ -289,83 +287,6 @@ endif
rm -f $(TEXTFILES)
rm -f *~ core
-#
-# Objects & executables
-#
-#$(OBJDIR)/%.o: %.c
-# $(CC) $(CFLAGS) -o $@ -c $<
-#
-#$(OBJDIR)/%.o: ../unix/%.c
-# $(CC) $(CFLAGS) -o $@ -c $<
-#
-#$(BINDIR)/%: $(OBJDIR)/%.o
-# $(PURIFY) $(LD) $(LDFLAGS) -o $@ $< $(LIBS)
-
-$(OBJDIR)/inet_gethost.o: inet_gethost.c
- $(CC) $(CFLAGS) -o $@ -c inet_gethost.c
-
-$(BINDIR)/inet_gethost@EXEEXT@: $(OBJDIR)/inet_gethost.o $(ENTRY_OBJ) $(ERTS_LIB)
- $(PURIFY) $(LD) $(LDFLAGS) $(ENTRY_LDFLAGS) -o $@ $(OBJDIR)/inet_gethost.o $(ENTRY_OBJ) $(LIBS) $(ERTS_INTERNAL_LIBS)
-
-$(BINDIR)/run_erl: $(OBJDIR)/safe_string.o $(OBJDIR)/run_erl.o
- $(LD) $(LDFLAGS) -o $@ $(OBJDIR)/safe_string.o $(OBJDIR)/run_erl.o $(LIBS)
-
-$(OBJDIR)/run_erl.o: ../unix/run_erl.c
- $(CC) $(CFLAGS) -o $@ -c ../unix/run_erl.c
-
-$(BINDIR)/to_erl: $(OBJDIR)/safe_string.o $(OBJDIR)/to_erl.o
- $(LD) $(LDFLAGS) -o $@ $(OBJDIR)/safe_string.o $(OBJDIR)/to_erl.o
-
-$(OBJDIR)/to_erl.o: ../unix/to_erl.c
- $(CC) $(CFLAGS) -o $@ -c ../unix/to_erl.c
-
-$(BINDIR)/dyn_erl: $(OBJDIR)/safe_string.o $(OBJDIR)/dyn_erl.o
- $(LD) $(LDFLAGS) -o $@ $(OBJDIR)/safe_string.o $(OBJDIR)/dyn_erl.o
-
-$(OBJDIR)/dyn_erl.o: ../unix/dyn_erl.c
- $(CC) $(CFLAGS) -o $@ -c ../unix/dyn_erl.c
-
-$(OBJDIR)/safe_string.o: ../unix/safe_string.c
- $(CC) $(CFLAGS) -o $@ -c ../unix/safe_string.c
-
-ifneq ($(TARGET),win32)
-$(BINDIR)/$(ERLEXEC): $(OBJDIR)/$(ERLEXEC).o $(ERTS_LIB)
- $(PURIFY) $(LD) $(LDFLAGS) -o $@ $(OBJDIR)/$(ERLEXEC).o $(ERTS_INTERNAL_LIBS)
-
-$(OBJDIR)/$(ERLEXEC).o: $(ERLEXECDIR)/$(ERLEXEC).c
- $(CC) -I$(EMUDIR) $(CFLAGS) -o $@ -c $(ERLEXECDIR)/$(ERLEXEC).c
-endif
-$(BINDIR)/erlc@EXEEXT@: $(OBJDIR)/erlc.o $(ERTS_LIB)
- $(PURIFY) $(LD) $(LDFLAGS) -o $@ $(OBJDIR)/erlc.o -L$(OBJDIR) $(LIBS) $(ERTS_INTERNAL_LIBS)
-
-$(OBJDIR)/erlc.o: erlc.c
- $(CC) $(CFLAGS) -o $@ -c erlc.c
-
-$(BINDIR)/dialyzer@EXEEXT@: $(OBJDIR)/dialyzer.o $(ERTS_LIB)
- $(PURIFY) $(LD) $(LDFLAGS) -o $@ $(OBJDIR)/dialyzer.o -L$(OBJDIR) $(LIBS) $(ERTS_INTERNAL_LIBS)
-
-$(OBJDIR)/dialyzer.o: dialyzer.c
- $(CC) $(CFLAGS) -o $@ -c dialyzer.c
-
-$(BINDIR)/typer@EXEEXT@: $(OBJDIR)/typer.o $(ERTS_LIB)
- $(PURIFY) $(LD) $(LDFLAGS) -o $@ $(OBJDIR)/typer.o -L$(OBJDIR) $(LIBS) $(ERTS_INTERNAL_LIBS)
-
-$(OBJDIR)/typer.o: typer.c
- $(CC) $(CFLAGS) -o $@ -c typer.c
-
-$(BINDIR)/escript@EXEEXT@: $(OBJDIR)/escript.o $(ERTS_LIB)
- $(PURIFY) $(LD) $(LDFLAGS) -o $@ $(OBJDIR)/escript.o -L$(OBJDIR) $(LIBS) $(ERTS_INTERNAL_LIBS)
-
-$(OBJDIR)/escript.o: escript.c
- $(CC) $(CFLAGS) -o $@ -c escript.c
-
-$(BINDIR)/ct_run@EXEEXT@: $(OBJDIR)/ct_run.o $(ERTS_LIB)
- $(PURIFY) $(LD) $(LDFLAGS) -o $@ $(OBJDIR)/ct_run.o -L$(OBJDIR) $(LIBS) $(ERTS_INTERNAL_LIBS)
-
-$(OBJDIR)/ct_run.o: ct_run.c
- $(CC) $(CFLAGS) -o $@ -c ct_run.c
-
-
#------------------------------------------------------------------------
# Windows specific targets
# The windows platform is quite different from the others. erl/werl are small C programs
@@ -391,58 +312,75 @@ $(BINDIR)/start_erl@EXEEXT@: $(OBJDIR)/start_erl.o
$(BINDIR)/Install@EXEEXT@: $(OBJDIR)/Install.o $(OBJDIR)/init_file.o
$(LD) $(LDFLAGS) -o $@ $(OBJDIR)/Install.o $(OBJDIR)/init_file.o
+# The service expects to be compiled with $(MT_FLAG) flag.
$(BINDIR)/erlsrv@EXEEXT@: $(ERLSRV_OBJECTS)
$(LD) $(LDFLAGS) $(MT_FLAG) -o $@ $(ERLSRV_OBJECTS)
-# The service expects to be compiled with $(MT_FLAG) flag.
-
-$(OBJDIR)/%.o: $(WINETC)/erlsrv/%.c $(ERLSRV_HEADERS)
- $(CC) $(CFLAGS) $(MT_FLAG) -o $@ -c $<
-
-$(OBJDIR)/erlsrv_util.o: $(WINETC)/erlsrv/erlsrv_util.c $(ERLSRV_HEADERS) \
-$(OBJDIR)/erlsrv_logmess.h
- $(CC) $(CFLAGS) -I$(OBJDIR) $(MT_FLAG) -o $@ -c $<
+# To fix a spooky parallel make build problem on Windows there are some
+# false dependencies on the $(MC), $(RC) and .o rules. The theory behind
+# is that the $(MC) and/or $(RC) compilers seems to temporarily create and
+# destroy a toplevel file vc100.pdb that simultaneous ordinary compilations
+# (that have been by flags explicitly ordered to not use .pdb files)
+# gets upset when that file vanishes from under their feet.
+#
+# The false dependencies are targeted to make make (pun intended) run
+# the $(MC) and $(RC) compilations to completion before all others.
+
+LOGMESS_GENERATED = $(OBJDIR)/LOGMESS-GENERATED
+$(MC_OUTPUTS): $(LOGMESS_GENERATED)
+$(LOGMESS_GENERATED): $(WINETC)/erlsrv/erlsrv_logmess.mc
+ $(MC) -o $(OBJDIR) $(WINETC)/erlsrv/erlsrv_logmess.mc && \
+ echo $? >$(LOGMESS_GENERATED)
+
+$(OBJDIR)/$(ERLRES_OBJ): $(WINETC)/erl.rc $(WINETC)/erlang.ico \
+ $(WINETC)/erl_icon.ico $(WINETC)/hrl_icon.ico \
+ $(WINETC)/beam_icon.ico $(LOGMESS_GENERATED)
+ $(RC) -o $@ -I$(WINETC) $(WINETC)/erl.rc
ifeq ($(USING_VC), yes)
-$(OBJDIR)/erlsrv_logmess.res: $(OBJDIR)/erlsrv_logmess.rc
+RC_GENERATED = $(OBJDIR)/erlsrv_logmess.res
+$(RC_GENERATED): $(OBJDIR)/erlsrv_logmess.rc $(OBJDIR)/$(ERLRES_OBJ)
$(RC) -o $(OBJDIR)/erlsrv_logmess.res -I$(OBJDIR) $(OBJDIR)/erlsrv_logmess.rc
else
-$(OBJDIR)/erlsrv_logmess.o: $(OBJDIR)/erlsrv_logmess.res
+RC_GENERATED = $(OBJDIR)/erlsrv_logmess.o
+$(RC_GENERATED): $(OBJDIR)/erlsrv_logmess.res $(OBJDIR)/$(ERLRES_OBJ)
$(RC) -o $(OBJDIR)/erlsrv_logmess.o -I$(OBJDIR) $(OBJDIR)/erlsrv_logmess.res
endif
-$(MC_OUTPUTS): $(WINETC)/erlsrv/erlsrv_logmess.mc
- $(MC) -o $(OBJDIR) $(WINETC)/erlsrv/erlsrv_logmess.mc
+# The service expects to be compiled with $(MT_FLAG) flag.
+$(OBJDIR)/%.o: $(WINETC)/erlsrv/%.c $(ERLSRV_HEADERS) $(RC_GENERATED)
+ $(CC) $(CFLAGS) $(MT_FLAG) -o $@ -c $<
-$(OBJDIR)/werl.o: $(WINETC)/erl.c
+$(OBJDIR)/erlsrv_util.o: $(WINETC)/erlsrv/erlsrv_util.c $(ERLSRV_HEADERS) \
+ $(OBJDIR)/erlsrv_logmess.h $(RC_GENERATED)
+ $(CC) $(CFLAGS) -I$(OBJDIR) $(MT_FLAG) -o $@ -c $<
+
+$(OBJDIR)/werl.o: $(WINETC)/erl.c $(WINETC)/init_file.h $(RC_GENERATED)
$(CC) $(CFLAGS) -DBUILD_TYPE=\"-$(TYPE)\" -DERL_RUN_SHARED_LIB=1 \
-DWIN32_WERL -o $@ -c $(WINETC)/erl.c
-$(OBJDIR)/erl.o: $(WINETC)/erl.c
+$(OBJDIR)/erl.o: $(WINETC)/erl.c $(WINETC)/init_file.h $(RC_GENERATED)
$(CC) $(CFLAGS) -DBUILD_TYPE=\"-$(TYPE)\" -DERL_RUN_SHARED_LIB=1 \
-o $@ -c $(WINETC)/erl.c
-$(OBJDIR)/erlexec.o: $(ERLEXECDIR)/erlexec.c
+$(OBJDIR)/erlexec.o: $(ERLEXECDIR)/erlexec.c $(RC_GENERATED)
$(CC) $(CFLAGS) -DBUILD_TYPE=\"-$(TYPE)\" -DERL_RUN_SHARED_LIB=1 \
-o $@ -c $(ERLEXECDIR)/erlexec.c
-$(OBJDIR)/win_erlexec.o: $(WINETC)/win_erlexec.c
+$(OBJDIR)/win_erlexec.o: $(WINETC)/win_erlexec.c $(RC_GENERATED)
$(CC) $(CFLAGS) -DBUILD_TYPE=\"-$(TYPE)\" -DERL_RUN_SHARED_LIB=1 \
-o $@ -c $(WINETC)/win_erlexec.c
-$(OBJDIR)/init_file.o: $(WINETC)/init_file.c $(WINETC)/init_file.h
+$(OBJDIR)/init_file.o: $(WINETC)/init_file.c $(WINETC)/init_file.h $(RC_GENERATED)
$(CC) $(CFLAGS) -o $@ -c $(WINETC)/init_file.c
-$(OBJDIR)/Install.o: $(WINETC)/Install.c $(WINETC)/init_file.h
+$(OBJDIR)/Install.o: $(WINETC)/Install.c $(WINETC)/init_file.h $(RC_GENERATED)
$(CC) $(CFLAGS) -o $@ -c $(WINETC)/Install.c
-$(OBJDIR)/$(ERLRES_OBJ): $(WINETC)/erl.rc $(WINETC)/erlang.ico $(WINETC)/erl_icon.ico $(WINETC)/hrl_icon.ico $(WINETC)/beam_icon.ico
- $(RC) -o $@ -I$(WINETC) $(WINETC)/erl.rc
-
-$(OBJDIR)/start_erl.o: $(WINETC)/start_erl.c
+$(OBJDIR)/start_erl.o: $(WINETC)/start_erl.c $(RC_GENERATED)
$(CC) $(CFLAGS) -o $@ -c $(WINETC)/start_erl.c
-$(ENTRY_OBJ): $(ENTRY_SRC)
+$(ENTRY_OBJ): $(ENTRY_SRC) $(RC_GENERATED)
$(CC) $(CFLAGS) -o $@ -c $(ENTRY_SRC)
Install.ini: ../$(TARGET)/Install.src ../../vsn.mk $(TARGET)/Makefile
@@ -451,6 +389,8 @@ Install.ini: ../$(TARGET)/Install.src ../../vsn.mk $(TARGET)/Makefile
../$(TARGET)/Install.src > Install.ini
+else
+RC_GENERATED =
endif
#---------------------------------------------------------
# End of windows specific targets.
@@ -478,7 +418,7 @@ $(BINDIR)/heart@EXEEXT@: $(OBJDIR)/heart.o $(ENTRY_OBJ)
$(LD) $(LDFLAGS) $(ENTRY_LDFLAGS) -o $@ $(OBJDIR)/heart.o \
$(ENTRY_OBJ) $(WINDSOCK)
-$(OBJDIR)/heart.o: heart.c
+$(OBJDIR)/heart.o: heart.c $(RC_GENERATED)
$(CC) $(CFLAGS) -o $@ -c heart.c
endif
@@ -506,6 +446,84 @@ $(OBJDIR)/vxcall.o: $(VXETC)/vxcall.c
+#
+# Objects & executables
+#
+#$(OBJDIR)/%.o: %.c
+# $(CC) $(CFLAGS) -o $@ -c $<
+#
+#$(OBJDIR)/%.o: ../unix/%.c
+# $(CC) $(CFLAGS) -o $@ -c $<
+#
+#$(BINDIR)/%: $(OBJDIR)/%.o
+# $(PURIFY) $(LD) $(LDFLAGS) -o $@ $< $(LIBS)
+
+$(OBJDIR)/inet_gethost.o: inet_gethost.c $(RC_GENERATED)
+ $(CC) $(CFLAGS) -o $@ -c inet_gethost.c
+
+$(BINDIR)/inet_gethost@EXEEXT@: $(OBJDIR)/inet_gethost.o $(ENTRY_OBJ) $(ERTS_LIB)
+ $(PURIFY) $(LD) $(LDFLAGS) $(ENTRY_LDFLAGS) -o $@ $(OBJDIR)/inet_gethost.o $(ENTRY_OBJ) $(LIBS) $(ERTS_INTERNAL_LIBS)
+
+$(BINDIR)/run_erl: $(OBJDIR)/safe_string.o $(OBJDIR)/run_erl.o
+ $(LD) $(LDFLAGS) -o $@ $(OBJDIR)/safe_string.o $(OBJDIR)/run_erl.o $(LIBS)
+
+$(OBJDIR)/run_erl.o: ../unix/run_erl.c $(RC_GENERATED)
+ $(CC) $(CFLAGS) -o $@ -c ../unix/run_erl.c
+
+$(BINDIR)/to_erl: $(OBJDIR)/safe_string.o $(OBJDIR)/to_erl.o
+ $(LD) $(LDFLAGS) -o $@ $(OBJDIR)/safe_string.o $(OBJDIR)/to_erl.o
+
+$(OBJDIR)/to_erl.o: ../unix/to_erl.c $(RC_GENERATED)
+ $(CC) $(CFLAGS) -o $@ -c ../unix/to_erl.c
+
+$(BINDIR)/dyn_erl: $(OBJDIR)/safe_string.o $(OBJDIR)/dyn_erl.o
+ $(LD) $(LDFLAGS) -o $@ $(OBJDIR)/safe_string.o $(OBJDIR)/dyn_erl.o
+
+$(OBJDIR)/dyn_erl.o: ../unix/dyn_erl.c $(RC_GENERATED)
+ $(CC) $(CFLAGS) -o $@ -c ../unix/dyn_erl.c
+
+$(OBJDIR)/safe_string.o: ../unix/safe_string.c $(RC_GENERATED)
+ $(CC) $(CFLAGS) -o $@ -c ../unix/safe_string.c
+
+ifneq ($(TARGET),win32)
+$(BINDIR)/$(ERLEXEC): $(OBJDIR)/$(ERLEXEC).o $(ERTS_LIB)
+ $(PURIFY) $(LD) $(LDFLAGS) -o $@ $(OBJDIR)/$(ERLEXEC).o $(ERTS_INTERNAL_LIBS)
+
+$(OBJDIR)/$(ERLEXEC).o: $(ERLEXECDIR)/$(ERLEXEC).c $(RC_GENERATED)
+ $(CC) -I$(EMUDIR) $(CFLAGS) -o $@ -c $(ERLEXECDIR)/$(ERLEXEC).c
+endif
+$(BINDIR)/erlc@EXEEXT@: $(OBJDIR)/erlc.o $(ERTS_LIB)
+ $(PURIFY) $(LD) $(LDFLAGS) -o $@ $(OBJDIR)/erlc.o -L$(OBJDIR) $(LIBS) $(ERTS_INTERNAL_LIBS)
+
+$(OBJDIR)/erlc.o: erlc.c $(RC_GENERATED)
+ $(CC) $(CFLAGS) -o $@ -c erlc.c
+
+$(BINDIR)/dialyzer@EXEEXT@: $(OBJDIR)/dialyzer.o $(ERTS_LIB)
+ $(PURIFY) $(LD) $(LDFLAGS) -o $@ $(OBJDIR)/dialyzer.o -L$(OBJDIR) $(LIBS) $(ERTS_INTERNAL_LIBS)
+
+$(OBJDIR)/dialyzer.o: dialyzer.c $(RC_GENERATED)
+ $(CC) $(CFLAGS) -o $@ -c dialyzer.c
+
+$(BINDIR)/typer@EXEEXT@: $(OBJDIR)/typer.o $(ERTS_LIB)
+ $(PURIFY) $(LD) $(LDFLAGS) -o $@ $(OBJDIR)/typer.o -L$(OBJDIR) $(LIBS) $(ERTS_INTERNAL_LIBS)
+
+$(OBJDIR)/typer.o: typer.c $(RC_GENERATED)
+ $(CC) $(CFLAGS) -o $@ -c typer.c
+
+$(BINDIR)/escript@EXEEXT@: $(OBJDIR)/escript.o $(ERTS_LIB)
+ $(PURIFY) $(LD) $(LDFLAGS) -o $@ $(OBJDIR)/escript.o -L$(OBJDIR) $(LIBS) $(ERTS_INTERNAL_LIBS)
+
+$(OBJDIR)/escript.o: escript.c $(RC_GENERATED)
+ $(CC) $(CFLAGS) -o $@ -c escript.c
+
+$(BINDIR)/ct_run@EXEEXT@: $(OBJDIR)/ct_run.o $(ERTS_LIB)
+ $(PURIFY) $(LD) $(LDFLAGS) -o $@ $(OBJDIR)/ct_run.o -L$(OBJDIR) $(LIBS) $(ERTS_INTERNAL_LIBS)
+
+$(OBJDIR)/ct_run.o: ct_run.c $(RC_GENERATED)
+ $(CC) $(CFLAGS) -o $@ -c ct_run.c
+
+
+
Install: ../unix/Install.src ../../vsn.mk $(TARGET)/Makefile
sed -e 's;%I_VSN%;$(VSN);' \
-e 's;%EMULATOR%;$(EMULATOR);' \
diff --git a/erts/preloaded/ebin/erlang.beam b/erts/preloaded/ebin/erlang.beam
index 9e369d5348..b78747bc84 100644
--- a/erts/preloaded/ebin/erlang.beam
+++ b/erts/preloaded/ebin/erlang.beam
Binary files differ
diff --git a/erts/preloaded/src/erlang.erl b/erts/preloaded/src/erlang.erl
index 4affc9bffe..4cbff3f36e 100644
--- a/erts/preloaded/src/erlang.erl
+++ b/erts/preloaded/src/erlang.erl
@@ -43,6 +43,9 @@
-export([memory/0, memory/1]).
-export([alloc_info/1, alloc_sizes/1]).
+-export([gather_sched_wall_time_result/1,
+ await_sched_wall_time_modifications/2]).
+
-deprecated([hash/2]).
% Get rid of autoimports of spawn to avoid clashes with ourselves.
@@ -1202,3 +1205,34 @@ receive_allocator(Ref, N, Acc) ->
{Ref, _, InfoList} ->
receive_allocator(Ref, N-1, insert_info(InfoList, Acc))
end.
+
+-spec await_sched_wall_time_modifications(Ref, Result) -> boolean() when
+ Ref :: reference(),
+ Result :: boolean().
+
+await_sched_wall_time_modifications(Ref, Result) ->
+ sched_wall_time(Ref, erlang:system_info(schedulers)),
+ Result.
+
+-spec gather_sched_wall_time_result(Ref) -> [{pos_integer(),
+ non_neg_integer(),
+ non_neg_integer()}] when
+ Ref :: reference().
+
+gather_sched_wall_time_result(Ref) when is_reference(Ref) ->
+ sched_wall_time(Ref, erlang:system_info(schedulers), []).
+
+sched_wall_time(_Ref, 0) ->
+ ok;
+sched_wall_time(Ref, N) ->
+ receive Ref -> sched_wall_time(Ref, N-1) end.
+
+sched_wall_time(_Ref, 0, Acc) ->
+ Acc;
+sched_wall_time(Ref, N, undefined) ->
+ receive {Ref, _} -> sched_wall_time(Ref, N-1, undefined) end;
+sched_wall_time(Ref, N, Acc) ->
+ receive
+ {Ref, undefined} -> sched_wall_time(Ref, N-1, undefined);
+ {Ref, SWT} -> sched_wall_time(Ref, N-1, [SWT|Acc])
+ end.
diff --git a/erts/vsn.mk b/erts/vsn.mk
index 053c0e9f52..bbf77b1a68 100644
--- a/erts/vsn.mk
+++ b/erts/vsn.mk
@@ -1,7 +1,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 1997-2011. All Rights Reserved.
+# Copyright Ericsson AB 1997-2012. All Rights Reserved.
#
# The contents of this file are subject to the Erlang Public License,
# Version 1.1, (the "License"); you may not use this file except in
diff --git a/lib/debugger/test/bs_construct_SUITE.erl b/lib/debugger/test/bs_construct_SUITE.erl
index 187c9f53b0..fa7b40ff1e 100644
--- a/lib/debugger/test/bs_construct_SUITE.erl
+++ b/lib/debugger/test/bs_construct_SUITE.erl
@@ -56,7 +56,7 @@ end_per_group(_GroupName, Config) ->
init_per_testcase(_Case, Config) ->
test_lib:interpret(?MODULE),
- Dog = test_server:timetrap(?t:minutes(1)),
+ Dog = test_server:timetrap(?t:minutes(15)),
[{watchdog,Dog}|Config].
end_per_testcase(_Case, Config) ->
diff --git a/lib/debugger/test/bs_match_misc_SUITE.erl b/lib/debugger/test/bs_match_misc_SUITE.erl
index 89fce263f5..ec3746d76a 100644
--- a/lib/debugger/test/bs_match_misc_SUITE.erl
+++ b/lib/debugger/test/bs_match_misc_SUITE.erl
@@ -57,7 +57,7 @@ end_per_suite(Config) when is_list(Config) ->
init_per_testcase(_Case, Config) ->
test_lib:interpret(?MODULE),
- Dog = test_server:timetrap(?t:minutes(1)),
+ Dog = test_server:timetrap(?t:minutes(15)),
[{watchdog,Dog}|Config].
end_per_testcase(_Case, Config) ->
diff --git a/lib/erl_docgen/priv/xsl/db_html.xsl b/lib/erl_docgen/priv/xsl/db_html.xsl
index 4f6c758e7b..7cf5465f90 100644
--- a/lib/erl_docgen/priv/xsl/db_html.xsl
+++ b/lib/erl_docgen/priv/xsl/db_html.xsl
@@ -555,6 +555,23 @@
<!-- End of Dialyzer type/spec tags -->
+ <!-- Cache for each module all the elements used for navigation. -->
+ <xsl:variable name="erlref.nav" select="exsl:node-set($erlref.nav_rtf)"/>
+
+ <xsl:variable name="erlref.nav_rtf">
+ <xsl:for-each select="//erlref">
+ <xsl:variable name="cval" select="module"/>
+ <xsl:variable name="link_cval"><xsl:value-of select="translate($cval, '&#173;', '')"/></xsl:variable>
+ <module name="{$cval}">
+ <xsl:call-template name="menu.funcs">
+ <xsl:with-param name="entries" select="funcs/func/name"/>
+ <xsl:with-param name="cval" select="$cval"/>
+ <xsl:with-param name="basename" select="$link_cval"/>
+ </xsl:call-template>
+ </module>
+ </xsl:for-each>
+ </xsl:variable>
+
<!-- Page layout -->
<xsl:template name="pagelayout">
<xsl:param name="chapnum"/>
@@ -1324,12 +1341,25 @@
Top of manual page
</a>
</li>
- <xsl:call-template name="menu.funcs">
- <xsl:with-param name="entries"
- select="funcs/func/name"/>
- <xsl:with-param name="basename"><xsl:value-of select="$link_cval"/></xsl:with-param>
- <xsl:with-param name="cval" select="$cval"/>
- </xsl:call-template>
+ <xsl:call-template name="nl"/>
+ <xsl:choose>
+ <xsl:when test="local-name() = 'erlref'">
+ <!-- Use the cached value in order to save time.
+ value-of a string node is _much_ faster than
+ copy-of a rtf -->
+ <xsl:value-of
+ disable-output-escaping="yes"
+ select="$erlref.nav/module[@name = $cval]"/>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:call-template name="menu.funcs">
+ <xsl:with-param name="entries"
+ select="funcs/func/name"/>
+ <xsl:with-param name="basename"><xsl:value-of select="$link_cval"/></xsl:with-param>
+ <xsl:with-param name="cval" select="$cval"/>
+ </xsl:call-template>
+ </xsl:otherwise>
+ </xsl:choose>
</ul>
</li>
</xsl:when>
@@ -1456,11 +1486,30 @@
<!-- Skip. Only works for Dialyzer specs. -->
</xsl:when>
<xsl:otherwise>
+<!--
<li title="{$fname}-{$arity}">
<a href="{$basename}.html#{$fname}-{$arity}">
<xsl:value-of select="$fname"/>/<xsl:value-of select="$arity"/>
</a>
</li>
+-->
+ <!-- Generate a text node -->
+ <xsl:text>&lt;li title="</xsl:text>
+ <xsl:value-of select="$fname"/>
+ <xsl:text>-</xsl:text>
+ <xsl:value-of select="$arity"/>
+ <xsl:text>">&lt;a href="</xsl:text>
+ <xsl:value-of select="$basename"/>
+ <xsl:text>.html#</xsl:text>
+ <xsl:value-of select="$fname"/>
+ <xsl:text>-</xsl:text>
+ <xsl:value-of select="$arity"/>
+ <xsl:text>"></xsl:text>
+ <xsl:value-of select="$fname"/>
+ <xsl:text>/</xsl:text>
+ <xsl:value-of select="$arity"/>
+ <xsl:text>&lt;/a>&lt;/li></xsl:text>
+ <xsl:call-template name="nl"/>
</xsl:otherwise>
</xsl:choose>
</xsl:when>
@@ -2226,4 +2275,9 @@
</xsl:template>
+ <xsl:template name="nl">
+ <xsl:text>
+</xsl:text>
+ </xsl:template>
+
</xsl:stylesheet>
diff --git a/lib/inviso/test/inviso_tool_SUITE.erl b/lib/inviso/test/inviso_tool_SUITE.erl
index 6b16e506eb..f8a9cea47f 100644
--- a/lib/inviso/test/inviso_tool_SUITE.erl
+++ b/lib/inviso/test/inviso_tool_SUITE.erl
@@ -52,7 +52,12 @@ end_per_group(_GroupName, Config) ->
%% -----------------------------------------------------------------------------
init_per_suite(Config) ->
- Config.
+ case test_server:is_native(lists) of
+ true ->
+ {skip,"Native libs -- tracing doesn't work"};
+ false ->
+ Config
+ end.
%% -----------------------------------------------------------------------------
end_per_suite(_Config) ->
diff --git a/lib/kernel/test/erl_prim_loader_SUITE.erl b/lib/kernel/test/erl_prim_loader_SUITE.erl
index 7599a89779..d0d52c5ea7 100644
--- a/lib/kernel/test/erl_prim_loader_SUITE.erl
+++ b/lib/kernel/test/erl_prim_loader_SUITE.erl
@@ -175,10 +175,10 @@ wait_really_started(Node, N) ->
inet_disconnects(doc) -> ["Start a node using the 'inet' loading method, ",
"then lose the connection."];
inet_disconnects(Config) when is_list(Config) ->
- case os:type() of
- vxworks ->
- {comment, "VxWorks: tested separately"};
- _ ->
+ case test_server:is_native(erl_boot_server) of
+ true ->
+ {skip,"erl_boot_server is native"};
+ false ->
?line Name = erl_prim_test_inet_disconnects,
?line Host = host(),
?line Cookie = atom_to_list(erlang:get_cookie()),
diff --git a/lib/observer/test/etop_SUITE.erl b/lib/observer/test/etop_SUITE.erl
index a0782ea809..a277453620 100644
--- a/lib/observer/test/etop_SUITE.erl
+++ b/lib/observer/test/etop_SUITE.erl
@@ -57,11 +57,14 @@ end_per_group(_GroupName, Config) ->
Config.
-text(suite) ->
- [];
-text(doc) ->
- ["Start etop with text presentation"];
-text(Config) when is_list(Config) ->
+%% Start etop with text presentation
+text(_) ->
+ case test_server:is_native(lists) of
+ true -> {skip,"Native libs -- tracing does not work"};
+ false -> text()
+ end.
+
+text() ->
?line {ok,Node} = ?t:start_node(node2,peer,[]),
%% Must spawn this process, else the test case will never end.
diff --git a/lib/runtime_tools/test/inviso_SUITE.erl b/lib/runtime_tools/test/inviso_SUITE.erl
index 758867cf45..33626ffd9e 100644
--- a/lib/runtime_tools/test/inviso_SUITE.erl
+++ b/lib/runtime_tools/test/inviso_SUITE.erl
@@ -66,13 +66,18 @@ end_per_group(_GroupName, Config) ->
init_per_suite(Config) ->
- %% No never know who skrewed up this node before this suite! :-)
- erlang:trace_pattern({'_','_','_'},[],[local]),
- erlang:trace_pattern({'_','_','_'},[],[global]),
- erlang:trace(all,false,[all]),
+ case test_server:is_native(lists) of
+ true ->
+ {skip,"Native libs -- tracing doesn't work"};
+ false ->
+ %% We never know who messed up this node before this suite! :-)
+ erlang:trace_pattern({'_','_','_'},[],[local]),
+ erlang:trace_pattern({'_','_','_'},[],[global]),
+ erlang:trace(all,false,[all]),
- ?l ok=application:start(runtime_tools),
- Config.
+ ok=application:start(runtime_tools),
+ Config
+ end.
end_per_suite(_Config) ->
?l ok=application:stop(runtime_tools).
diff --git a/lib/snmp/doc/src/notes.xml b/lib/snmp/doc/src/notes.xml
index 942d943c3c..704ff0a20f 100644
--- a/lib/snmp/doc/src/notes.xml
+++ b/lib/snmp/doc/src/notes.xml
@@ -34,6 +34,64 @@
<section>
+ <title>SNMP Development Toolkit 4.21.7</title>
+ <p>Version 4.21.7 supports code replacement in runtime from/to
+ version 4.21.6, 4.21.5, 4.21.4, 4.21.3, 4.21.2, 4.21.1, 4.21, 4.20.1 and
+ 4.20. </p>
+
+ <section>
+ <title>Improvements and new features</title>
+ <p>-</p>
+
+ <!--
+ <list type="bulleted">
+ <item>
+ <p>[agent] DoS attack using GET-BULK with large value of
+ MaxRepetitions.
+ A preventive method has been implementing by simply
+ limit the number of varbinds that can be included in
+ a Get-BULK response message. This is specified by the
+ new config option,
+ <seealso marker="snmp_app#agent_gb_max_vbs">gb_max_vbs</seealso>.
+ </p>
+ <p>Own Id: OTP-9700</p>
+ </item>
+
+ </list>
+ -->
+
+ </section>
+
+ <section>
+ <title>Reported Fixed Bugs and Malfunctions</title>
+ <!--
+ <p>-</p>
+ -->
+
+ <list type="bulleted">
+ <item>
+ <p>[agent] Simultaneous
+ <seealso marker="snmpa#backup">snmpa:backup/1,2</seealso>
+ calls can interfere.
+ The master agent did not check if a backup was already in
+ progress when a backup request was accepted. </p>
+ <p>Own Id: OTP-9884</p>
+ <p>Aux Id: Seq 11995</p>
+ </item>
+
+ </list>
+
+ </section>
+
+ <section>
+ <title>Incompatibilities</title>
+ <p>-</p>
+ </section>
+
+ </section> <!-- 4.21.7 -->
+
+
+ <section>
<title>SNMP Development Toolkit 4.21.6</title>
<p>Version 4.21.6 supports code replacement in runtime from/to
version 4.21.5, 4.21.4, 4.21.3, 4.21.2, 4.21.1, 4.21, 4.20.1 and
diff --git a/lib/snmp/doc/src/snmpa.xml b/lib/snmp/doc/src/snmpa.xml
index 27d89ea4e3..2322af28cc 100644
--- a/lib/snmp/doc/src/snmpa.xml
+++ b/lib/snmp/doc/src/snmpa.xml
@@ -4,7 +4,7 @@
<erlref>
<header>
<copyright>
- <year>2004</year><year>2011</year>
+ <year>2004</year><year>2012</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -198,12 +198,18 @@ notification_delivery_info() = #snmpa_notification_delivery_info{}
<type>
<v>BackupDir = string()</v>
<v>Agent = pid() | atom()</v>
+ <v>Reason = backup_in_progress | term()</v>
</type>
<desc>
<p>Backup persistent/permanent data handled by the agent
(such as local-db, mib-data and vacm). </p>
<p>Data stored by mnesia is not handled. </p>
<p>BackupDir cannot be identical to DbDir. </p>
+ <p>Simultaneous backup calls are <em>not</em> allowed.
+ That is, two different processes cannot simultaneously
+ successfully call this function. One of them will be first,
+ and succeed. The second will fail with the error reason
+ <c>backup_in_progress</c>. </p>
<marker id="info"></marker>
</desc>
@@ -217,13 +223,13 @@ notification_delivery_info() = #snmpa_notification_delivery_info{}
</type>
<desc>
<p>Returns a list (a dictionary) containing information about
- the agent. Information includes loaded MIBs, registered
- sub-agents, some information about the memory allocation. </p>
- <p>As of version 4.4 the format of the info has been changed.
- To convert the info to the old format, call the
- <seealso marker="#old_info_format">old_info_format</seealso>
- function. </p>
-
+ the agent. Information includes loaded MIBs, registered
+ sub-agents, some information about the memory allocation. </p>
+ <p>As of version 4.4 the format of the info has been changed.
+ To convert the info to the old format, call the
+ <seealso marker="#old_info_format">old_info_format</seealso>
+ function. </p>
+
<marker id="old_info_format"></marker>
</desc>
</func>
diff --git a/lib/snmp/src/agent/snmpa_agent.erl b/lib/snmp/src/agent/snmpa_agent.erl
index 17cb9c9fe3..9cc986cf47 100644
--- a/lib/snmp/src/agent/snmpa_agent.erl
+++ b/lib/snmp/src/agent/snmpa_agent.erl
@@ -1262,7 +1262,8 @@ handle_call(info, _From, S) ->
handle_call(get_net_if, _From, S) ->
{reply, get(net_if), S};
-handle_call({backup, BackupDir}, From, S) ->
+%% Only accept a backup request if there is none already in progress
+handle_call({backup, BackupDir}, From, #state{backup = undefined} = S) ->
?vlog("backup: ~p", [BackupDir]),
Pid = self(),
V = get(verbosity),
@@ -1279,7 +1280,11 @@ handle_call({backup, BackupDir}, From, S) ->
end),
?vtrace("backup server: ~p", [BackupServer]),
{noreply, S#state{backup = {BackupServer, From}}};
-
+
+handle_call({backup, _BackupDir}, From, #state{backup = Backup} = S) ->
+ ?vinfo("backup already in progress: ~p", [Backup]),
+ {reply, {error, backup_in_progress}, S};
+
handle_call(dump_mibs, _From, S) ->
Reply = snmpa_mib:dump(get(mibserver)),
{reply, Reply, S};
diff --git a/lib/snmp/src/agent/snmpa_local_db.erl b/lib/snmp/src/agent/snmpa_local_db.erl
index 5b04c70054..1ec8dd3874 100644
--- a/lib/snmp/src/agent/snmpa_local_db.erl
+++ b/lib/snmp/src/agent/snmpa_local_db.erl
@@ -486,7 +486,11 @@ handle_call({match, Name, Db, Pattern}, _From, State) ->
L1 = match(Db, Name, Pattern, State),
{reply, lists:delete([undef], L1), State};
-handle_call({backup, BackupDir}, From, #state{dets = Dets} = State) ->
+%% This check (that there is no backup already in progress) is also
+%% done in the master agent process, but just in case a user issues
+%% a backup call to this process directly, we add a similar check here.
+handle_call({backup, BackupDir}, From,
+ #state{backup = undefined, dets = Dets} = State) ->
?vlog("backup: ~p",[BackupDir]),
Pid = self(),
V = get(verbosity),
@@ -511,6 +515,10 @@ handle_call({backup, BackupDir}, From, #state{dets = Dets} = State) ->
{reply, Error, State}
end;
+handle_call({backup, _BackupDir}, From, #state{backup = Backup} = S) ->
+ ?vinfo("backup already in progress: ~p", [Backup]),
+ {reply, {error, backup_in_progress}, S};
+
handle_call(dump, _From, #state{dets = Dets} = State) ->
?vlog("dump",[]),
dets_sync(Dets),
diff --git a/lib/snmp/src/agent/snmpa_mib.erl b/lib/snmp/src/agent/snmpa_mib.erl
index ce90db18b3..574467d38f 100644
--- a/lib/snmp/src/agent/snmpa_mib.erl
+++ b/lib/snmp/src/agent/snmpa_mib.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2010. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2012. 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
@@ -552,8 +552,12 @@ handle_call({dump, File}, _From, #state{data = Data} = State) ->
Reply = snmpa_mib_data:dump(Data, File),
{reply, Reply, State};
-handle_call({backup, BackupDir}, From, #state{data = Data} = State) ->
- ?vlog("backup to ~s",[BackupDir]),
+%% This check (that there is no backup already in progress) is also
+%% done in the master agent process, but just in case a user issues
+%% a backup call to this process directly, we add a similar check here.
+handle_call({backup, BackupDir}, From,
+ #state{backup = undefined, data = Data} = State) ->
+ ?vlog("backup to ~s", [BackupDir]),
Pid = self(),
V = get(verbosity),
case file:read_file_info(BackupDir) of
@@ -576,6 +580,10 @@ handle_call({backup, BackupDir}, From, #state{data = Data} = State) ->
{reply, Error, State}
end;
+handle_call({backup, _BackupDir}, From, #state{backup = Backup} = S) ->
+ ?vinfo("backup already in progress: ~p", [Backup]),
+ {reply, {error, backup_in_progress}, S};
+
handle_call(stop, _From, State) ->
?vlog("stop",[]),
{stop, normal, ok, State};
diff --git a/lib/snmp/src/agent/snmpa_mpd.erl b/lib/snmp/src/agent/snmpa_mpd.erl
index 0305e1fbec..2d37ea56f0 100644
--- a/lib/snmp/src/agent/snmpa_mpd.erl
+++ b/lib/snmp/src/agent/snmpa_mpd.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2011. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2012. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
diff --git a/lib/snmp/src/app/snmp.appup.src b/lib/snmp/src/app/snmp.appup.src
index 254e697039..c8e5eec6db 100644
--- a/lib/snmp/src/app/snmp.appup.src
+++ b/lib/snmp/src/app/snmp.appup.src
@@ -22,15 +22,24 @@
%% ----- U p g r a d e -------------------------------------------------------
[
+ {"4.21.6",
+ [
+ {update, snmpa_local_db, soft, soft_purge, soft_purge, []},
+ {update, snmpa_mib, soft, soft_purge, soft_purge, []},
+ {update, snmpa_agent, soft, soft_purge, soft_purge, []}
+ ]
+ },
{"4.21.5",
[
{load_module, snmpa, soft_purge, soft_purge, []},
- {load_module, snmp_target_mib, soft_purge, soft_purge, [snmpa_mib_lib]},
- {load_module, snmpa_mib_lib, soft_purge, soft_purge, []},
- {load_module, snmpa_trap, soft_purge, soft_purge, []},
- {load_module, snmpa_vacm, soft_purge, soft_purge, []},
+ {load_module, snmp_target_mib, soft_purge, soft_purge, [snmpa_mib_lib]},
+ {load_module, snmpa_mib_lib, soft_purge, soft_purge, []},
+ {load_module, snmpa_trap, soft_purge, soft_purge, []},
+ {load_module, snmpa_vacm, soft_purge, soft_purge, []},
+ {update, snmpa_local_db, soft, soft_purge, soft_purge, []},
+ {update, snmpa_mib, soft, soft_purge, soft_purge, []},
{update, snmpa_supervisor, soft, soft_purge, soft_purge, []},
- {update, snmpa_agent, soft, soft_purge, soft_purge, []}
+ {update, snmpa_agent, soft, soft_purge, soft_purge, []}
]
},
{"4.21.4",
@@ -44,7 +53,9 @@
{load_module, snmp_generic_mnesia, soft_purge, soft_purge, []},
{load_module, snmp_view_based_acm_mib, soft_purge, soft_purge, []},
{load_module, snmpa_vacm, soft_purge, soft_purge, []},
- {update, snmpa_agent, soft, soft_purge, soft_purge, []}
+ {update, snmpa_local_db, soft, soft_purge, soft_purge, []},
+ {update, snmpa_mib, soft, soft_purge, soft_purge, []},
+ {update, snmpa_agent, soft, soft_purge, soft_purge, []}
]
},
{"4.21.3",
@@ -59,7 +70,8 @@
{load_module, snmp_view_based_acm_mib, soft_purge, soft_purge, []},
{load_module, snmpa_vacm, soft_purge, soft_purge, []},
{update, snmpa_local_db, soft, soft_purge, soft_purge, []},
- {update, snmpa_agent, soft, soft_purge, soft_purge, []}
+ {update, snmpa_mib, soft, soft_purge, soft_purge, []},
+ {update, snmpa_agent, soft, soft_purge, soft_purge, []}
]
},
{"4.21.2",
@@ -76,7 +88,8 @@
{load_module, snmpa_trap, soft_purge, soft_purge, []},
{load_module, snmp_generic_mnesia, soft_purge, soft_purge, []},
{update, snmpa_local_db, soft, soft_purge, soft_purge, []},
- {update, snmpa_agent, soft, soft_purge, soft_purge, []}
+ {update, snmpa_mib, soft, soft_purge, soft_purge, []},
+ {update, snmpa_agent, soft, soft_purge, soft_purge, []}
]
},
{"4.21.1",
@@ -92,8 +105,9 @@
{load_module, snmpa_set_lib, soft_purge, soft_purge, []},
{load_module, snmpa_trap, soft_purge, soft_purge, []},
{load_module, snmp_generic_mnesia, soft_purge, soft_purge, []},
- {update, snmpa_local_db, soft, soft_purge, soft_purge, []},
- {update, snmpa_agent, soft, soft_purge, soft_purge, []},
+ {update, snmpa_local_db, soft, soft_purge, soft_purge, []},
+ {update, snmpa_mib, soft, soft_purge, soft_purge, []},
+ {update, snmpa_agent, soft, soft_purge, soft_purge, []},
{update, snmp_note_store, soft, soft_purge, soft_purge, []}
]
},
@@ -110,8 +124,9 @@
{load_module, snmpa_trap, soft_purge, soft_purge, []},
{load_module, snmp_target_mib, soft_purge, soft_purge, [snmpa_mib_lib]},
{load_module, snmp_generic_mnesia, soft_purge, soft_purge, []},
- {update, snmpa_local_db, soft, soft_purge, soft_purge, []},
- {update, snmpa_agent, soft, soft_purge, soft_purge, []},
+ {update, snmpa_local_db, soft, soft_purge, soft_purge, []},
+ {update, snmpa_mib, soft, soft_purge, soft_purge, []},
+ {update, snmpa_agent, soft, soft_purge, soft_purge, []},
{update, snmp_note_store, soft, soft_purge, soft_purge, []}
]
},
@@ -138,7 +153,8 @@
{update, snmp_note_store, soft, soft_purge, soft_purge, []},
{load_module, snmp_generic_mnesia, soft_purge, soft_purge, []},
{update, snmpa_local_db, soft, soft_purge, soft_purge, []},
- {update, snmpa_agent, soft, soft_purge, soft_purge, [snmpa_mpd]},
+ {update, snmpa_mib, soft, soft_purge, soft_purge, []},
+ {update, snmpa_agent, soft, soft_purge, soft_purge, [snmpa_mpd]},
{update, snmpm_config, soft, soft_purge, soft_purge, [snmp_conf]},
{update, snmpm_server, soft, soft_purge, soft_purge,
[snmpm_net_if, snmpm_mpd, snmpm_config]},
@@ -170,6 +186,7 @@
{update, snmp_note_store, soft, soft_purge, soft_purge, []},
{load_module, snmp_generic_mnesia, soft_purge, soft_purge, []},
{update, snmpa_local_db, soft, soft_purge, soft_purge, []},
+ {update, snmpa_mib, soft, soft_purge, soft_purge, []},
{update, snmpa_agent, soft, soft_purge, soft_purge, [snmpa_mpd]},
{update, snmpm_config, soft, soft_purge, soft_purge, [snmp_conf]},
{update, snmpm_server, soft, soft_purge, soft_purge,
@@ -183,15 +200,24 @@
%% ------D o w n g r a d e ---------------------------------------------------
[
+ {"4.21.6",
+ [
+ {update, snmpa_local_db, soft, soft_purge, soft_purge, []},
+ {update, snmpa_mib, soft, soft_purge, soft_purge, []},
+ {update, snmpa_agent, soft, soft_purge, soft_purge, []}
+ ]
+ },
{"4.21.5",
[
{load_module, snmpa, soft_purge, soft_purge, []},
- {load_module, snmp_target_mib, soft_purge, soft_purge, [snmpa_mib_lib]},
- {load_module, snmpa_mib_lib, soft_purge, soft_purge, []},
- {load_module, snmpa_trap, soft_purge, soft_purge, []},
- {load_module, snmpa_vacm, soft_purge, soft_purge, []},
+ {load_module, snmp_target_mib, soft_purge, soft_purge, [snmpa_mib_lib]},
+ {load_module, snmpa_mib_lib, soft_purge, soft_purge, []},
+ {load_module, snmpa_trap, soft_purge, soft_purge, []},
+ {load_module, snmpa_vacm, soft_purge, soft_purge, []},
{update, snmpa_supervisor, soft, soft_purge, soft_purge, []},
- {update, snmpa_agent, soft, soft_purge, soft_purge, []}
+ {update, snmpa_local_db, soft, soft_purge, soft_purge, []},
+ {update, snmpa_mib, soft, soft_purge, soft_purge, []},
+ {update, snmpa_agent, soft, soft_purge, soft_purge, []}
]
},
{"4.21.4",
@@ -205,7 +231,9 @@
{load_module, snmp_generic_mnesia, soft_purge, soft_purge, []},
{load_module, snmp_view_based_acm_mib, soft_purge, soft_purge, []},
{load_module, snmpa_vacm, soft_purge, soft_purge, []},
- {update, snmpa_agent, soft, soft_purge, soft_purge, []}
+ {update, snmpa_local_db, soft, soft_purge, soft_purge, []},
+ {update, snmpa_mib, soft, soft_purge, soft_purge, []},
+ {update, snmpa_agent, soft, soft_purge, soft_purge, []}
]
},
{"4.21.3",
@@ -220,7 +248,8 @@
{load_module, snmp_view_based_acm_mib, soft_purge, soft_purge, []},
{load_module, snmpa_vacm, soft_purge, soft_purge, []},
{update, snmpa_local_db, soft, soft_purge, soft_purge, []},
- {update, snmpa_agent, soft, soft_purge, soft_purge, []}
+ {update, snmpa_mib, soft, soft_purge, soft_purge, []},
+ {update, snmpa_agent, soft, soft_purge, soft_purge, []}
]
},
{"4.21.2",
@@ -237,7 +266,8 @@
{load_module, snmpa_trap, soft_purge, soft_purge, []},
{load_module, snmp_generic_mnesia, soft_purge, soft_purge, []},
{update, snmpa_local_db, soft, soft_purge, soft_purge, []},
- {update, snmpa_agent, soft, soft_purge, soft_purge, []}
+ {update, snmpa_mib, soft, soft_purge, soft_purge, []},
+ {update, snmpa_agent, soft, soft_purge, soft_purge, []}
]
},
{"4.21.1",
@@ -253,8 +283,9 @@
{load_module, snmpa_set_lib, soft_purge, soft_purge, []},
{load_module, snmpa_trap, soft_purge, soft_purge, []},
{load_module, snmp_generic_mnesia, soft_purge, soft_purge, []},
- {update, snmpa_local_db, soft, soft_purge, soft_purge, []},
- {update, snmpa_agent, soft, soft_purge, soft_purge, []},
+ {update, snmpa_local_db, soft, soft_purge, soft_purge, []},
+ {update, snmpa_mib, soft, soft_purge, soft_purge, []},
+ {update, snmpa_agent, soft, soft_purge, soft_purge, []},
{update, snmp_note_store, soft, soft_purge, soft_purge, []}
]
},
@@ -271,8 +302,9 @@
{load_module, snmpa_trap, soft_purge, soft_purge, []},
{load_module, snmp_target_mib, soft_purge, soft_purge, []},
{load_module, snmp_generic_mnesia, soft_purge, soft_purge, []},
- {update, snmpa_local_db, soft, soft_purge, soft_purge, []},
- {update, snmpa_agent, soft, soft_purge, soft_purge, []},
+ {update, snmpa_local_db, soft, soft_purge, soft_purge, []},
+ {update, snmpa_mib, soft, soft_purge, soft_purge, []},
+ {update, snmpa_agent, soft, soft_purge, soft_purge, []},
{update, snmp_note_store, soft, soft_purge, soft_purge, []}
]
},
@@ -299,7 +331,8 @@
{update, snmp_note_store, soft, soft_purge, soft_purge, []},
{load_module, snmp_generic_mnesia, soft_purge, soft_purge, []},
{update, snmpa_local_db, soft, soft_purge, soft_purge, []},
- {update, snmpa_agent, soft, soft_purge, soft_purge, [snmpa_mpd]},
+ {update, snmpa_mib, soft, soft_purge, soft_purge, []},
+ {update, snmpa_agent, soft, soft_purge, soft_purge, [snmpa_mpd]},
{update, snmpm_config, soft, soft_purge, soft_purge, [snmp_conf]},
{update, snmpm_server, soft, soft_purge, soft_purge,
[snmpm_net_if, snmpm_mpd, snmpm_config]},
@@ -330,7 +363,8 @@
{update, snmp_note_store, soft, soft_purge, soft_purge, []},
{load_module, snmp_generic_mnesia, soft_purge, soft_purge, []},
{update, snmpa_local_db, soft, soft_purge, soft_purge, []},
- {update, snmpa_agent, soft, soft_purge, soft_purge, [snmpa_mpd]},
+ {update, snmpa_mib, soft, soft_purge, soft_purge, []},
+ {update, snmpa_agent, soft, soft_purge, soft_purge, [snmpa_mpd]},
{update, snmpm_config, soft, soft_purge, soft_purge, [snmp_conf]},
{update, snmpm_server, soft, soft_purge, soft_purge,
[snmpm_net_if, snmpm_mpd, snmpm_config]},
diff --git a/lib/snmp/test/snmp_agent_test.erl b/lib/snmp/test/snmp_agent_test.erl
index abfd528639..e968bc65b1 100644
--- a/lib/snmp/test/snmp_agent_test.erl
+++ b/lib/snmp/test/snmp_agent_test.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2003-2011. All Rights Reserved.
+%% Copyright Ericsson AB 2003-2012. 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
@@ -222,7 +222,7 @@ groups() ->
{group, otp_7157}
]
},
- {tickets2, [], [otp8395]},
+ {tickets2, [], [otp8395, otp9884]},
{otp_4394, [], [otp_4394_test]},
{otp_7157, [], [otp_7157_test]
}
@@ -322,6 +322,12 @@ init_per_testcase(otp8395 = Case, Config) when is_list(Config) ->
"~n Config: ~p", [Case, Config]),
Config2 = init_per_testcase2(Case, init_per_suite(Config)),
otp8395({init, Config2});
+init_per_testcase(otp9884 = Case, Config) when is_list(Config) ->
+ ?DBG("init_per_testcase -> entry with"
+ "~n Case: ~p"
+ "~n Config: ~p", [Case, Config]),
+ Config2 = init_per_testcase2(Case, init_per_suite(Config)),
+ otp9884({init, Config2});
init_per_testcase(otp_7157_test = _Case, Config) when is_list(Config) ->
?DBG("init_per_testcase -> entry with"
"~n Case: ~p"
@@ -349,6 +355,8 @@ init_per_testcase(_Case, Config) when is_list(Config) ->
end_per_testcase(otp8395, Config) when is_list(Config) ->
otp8395({fin, Config});
+end_per_testcase(otp9884, Config) when is_list(Config) ->
+ otp9884({fin, Config});
end_per_testcase(_Case, Config) when is_list(Config) ->
?DBG("end_per_testcase -> entry with"
"~n Case: ~p"
@@ -5238,16 +5246,6 @@ loop_it_2(Oid, N) ->
%%%-----------------------------------------------------------------
-
-
-
-%% These are (ticket) test cases where the initiation has to be done
-%% individually.
-
-
-
-
-
%%-----------------------------------------------------------------
%% Ticket: OTP-1128
%% Slogan: Bug in handling of createAndWait set-requests.
@@ -5888,7 +5886,7 @@ otp_7157_test1(MA) ->
otp8395({init, Config}) when is_list(Config) ->
?DBG("otp8395(init) -> entry with"
"~n Config: ~p", [Config]),
-
+
%% --
%% Start nodes
%%
@@ -5896,7 +5894,7 @@ otp8395({init, Config}) when is_list(Config) ->
{ok, AgentNode} = start_node(agent),
%% {ok, SubAgentNode} = start_node(sub_agent),
{ok, ManagerNode} = start_node(manager),
-
+
%% --
%% Mnesia init
%%
@@ -5904,10 +5902,10 @@ otp8395({init, Config}) when is_list(Config) ->
AgentDbDir = ?config(agent_db_dir, Config),
AgentMnesiaDir = filename:join([AgentDbDir, "mnesia"]),
mnesia_init(AgentNode, AgentMnesiaDir),
-
-%% SubAgentDir = ?config(sub_agent_dir, Config),
-%% SubAgentMnesiaDir = filename:join([SubAgentDir, "mnesia"]),
-%% mnesia_init(SubAgentNode, SubAgentMnesiaDir),
+
+ %% SubAgentDir = ?config(sub_agent_dir, Config),
+ %% SubAgentMnesiaDir = filename:join([SubAgentDir, "mnesia"]),
+ %% mnesia_init(SubAgentNode, SubAgentMnesiaDir),
%% ok = mnesia_create_schema(AgentNode, [AgentNode, SubAgentNode]),
%% ok = mnesia:create_schema([AgentNode, SubAgentNode]),
@@ -5932,12 +5930,12 @@ otp8395({init, Config}) when is_list(Config) ->
%% SubAgentIP = tuple_to_list(SubAgentIP0),
{ok, ManagerIP0} = snmp_misc:ip(ManagerHost),
ManagerIP = tuple_to_list(ManagerIP0),
-
+
%% --
%% Write agent config
%%
-
+
Vsns = [v1],
AgentConfDir = ?config(agent_conf_dir, Config),
ManagerConfDir = ?config(manager_top_dir, Config),
@@ -5961,7 +5959,7 @@ otp8395({init, Config}) when is_list(Config) ->
{manager_node, ManagerNode},
{manager_host, ManagerHost},
{manager_ip, ManagerIP}|Config]),
-
+
%% --
%% Create watchdog
%%
@@ -5973,7 +5971,7 @@ otp8395({init, Config}) when is_list(Config) ->
otp8395({fin, Config}) when is_list(Config) ->
?DBG("otp8395(fin) -> entry with"
"~n Config: ~p", [Config]),
-
+
AgentNode = ?config(agent_node, Config),
ManagerNode = ?config(manager_node, Config),
@@ -5981,11 +5979,11 @@ otp8395({fin, Config}) when is_list(Config) ->
%% Stop agent (this is the nice way to do it,
%% so logs and files can be closed in the proper way).
%%
-
+
AgentSup = ?config(agent_sup, Config),
?DBG("otp8395(fin) -> stop (stand-alone) agent: ~p", [AgentSup]),
stop_stdalone_agent(AgentSup),
-
+
%% -
%% Stop mnesia
%%
@@ -6001,8 +5999,8 @@ otp8395({fin, Config}) when is_list(Config) ->
stop_node(AgentNode),
-%% SubAgentNode = ?config(sub_agent_node, Config),
-%% stop_node(SubAgentNode),
+ %% SubAgentNode = ?config(sub_agent_node, Config),
+ %% stop_node(SubAgentNode),
%% -
@@ -6022,7 +6020,7 @@ otp8395(doc) ->
otp8395(Config) when is_list(Config) ->
?DBG("otp8395 -> entry with"
"~n Config: ~p", [Config]),
-
+
?SLEEP(1000),
%% This is just to dirty trick for the ***old*** test-code
@@ -6040,8 +6038,8 @@ otp8395(Config) when is_list(Config) ->
{ok, LogInfo} = rpc:call(AgentNode, snmpa, log_info, []),
?DBG("otp8395 -> LogInfo: ~p", [LogInfo]),
-%% SyncRes = rpc:call(AgentNode, snmp, log_sync, [?audit_trail_log_name]),
-%% ?DBG("otp8395 -> SyncRes: ~p", [SyncRes]),
+ %% SyncRes = rpc:call(AgentNode, snmp, log_sync, [?audit_trail_log_name]),
+ %% ?DBG("otp8395 -> SyncRes: ~p", [SyncRes]),
ok = agent_log_validation(AgentNode),
LTTRes =
@@ -6051,7 +6049,195 @@ otp8395(Config) when is_list(Config) ->
?SLEEP(1000),
?DBG("otp8395 -> done", []),
ok.
-
+
+
+%%-----------------------------------------------------------------
+
+otp9884({init, Config}) when is_list(Config) ->
+ ?DBG("otp9884(init) -> entry with"
+ "~n Config: ~p", [Config]),
+
+ %% --
+ %% Start nodes
+ %%
+
+ {ok, AgentNode} = start_node(agent),
+
+ %% We don't use a manager in this test but the (common) config
+ %% function takes an argument that is derived from this
+ {ok, ManagerNode} = start_node(manager),
+
+ %% --
+ %% Mnesia init
+ %%
+
+ AgentDbDir = ?config(agent_db_dir, Config),
+ AgentMnesiaDir = filename:join([AgentDbDir, "mnesia"]),
+ mnesia_init(AgentNode, AgentMnesiaDir),
+
+ mnesia_create_schema(AgentNode, [AgentNode]),
+
+ mnesia_start(AgentNode),
+
+ %% --
+ %% Host & IP
+ %%
+
+ AgentHost = ?HOSTNAME(AgentNode),
+ ManagerHost = ?HOSTNAME(ManagerNode),
+
+ Host = snmp_test_lib:hostname(),
+ Ip = ?LOCALHOST(),
+ {ok, AgentIP0} = snmp_misc:ip(AgentHost),
+ AgentIP = tuple_to_list(AgentIP0),
+ {ok, ManagerIP0} = snmp_misc:ip(ManagerHost),
+ ManagerIP = tuple_to_list(ManagerIP0),
+
+
+ %% --
+ %% Write agent config
+ %%
+
+ Vsns = [v1],
+ ManagerConfDir = ?config(manager_top_dir, Config),
+ AgentConfDir = ?config(agent_conf_dir, Config),
+ AgentTopDir = ?config(agent_top_dir, Config),
+ AgentBkpDir1 = filename:join([AgentTopDir, backup1]),
+ AgentBkpDir2 = filename:join([AgentTopDir, backup2]),
+ ok = file:make_dir(AgentBkpDir1),
+ ok = file:make_dir(AgentBkpDir2),
+ AgentBkpDirs = [AgentBkpDir1, AgentBkpDir2],
+ snmp_agent_test_lib:config(Vsns,
+ ManagerConfDir, AgentConfDir,
+ ManagerIP, AgentIP),
+
+
+ %% --
+ %% Start the agent
+ %%
+
+ Config2 = start_agent([{host, Host},
+ {ip, Ip},
+ {agent_node, AgentNode},
+ {agent_host, AgentHost},
+ {agent_ip, AgentIP},
+ {agent_backup_dirs, AgentBkpDirs}|Config]),
+
+ %% --
+ %% Create watchdog
+ %%
+
+ Dog = ?WD_START(?MINS(1)),
+
+ [{watchdog, Dog} | Config2];
+
+otp9884({fin, Config}) when is_list(Config) ->
+ ?DBG("otp9884(fin) -> entry with"
+ "~n Config: ~p", [Config]),
+
+ AgentNode = ?config(agent_node, Config),
+ ManagerNode = ?config(manager_node, Config),
+
+ %% -
+ %% Stop agent (this is the nice way to do it,
+ %% so logs and files can be closed in the proper way).
+ %%
+
+ AgentSup = ?config(agent_sup, Config),
+ ?DBG("otp9884(fin) -> stop (stand-alone) agent: ~p", [AgentSup]),
+ stop_stdalone_agent(AgentSup),
+
+ %% -
+ %% Stop mnesia
+ %%
+ ?DBG("otp9884(fin) -> stop mnesia", []),
+ mnesia_stop(AgentNode),
+
+
+ %% -
+ %% Stop the agent node
+ %%
+
+ ?DBG("otp9884(fin) -> stop agent node", []),
+ stop_node(AgentNode),
+
+
+ %% SubAgentNode = ?config(sub_agent_node, Config),
+ %% stop_node(SubAgentNode),
+
+
+ %% -
+ %% Stop the manager node
+ %%
+
+ ?DBG("otp9884(fin) -> stop manager node", []),
+ stop_node(ManagerNode),
+
+ Dog = ?config(watchdog, Config),
+ ?WD_STOP(Dog),
+ lists:keydelete(watchdog, 1, Config);
+
+otp9884(doc) ->
+ "OTP-9884 - Simlutaneous backup call should not work. ";
+
+otp9884(Config) when is_list(Config) ->
+ ?DBG("otp9884 -> entry with"
+ "~n Config: ~p", [Config]),
+
+ AgentNode = ?config(agent_node, Config),
+ [AgentBkpDir1, AgentBkpDir2] = ?config(agent_backup_dirs, Config),
+ Self = self(),
+ timer:apply_after(1000,
+ ?MODULE, otp9884_backup, [AgentNode, Self, first, AgentBkpDir1]),
+ timer:apply_after(1000,
+ ?MODULE, otp9884_backup, [AgentNode, Self, second, AgentBkpDir2]),
+ otp9884_await_backup_completion(undefined, undefined),
+
+ ?DBG("otp9884 -> done", []),
+ ok.
+
+
+otp9884_backup(Node, Pid, Tag, Dir) ->
+ io:format("[~w] call backup function~n", [Tag]),
+ Res = rpc:call(Node, snmpa, backup, [Dir]),
+ io:format("[~w] backup result: ~p~n", [Tag, Res]),
+ Pid ! {otp9884_backup_complete, Tag, Res}.
+
+otp9884_await_backup_completion(ok, Second)
+ when ((Second =/= ok) andalso (Second =/= undefined)) ->
+ io:format("otp9884_await_backup_completion -> "
+ "first backup succeed and second failed (~p)~n", [Second]),
+ ok;
+otp9884_await_backup_completion(First, ok)
+ when ((First =/= ok) andalso (First =/= undefined)) ->
+ io:format("otp9884_await_backup_completion -> "
+ "second backup succeed and first failed (~p)~n", [First]),
+ ok;
+otp9884_await_backup_completion(First, Second)
+ when (((First =:= undefined) andalso (Second =:= undefined))
+ orelse
+ ((First =:= undefined) andalso (Second =/= undefined))
+ orelse
+ ((First =/= undefined) andalso (Second =:= undefined))) ->
+ io:format("otp9884_await_backup_completion -> await complete messages~n", []),
+ receive
+ {otp9884_backup_complete, first, Res} ->
+ io:format("otp9884_await_backup_completion -> "
+ "received complete message for first: ~p~n", [Res]),
+ otp9884_await_backup_completion(Res, Second);
+ {otp9884_backup_complete, second, Res} ->
+ io:format("otp9884_await_backup_completion -> "
+ "received complete message for second: ~p~n", [Res]),
+ otp9884_await_backup_completion(First, Res)
+ after 10000 ->
+ %% we have waited long enough
+ throw({error, {timeout, First, Second}})
+ end;
+otp9884_await_backup_completion(First, Second) ->
+ throw({error, {bad_completion, First, Second}}).
+
+
+%%-----------------------------------------------------------------
agent_log_validation(Node) ->
rpc:call(Node, ?MODULE, agent_log_validation, []).
diff --git a/lib/snmp/vsn.mk b/lib/snmp/vsn.mk
index 1fbad654f7..fb1dcb6c41 100644
--- a/lib/snmp/vsn.mk
+++ b/lib/snmp/vsn.mk
@@ -18,7 +18,6 @@
# %CopyrightEnd%
APPLICATION = snmp
-SNMP_VSN = 4.21.6
+SNMP_VSN = 4.21.7
PRE_VSN =
APP_VSN = "$(APPLICATION)-$(SNMP_VSN)$(PRE_VSN)"
-
diff --git a/lib/stdlib/test/erl_eval_SUITE.erl b/lib/stdlib/test/erl_eval_SUITE.erl
index 369d8b224e..ca2f18a05a 100644
--- a/lib/stdlib/test/erl_eval_SUITE.erl
+++ b/lib/stdlib/test/erl_eval_SUITE.erl
@@ -1167,15 +1167,22 @@ do_funs(LFH, EFH) ->
[[[0]]], ['F'], LFH, EFH),
%% Tests for a bug found by the Dialyzer - used to crash.
- ?line check(fun() -> Pmod = erl_eval_helper:new(42), Pmod:add(5) end,
- "begin Pmod = erl_eval_helper:new(42), Pmod:add(5) end.",
- 47,
- ['Pmod'], LFH, EFH),
- ?line check(fun() -> Pmod = erl_eval_helper:new(42), B = Pmod:add(7), B end,
- "begin Pmod = erl_eval_helper:new(42), B = Pmod:add(7), B end.",
- 49,
- ['B','Pmod'], LFH, EFH),
-
+ case test_server:is_native(erl_eval) of
+ true ->
+ %% Parameterized modules are not supported by HiPE.
+ ok;
+ false ->
+ check(fun() -> Pmod = erl_eval_helper:new(42), Pmod:add(5) end,
+ "begin Pmod = erl_eval_helper:new(42), Pmod:add(5) end.",
+ 47,
+ ['Pmod'], LFH, EFH),
+ check(fun() -> Pmod = erl_eval_helper:new(42),
+ B = Pmod:add(7), B end,
+ "begin Pmod = erl_eval_helper:new(42), "
+ "B = Pmod:add(7), B end.",
+ 49,
+ ['B','Pmod'], LFH, EFH)
+ end,
ok.
count_down(F, N) when N > 0 ->
diff --git a/lib/stdlib/test/re_SUITE.erl b/lib/stdlib/test/re_SUITE.erl
index 3b2e637c84..d6d946a28f 100644
--- a/lib/stdlib/test/re_SUITE.erl
+++ b/lib/stdlib/test/re_SUITE.erl
@@ -445,9 +445,17 @@ split_specials(Config) when is_list(Config) ->
ok.
-error_handling(doc) ->
- ["Test that errors are handled correctly by the erlang code."];
-error_handling(Config) when is_list(Config) ->
+%% Test that errors are handled correctly by the erlang code.
+error_handling(_Config) ->
+ case test_server:is_native(re) of
+ true ->
+ %% Exceptions from native code look too different.
+ {skip,"re is native"};
+ false ->
+ error_handling()
+ end.
+
+error_handling() ->
% This test checks the exception tuples manufactured in the erlang
% code to hide the trapping from the user at least when it comes to errors
Dog = ?t:timetrap(?t:minutes(1)),
@@ -455,14 +463,14 @@ error_handling(Config) when is_list(Config) ->
% the trap to re:grun from grun, in the grun function clause
% that handles precompiled expressions
?line {'EXIT',{badarg,[{re,run,["apa",{1,2,3,4},[global]],_},
- {?MODULE,error_handling,1,_} | _]}} =
+ {?MODULE,error_handling,0,_} | _]}} =
(catch re:run("apa",{1,2,3,4},[global])),
% An invalid capture list will also cause a badarg late,
% but with a non pre compiled RE, the exception should be thrown by the
% grun function clause that handles RE's compiled implicitly by
% the run/3 BIF before trapping.
?line {'EXIT',{badarg,[{re,run,["apa","p",[{capture,[1,{a}]},global]],_},
- {?MODULE,error_handling,1,_} | _]}} =
+ {?MODULE,error_handling,0,_} | _]}} =
(catch re:run("apa","p",[{capture,[1,{a}]},global])),
% And so the case of a precompiled expression together with
% a compile-option (binary and list subject):
@@ -473,88 +481,88 @@ error_handling(Config) when is_list(Config) ->
[<<"apa">>,
{re_pattern,1,0,_},
[global,unicode]],_},
- {?MODULE,error_handling,1,_} | _]}} =
+ {?MODULE,error_handling,0,_} | _]}} =
(catch re:run(<<"apa">>,RE,[global,unicode])),
?line {'EXIT',{badarg,[{re,run,
["apa",
{re_pattern,1,0,_},
[global,unicode]],_},
- {?MODULE,error_handling,1,_} | _]}} =
+ {?MODULE,error_handling,0,_} | _]}} =
(catch re:run("apa",RE,[global,unicode])),
?line {'EXIT',{badarg,_}} = (catch re:run("apa","(p",[])),
?line {'EXIT',{badarg,_}} = (catch re:run("apa","(p",[global])),
% The replace errors:
?line {'EXIT',{badarg,[{re,replace,["apa",{1,2,3,4},"X",[]],_},
- {?MODULE,error_handling,1,_} | _]}} =
+ {?MODULE,error_handling,0,_} | _]}} =
(catch re:replace("apa",{1,2,3,4},"X",[])),
?line {'EXIT',{badarg,[{re,replace,["apa",{1,2,3,4},"X",[global]],_},
- {?MODULE,error_handling,1,_} | _]}} =
+ {?MODULE,error_handling,0,_} | _]}} =
(catch re:replace("apa",{1,2,3,4},"X",[global])),
?line {'EXIT',{badarg,[{re,replace,
["apa",
{re_pattern,1,0,_},
"X",
[unicode]],_},
- {?MODULE,error_handling,1,_} | _]}} =
+ {?MODULE,error_handling,0,_} | _]}} =
(catch re:replace("apa",RE,"X",[unicode])),
?line <<"aXa">> = iolist_to_binary(re:replace("apa","p","X",[])),
?line {'EXIT',{badarg,[{re,replace,
["apa","p","X",[{capture,all,binary}]],_},
- {?MODULE,error_handling,1,_} | _]}} =
+ {?MODULE,error_handling,0,_} | _]}} =
(catch iolist_to_binary(re:replace("apa","p","X",
[{capture,all,binary}]))),
?line {'EXIT',{badarg,[{re,replace,
["apa","p","X",[{capture,all}]],_},
- {?MODULE,error_handling,1,_} | _]}} =
+ {?MODULE,error_handling,0,_} | _]}} =
(catch iolist_to_binary(re:replace("apa","p","X",
[{capture,all}]))),
?line {'EXIT',{badarg,[{re,replace,
["apa","p","X",[{return,banana}]],_},
- {?MODULE,error_handling,1,_} | _]}} =
+ {?MODULE,error_handling,0,_} | _]}} =
(catch iolist_to_binary(re:replace("apa","p","X",
[{return,banana}]))),
?line {'EXIT',{badarg,_}} = (catch re:replace("apa","(p","X",[])),
% Badarg, not compile error.
?line {'EXIT',{badarg,[{re,replace,
["apa","(p","X",[{return,banana}]],_},
- {?MODULE,error_handling,1,_} | _]}} =
+ {?MODULE,error_handling,0,_} | _]}} =
(catch iolist_to_binary(re:replace("apa","(p","X",
[{return,banana}]))),
% And the split errors:
?line [<<"a">>,<<"a">>] = (catch re:split("apa","p",[])),
?line [<<"a">>,<<"p">>,<<"a">>] = (catch re:split("apa",RE,[])),
?line {'EXIT',{badarg,[{re,split,["apa","p",[global]],_},
- {?MODULE,error_handling,1,_} | _]}} =
+ {?MODULE,error_handling,0,_} | _]}} =
(catch re:split("apa","p",[global])),
?line {'EXIT',{badarg,[{re,split,["apa","p",[{capture,all}]],_},
- {?MODULE,error_handling,1,_} | _]}} =
+ {?MODULE,error_handling,0,_} | _]}} =
(catch re:split("apa","p",[{capture,all}])),
?line {'EXIT',{badarg,[{re,split,["apa","p",[{capture,all,binary}]],_},
- {?MODULE, error_handling,1,_} | _]}} =
+ {?MODULE, error_handling,0,_} | _]}} =
(catch re:split("apa","p",[{capture,all,binary}])),
?line {'EXIT',{badarg,[{re,split,["apa",{1,2,3,4},[]],_},
- {?MODULE,error_handling,1,_} | _]}} =
+ {?MODULE,error_handling,0,_} | _]}} =
(catch re:split("apa",{1,2,3,4})),
?line {'EXIT',{badarg,[{re,split,["apa",{1,2,3,4},[]],_},
- {?MODULE,error_handling,1,_} | _]}} =
+ {?MODULE,error_handling,0,_} | _]}} =
(catch re:split("apa",{1,2,3,4},[])),
?line {'EXIT',{badarg,[{re,split,
["apa",
RE,
[unicode]],_},
- {?MODULE,error_handling,1,_} | _]}} =
+ {?MODULE,error_handling,0,_} | _]}} =
(catch re:split("apa",RE,[unicode])),
?line {'EXIT',{badarg,[{re,split,
["apa",
RE,
[{return,banana}]],_},
- {?MODULE,error_handling,1,_} | _]}} =
+ {?MODULE,error_handling,0,_} | _]}} =
(catch re:split("apa",RE,[{return,banana}])),
?line {'EXIT',{badarg,[{re,split,
["apa",
RE,
[banana]],_},
- {?MODULE,error_handling,1,_} | _]}} =
+ {?MODULE,error_handling,0,_} | _]}} =
(catch re:split("apa",RE,[banana])),
?line {'EXIT',{badarg,_}} = (catch re:split("apa","(p")),
%Exception on bad argument, not compilation error
@@ -562,7 +570,7 @@ error_handling(Config) when is_list(Config) ->
["apa",
"(p",
[banana]],_},
- {?MODULE,error_handling,1,_} | _]}} =
+ {?MODULE,error_handling,0,_} | _]}} =
(catch re:split("apa","(p",[banana])),
?t:timetrap_cancel(Dog),
ok.
diff --git a/lib/stdlib/test/shell_SUITE.erl b/lib/stdlib/test/shell_SUITE.erl
index b6019b86f0..a881742f13 100644
--- a/lib/stdlib/test/shell_SUITE.erl
+++ b/lib/stdlib/test/shell_SUITE.erl
@@ -2388,13 +2388,28 @@ otp_6554(Config) when is_list(Config) ->
comm_err(<<"V = lists:seq(1, 20), case V of a -> ok end.">>),
?line "exception error: no function clause matching" =
comm_err(<<"fun(P) when is_pid(P) -> true end(a).">>),
- ?line "exception error: {function_clause," =
- comm_err(<<"erlang:error(function_clause, [unproper | list]).">>),
+ case test_server:is_native(erl_eval) of
+ true ->
+ %% Native code has different exit reason. Don't bother
+ %% testing them.
+ ok;
+ false ->
+ "exception error: {function_clause," =
+ comm_err(<<"erlang:error(function_clause, "
+ "[unproper | list]).">>),
+ %% Cheating:
+ "exception error: no function clause matching "
+ "erl_eval:do_apply(4)" ++ _ =
+ comm_err(<<"erlang:error(function_clause, [4]).">>),
+ "exception error: no function clause matching "
+ "lists:reverse(" ++ _ =
+ comm_err(<<"F=fun() -> hello end, lists:reverse(F).">>),
+ "exception error: no function clause matching "
+ "lists:reverse(34) (lists.erl, line " ++ _ =
+ comm_err(<<"lists:reverse(34).">>)
+ end,
?line "exception error: function_clause" =
comm_err(<<"erlang:error(function_clause, 4).">>),
- %% Cheating:
- ?line "exception error: no function clause matching erl_eval:do_apply(4)" ++ _ =
- comm_err(<<"erlang:error(function_clause, [4]).">>),
?line "exception error: no function clause matching" ++ _ =
comm_err(<<"fun(a, b, c, d) -> foo end"
" (lists:seq(1,17),"
@@ -2404,10 +2419,6 @@ otp_6554(Config) when is_list(Config) ->
?line "exception error: no function clause matching" =
comm_err(<<"fun(P, q) when is_pid(P) -> true end(a, b).">>),
- ?line "exception error: no function clause matching lists:reverse(" ++ _ =
- comm_err(<<"F=fun() -> hello end, lists:reverse(F).">>),
- ?line "exception error: no function clause matching lists:reverse(34) (lists.erl, line " ++ _ =
- comm_err(<<"lists:reverse(34).">>),
?line "exception error: no true branch found when evaluating an if expression" =
comm_err(<<"if length([a,b]) > 17 -> a end.">>),
?line "exception error: no such process or port" =
diff --git a/lib/stdlib/test/sofs_SUITE.erl b/lib/stdlib/test/sofs_SUITE.erl
index 73b282149a..c8dca9a6e6 100644
--- a/lib/stdlib/test/sofs_SUITE.erl
+++ b/lib/stdlib/test/sofs_SUITE.erl
@@ -1879,12 +1879,9 @@ digraph(Conf) when is_list(Conf) ->
?line {'EXIT', {badarg, _}} =
(catch family_to_digraph(set([a]))),
- ?line {'EXIT', {badarg, [{sofs,family_to_digraph,[_,_],_}|_]}} =
- (catch family_to_digraph(set([a]), [foo])),
- ?line {'EXIT', {badarg, [{sofs,family_to_digraph,[_,_],_}|_]}} =
- (catch family_to_digraph(F, [foo])),
- ?line {'EXIT', {cyclic, [{sofs,family_to_digraph,[_,_],_}|_]}} =
- (catch family_to_digraph(family([{a,[a]}]),[acyclic])),
+ digraph_fail(badarg, catch family_to_digraph(set([a]), [foo])),
+ digraph_fail(badarg, catch family_to_digraph(F, [foo])),
+ digraph_fail(cyclic, catch family_to_digraph(family([{a,[a]}]),[acyclic])),
?line G1 = family_to_digraph(E),
?line {'EXIT', {badarg, _}} = (catch digraph_to_family(G1, foo)),
@@ -1927,6 +1924,13 @@ digraph(Conf) when is_list(Conf) ->
?line true = T0 == ets:all(),
ok.
+digraph_fail(ExitReason, Fail) ->
+ {'EXIT', {ExitReason, [{sofs,family_to_digraph,A,_}|_]}} = Fail,
+ case {test_server:is_native(sofs),A} of
+ {false,[_,_]} -> ok;
+ {true,2} -> ok
+ end.
+
constant_function(suite) -> [];
constant_function(doc) -> [""];
constant_function(Conf) when is_list(Conf) ->
@@ -1954,6 +1958,17 @@ misc(Conf) when is_list(Conf) ->
difference(S, RR)),
%% The function external:foo/1 is undefined.
+ case test_server:is_native(sofs) of
+ true ->
+ %% Create an export entry for external:foo/1 to work
+ %% around a bug in the native code. If there is no
+ %% export entry, the exception will be
+ %% {badfun,{external,foo}}. Remove in R16 when tuple
+ %% funs are removed.
+ (catch external:foo([]));
+ false ->
+ ok
+ end,
?line {'EXIT', {undef, _}} =
(catch projection({external,foo}, set([a,b,c]))),
ok.
diff --git a/lib/tools/test/fprof_SUITE.erl b/lib/tools/test/fprof_SUITE.erl
index 0da6d4a9ea..f491c1e227 100644
--- a/lib/tools/test/fprof_SUITE.erl
+++ b/lib/tools/test/fprof_SUITE.erl
@@ -191,11 +191,17 @@ tail_seq(Config) when is_list(Config) ->
%%%---------------------------------------------------------------------
-create_file_slow(doc) ->
- ["Tests the create_file_slow benchmark"];
-create_file_slow(suite) ->
- [];
-create_file_slow(Config) when is_list(Config) ->
+%% Tests the create_file_slow benchmark.
+create_file_slow(Config) ->
+ case test_server:is_native(lists) orelse
+ test_server:is_native(file) of
+ true ->
+ {skip,"Native libs -- tracing does not work"};
+ false ->
+ do_create_file_slow(Config)
+ end.
+
+do_create_file_slow(Config) ->
?line Timetrap = ?t:timetrap(?t:seconds(40)),
?line PrivDir = ?config(priv_dir, Config),
?line TraceFile =