aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--erts/doc/src/erl.xml24
-rw-r--r--erts/doc/src/erlang.xml16
-rw-r--r--erts/emulator/beam/beam_bp.h12
-rw-r--r--erts/emulator/beam/bif.c4
-rw-r--r--erts/emulator/beam/break.c6
-rw-r--r--erts/emulator/beam/erl_bif_info.c7
-rw-r--r--erts/emulator/beam/erl_gc.c20
-rw-r--r--erts/emulator/beam/erl_init.c48
-rw-r--r--erts/emulator/beam/erl_process.h11
-rw-r--r--erts/emulator/beam/erl_trace.c41
-rw-r--r--erts/emulator/beam/utils.c35
-rw-r--r--erts/emulator/nifs/common/erl_tracer_nif.c3
-rw-r--r--erts/emulator/test/match_spec_SUITE.erl11
-rw-r--r--erts/emulator/test/message_queue_data_SUITE.erl32
-rw-r--r--erts/emulator/test/port_trace_SUITE.erl34
-rw-r--r--erts/emulator/test/port_trace_SUITE_data/echo_drv.c4
-rw-r--r--erts/emulator/test/trace_SUITE.erl79
-rw-r--r--erts/etc/common/erlexec.c23
-rw-r--r--lib/kernel/test/seq_trace_SUITE.erl16
-rw-r--r--lib/observer/src/observer_alloc_wx.erl1
-rw-r--r--lib/observer/src/observer_lib.erl101
-rw-r--r--lib/observer/src/observer_perf_wx.erl2
-rw-r--r--lib/observer/src/observer_procinfo.erl4
-rw-r--r--lib/runtime_tools/src/system_information.erl52
-rw-r--r--lib/runtime_tools/test/dbg_SUITE.erl24
-rw-r--r--lib/ssh/src/sshc_sup.erl4
-rw-r--r--lib/ssh/test/ssh_sup_SUITE.erl9
-rw-r--r--lib/ssl/src/ssl_cipher.erl16
-rw-r--r--lib/ssl/src/ssl_manager.erl4
-rw-r--r--lib/ssl/src/tls_handshake.erl5
-rw-r--r--lib/ssl/test/ssl_basic_SUITE.erl11
-rw-r--r--lib/stdlib/src/erl_lint.erl97
-rw-r--r--lib/stdlib/src/proc_lib.erl4
-rw-r--r--lib/stdlib/test/erl_lint_SUITE.erl156
34 files changed, 506 insertions, 410 deletions
diff --git a/erts/doc/src/erl.xml b/erts/doc/src/erl.xml
index e13470c83c..c499fc8081 100644
--- a/erts/doc/src/erl.xml
+++ b/erts/doc/src/erl.xml
@@ -632,6 +632,15 @@
<p>Sets the initial process dictionary size of processes to the size
<c><![CDATA[Size]]></c>.</p>
</item>
+ <tag><marker id="+hmqd"><c>+hmqd off_heap|on_heap|mixed</c></marker></tag>
+ <item><p>
+ Sets the default value for the process flag
+ <c>message_queue_data</c>. If <c>+hmqd</c> is not
+ passed, <c>mixed</c> will be the default. For more information,
+ see the documentation of
+ <seealso marker="erlang#process_flag_message_queue_data"><c>process_flag(message_queue_data,
+ MQD)</c></seealso>.
+ </p></item>
<tag><c><![CDATA[+K true | false]]></c></tag>
<item>
<p>Enables or disables the kernel poll functionality if
@@ -1361,21 +1370,6 @@
<seealso marker="kernel:error_logger#warning_map/0">error_logger(3)</seealso>
for further information.</p>
</item>
- <tag><c><![CDATA[+xFlag Value]]></c></tag>
- <item>
- <p>Default process flag settings.</p>
- <taglist>
- <tag><marker id="+xmqd"><c>+xmqd off_heap|on_heap|mixed</c></marker></tag>
- <item><p>
- Sets the default value for the process flag
- <c>message_queue_data</c>. If <c>+xmqd</c> is not
- passed, <c>mixed</c> will be the default. For more information,
- see the documentation of
- <seealso marker="erlang#process_flag_message_queue_data"><c>process_flag(message_queue_data,
- MQD)</c></seealso>.
- </p></item>
- </taglist>
- </item>
<tag><c><![CDATA[+zFlag Value]]></c></tag>
<item>
<p>Miscellaneous flags.</p>
diff --git a/erts/doc/src/erlang.xml b/erts/doc/src/erlang.xml
index 423ccdf98f..4b5a27751a 100644
--- a/erts/doc/src/erlang.xml
+++ b/erts/doc/src/erlang.xml
@@ -4371,7 +4371,7 @@ os_prompt% </pre>
</taglist>
<p>
The default <c>message_queue_data</c> process flag is determined
- by the <seealso marker="erl#+xmqd"><c>+xmqd</c></seealso>
+ by the <seealso marker="erl#+hmqd"><c>+hmqd</c></seealso>
<c>erl</c> command line argument.
</p>
<p>
@@ -4878,7 +4878,9 @@ os_prompt% </pre>
<tag><c>{total_heap_size, <anno>Size</anno>}</c></tag>
<item>
<p><c><anno>Size</anno></c> is the total size, in words, of all heap
- fragments of the process. This includes the process stack.</p>
+ fragments of the process. This includes the process stack and
+ any unreceived messages that are considered to be part of the
+ heap. </p>
</item>
<tag><c>{trace, <anno>InternalTraceFlags</anno>}</c></tag>
<item>
@@ -5709,7 +5711,7 @@ true</pre>
flag. <c><anno>MQD</anno></c> should be either <c>off_heap</c>,
<c>on_heap</c>, or <c>mixed</c>. The default
<c>message_queue_data</c> process flag is determined by the
- <seealso marker="erl#+xmqd"><c>+xmqd</c></seealso> <c>erl</c>
+ <seealso marker="erl#+hmqd"><c>+hmqd</c></seealso> <c>erl</c>
command line argument. For more information, see the
documentation of
<seealso marker="#process_flag_message_queue_data"><c>process_flag(message_queue_data,
@@ -7388,7 +7390,7 @@ ok
<p>Returns the default value of the <c>message_queue_data</c>
process flag which is either <c>off_heap</c>, <c>on_heap</c>, or <c>mixed</c>.
This default is set by the <c>erl</c> command line argument
- <seealso marker="erl#+xmqd"><c>+xmqd</c></seealso>. For more information on the
+ <seealso marker="erl#+hmqd"><c>+hmqd</c></seealso>. For more information on the
<c>message_queue_data</c> process flag, see documentation of
<seealso marker="#process_flag_message_queue_data"><c>process_flag(message_queue_data,
MQD)</c></seealso>.</p>
@@ -8637,8 +8639,8 @@ timestamp() ->
<p>Specifies that a tracer module should be called
instead of sending a trace message. The tracer module
can then ignore or change the trace message. For more details
- on how to write a tracer module see <seealso marker="erl_tracer">
- erl_tracer</seealso>
+ on how to write a tracer module see
+ <seealso marker="erts:erl_tracer"><c>erl_tracer</c></seealso>
</p>
</item>
</taglist>
@@ -8989,7 +8991,7 @@ timestamp() ->
<c>erlang:trace_delivered(<anno>Tracee</anno>)</c> resides on.
The special <c><anno>Tracee</anno></c> atom <c>all</c>
denotes all processes that currently are traced in the node.</p>
- <p>When used together with an <seealso marker="#erl_tracer">
+ <p>When used together with an <seealso marker="erts:erl_tracer">
Tracer Module</seealso> any message sent in the trace callback
is guaranteed to have reached it's recipient before the
<c>trace_delivered</c> message is sent.</p>
diff --git a/erts/emulator/beam/beam_bp.h b/erts/emulator/beam/beam_bp.h
index bb171be8a6..08641b86d6 100644
--- a/erts/emulator/beam/beam_bp.h
+++ b/erts/emulator/beam/beam_bp.h
@@ -173,19 +173,7 @@ void erts_clear_time_trace_bif(BeamInstr *pc);
BeamInstr *erts_find_local_func(Eterm mfa[3]);
-ERTS_GLB_INLINE Uint erts_bp_sched2ix(void);
-
#if ERTS_GLB_INLINE_INCL_FUNC_DEF
-ERTS_GLB_INLINE Uint erts_bp_sched2ix(void)
-{
-#ifdef ERTS_SMP
- ErtsSchedulerData *esdp;
- esdp = erts_get_scheduler_data();
- return esdp->no - 1;
-#else
- return 0;
-#endif
-}
extern erts_smp_atomic32_t erts_active_bp_index;
extern erts_smp_atomic32_t erts_staging_bp_index;
diff --git a/erts/emulator/beam/bif.c b/erts/emulator/beam/bif.c
index ed5b2983dd..c38d031ab8 100644
--- a/erts/emulator/beam/bif.c
+++ b/erts/emulator/beam/bif.c
@@ -1736,7 +1736,9 @@ BIF_RETTYPE process_flag_2(BIF_ALIST_2)
ERTS_TRACE_FLAGS(BIF_P) &= ~F_SENSITIVE;
}
erts_smp_proc_unlock(BIF_P, ERTS_PROC_LOCKS_ALL_MINOR);
- BIF_RET(old_value);
+ /* make sure to bump all reds so that we get
+ rescheduled immediately so setting takes effect */
+ BIF_RET2(old_value, CONTEXT_REDS);
}
else if (BIF_ARG_1 == am_monitor_nodes) {
/*
diff --git a/erts/emulator/beam/break.c b/erts/emulator/beam/break.c
index 4f5e80f2e5..d02c6828f9 100644
--- a/erts/emulator/beam/break.c
+++ b/erts/emulator/beam/break.c
@@ -347,8 +347,11 @@ print_process_info(int to, void *to_arg, Process *p)
static void
print_garb_info(int to, void *to_arg, Process* p)
{
+#ifdef ERTS_SMP
/* ERTS_SMP: A scheduler is probably concurrently doing gc... */
-#ifndef ERTS_SMP
+ if (!ERTS_IS_CRASH_DUMPING)
+ return;
+#endif
erts_print(to, to_arg, "New heap start: %bpX\n", p->heap);
erts_print(to, to_arg, "New heap top: %bpX\n", p->htop);
erts_print(to, to_arg, "Stack top: %bpX\n", p->stop);
@@ -356,7 +359,6 @@ print_garb_info(int to, void *to_arg, Process* p)
erts_print(to, to_arg, "Old heap start: %bpX\n", OLD_HEAP(p));
erts_print(to, to_arg, "Old heap top: %bpX\n", OLD_HTOP(p));
erts_print(to, to_arg, "Old heap end: %bpX\n", OLD_HEND(p));
-#endif
}
void
diff --git a/erts/emulator/beam/erl_bif_info.c b/erts/emulator/beam/erl_bif_info.c
index c9741b361f..99fe847ba2 100644
--- a/erts/emulator/beam/erl_bif_info.c
+++ b/erts/emulator/beam/erl_bif_info.c
@@ -1359,9 +1359,10 @@ process_info_aux(Process *BIF_P,
total_heap_size += rp->mbuf_sz;
- for (mp = rp->msg.first; mp; mp = mp->next)
- if (mp->data.attached)
- total_heap_size += erts_msg_attached_data_size(mp);
+ if (rp->flags & F_ON_HEAP_MSGQ)
+ for (mp = rp->msg.first; mp; mp = mp->next)
+ if (mp->data.attached)
+ total_heap_size += erts_msg_attached_data_size(mp);
(void) erts_bld_uint(NULL, &hsz, total_heap_size);
hp = HAlloc(BIF_P, hsz);
diff --git a/erts/emulator/beam/erl_gc.c b/erts/emulator/beam/erl_gc.c
index df5d0f4918..cf54f1e384 100644
--- a/erts/emulator/beam/erl_gc.c
+++ b/erts/emulator/beam/erl_gc.c
@@ -3009,10 +3009,30 @@ erts_process_gc_info(Process *p, Uint *sizep, Eterm **hpp)
};
Eterm res = THE_NON_VALUE;
+ ErtsMessage *mp;
ERTS_CT_ASSERT(sizeof(values)/sizeof(*values) == sizeof(tags)/sizeof(*tags));
ERTS_CT_ASSERT(sizeof(values)/sizeof(*values) == ERTS_PROCESS_GC_INFO_MAX_TERMS);
+ if (p->abandoned_heap) {
+ Eterm *htop, *heap;
+ ERTS_GET_ORIG_HEAP(p, heap, htop);
+ values[3] = HIGH_WATER(p) - heap;
+ values[6] = htop - heap;
+ }
+
+ if (p->flags & F_ON_HEAP_MSGQ) {
+ /* If on heap messages in the internal queue are counted
+ as being part of the heap, so we have to add them to the
+ am_mbuf_size value. process_info(total_heap_size) should
+ be the same as adding old_heap_block_size + heap_block_size
+ + mbuf_size.
+ */
+ for (mp = p->msg.first; mp; mp = mp->next)
+ if (mp->data.attached)
+ values[2] += erts_msg_attached_data_size(mp);
+ }
+
res = erts_bld_atom_uword_2tup_list(hpp,
sizep,
sizeof(values)/sizeof(*values),
diff --git a/erts/emulator/beam/erl_init.c b/erts/emulator/beam/erl_init.c
index dec9bdfedc..2fd1eeb785 100644
--- a/erts/emulator/beam/erl_init.c
+++ b/erts/emulator/beam/erl_init.c
@@ -578,6 +578,8 @@ void erts_usage(void)
VH_DEFAULT_SIZE);
erts_fprintf(stderr, "-hpds size initial process dictionary size (default %d)\n",
erts_pd_initial_size);
+ erts_fprintf(stderr, "-hmqd val set default message queue data flag for processes,\n");
+ erts_fprintf(stderr, " valid values are: off_heap | on_heap | mixed\n");
/* erts_fprintf(stderr, "-i module set the boot module (default init)\n"); */
@@ -655,8 +657,6 @@ void erts_usage(void)
erts_fprintf(stderr, "-W<i|w|e> set error logger warnings mapping,\n");
erts_fprintf(stderr, " see error_logger documentation for details\n");
- erts_fprintf(stderr, "-xmqd val set default message queue data flag for processes,\n");
- erts_fprintf(stderr, " valid values are: off_heap | on_heap | mixed\n");
erts_fprintf(stderr, "-zdbbl size set the distribution buffer busy limit in kilobytes\n");
erts_fprintf(stderr, " valid range is [1-%d]\n", INT_MAX/1024);
erts_fprintf(stderr, "-zdntgc time set delayed node table gc in seconds\n");
@@ -1487,6 +1487,7 @@ erl_start(int argc, char **argv)
* h|ms - min_heap_size
* h|mbs - min_bin_vheap_size
* h|pds - erts_pd_initial_size
+ * h|mqd - message_queue_data
*
*/
if (has_prefix("mbs", sub_param)) {
@@ -1512,6 +1513,23 @@ erl_start(int argc, char **argv)
}
VERBOSE(DEBUG_SYSTEM, ("using initial process dictionary size %d\n",
erts_pd_initial_size));
+ } else if (has_prefix("mqd", sub_param)) {
+ arg = get_arg(sub_param+3, argv[i+1], &i);
+ if (sys_strcmp(arg, "mixed") == 0)
+ erts_default_spo_flags &= ~(SPO_ON_HEAP_MSGQ|SPO_OFF_HEAP_MSGQ);
+ else if (sys_strcmp(arg, "on_heap") == 0) {
+ erts_default_spo_flags &= ~SPO_OFF_HEAP_MSGQ;
+ erts_default_spo_flags |= SPO_ON_HEAP_MSGQ;
+ }
+ else if (sys_strcmp(arg, "off_heap") == 0) {
+ erts_default_spo_flags &= ~SPO_ON_HEAP_MSGQ;
+ erts_default_spo_flags |= SPO_OFF_HEAP_MSGQ;
+ }
+ else {
+ erts_fprintf(stderr,
+ "Invalid message_queue_data flag: %s\n", arg);
+ erts_usage();
+ }
} else {
/* backward compatibility */
arg = get_arg(argv[i]+2, argv[i+1], &i);
@@ -2047,32 +2065,6 @@ erl_start(int argc, char **argv)
}
break;
- case 'x': {
- char *sub_param = argv[i]+2;
- if (has_prefix("mqd", sub_param)) {
- arg = get_arg(sub_param+3, argv[i+1], &i);
- if (sys_strcmp(arg, "mixed") == 0)
- erts_default_spo_flags &= ~(SPO_ON_HEAP_MSGQ|SPO_OFF_HEAP_MSGQ);
- else if (sys_strcmp(arg, "on_heap") == 0) {
- erts_default_spo_flags &= ~SPO_OFF_HEAP_MSGQ;
- erts_default_spo_flags |= SPO_ON_HEAP_MSGQ;
- }
- else if (sys_strcmp(arg, "off_heap") == 0) {
- erts_default_spo_flags &= ~SPO_ON_HEAP_MSGQ;
- erts_default_spo_flags |= SPO_OFF_HEAP_MSGQ;
- }
- else {
- erts_fprintf(stderr,
- "Invalid message_queue_data flag: %s\n", arg);
- erts_usage();
- }
- } else {
- erts_fprintf(stderr, "bad -x option %s\n", argv[i]);
- erts_usage();
- }
- break;
- }
-
case 'z': {
char *sub_param = argv[i]+2;
diff --git a/erts/emulator/beam/erl_process.h b/erts/emulator/beam/erl_process.h
index 61acf5924b..1c01d705a7 100644
--- a/erts/emulator/beam/erl_process.h
+++ b/erts/emulator/beam/erl_process.h
@@ -925,7 +925,6 @@ struct process {
Eterm* stop; /* Stack top */
Eterm* heap; /* Heap start */
Eterm* hend; /* Heap end */
- Eterm* abandoned_heap;
Uint heap_sz; /* Size of heap in words */
Uint min_heap_size; /* Minimum size of heap (in words). */
Uint min_vheap_size; /* Minimum size of virtual heap (in words). */
@@ -941,6 +940,16 @@ struct process {
#endif
/*
+ * Moved to after "struct hipe_process_state hipe", as a temporary fix for
+ * LLVM hard-coding offsetof(struct process, hipe.nstack) (sic!)
+ * (see void X86FrameLowering::adjustForHiPEPrologue(...) in
+ * lib/Target/X86/X86FrameLowering.cpp).
+ *
+ * Used to be below "Eterm* hend".
+ */
+ Eterm* abandoned_heap;
+
+ /*
* Saved x registers.
*/
Uint arity; /* Number of live argument registers (only valid
diff --git a/erts/emulator/beam/erl_trace.c b/erts/emulator/beam/erl_trace.c
index 56899f574a..128696270b 100644
--- a/erts/emulator/beam/erl_trace.c
+++ b/erts/emulator/beam/erl_trace.c
@@ -658,6 +658,7 @@ do { \
# define GET_NOW(m, s, u) do {get_now(m, s, u);} while (0)
#endif
+
static void
write_sys_msg_to_port(Eterm unused_to,
Port* trace_port,
@@ -1737,41 +1738,6 @@ profile_scheduler(Eterm scheduler_id, Eterm state) {
}
-void
-profile_scheduler_q(Eterm scheduler_id, Eterm state, Eterm no_schedulers, Uint Ms, Uint s, Uint us) {
- Eterm *hp, msg, timestamp;
-
-#ifndef ERTS_SMP
-#define LOCAL_HEAP_SIZE (4 + 7)
- DeclareTmpHeapNoproc(local_heap,LOCAL_HEAP_SIZE);
- UseTmpHeapNoproc(LOCAL_HEAP_SIZE);
-
- hp = local_heap;
-#else
- ErlHeapFragment *bp;
- Uint hsz;
-
- hsz = 4 + 7;
-
- bp = new_message_buffer(hsz);
- hp = bp->mem;
-#endif
-
- erts_smp_mtx_lock(&smq_mtx);
-
- timestamp = TUPLE3(hp, make_small(Ms), make_small(s), make_small(us)); hp += 4;
- msg = TUPLE6(hp, am_profile, am_scheduler, scheduler_id, state, no_schedulers, timestamp); hp += 7;
-#ifndef ERTS_SMP
- profile_send(NIL, msg);
- UnUseTmpHeapNoproc(LOCAL_HEAP_SIZE);
-#undef LOCAL_HEAP_SIZE
-#else
- enqueue_sys_msg_unlocked(SYS_MSG_TYPE_SYSPROF, NIL, NIL, msg, bp);
-#endif
- erts_smp_mtx_unlock(&smq_mtx);
-
-}
-
/* Port profiling */
void
@@ -1935,7 +1901,10 @@ trace_port_receive(Port *t_p, Eterm caller, Eterm what, ...)
}
data = TUPLE2(hp, caller, data);
- send_to_tracer_nif(NULL, &t_p->common, t_p->common.id, tnif, TRACE_FUN_T_RECEIVE,
+ hp += 3;
+ ASSERT(hp <= (local_heap + LOCAL_HEAP_SIZE) || orig_hp);
+ send_to_tracer_nif(NULL, &t_p->common, t_p->common.id, tnif,
+ TRACE_FUN_T_RECEIVE,
am_receive, data, THE_NON_VALUE);
if (bptr && erts_refc_dectest(&bptr->refc, 1) == 0)
diff --git a/erts/emulator/beam/utils.c b/erts/emulator/beam/utils.c
index b280995488..68006e7ef3 100644
--- a/erts/emulator/beam/utils.c
+++ b/erts/emulator/beam/utils.c
@@ -71,41 +71,6 @@
#define HAVE_MALLOPT 0
#endif
-/* profile_scheduler mini message queue */
-
-typedef struct {
- Uint scheduler_id;
- Uint no_schedulers;
- Uint Ms;
- Uint s;
- Uint us;
- Eterm state;
-} profile_sched_msg;
-
-typedef struct {
- profile_sched_msg msg[2];
- Uint n;
-} profile_sched_msg_q;
-
-#ifdef ERTS_SMP
-
-#if 0 /* Unused */
-static void
-dispatch_profile_msg_q(profile_sched_msg_q *psmq)
-{
- int i = 0;
- profile_sched_msg *msg = NULL;
- ASSERT(psmq != NULL);
- for (i = 0; i < psmq->n; i++) {
- msg = &(psmq->msg[i]);
- profile_scheduler_q(make_small(msg->scheduler_id), msg->state, am_undefined, msg->Ms, msg->s, msg->us);
- }
-}
-#endif
-
-#endif
-
-
Eterm*
erts_heap_alloc(Process* p, Uint need, Uint xtra)
{
diff --git a/erts/emulator/nifs/common/erl_tracer_nif.c b/erts/emulator/nifs/common/erl_tracer_nif.c
index 1bb6b940c4..b0c937592a 100644
--- a/erts/emulator/nifs/common/erl_tracer_nif.c
+++ b/erts/emulator/nifs/common/erl_tracer_nif.c
@@ -130,6 +130,9 @@ static ERL_NIF_TERM enabled(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
if (!enif_is_port_alive(env, &to_port))
/* tracer is dead so we should remove this trace point */
return atom_remove;
+ } else {
+ /* The state was not a pid or a port */
+ return atom_remove;
}
/* Only generate trace for when tracer != tracee */
diff --git a/erts/emulator/test/match_spec_SUITE.erl b/erts/emulator/test/match_spec_SUITE.erl
index ea973276db..6733237b20 100644
--- a/erts/emulator/test/match_spec_SUITE.erl
+++ b/erts/emulator/test/match_spec_SUITE.erl
@@ -597,16 +597,15 @@ ms_trace3(Config) when is_list(Config) ->
end),
ok.
-ms_trace_dead(doc) ->
- ["Test that a dead tracer is removed using ms"];
-ms_trace_dead(suite) -> [];
-ms_trace_dead(Config) when is_list(Config) ->
+%% Test that a dead tracer is removed using ms
+ms_trace_dead(_Config) ->
Self = self(),
TFun = fun F() -> receive M -> Self ! M, F() end end,
{Tracer, MRef} = spawn_monitor(TFun),
MetaTracer = spawn_link(TFun),
erlang:trace_pattern({?MODULE, f1, '_'},
- [{'_',[],[{trace,[],
+ [{'_',[],[{message, false},
+ {trace,[],
[call,{const,{tracer,Tracer}}]}]}],
[{meta, MetaTracer}]),
erlang:trace_pattern({?MODULE, f2, '_'}, []),
@@ -623,8 +622,6 @@ ms_trace_dead(Config) when is_list(Config) ->
?MODULE:f2(3,4),
TRef = erlang:trace_delivered(all),
receive {trace_delivered, _, TRef} -> ok end,
- receive {trace_ts, Self, call, {?MODULE, f1, _}, _} -> ok end,
- receive {trace_ts, Self, call, {?MODULE, f1, _}, _} -> ok end,
receive M -> ct:fail({unexpected, M}) after 10 -> ok end.
%% Test that destructive operations in test bif does not really happen
diff --git a/erts/emulator/test/message_queue_data_SUITE.erl b/erts/emulator/test/message_queue_data_SUITE.erl
index 6efca5b39e..226462676c 100644
--- a/erts/emulator/test/message_queue_data_SUITE.erl
+++ b/erts/emulator/test/message_queue_data_SUITE.erl
@@ -21,7 +21,7 @@
-module(message_queue_data_SUITE).
-export([all/0, suite/0]).
--export([basic/1, process_info_messages/1]).
+-export([basic/1, process_info_messages/1, total_heap_size/1]).
-export([basic_test/1]).
@@ -32,7 +32,7 @@ suite() ->
{timetrap, {minutes, 2}}].
all() ->
- [basic, process_info_messages].
+ [basic, process_info_messages, total_heap_size].
%%
%%
@@ -44,15 +44,15 @@ basic(Config) when is_list(Config) ->
basic_test(erlang:system_info(message_queue_data)),
- {ok, Node1} = start_node(Config, "+xmqd off_heap"),
+ {ok, Node1} = start_node(Config, "+hmqd off_heap"),
ok = rpc:call(Node1, ?MODULE, basic_test, [off_heap]),
stop_node(Node1),
- {ok, Node2} = start_node(Config, "+xmqd on_heap"),
+ {ok, Node2} = start_node(Config, "+hmqd on_heap"),
ok = rpc:call(Node2, ?MODULE, basic_test, [on_heap]),
stop_node(Node2),
- {ok, Node3} = start_node(Config, "+xmqd mixed"),
+ {ok, Node3} = start_node(Config, "+hmqd mixed"),
ok = rpc:call(Node3, ?MODULE, basic_test, [mixed]),
stop_node(Node3),
@@ -190,6 +190,28 @@ process_info_messages(Config) when is_list(Config) ->
ok.
+total_heap_size(_Config) ->
+
+ Fun = fun F() -> receive Pid when is_pid(Pid) -> Pid ! ok,F() end end,
+
+ %% Test that on_heap messages grow the heap even if they are not received
+ OnPid = spawn_opt(Fun, [{message_queue_data, on_heap}]),
+ {total_heap_size, OnSize} = erlang:process_info(OnPid, total_heap_size),
+ [OnPid ! lists:duplicate(N,N) || N <- lists:seq(1,100)],
+ OnPid ! self(), receive ok -> ok end,
+ {total_heap_size, OnSizeAfter} = erlang:process_info(OnPid, total_heap_size),
+ ct:log("OnSize = ~p, OnSizeAfter = ~p",[OnSize, OnSizeAfter]),
+ true = OnSize < OnSizeAfter,
+
+ %% Test that off_heap messages do not grow the heap if they are not received
+ OffPid = spawn_opt(Fun, [{message_queue_data, off_heap}]),
+ {total_heap_size, OffSize} = erlang:process_info(OffPid, total_heap_size),
+ [OffPid ! lists:duplicate(N,N) || N <- lists:seq(1,100)],
+ OffPid ! self(), receive ok -> ok end,
+ {total_heap_size, OffSizeAfter} = erlang:process_info(OffPid, total_heap_size),
+ ct:log("OffSize = ~p, OffSizeAfter = ~p",[OffSize, OffSizeAfter]),
+ true = OffSize == OffSizeAfter.
+
%%
%%
%% helpers
diff --git a/erts/emulator/test/port_trace_SUITE.erl b/erts/emulator/test/port_trace_SUITE.erl
index 41e8a316c4..bfdea0761b 100644
--- a/erts/emulator/test/port_trace_SUITE.erl
+++ b/erts/emulator/test/port_trace_SUITE.erl
@@ -240,19 +240,23 @@ command(Config) ->
Prt ! {S, {command, <<?ECHO_DRV_NOOP:8>>}},
[{trace, Prt, 'receive', {S, {command, <<?ECHO_DRV_NOOP:8>>}}}] = flush(),
+ OutputMsg = <<?ECHO_DRV_NOOP:8,0:(8*512)>>,
+ Prt ! {S, {command, OutputMsg}},
+ [{trace, Prt, 'receive', {S, {command, OutputMsg}}}] = flush(),
+
close(Prt, Flags),
os:putenv("OUTPUTV","true"),
reload_drv(Config),
Prt2 = erlang:open_port({spawn, echo_drv}, [binary]),
- Msg = [<<0:8>>,<<0:(8*512)>>,<<0:(8*256)>>,<<0:8>>],
+ OutputvMsg = [<<0:8>>,<<0:(8*512)>>,<<0:(8*256)>>,<<0:8>>],
- erlang:port_command(Prt2, Msg),
- [{trace, Prt2, 'receive', {S, {command, Msg}}}] = flush(),
+ erlang:port_command(Prt2, OutputvMsg),
+ [{trace, Prt2, 'receive', {S, {command, OutputvMsg}}}] = flush(),
- Prt2 ! {S, {command, Msg}},
- [{trace, Prt2, 'receive', {S, {command, Msg}}}] = flush(),
+ Prt2 ! {S, {command, OutputvMsg}},
+ [{trace, Prt2, 'receive', {S, {command, OutputvMsg}}}] = flush(),
close(Prt2, Flags),
@@ -274,6 +278,12 @@ control(_Config) ->
[{trace, Prt, 'receive', {S, {control, {(1 bsl 32) - 1, <<?ECHO_DRV_NOOP:8, 0:8>>}}}},
{trace, Prt, send, {Prt, {control, <<0:8>>}}, S}] = flush(),
+ Msg = <<?ECHO_DRV_NOOP:8, 0:(8*512)>>,
+ Pat = lists:duplicate(512, 0),
+ Pat = erlang:port_control(Prt, 1, Msg),
+ [{trace, Prt, 'receive', {S, {control, {1, Msg}}}},
+ {trace, Prt, send, {Prt, {control, <<0:(8*512)>>}}, S}] = flush(),
+
close(Prt, Flags),
ok.
@@ -331,12 +341,16 @@ call(_Config) ->
Flags = [send,'receive'],
{Prt, S} = trace_and_open(Flags,[binary]),
- Msg = {hello, world, make_ref()},
- BinMsg = term_to_binary(Msg),
+ Test = fun(Msg) ->
+ BinMsg = term_to_binary(Msg),
+
+ Msg = erlang:port_call(Prt, 0, Msg),
+ [{trace, Prt, 'receive', {S, {call, {0, BinMsg}}}},
+ {trace, Prt, send, {Prt, {call, BinMsg}}, S}] = flush()
+ end,
- Msg = erlang:port_call(Prt, 0, Msg),
- [{trace, Prt, 'receive', {S, {call, {0, BinMsg}}}},
- {trace, Prt, send, {Prt, {call, BinMsg}}, S}] = flush(),
+ Test({hello, world, make_ref()}),
+ Test({hello, world, lists:seq(1,1000)}),
close(Prt, Flags),
diff --git a/erts/emulator/test/port_trace_SUITE_data/echo_drv.c b/erts/emulator/test/port_trace_SUITE_data/echo_drv.c
index b5728bc170..b5ae9389b4 100644
--- a/erts/emulator/test/port_trace_SUITE_data/echo_drv.c
+++ b/erts/emulator/test/port_trace_SUITE_data/echo_drv.c
@@ -217,6 +217,8 @@ static ErlDrvSSizeT echo_drv_control(ErlDrvData drv_data,
char *buf, ErlDrvSizeT len,
char **rbuf, ErlDrvSizeT rlen)
{
+ if ((len - 1) > rlen)
+ *rbuf = driver_alloc(len - 1);
memcpy(*rbuf, buf+1, len-1);
return len-1;
}
@@ -232,6 +234,8 @@ static ErlDrvSSizeT echo_drv_call(ErlDrvData drv_data,
char **rbuf, ErlDrvSizeT rlen,
unsigned int *flags)
{
+ if ((len - command) > rlen)
+ *rbuf = driver_alloc(len - command);
memcpy(*rbuf, buf+command, len-command);
return len-command;
}
diff --git a/erts/emulator/test/trace_SUITE.erl b/erts/emulator/test/trace_SUITE.erl
index b7f312635e..29e043dd5c 100644
--- a/erts/emulator/test/trace_SUITE.erl
+++ b/erts/emulator/test/trace_SUITE.erl
@@ -27,11 +27,12 @@
-export([all/0, suite/0, link_receive_call_correlation/0,
receive_trace/1, link_receive_call_correlation/1, self_send/1,
timeout_trace/1, send_trace/1,
- procs_trace/1, dist_procs_trace/1,
+ procs_trace/1, dist_procs_trace/1, procs_new_trace/1,
suspend/1, mutual_suspend/1, suspend_exit/1, suspender_exit/1,
suspend_system_limit/1, suspend_opts/1, suspend_waiting/1,
new_clear/1, existing_clear/1,
set_on_spawn/1, set_on_first_spawn/1, cpu_timestamp/1,
+ set_on_link/1, set_on_first_link/1,
system_monitor_args/1, more_system_monitor_args/1,
system_monitor_long_gc_1/1, system_monitor_long_gc_2/1,
system_monitor_large_heap_1/1, system_monitor_large_heap_2/1,
@@ -54,7 +55,8 @@ all() ->
mutual_suspend, suspend_exit, suspender_exit,
suspend_system_limit, suspend_opts, suspend_waiting,
new_clear, existing_clear, set_on_spawn,
- set_on_first_spawn, system_monitor_args,
+ set_on_first_spawn, set_on_link, set_on_first_link,
+ system_monitor_args,
more_system_monitor_args, system_monitor_long_gc_1,
system_monitor_long_gc_2, system_monitor_large_heap_1,
system_monitor_long_schedule,
@@ -454,6 +456,34 @@ dist_procs_trace(Config) when is_list(Config) ->
true = stop_node(OtherNode),
ok.
+%% Test trace(new, How, [procs]).
+procs_new_trace(Config) when is_list(Config) ->
+ Self = self(),
+ process_flag(trap_exit, true),
+ %%
+ Proc1 = spawn_link(?MODULE, process, [Self]),
+ io:format("Proc1 = ~p ~n", [Proc1]),
+ %%
+ 0 = erlang:trace(new, true, [procs]),
+
+ MFA = {?MODULE, process, [Self]},
+ %%
+ %% spawn, link
+ Proc1 ! {spawn_link_please, Self, MFA},
+ Proc3 = receive {spawned, Proc1, P3} -> P3 end,
+ receive {trace, Proc3, spawned, Proc1, MFA} -> ok end,
+ receive {trace, Proc3, getting_linked, Proc1} -> ok end,
+ io:format("Proc3 = ~p ~n", [Proc3]),
+ receive_nothing(),
+ %%
+ %%
+ %% exit (not linked to tracing process)
+ Reason1 = make_ref(),
+ Proc1 ! {exit_please, Reason1},
+ receive {'EXIT', Proc1, Reason1} -> ok end,
+ {trace, Proc3, exit, Reason1} = receive_first_trace(),
+ receive_nothing(),
+ ok.
@@ -501,6 +531,51 @@ set_on_first_spawn(Config) when is_list(Config) ->
receive_nothing(),
ok.
+%% Tests trace(Pid, How, [set_on_link]).
+
+set_on_link(Config) ->
+ Listener = fun_spawn(fun process/0),
+
+ %% Create and trace a process with the set_on_link flag.
+ %% Make sure it is traced.
+ Father_SOL = fun_spawn(fun process/0),
+ 1 = erlang:trace(Father_SOL, true, [send, set_on_link]),
+ true = is_send_traced(Father_SOL, Listener, sol_father),
+
+ %% Have the process spawn of two children and test that they
+ %% are traced.
+ [Child1, Child2] = spawn_children(Father_SOL, 2),
+ true = is_send_traced(Child1, Listener, child1),
+ true = is_send_traced(Child2, Listener, child2),
+
+ %% Second generation.
+ [Child11, Child12] = spawn_children(Child1, 2),
+ true = is_send_traced(Child11, Listener, child11),
+ true = is_send_traced(Child12, Listener, child12),
+ ok.
+
+%% Tests trace(Pid, How, [set_on_first_spawn]).
+
+set_on_first_link(Config) ->
+ ct:timetrap({seconds, 10}),
+ Listener = fun_spawn(fun process/0),
+
+ %% Create and trace a process with the set_on_first_spawn flag.
+ %% Make sure it is traced.
+ Parent = fun_spawn(fun process/0),
+ 1 = erlang:trace(Parent, true, [send, set_on_first_link]),
+ is_send_traced(Parent, Listener, sol_father),
+
+ %% Have the process spawn off three children and test that the
+ %% first is traced.
+ [Child1, Child2, Child3] = spawn_children(Parent, 3),
+ true = is_send_traced(Child1, Listener, child1),
+ false = is_send_traced(Child2, Listener, child2),
+ false = is_send_traced(Child3, Listener, child3),
+ receive_nothing(),
+ ok.
+
+
%% Tests arguments to erlang:system_monitor/0,1,2
system_monitor_args(Config) when is_list(Config) ->
diff --git a/erts/etc/common/erlexec.c b/erts/etc/common/erlexec.c
index 82a0303f86..5a5021b003 100644
--- a/erts/etc/common/erlexec.c
+++ b/erts/etc/common/erlexec.c
@@ -150,6 +150,7 @@ static char *plush_val_switches[] = {
"ms",
"mbs",
"pds",
+ "mqd",
"",
NULL
};
@@ -160,12 +161,6 @@ static char *plusr_val_switches[] = {
NULL
};
-/* +x arguments with values */
-static char *plusx_val_switches[] = {
- "mqd",
- NULL
-};
-
/* +z arguments with values */
static char *plusz_val_switches[] = {
"dbbl",
@@ -986,20 +981,6 @@ int main(int argc, char **argv)
add_Eargs(argv[i+1]);
i++;
break;
- case 'x':
- if (!is_one_of_strings(&argv[i][2], plusx_val_switches)) {
- goto the_default;
- } else {
- if (i+1 >= argc
- || argv[i+1][0] == '-'
- || argv[i+1][0] == '+')
- usage(argv[i]);
- argv[i][0] = '-';
- add_Eargs(argv[i]);
- add_Eargs(argv[i+1]);
- i++;
- }
- break;
case 'z':
if (!is_one_of_strings(&argv[i][2], plusz_val_switches)) {
goto the_default;
@@ -1200,7 +1181,7 @@ usage_aux(void)
"[+S NO_SCHEDULERS:NO_SCHEDULERS_ONLINE] "
"[+SP PERCENTAGE_SCHEDULERS:PERCENTAGE_SCHEDULERS_ONLINE] "
"[+T LEVEL] [+V] [+v] "
- "[+W<i|w|e>] [+x DEFAULT_PROC_FLAGS] [+z MISC_OPTION] [args ...]\n");
+ "[+W<i|w|e>] [+z MISC_OPTION] [args ...]\n");
exit(1);
}
diff --git a/lib/kernel/test/seq_trace_SUITE.erl b/lib/kernel/test/seq_trace_SUITE.erl
index 000994751f..be23a1933f 100644
--- a/lib/kernel/test/seq_trace_SUITE.erl
+++ b/lib/kernel/test/seq_trace_SUITE.erl
@@ -498,7 +498,13 @@ match_set_seq_token(Config) when is_list(Config) ->
exit(P2, timeout),
{error, "Test node hung"}
end,
- ok = check_match_set_seq_token_log(Lbl, Log),
+
+ %% Sort the log on Pid, as events from different processes
+ %% are not guaranteed to arrive in a certain order to the
+ %% tracer
+ SortedLog = lists:keysort(2, Log),
+
+ ok = check_match_set_seq_token_log(Lbl, SortedLog),
%%
stop_node(Sandbox),
ok.
@@ -551,13 +557,13 @@ do_match_set_seq_token(Label) ->
check_match_set_seq_token_log(
Label,
- [{trace,C,call,{?MODULE,countdown,[B,Ref]}, {0,Label,0,C,0}},
+ [{trace,B,call,{?MODULE,bounce, [Ref]}, {0,Label,2,B,1}},
+ {trace,B,call,{?MODULE,bounce, [Ref]}, {0,Label,4,B,3}},
+ {trace,B,call,{?MODULE,bounce, [Ref]}, {0,Label,6,B,5}},
+ {trace,C,call,{?MODULE,countdown,[B,Ref]}, {0,Label,0,C,0}},
{trace,C,call,{?MODULE,countdown,[B,Ref,3]},{0,Label,0,C,0}},
- {trace,B,call,{?MODULE,bounce, [Ref]}, {0,Label,2,B,1}},
{trace,C,call,{?MODULE,countdown,[B,Ref,2]},{0,Label,2,B,1}},
- {trace,B,call,{?MODULE,bounce, [Ref]}, {0,Label,4,B,3}},
{trace,C,call,{?MODULE,countdown,[B,Ref,1]},{0,Label,4,B,3}},
- {trace,B,call,{?MODULE,bounce, [Ref]}, {0,Label,6,B,5}},
{trace,C,call,{?MODULE,countdown,[B,Ref,0]},{0,Label,6,B,5}}
]) ->
ok;
diff --git a/lib/observer/src/observer_alloc_wx.erl b/lib/observer/src/observer_alloc_wx.erl
index d37623d1cc..220276ac0c 100644
--- a/lib/observer/src/observer_alloc_wx.erl
+++ b/lib/observer/src/observer_alloc_wx.erl
@@ -250,7 +250,6 @@ sum_alloc_one_instance([],BS,CS,TotalBS,TotalCS) ->
create_mem_info(Parent) ->
Panel = wxPanel:new(Parent),
- wxWindow:setBackgroundColour(Panel, {255,255,255}),
Style = ?wxLC_REPORT bor ?wxLC_SINGLE_SEL bor ?wxLC_HRULES bor ?wxLC_VRULES,
Grid = wxListCtrl:new(Panel, [{style, Style}]),
Li = wxListItem:new(),
diff --git a/lib/observer/src/observer_lib.erl b/lib/observer/src/observer_lib.erl
index f0b8a004ec..5d5ac37ce9 100644
--- a/lib/observer/src/observer_lib.erl
+++ b/lib/observer/src/observer_lib.erl
@@ -122,7 +122,7 @@ display_yes_no_dialog(Str) ->
%% display_info(Parent, [{Title, [{Label, Info}]}]) -> {Panel, Sizer, InfoFieldsToUpdate}
display_info(Frame, Info) ->
Panel = wxPanel:new(Frame),
- wxWindow:setBackgroundColour(Panel, {255,255,255}),
+ wxWindow:setBackgroundStyle(Panel, ?wxBG_STYLE_SYSTEM),
Sizer = wxBoxSizer:new(?wxVERTICAL),
wxSizer:addSpacer(Sizer, 5),
Add = fun(BoxInfo) ->
@@ -201,22 +201,21 @@ update_info2([Scroll = {_, _, _}|Fs], [{_, NewInfo}|Rest]) ->
update_scroll_boxes(Scroll, NewInfo),
update_info2(Fs, Rest);
update_info2([Field|Fs], [{_Str, {click, Value}}|Rest]) ->
- wxTextCtrl:setValue(Field, to_str(Value)),
+ wxStaticText:setLabel(Field, to_str(Value)),
update_info2(Fs, Rest);
update_info2([Field|Fs], [{_Str, Value}|Rest]) ->
- wxTextCtrl:setValue(Field, to_str(Value)),
+ wxStaticText:setLabel(Field, to_str(Value)),
update_info2(Fs, Rest);
update_info2([Field|Fs], [undefined|Rest]) ->
- wxTextCtrl:setValue(Field, ""),
+ wxStaticText:setLabel(Field, ""),
update_info2(Fs, Rest);
update_info2([], []) -> ok.
update_scroll_boxes({_, _, 0}, {_, []}) -> ok;
update_scroll_boxes({Win, Sizer, _}, {Type, List}) ->
[wxSizerItem:deleteWindows(Child) || Child <- wxSizer:getChildren(Sizer)],
- BC = wxWindow:getBackgroundColour(Win),
Cursor = wxCursor:new(?wxCURSOR_HAND),
- add_entries(Type, List, Win, Sizer, BC, Cursor),
+ add_entries(Type, List, Win, Sizer, Cursor),
wxCursor:destroy(Cursor),
wxSizer:recalcSizes(Sizer),
wxWindow:refresh(Win),
@@ -379,25 +378,22 @@ add_box(Panel, OuterBox, Cursor, Title, Proportion, {Format, List}) ->
wxScrolledWindow:setScrollbars(Scroll,1,1,0,0),
ScrollSizer = wxBoxSizer:new(?wxVERTICAL),
wxScrolledWindow:setSizer(Scroll, ScrollSizer),
- BC = wxWindow:getBackgroundColour(Panel),
- wxWindow:setBackgroundColour(Scroll,BC),
- add_entries(Format, List, Scroll, ScrollSizer, BC, Cursor),
+ wxWindow:setBackgroundStyle(Scroll, ?wxBG_STYLE_SYSTEM),
+ add_entries(Format, List, Scroll, ScrollSizer, Cursor),
wxSizer:add(Box,Scroll,[{proportion,1},{flag,?wxEXPAND}]),
wxSizer:add(OuterBox,Box,[{proportion,Proportion},{flag,?wxEXPAND}]),
{Scroll,ScrollSizer,length(List)}.
-add_entries(click, List, Scroll, ScrollSizer, BC, Cursor) ->
+add_entries(click, List, Scroll, ScrollSizer, Cursor) ->
Add = fun(Link) ->
TC = link_entry(Scroll, Link, Cursor),
- wxWindow:setBackgroundColour(TC,BC),
- wxSizer:add(ScrollSizer,TC,[{flag,?wxEXPAND}])
+ wxWindow:setBackgroundStyle(TC, ?wxBG_STYLE_SYSTEM),
+ wxSizer:add(ScrollSizer,TC, [{flag,?wxEXPAND}])
end,
[Add(Link) || Link <- List];
-add_entries(plain, List, Scroll, ScrollSizer, _, _) ->
+add_entries(plain, List, Scroll, ScrollSizer, _) ->
Add = fun(String) ->
- TC = wxTextCtrl:new(Scroll, ?wxID_ANY,
- [{style,?SINGLE_LINE_STYLE},
- {value,String}]),
+ TC = wxStaticText:new(Scroll, ?wxID_ANY, String),
wxSizer:add(ScrollSizer,TC,[{flag,?wxEXPAND}])
end,
[Add(String) || String <- List].
@@ -435,51 +431,44 @@ create_box(Panel, {scroll_boxes,Data}) ->
wxSizer:layout(OuterBox),
{OuterBox, Boxes};
-create_box(Panel, Data) ->
+create_box(Parent, Data) ->
{Title, Align, Info} = get_box_info(Data),
- Box = wxStaticBoxSizer:new(?wxVERTICAL, Panel, [{label, Title}]),
- LeftSize = get_max_size(Panel,Info),
- LeftProportion = [{proportion,0}],
- RightProportion = [{proportion,1}, {flag, Align bor ?wxEXPAND}],
+ Top = wxStaticBoxSizer:new(?wxVERTICAL, Parent, [{label, Title}]),
+ Panel = wxPanel:new(Parent),
+ Box = wxBoxSizer:new(?wxVERTICAL),
+ LeftSize = get_max_width(Panel,Info),
+ RightProportion = [{flag, Align bor ?wxEXPAND}],
AddRow = fun({Desc0, Value0}) ->
Desc = Desc0++":",
Line = wxBoxSizer:new(?wxHORIZONTAL),
- wxSizer:add(Line,
- wxTextCtrl:new(Panel, ?wxID_ANY,
- [{style,?SINGLE_LINE_STYLE},
- {size,LeftSize},
- {value,Desc}]),
- LeftProportion),
+ Label = wxStaticText:new(Panel, ?wxID_ANY, Desc),
+ wxSizer:add(Line, 5, 0),
+ wxSizer:add(Line, Label),
+ wxSizer:setItemMinSize(Line, Label, LeftSize, -1),
Field =
case Value0 of
{click,"unknown"} ->
- wxTextCtrl:new(Panel, ?wxID_ANY,
- [{style,?SINGLE_LINE_STYLE},
- {value,"unknown"}]);
+ wxStaticText:new(Panel, ?wxID_ANY,"unknown");
{click,Value} ->
link_entry(Panel,Value);
_ ->
Value = to_str(Value0),
- TCtrl = wxTextCtrl:new(Panel, ?wxID_ANY,
- [{style,?SINGLE_LINE_STYLE},
- {value,Value}]),
+ TCtrl = wxStaticText:new(Panel, ?wxID_ANY,Value),
length(Value) > 50 andalso
wxWindow:setToolTip(TCtrl,wxToolTip:new(Value)),
TCtrl
end,
wxSizer:add(Line, 10, 0), % space of size 10 horisontally
wxSizer:add(Line, Field, RightProportion),
-
- {_,H,_,_} = wxTextCtrl:getTextExtent(Field,"Wj"),
- wxTextCtrl:setMinSize(Field,{0,H}),
-
- wxSizer:add(Box, Line, [{proportion,0},{flag,?wxEXPAND}]),
+ wxSizer:add(Box, Line, [{proportion,1},{flag,?wxEXPAND}]),
Field;
(undefined) ->
undefined
end,
InfoFields = [AddRow(Entry) || Entry <- Info],
- {Box, InfoFields}.
+ wxWindow:setSizer(Panel, Box),
+ wxSizer:add(Top, Panel, [{proportion,1},{flag,?wxEXPAND}]),
+ {Top, InfoFields}.
link_entry(Panel, Link) ->
Cursor = wxCursor:new(?wxCURSOR_HAND),
@@ -490,13 +479,12 @@ link_entry(Panel, Link, Cursor) ->
link_entry2(Panel, to_link(Link), Cursor).
link_entry2(Panel,{Target,Str},Cursor) ->
- TC = wxTextCtrl:new(Panel, ?wxID_ANY, [{style, ?SINGLE_LINE_STYLE}]),
- wxTextCtrl:setForegroundColour(TC,?wxBLUE),
- wxTextCtrl:appendText(TC, Str),
+ TC = wxStaticText:new(Panel, ?wxID_ANY, Str),
+ wxWindow:setForegroundColour(TC,?wxBLUE),
wxWindow:setCursor(TC, Cursor),
- wxTextCtrl:connect(TC, left_down, [{userData,Target}]),
- wxTextCtrl:connect(TC, enter_window),
- wxTextCtrl:connect(TC, leave_window),
+ wxWindow:connect(TC, left_down, [{userData,Target}]),
+ wxWindow:connect(TC, enter_window),
+ wxWindow:connect(TC, leave_window),
ToolTip = wxToolTip:new("Click to see properties for " ++ Str),
wxWindow:setToolTip(TC, ToolTip),
TC.
@@ -521,23 +509,12 @@ html_window(Panel, Html) ->
wxHtmlWindow:setPage(Win, Html),
Win.
-get_max_size(Panel,Info) ->
- Txt = wxTextCtrl:new(Panel, ?wxID_ANY, []),
- Size = get_max_size(Txt,Info,0,0),
- wxTextCtrl:destroy(Txt),
- Size.
-
-get_max_size(Txt,[{Desc,_}|Info],MaxX,MaxY) ->
- {X,Y,_,_} = wxTextCtrl:getTextExtent(Txt,Desc++":"),
- if X>MaxX ->
- get_max_size(Txt,Info,X,Y);
- true ->
- get_max_size(Txt,Info,MaxX,MaxY)
- end;
-get_max_size(Txt,[undefined|Info],MaxX,MaxY) ->
- get_max_size(Txt,Info,MaxX,MaxY);
-get_max_size(_,[],X,_Y) ->
- {X+2,-1}.
+get_max_width(Parent,Info) ->
+ lists:foldl(fun({Desc,_}, Max) ->
+ {W, _, _, _} = wxWindow:getTextExtent(Parent, Desc),
+ max(W,Max);
+ (_, Max) -> Max
+ end, 0, Info).
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
set_listctrl_col_size(LCtrl, Total) ->
diff --git a/lib/observer/src/observer_perf_wx.erl b/lib/observer/src/observer_perf_wx.erl
index 017f07d2c4..45af08026a 100644
--- a/lib/observer/src/observer_perf_wx.erl
+++ b/lib/observer/src/observer_perf_wx.erl
@@ -100,7 +100,7 @@ setup_graph_drawing(Panels) ->
IsWindows = element(1, os:type()) =:= win32,
IgnoreCB = {callback, fun(_,_) -> ok end},
Do = fun(#win{panel=Panel}) ->
- wxWindow:setBackgroundColour(Panel, ?wxWHITE),
+ wxWindow:setBackgroundStyle(Panel, ?wxBG_STYLE_SYSTEM),
wxPanel:connect(Panel, paint, [callback]),
IsWindows andalso
wxPanel:connect(Panel, erase_background, [IgnoreCB])
diff --git a/lib/observer/src/observer_procinfo.erl b/lib/observer/src/observer_procinfo.erl
index 9d6aa84384..cff5fbb474 100644
--- a/lib/observer/src/observer_procinfo.erl
+++ b/lib/observer/src/observer_procinfo.erl
@@ -125,11 +125,11 @@ handle_event(#wx{event=#wxMouse{type=left_down}, userData=TargetPid}, State) ->
{noreply, State};
handle_event(#wx{obj=Obj, event=#wxMouse{type=enter_window}}, State) ->
- wxTextCtrl:setForegroundColour(Obj,{0,0,100,255}),
+ wxStaticText:setForegroundColour(Obj,{0,0,100,255}),
{noreply, State};
handle_event(#wx{obj=Obj, event=#wxMouse{type=leave_window}}, State) ->
- wxTextCtrl:setForegroundColour(Obj,?wxBLUE),
+ wxStaticText:setForegroundColour(Obj,?wxBLUE),
{noreply, State};
handle_event(#wx{event=#wxHtmlLink{linkInfo=#wxHtmlLinkInfo{href=Href}}},
diff --git a/lib/runtime_tools/src/system_information.erl b/lib/runtime_tools/src/system_information.erl
index ad7ee7311c..1add01612d 100644
--- a/lib/runtime_tools/src/system_information.erl
+++ b/lib/runtime_tools/src/system_information.erl
@@ -28,31 +28,25 @@
-behaviour(gen_server).
%% API
--export([
- report/0,
+-export([report/0,
from_file/1,
- to_file/1
- ]).
--export([
- start/0, stop/0,
- load_report/0, load_report/2,
- applications/0, applications/1,
- application/1, application/2,
- environment/0, environment/1,
- module/1, module/2,
- modules/1,
- sanity_check/0
- ]).
+ to_file/1]).
+-export([start/0, stop/0,
+ load_report/0, load_report/2,
+ applications/0, applications/1,
+ application/1, application/2,
+ environment/0, environment/1,
+ module/1, module/2,
+ modules/1,
+ sanity_check/0]).
%% gen_server callbacks
--export([
- init/1,
- handle_call/3,
- handle_cast/2,
- handle_info/2,
- terminate/2,
- code_change/3
- ]).
+-export([init/1,
+ handle_call/3,
+ handle_cast/2,
+ handle_info/2,
+ terminate/2,
+ code_change/3]).
-define(SERVER, ?MODULE).
@@ -71,13 +65,13 @@ start() ->
gen_server:start({local, ?SERVER}, ?MODULE, [], []).
stop() ->
- gen_server:call(?SERVER, stop).
+ gen_server:call(?SERVER, stop, infinity).
load_report() -> load_report(data, report()).
load_report(file, File) -> load_report(data, from_file(File));
load_report(data, Report) ->
- start(), gen_server:call(?SERVER, {load_report, Report}).
+ start(), gen_server:call(?SERVER, {load_report, Report}, infinity).
report() -> [
{init_arguments, init:get_arguments()},
@@ -120,22 +114,22 @@ from_file(File) ->
applications() -> applications([]).
applications(Opts) when is_list(Opts) ->
- gen_server:call(?SERVER, {applications, Opts}).
+ gen_server:call(?SERVER, {applications, Opts}, infinity).
application(App) when is_atom(App) -> application(App, []).
application(App, Opts) when is_atom(App), is_list(Opts) ->
- gen_server:call(?SERVER, {application, App, Opts}).
+ gen_server:call(?SERVER, {application, App, Opts}, infinity).
environment() -> environment([]).
environment(Opts) when is_list(Opts) ->
- gen_server:call(?SERVER, {environment, Opts}).
+ gen_server:call(?SERVER, {environment, Opts}, infinity).
module(M) when is_atom(M) -> module(M, []).
module(M, Opts) when is_atom(M), is_list(Opts) ->
- gen_server:call(?SERVER, {module, M, Opts}).
+ gen_server:call(?SERVER, {module, M, Opts}, infinity).
modules(Opt) when is_atom(Opt) ->
- gen_server:call(?SERVER, {modules, Opt}).
+ gen_server:call(?SERVER, {modules, Opt}, infinity).
-spec sanity_check() -> ok | {failed, Failures} when
diff --git a/lib/runtime_tools/test/dbg_SUITE.erl b/lib/runtime_tools/test/dbg_SUITE.erl
index 9c9d6ca352..6b6e35fc31 100644
--- a/lib/runtime_tools/test/dbg_SUITE.erl
+++ b/lib/runtime_tools/test/dbg_SUITE.erl
@@ -447,12 +447,6 @@ file_port_schedfix1(Config) when is_list(Config) ->
%%
{ok,[{matched,_,_}]} = dbg:p(all, [clear]),
stop(),
- % Some debug code to run on all platforms, for finding the fault on genny
- % Dont touch please /PaN
- io:format("Trace dump by PaN BEGIN~n"),
- dbg:trace_client(file,{FName, wrap, ".wraplog"},{fun(end_of_trace,Pid)-> Pid ! done; (Mesg,Pid) -> io:format("~w~n",[Mesg]),Pid end,self()}),
- receive done -> ok end,
- io:format("Trace dump by PaN END~n"),
%%
%% Get the trace result
%%
@@ -473,14 +467,12 @@ file_port_schedfix1(Config) when is_list(Config) ->
%%
%% Analyze the result
%%
- {Min, Max} =
- lists:foldl(
- fun({_Pid, M}, {Mi, Ma}) ->
- {if M < Mi -> M; true -> Mi end,
- if M > Ma -> M; true -> Ma end}
- end,
- {void, 0},
- Result),
+ {Min, Max} = lists:foldl(fun({_Pid, M}, {Mi, Ma}) ->
+ {if M < Mi -> M; true -> Mi end,
+ if M > Ma -> M; true -> Ma end}
+ end,
+ {void, 0},
+ Result),
% More PaN debug
io:format("Min = ~f, Max = ~f~n",[Min,Max]),
%%
@@ -895,6 +887,10 @@ schedstat_handler(TraceMsg, {Parent, Tag, Data} = State) ->
Data
end,
{Parent, Tag, NewData};
+ {trace_ts,_Pid,spawned,_OtherPid,_,_Ts} ->
+ State;
+ {trace_ts,_Pid,getting_linked,_OtherPid,_Ts} ->
+ State;
{trace_ts, Pid, exit, normal, {A3, B3, C3}} ->
NewData =
case lists:keysearch(Pid, 1, Data) of
diff --git a/lib/ssh/src/sshc_sup.erl b/lib/ssh/src/sshc_sup.erl
index 5667fd2aec..71b5c2c46a 100644
--- a/lib/ssh/src/sshc_sup.erl
+++ b/lib/ssh/src/sshc_sup.erl
@@ -64,7 +64,7 @@ child_spec(_) ->
Name = undefined, % As simple_one_for_one is used.
StartFunc = {ssh_connection_handler, start_link, []},
Restart = temporary,
- Shutdown = infinity,
+ Shutdown = 4000,
Modules = [ssh_connection_handler],
- Type = supervisor,
+ Type = worker,
{Name, StartFunc, Restart, Shutdown, Type, Modules}.
diff --git a/lib/ssh/test/ssh_sup_SUITE.erl b/lib/ssh/test/ssh_sup_SUITE.erl
index 2dc4263603..f8929b30ff 100644
--- a/lib/ssh/test/ssh_sup_SUITE.erl
+++ b/lib/ssh/test/ssh_sup_SUITE.erl
@@ -108,18 +108,19 @@ sshc_subtree(Config) when is_list(Config) ->
{ok, Pid1} = ssh:connect(Host, Port, [{silently_accept_hosts, true},
{user_interaction, false},
{user, ?USER}, {password, ?PASSWD},{user_dir, UserDir}]),
- ?wait_match([{_, _,supervisor,[ssh_connection_handler]}],
+
+ ?wait_match([{_, _,worker,[ssh_connection_handler]}],
supervisor:which_children(sshc_sup)),
{ok, Pid2} = ssh:connect(Host, Port, [{silently_accept_hosts, true},
{user_interaction, false},
{user, ?USER}, {password, ?PASSWD}, {user_dir, UserDir}]),
- ?wait_match([{_,_,supervisor,[ssh_connection_handler]},
- {_,_,supervisor,[ssh_connection_handler]}],
+ ?wait_match([{_,_,worker,[ssh_connection_handler]},
+ {_,_,worker,[ssh_connection_handler]}],
supervisor:which_children(sshc_sup)),
ssh:close(Pid1),
- ?wait_match([{_,_,supervisor,[ssh_connection_handler]}],
+ ?wait_match([{_,_,worker,[ssh_connection_handler]}],
supervisor:which_children(sshc_sup)),
ssh:close(Pid2),
?wait_match([], supervisor:which_children(sshc_sup)).
diff --git a/lib/ssl/src/ssl_cipher.erl b/lib/ssl/src/ssl_cipher.erl
index 544d9b41cd..dc0a0c2cc4 100644
--- a/lib/ssl/src/ssl_cipher.erl
+++ b/lib/ssl/src/ssl_cipher.erl
@@ -992,21 +992,21 @@ suite({ecdh_rsa, aes_256_cbc, sha384, sha384}) ->
%% RFC 5288 AES-GCM Cipher Suites
suite({rsa, aes_128_gcm, null, sha256}) ->
?TLS_RSA_WITH_AES_128_GCM_SHA256;
-suite({rsa, aes_256_gcm, null}) ->
+suite({rsa, aes_256_gcm, null, sha384}) ->
?TLS_RSA_WITH_AES_256_GCM_SHA384;
-suite({dhe_rsa, aes_128_gcm, null, sha384}) ->
+suite({dhe_rsa, aes_128_gcm, null, sha256}) ->
?TLS_DHE_RSA_WITH_AES_128_GCM_SHA256;
-suite({dhe_rsa, aes_256_gcm, null, sha256}) ->
+suite({dhe_rsa, aes_256_gcm, null, sha384}) ->
?TLS_DHE_RSA_WITH_AES_256_GCM_SHA384;
-suite({dh_rsa, aes_128_gcm, null, sha384}) ->
+suite({dh_rsa, aes_128_gcm, null, sha256}) ->
?TLS_DH_RSA_WITH_AES_128_GCM_SHA256;
-suite({dh_rsa, aes_256_gcm, null, sha256}) ->
+suite({dh_rsa, aes_256_gcm, null, sha384}) ->
?TLS_DH_RSA_WITH_AES_256_GCM_SHA384;
-suite({dhe_dss, aes_128_gcm, null, sha384}) ->
+suite({dhe_dss, aes_128_gcm, null, sha256}) ->
?TLS_DHE_DSS_WITH_AES_128_GCM_SHA256;
-suite({dhe_dss, aes_256_gcm, null, sha256}) ->
+suite({dhe_dss, aes_256_gcm, null, sha384}) ->
?TLS_DHE_DSS_WITH_AES_256_GCM_SHA384;
-suite({dh_dss, aes_128_gcm, null, sha384}) ->
+suite({dh_dss, aes_128_gcm, null, sha256}) ->
?TLS_DH_DSS_WITH_AES_128_GCM_SHA256;
suite({dh_dss, aes_256_gcm, null, sha384}) ->
?TLS_DH_DSS_WITH_AES_256_GCM_SHA384;
diff --git a/lib/ssl/src/ssl_manager.erl b/lib/ssl/src/ssl_manager.erl
index 2349158b11..60b4fbe995 100644
--- a/lib/ssl/src/ssl_manager.erl
+++ b/lib/ssl/src/ssl_manager.erl
@@ -610,8 +610,8 @@ server_register_session(Port, Session, #state{session_cache_server_max = Max,
do_register_session(Key, Session, Max, Pid, Cache, CacheCb) ->
try CacheCb:size(Cache) of
- N when N > Max ->
- invalidate_session_cache(Pid, CacheCb, Cache);
+ Max ->
+ invalidate_session_cache(Pid, CacheCb, Cache);
_ ->
CacheCb:update(Cache, Key, Session),
Pid
diff --git a/lib/ssl/src/tls_handshake.erl b/lib/ssl/src/tls_handshake.erl
index ef718c13df..102dbba198 100644
--- a/lib/ssl/src/tls_handshake.erl
+++ b/lib/ssl/src/tls_handshake.erl
@@ -278,10 +278,11 @@ handle_server_hello_extensions(Version, SessionId, Random, CipherSuite,
{Version, SessionId, ConnectionStates, ProtoExt, Protocol}
end.
-available_signature_algs(undefined, SupportedHashSigns, _, {Major, Minor}) when (Major < 3) andalso (Minor < 3) ->
+available_signature_algs(undefined, SupportedHashSigns, _, {Major, Minor}) when
+ (Major >= 3) andalso (Minor >= 3) ->
SupportedHashSigns;
available_signature_algs(#hash_sign_algos{hash_sign_algos = ClientHashSigns}, SupportedHashSigns,
- _, {Major, Minor}) when (Major < 3) andalso (Minor < 3) ->
+ _, {Major, Minor}) when (Major >= 3) andalso (Minor >= 3) ->
ordsets:intersection(ClientHashSigns, SupportedHashSigns);
available_signature_algs(_, _, _, _) ->
undefined.
diff --git a/lib/ssl/test/ssl_basic_SUITE.erl b/lib/ssl/test/ssl_basic_SUITE.erl
index 0c3c7aa39b..3fea38078f 100644
--- a/lib/ssl/test/ssl_basic_SUITE.erl
+++ b/lib/ssl/test/ssl_basic_SUITE.erl
@@ -88,7 +88,8 @@ basic_tests() ->
connect_dist,
clear_pem_cache,
defaults,
- fallback
+ fallback,
+ cipher_format
].
options_tests() ->
@@ -764,6 +765,14 @@ fallback(Config) when is_list(Config) ->
Client, {error,{tls_alert,"inappropriate fallback"}}).
%%--------------------------------------------------------------------
+cipher_format() ->
+ [{doc, "Test that cipher conversion from tuples to binarys works"}].
+cipher_format(Config) when is_list(Config) ->
+ {ok, Socket} = ssl:listen(0, [{ciphers, ssl:cipher_suites()}]),
+ ssl:close(Socket).
+
+%%--------------------------------------------------------------------
+
peername() ->
[{doc,"Test API function peername/1"}].
diff --git a/lib/stdlib/src/erl_lint.erl b/lib/stdlib/src/erl_lint.erl
index b14102ac38..2508f96b91 100644
--- a/lib/stdlib/src/erl_lint.erl
+++ b/lib/stdlib/src/erl_lint.erl
@@ -1502,7 +1502,7 @@ pattern({op,_Line,'++',{string,_Li,_S},R}, Vt, Old, Bvt, St) ->
pattern({match,_Line,Pat1,Pat2}, Vt, Old, Bvt, St0) ->
{Lvt,Bvt1,St1} = pattern(Pat1, Vt, Old, Bvt, St0),
{Rvt,Bvt2,St2} = pattern(Pat2, Vt, Old, Bvt, St1),
- St3 = reject_bin_alias(Pat1, Pat2, St2),
+ St3 = reject_invalid_alias(Pat1, Pat2, Vt, St2),
{vtmerge_pat(Lvt, Rvt),vtmerge_pat(Bvt1,Bvt2),St3};
%% Catch legal constant expressions, including unary +,-.
pattern(Pat, _Vt, _Old, _Bvt, St) ->
@@ -1517,56 +1517,77 @@ pattern_list(Ps, Vt, Old, Bvt0, St) ->
{vtmerge_pat(Pvt, Psvt),vtmerge_pat(Bvt,Bvt1),St1}
end, {[],[],St}, Ps).
-%% reject_bin_alias(Pat, Expr, St) -> St'
+
+
+%% reject_invalid_alias(Pat, Expr, Vt, St) -> St'
%% Reject aliases for binary patterns at the top level.
+%% Reject aliases for maps patterns at the top level.
+%% The variables table (Vt) are for maps checkking.
+
+reject_invalid_alias_expr({bin,_,_}=P, {match,_,P0,E}, Vt, St0) ->
+ St = reject_invalid_alias(P, P0, Vt, St0),
+ reject_invalid_alias_expr(P, E, Vt, St);
+reject_invalid_alias_expr({map,_,_}=P, {match,_,P0,E}, Vt, St0) ->
+ St = reject_invalid_alias(P, P0, Vt, St0),
+ reject_invalid_alias_expr(P, E, Vt, St);
+reject_invalid_alias_expr({match,_,_,_}=P, {match,_,P0,E}, Vt, St0) ->
+ St = reject_invalid_alias(P, P0, Vt, St0),
+ reject_invalid_alias_expr(P, E, Vt, St);
+reject_invalid_alias_expr(_, _, _, St) -> St.
-reject_bin_alias_expr({bin,_,_}=P, {match,_,P0,E}, St0) ->
- St = reject_bin_alias(P, P0, St0),
- reject_bin_alias_expr(P, E, St);
-reject_bin_alias_expr({match,_,_,_}=P, {match,_,P0,E}, St0) ->
- St = reject_bin_alias(P, P0, St0),
- reject_bin_alias_expr(P, E, St);
-reject_bin_alias_expr(_, _, St) -> St.
-%% reject_bin_alias(Pat1, Pat2, St) -> St'
+%% reject_invalid_alias(Pat1, Pat2, St) -> St'
%% Aliases of binary patterns, such as <<A:8>> = <<B:4,C:4>> or even
%% <<A:8>> = <<A:8>>, are not allowed. Traverse the patterns in parallel
%% and generate an error if any binary aliases are found.
%% We generate an error even if is obvious that the overall pattern can't
%% possibly match, for instance, {a,<<A:8>>,c}={x,<<A:8>>} WILL generate an
%% error.
+%% Maps should reject unbound variables here.
-reject_bin_alias({bin,Line,_}, {bin,_,_}, St) ->
+reject_invalid_alias({bin,Line,_}, {bin,_,_}, _, St) ->
add_error(Line, illegal_bin_pattern, St);
-reject_bin_alias({cons,_,H1,T1}, {cons,_,H2,T2}, St0) ->
- St = reject_bin_alias(H1, H2, St0),
- reject_bin_alias(T1, T2, St);
-reject_bin_alias({tuple,_,Es1}, {tuple,_,Es2}, St) ->
- reject_bin_alias_list(Es1, Es2, St);
-reject_bin_alias({record,_,Name1,Pfs1}, {record,_,Name2,Pfs2},
+reject_invalid_alias({map,_Line,Ps1}, {map,_,Ps2}, Vt, St0) ->
+ Fun = fun ({map_field_exact,L,{var,_,K},_V}, Sti) ->
+ case is_var_bound(K,Vt) of
+ true ->
+ Sti;
+ false ->
+ add_error(L, {unbound_var,K}, Sti)
+ end;
+ ({map_field_exact,_L,_K,_V}, Sti) ->
+ Sti
+ end,
+ foldl(Fun, foldl(Fun, St0, Ps1), Ps2);
+reject_invalid_alias({cons,_,H1,T1}, {cons,_,H2,T2}, Vt, St0) ->
+ St = reject_invalid_alias(H1, H2, Vt, St0),
+ reject_invalid_alias(T1, T2, Vt, St);
+reject_invalid_alias({tuple,_,Es1}, {tuple,_,Es2}, Vt, St) ->
+ reject_invalid_alias_list(Es1, Es2, Vt, St);
+reject_invalid_alias({record,_,Name1,Pfs1}, {record,_,Name2,Pfs2}, Vt,
#lint{records=Recs}=St) ->
case {dict:find(Name1, Recs),dict:find(Name2, Recs)} of
{{ok,{_Line1,Fields1}},{ok,{_Line2,Fields2}}} ->
- reject_bin_alias_rec(Pfs1, Pfs2, Fields1, Fields2, St);
+ reject_invalid_alias_rec(Pfs1, Pfs2, Fields1, Fields2, Vt, St);
{_,_} ->
%% One or more non-existing records. (An error messages has
%% already been generated, so we are done here.)
St
end;
-reject_bin_alias({match,_,P1,P2}, P, St0) ->
- St = reject_bin_alias(P1, P, St0),
- reject_bin_alias(P2, P, St);
-reject_bin_alias(P, {match,_,_,_}=M, St) ->
- reject_bin_alias(M, P, St);
-reject_bin_alias(_P1, _P2, St) -> St.
-
-reject_bin_alias_list([E1|Es1], [E2|Es2], St0) ->
- St = reject_bin_alias(E1, E2, St0),
- reject_bin_alias_list(Es1, Es2, St);
-reject_bin_alias_list(_, _, St) -> St.
-
-reject_bin_alias_rec(PfsA0, PfsB0, FieldsA0, FieldsB0, St) ->
+reject_invalid_alias({match,_,P1,P2}, P, Vt, St0) ->
+ St = reject_invalid_alias(P1, P, Vt, St0),
+ reject_invalid_alias(P2, P, Vt, St);
+reject_invalid_alias(P, {match,_,_,_}=M, Vt, St) ->
+ reject_invalid_alias(M, P, Vt, St);
+reject_invalid_alias(_P1, _P2, _Vt, St) -> St.
+
+reject_invalid_alias_list([E1|Es1], [E2|Es2], Vt, St0) ->
+ St = reject_invalid_alias(E1, E2, Vt, St0),
+ reject_invalid_alias_list(Es1, Es2, Vt, St);
+reject_invalid_alias_list(_, _, _, St) -> St.
+
+reject_invalid_alias_rec(PfsA0, PfsB0, FieldsA0, FieldsB0, Vt, St) ->
%% We treat records as if they have been converted to tuples.
PfsA1 = rbia_field_vars(PfsA0),
PfsB1 = rbia_field_vars(PfsB0),
@@ -1582,7 +1603,7 @@ reject_bin_alias_rec(PfsA0, PfsB0, FieldsA0, FieldsB0, St) ->
D = sofs:projection({external,fun({_,_,P1,_,P2}) -> {P1,P2} end}, C),
E = sofs:to_external(D),
{Ps1,Ps2} = lists:unzip(E),
- reject_bin_alias_list(Ps1, Ps2, St).
+ reject_invalid_alias_list(Ps1, Ps2, Vt, St).
rbia_field_vars(Fs) ->
[{Name,Pat} || {record_field,_,{atom,_,Name},Pat} <- Fs].
@@ -2284,7 +2305,7 @@ expr({'catch',Line,E}, Vt, St0) ->
expr({match,_Line,P,E}, Vt, St0) ->
{Evt,St1} = expr(E, Vt, St0),
{Pvt,Bvt,St2} = pattern(P, vtupdate(Evt, Vt), St1),
- St = reject_bin_alias_expr(P, E, St2),
+ St = reject_invalid_alias_expr(P, E, Vt, St2),
{vtupdate(Bvt, vtmerge(Evt, Pvt)),St};
%% No comparison or boolean operators yet.
expr({op,_Line,_Op,A}, Vt, St) ->
@@ -2381,7 +2402,7 @@ is_valid_call(Call) ->
_ -> true
end.
-%% is_valid_map_key(K,St) -> true | false
+%% is_valid_map_key(K) -> true | false
%% variables are allowed for patterns only at the top of the tree
is_valid_map_key({var,_,_}) -> true;
@@ -3413,6 +3434,14 @@ warn_unused_vars(U, Vt, St0) ->
UVt = map(fun ({V,{State,_,Ls}}) -> {V,{State,used,Ls}} end, U),
{vtmerge(Vt, UVt), St1}.
+
+is_var_bound(V, Vt) ->
+ case orddict:find(V, Vt) of
+ {ok,{bound,_Usage,_}} -> true;
+ _ -> false
+ end.
+
+
%% vtupdate(UpdVarTable, VarTable) -> VarTable.
%% Add the variables in the updated vartable to VarTable. The variables
%% will be updated with their property in UpdVarTable. The state of
diff --git a/lib/stdlib/src/proc_lib.erl b/lib/stdlib/src/proc_lib.erl
index 3f79ed0f87..fdc2ae4070 100644
--- a/lib/stdlib/src/proc_lib.erl
+++ b/lib/stdlib/src/proc_lib.erl
@@ -48,7 +48,9 @@
| {'priority', priority_level()}
| {'min_heap_size', non_neg_integer()}
| {'min_bin_vheap_size', non_neg_integer()}
- | {'fullsweep_after', non_neg_integer()}.
+ | {'fullsweep_after', non_neg_integer()}
+ | {'message_queue_data',
+ 'off_heap' | 'on_heap' | 'mixed' }.
-type dict_or_pid() :: pid()
| (ProcInfo :: [_])
diff --git a/lib/stdlib/test/erl_lint_SUITE.erl b/lib/stdlib/test/erl_lint_SUITE.erl
index 6fea198af3..b0214e5238 100644
--- a/lib/stdlib/test/erl_lint_SUITE.erl
+++ b/lib/stdlib/test/erl_lint_SUITE.erl
@@ -33,47 +33,38 @@
-define(privdir, proplists:get_value(priv_dir, Conf)).
-endif.
--export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1,
- init_per_group/2,end_per_group/2,
- init_per_testcase/2, end_per_testcase/2]).
-
--export([
- unused_vars_warn_basic/1,
- unused_vars_warn_lc/1,
- unused_vars_warn_rec/1,
- unused_vars_warn_fun/1,
- unused_vars_OTP_4858/1,
- unused_unsafe_vars_warn/1,
- export_vars_warn/1,
- shadow_vars/1,
- unused_import/1,
- unused_function/1,
- unsafe_vars/1,unsafe_vars2/1,
- unsafe_vars_try/1,
- unsized_binary_in_bin_gen_pattern/1,
- guard/1, otp_4886/1, otp_4988/1, otp_5091/1, otp_5276/1, otp_5338/1,
- otp_5362/1, otp_5371/1, otp_7227/1, otp_5494/1, otp_5644/1, otp_5878/1,
- otp_5917/1, otp_6585/1, otp_6885/1, otp_10436/1, otp_11254/1,
- otp_11772/1, otp_11771/1, otp_11872/1,
- export_all/1,
- bif_clash/1,
- behaviour_basic/1, behaviour_multiple/1, otp_11861/1,
- otp_7550/1,
- otp_8051/1,
- format_warn/1,
- on_load_successful/1, on_load_failing/1,
- too_many_arguments/1,
- basic_errors/1,bin_syntax_errors/1,
- predef/1,
- maps/1,maps_type/1,otp_11851/1,otp_11879/1,otp_13230/1,
- record_errors/1
- ]).
-
-init_per_testcase(_Case, Config) ->
- Config.
-
-end_per_testcase(_Case, _Config) ->
- ok.
+-export([all/0, suite/0, groups/0]).
+
+-export([unused_vars_warn_basic/1,
+ unused_vars_warn_lc/1,
+ unused_vars_warn_rec/1,
+ unused_vars_warn_fun/1,
+ unused_vars_OTP_4858/1,
+ unused_unsafe_vars_warn/1,
+ export_vars_warn/1,
+ shadow_vars/1,
+ unused_import/1,
+ unused_function/1,
+ unsafe_vars/1,unsafe_vars2/1,
+ unsafe_vars_try/1,
+ unsized_binary_in_bin_gen_pattern/1,
+ guard/1, otp_4886/1, otp_4988/1, otp_5091/1, otp_5276/1, otp_5338/1,
+ otp_5362/1, otp_5371/1, otp_7227/1, otp_5494/1, otp_5644/1, otp_5878/1,
+ otp_5917/1, otp_6585/1, otp_6885/1, otp_10436/1, otp_11254/1,
+ otp_11772/1, otp_11771/1, otp_11872/1,
+ export_all/1,
+ bif_clash/1,
+ behaviour_basic/1, behaviour_multiple/1, otp_11861/1,
+ otp_7550/1,
+ otp_8051/1,
+ format_warn/1,
+ on_load_successful/1, on_load_failing/1,
+ too_many_arguments/1,
+ basic_errors/1,bin_syntax_errors/1,
+ predef/1,
+ maps/1,maps_type/1,maps_parallel_match/1,
+ otp_11851/1,otp_11879/1,otp_13230/1,
+ record_errors/1]).
suite() ->
[{ct_hooks,[ts_install_cth]},
@@ -91,7 +82,8 @@ all() ->
bif_clash, behaviour_basic, behaviour_multiple, otp_11861,
otp_7550, otp_8051, format_warn, {group, on_load},
too_many_arguments, basic_errors, bin_syntax_errors, predef,
- maps, maps_type, otp_11851, otp_11879, otp_13230,
+ maps, maps_type, maps_parallel_match,
+ otp_11851, otp_11879, otp_13230,
record_errors].
groups() ->
@@ -101,19 +93,6 @@ groups() ->
unused_vars_OTP_4858, unused_unsafe_vars_warn]},
{on_load, [], [on_load_successful, on_load_failing]}].
-init_per_suite(Config) ->
- Config.
-
-end_per_suite(_Config) ->
- ok.
-
-init_per_group(_GroupName, Config) ->
- Config.
-
-end_per_group(_GroupName, Config) ->
- Config.
-
-
%% Warnings for unused variables in some simple cases.
unused_vars_warn_basic(Config) when is_list(Config) ->
@@ -3583,8 +3562,6 @@ predef(Config) when is_list(Config) ->
ok.
maps(Config) ->
- %% TODO: test key patterns, not done because map patterns are going to be
- %% changed a lot.
Ts = [{illegal_map_construction,
<<"t() ->
#{ a := b,
@@ -3626,6 +3603,26 @@ maps(Config) ->
{errors,[{1,erl_lint,illegal_map_construction},
{1,erl_lint,{unbound_var,'X'}}],
[]}},
+ {legal_map_pattern,
+ <<"
+ -record(mapkey, {a=1,b=2}).
+ t(M,K1) ->
+ #{ a := 1,
+ $a := 1, $z := 99,
+ #{a=>val} := 2,
+ K1 := 1337,
+ #mapkey{a = 10} := wat,
+ #{{a,val}=>val} := 2,
+ #{ \"hi\" => wazzup, hi => ho } := yep,
+ ok := 1.0,
+ [3+3] := nope,
+ 1.0 := yep,
+ {3.0+3} := nope,
+ {yep} := yep
+ } = M.
+ ">>,
+ [],
+ []},
{legal_map_construction,
<<"t(V) -> #{ a => 1,
#{a=>V} => 2,
@@ -3692,6 +3689,51 @@ maps_type(Config) when is_list(Config) ->
[] = run(Config, Ts),
ok.
+maps_parallel_match(Config) when is_list(Config) ->
+ Ts = [{parallel_map_patterns_unbound1,
+ <<"
+ t(#{} = M) ->
+ #{K := V} = #{k := K} = M,
+ V.
+ ">>,
+ [],
+ {errors,[{3,erl_lint,{unbound_var,'K'}}],[]}},
+ {parallel_map_patterns_unbound2,
+ <<"
+ t(#{} = M) ->
+ #{K1 := V1} =
+ #{K2 := V2} =
+ #{k1 := K1,k2 := K2} = M,
+ [V1,V2].
+ ">>,
+ [],
+ {errors,[{3,erl_lint,{unbound_var,'K1'}},
+ {3,erl_lint,{unbound_var,'K1'}},
+ {4,erl_lint,{unbound_var,'K2'}},
+ {4,erl_lint,{unbound_var,'K2'}}],[]}},
+ {parallel_map_patterns_bound,
+ <<"
+ t(#{} = M,K1,K2) ->
+ #{K1 := V1} =
+ #{K2 := V2} =
+ #{k1 := K1,k2 := K2} = M,
+ [V1,V2].
+ ">>,
+ [],
+ []},
+ {parallel_map_patterns_literal,
+ <<"
+ t(#{} = M) ->
+ #{k1 := V1} =
+ #{k2 := V2} =
+ #{k1 := V1,k2 := V2} = M,
+ [V1,V2].
+ ">>,
+ [],
+ []}],
+ [] = run(Config, Ts),
+ ok.
+
%% OTP-11851: More atoms can be used as type names + bug fixes.
otp_11851(Config) when is_list(Config) ->
Ts = [