aboutsummaryrefslogtreecommitdiffstats
path: root/erts/emulator
diff options
context:
space:
mode:
Diffstat (limited to 'erts/emulator')
-rw-r--r--erts/emulator/beam/atom.names1
-rw-r--r--erts/emulator/beam/bif.c188
-rw-r--r--erts/emulator/beam/bif.tab13
-rw-r--r--erts/emulator/beam/big.c134
-rw-r--r--erts/emulator/beam/big.h8
-rw-r--r--erts/emulator/beam/binary.c112
-rw-r--r--erts/emulator/beam/break.c41
-rw-r--r--erts/emulator/beam/erl_bif_info.c3
-rw-r--r--erts/emulator/beam/erl_bif_port.c16
-rw-r--r--erts/emulator/beam/erl_db_util.c2
-rw-r--r--erts/emulator/beam/erl_gc.c26
-rw-r--r--erts/emulator/beam/erl_init.c101
-rw-r--r--erts/emulator/beam/erl_printf_term.c4
-rw-r--r--erts/emulator/beam/erl_proc_sig_queue.c1
-rw-r--r--erts/emulator/beam/erl_proc_sig_queue.h3
-rw-r--r--erts/emulator/beam/erl_process.c158
-rw-r--r--erts/emulator/beam/erl_process.h2
-rw-r--r--erts/emulator/beam/erl_trace.c44
-rw-r--r--erts/emulator/beam/erl_trace.h2
-rw-r--r--erts/emulator/beam/global.h11
-rw-r--r--erts/emulator/beam/utils.c110
-rw-r--r--erts/emulator/drivers/common/inet_drv.c6
-rw-r--r--erts/emulator/nifs/common/prim_file_nif.c2
-rw-r--r--erts/emulator/test/big_SUITE.erl18
-rw-r--r--erts/emulator/test/num_bif_SUITE.erl14
-rw-r--r--erts/emulator/test/persistent_term_SUITE.erl80
-rw-r--r--erts/emulator/test/process_SUITE.erl14
-rw-r--r--erts/emulator/test/system_info_SUITE.erl84
28 files changed, 767 insertions, 431 deletions
diff --git a/erts/emulator/beam/atom.names b/erts/emulator/beam/atom.names
index a14f22b19e..291bc95604 100644
--- a/erts/emulator/beam/atom.names
+++ b/erts/emulator/beam/atom.names
@@ -546,6 +546,7 @@ atom reload
atom rem
atom report_errors
atom reset
+atom reset_seq_trace
atom restart
atom return_from
atom return_to
diff --git a/erts/emulator/beam/bif.c b/erts/emulator/beam/bif.c
index 015c051cc1..000397e790 100644
--- a/erts/emulator/beam/bif.c
+++ b/erts/emulator/beam/bif.c
@@ -2810,38 +2810,110 @@ BIF_RETTYPE list_to_existing_atom_1(BIF_ALIST_1)
/* convert an integer to a list of ascii integers */
-BIF_RETTYPE integer_to_list_1(BIF_ALIST_1)
+static Eterm integer_to_list(Process *c_p, Eterm num, int base)
{
- Eterm* hp;
+ Eterm *hp;
+ Eterm res;
Uint need;
+ if (is_small(num)) {
+ char s[128];
+ char *c = s;
+ Uint digits;
+
+ digits = Sint_to_buf(signed_val(num), base, &c, sizeof(s));
+ need = 2 * digits;
+
+ hp = HAlloc(c_p, need);
+ res = buf_to_intlist(&hp, c, digits, NIL);
+ } else {
+ const int DIGITS_PER_RED = 16;
+ Eterm *hp_end;
+ Uint digits;
+
+ digits = big_integer_estimate(num, base);
+
+ if ((digits / DIGITS_PER_RED) > ERTS_BIF_REDS_LEFT(c_p)) {
+ ErtsSchedulerData *esdp = erts_get_scheduler_data();
+
+ /* This could take a very long time, tell the caller to reschedule
+ * us to a dirty CPU scheduler if we aren't already on one. */
+ if (esdp->type == ERTS_SCHED_NORMAL) {
+ return THE_NON_VALUE;
+ }
+ } else {
+ BUMP_REDS(c_p, digits / DIGITS_PER_RED);
+ }
+
+ need = 2 * digits;
+
+ hp = HAlloc(c_p, need);
+ hp_end = hp + need;
+
+ res = erts_big_to_list(num, base, &hp);
+ HRelease(c_p, hp_end, hp);
+ }
+
+ return res;
+}
+
+BIF_RETTYPE integer_to_list_1(BIF_ALIST_1)
+{
+ Eterm res;
+
if (is_not_integer(BIF_ARG_1)) {
- BIF_ERROR(BIF_P, BADARG);
+ BIF_ERROR(BIF_P, BADARG);
}
- if (is_small(BIF_ARG_1)) {
- char *c;
- int n;
- struct Sint_buf ibuf;
+ res = integer_to_list(BIF_P, BIF_ARG_1, 10);
- c = Sint_to_buf(signed_val(BIF_ARG_1), &ibuf);
- n = sys_strlen(c);
- need = 2*n;
- hp = HAlloc(BIF_P, need);
- BIF_RET(buf_to_intlist(&hp, c, n, NIL));
+ if (is_non_value(res)) {
+ Eterm args[1];
+ args[0] = BIF_ARG_1;
+ return erts_schedule_bif(BIF_P,
+ args,
+ BIF_I,
+ integer_to_list_1,
+ ERTS_SCHED_DIRTY_CPU,
+ am_erlang,
+ am_integer_to_list,
+ 1);
}
- else {
- int n = big_decimal_estimate(BIF_ARG_1);
- Eterm res;
- Eterm* hp_end;
- need = 2*n;
- hp = HAlloc(BIF_P, need);
- hp_end = hp + need;
- res = erts_big_to_list(BIF_ARG_1, &hp);
- HRelease(BIF_P,hp_end,hp);
- BIF_RET(res);
+ return res;
+}
+
+BIF_RETTYPE integer_to_list_2(BIF_ALIST_2)
+{
+ Eterm res;
+ SWord base;
+
+ if (is_not_integer(BIF_ARG_1) || is_not_small(BIF_ARG_2)) {
+ BIF_ERROR(BIF_P, BADARG);
}
+
+ base = signed_val(BIF_ARG_2);
+ if (base < 2 || base > 36) {
+ BIF_ERROR(BIF_P, BADARG);
+ }
+
+ res = integer_to_list(BIF_P, BIF_ARG_1, base);
+
+ if (is_non_value(res)) {
+ Eterm args[2];
+ args[0] = BIF_ARG_1;
+ args[1] = BIF_ARG_2;
+ return erts_schedule_bif(BIF_P,
+ args,
+ BIF_I,
+ integer_to_list_2,
+ ERTS_SCHED_DIRTY_CPU,
+ am_erlang,
+ am_integer_to_list,
+ 2);
+ }
+
+ return res;
}
/**********************************************************************/
@@ -4490,11 +4562,12 @@ BIF_RETTYPE system_flag_2(BIF_ALIST_2)
ERTS_TRACER_CLEAR(&old_seq_tracer);
BIF_RET(ret);
- } else if (BIF_ARG_1 == make_small(1)) {
+ } else if (BIF_ARG_1 == am_reset_seq_trace) {
int i, max;
- erts_proc_unlock(BIF_P, ERTS_PROC_LOCK_MAIN);
- erts_thr_progress_block();
+ erts_proc_unlock(BIF_P, ERTS_PROC_LOCK_MAIN);
+ erts_thr_progress_block();
+
max = erts_ptab_max(&erts_proc);
for (i = 0; i < max; i++) {
Process *p = erts_pix2proc(i);
@@ -4506,13 +4579,14 @@ BIF_RETTYPE system_flag_2(BIF_ALIST_2)
#endif
p->seq_trace_clock = 0;
p->seq_trace_lastcnt = 0;
-
+ erts_proc_lock(p, ERTS_PROC_LOCK_MAIN|ERTS_PROC_LOCK_MSGQ);
erts_proc_sig_clear_seq_trace_tokens(p);
+ erts_proc_unlock(p, ERTS_PROC_LOCK_MAIN|ERTS_PROC_LOCK_MSGQ);
}
}
- erts_thr_progress_unblock();
- erts_proc_lock(BIF_P, ERTS_PROC_LOCK_MAIN);
+ erts_thr_progress_unblock();
+ erts_proc_lock(BIF_P, ERTS_PROC_LOCK_MAIN);
BIF_RET(am_true);
} else if (BIF_ARG_1 == am_scheduler_wall_time) {
@@ -4627,6 +4701,9 @@ BIF_RETTYPE system_flag_2(BIF_ALIST_2)
return erts_bind_schedulers(BIF_P, BIF_ARG_2);
} else if (ERTS_IS_ATOM_STR("erts_alloc", BIF_ARG_1)) {
return erts_alloc_set_dyn_param(BIF_P, BIF_ARG_2);
+ } else if (ERTS_IS_ATOM_STR("system_logger", BIF_ARG_1)) {
+ Eterm res = erts_set_system_logger(BIF_ARG_2);
+ if (is_value(res)) BIF_RET(res);
}
error:
BIF_ERROR(BIF_P, BADARG);
@@ -5129,61 +5206,6 @@ erts_call_dirty_bif(ErtsSchedulerData *esdp, Process *c_p, BeamInstr *I, Eterm *
return exiting;
}
-
-
-#ifdef HARDDEBUG
-/*
-You'll need this line in bif.tab to be able to use this debug bif
-
-bif erlang:send_to_logger/2
-
-*/
-BIF_RETTYPE send_to_logger_2(BIF_ALIST_2)
-{
- byte *buf;
- ErlDrvSizeT len;
- if (!is_atom(BIF_ARG_1) || !(is_list(BIF_ARG_2) ||
- is_nil(BIF_ARG_1))) {
- BIF_ERROR(BIF_P,BADARG);
- }
- if (erts_iolist_size(BIF_ARG_2, &len) != 0)
- BIF_ERROR(BIF_P,BADARG);
- else if (len == 0)
- buf = "";
- else {
-#ifdef DEBUG
- ErlDrvSizeT len2;
-#endif
- buf = (byte *) erts_alloc(ERTS_ALC_T_TMP, len+1);
-#ifdef DEBUG
- len2 =
-#else
- (void)
-#endif
- erts_iolist_to_buf(BIF_ARG_2, buf, len);
- ASSERT(len2 == len);
- buf[len] = '\0';
- switch (BIF_ARG_1) {
- case am_info:
- erts_send_info_to_logger(BIF_P->group_leader, buf, len);
- break;
- case am_warning:
- erts_send_warning_to_logger(BIF_P->group_leader, buf, len);
- break;
- case am_error:
- erts_send_error_to_logger(BIF_P->group_leader, buf, len);
- break;
- default:
- {
- BIF_ERROR(BIF_P,BADARG);
- }
- }
- erts_free(ERTS_ALC_T_TMP, (void *) buf);
- }
- BIF_RET(am_true);
-}
-#endif /* HARDDEBUG */
-
BIF_RETTYPE get_module_info_1(BIF_ALIST_1)
{
Eterm ret = erts_module_info_0(BIF_P, BIF_ARG_1);
diff --git a/erts/emulator/beam/bif.tab b/erts/emulator/beam/bif.tab
index d4ba90a61a..c96278b10c 100644
--- a/erts/emulator/beam/bif.tab
+++ b/erts/emulator/beam/bif.tab
@@ -725,3 +725,16 @@ bif erts_internal:counters_get/2
bif erts_internal:counters_add/3
bif erts_internal:counters_put/3
bif erts_internal:counters_info/1
+
+#
+# New in 21.2.3
+#
+
+bif erts_internal:spawn_system_process/3
+
+#
+# New in 21.3
+#
+
+bif erlang:integer_to_list/2
+bif erlang:integer_to_binary/2
diff --git a/erts/emulator/beam/big.c b/erts/emulator/beam/big.c
index b373d3a577..522f50287a 100644
--- a/erts/emulator/beam/big.c
+++ b/erts/emulator/beam/big.c
@@ -429,6 +429,7 @@
static const byte digits_per_sint_lookup[36-1];
static const byte digits_per_small_lookup[36-1];
static const Sint largest_power_of_base_lookup[36-1];
+static const double lg2_lookup[36-1];
static ERTS_INLINE byte get_digits_per_signed_int(Uint base) {
return digits_per_sint_lookup[base-2];
@@ -442,6 +443,10 @@ static ERTS_INLINE Sint get_largest_power_of_base(Uint base) {
return largest_power_of_base_lookup[base-2];
}
+static ERTS_INLINE double lookup_log2(Uint base) {
+ return lg2_lookup[base - 2];
+}
+
/*
** compare two number vectors
*/
@@ -668,27 +673,25 @@ static dsize_t I_mul(ErtsDigit* x, dsize_t xl, ErtsDigit* y, dsize_t yl, ErtsDig
static dsize_t I_sqr(ErtsDigit* x, dsize_t xl, ErtsDigit* r)
{
- ErtsDigit d_next = *x;
ErtsDigit d;
ErtsDigit* r0 = r;
ErtsDigit* s = r;
if ((r + xl) == x) /* "Inline" operation */
*x = 0;
- x++;
while(xl--) {
- ErtsDigit* y = x;
+ ErtsDigit* y;
ErtsDigit y_0 = 0, y_1 = 0, y_2 = 0, y_3 = 0;
ErtsDigit b0, b1;
ErtsDigit z0, z1, z2;
ErtsDigit t;
dsize_t y_l = xl;
-
+
+ d = *x;
+ x++;
+ y = x;
s = r;
- d = d_next;
- d_next = *x;
- x++;
DMUL(d, d, b1, b0);
DSUMc(*s, b0, y_3, t);
@@ -1722,23 +1725,23 @@ double_to_big(double x, Eterm *heap, Uint hsz)
/*
- ** Estimate the number of decimal digits (include sign)
+ ** Estimate the number of digits in given base (include sign)
*/
-int big_decimal_estimate(Wterm x)
+int big_integer_estimate(Wterm x, Uint base)
{
Eterm* xp = big_val(x);
int lg = I_lg(BIG_V(xp), BIG_SIZE(xp));
- int lg10 = ((lg+1)*28/93)+1;
+ int lgBase = ((lg + 1) / lookup_log2(base)) + 1;
- if (BIG_SIGN(xp)) lg10++; /* add sign */
- return lg10+1; /* add null */
+ if (BIG_SIGN(xp)) lgBase++; /* add sign */
+ return lgBase + 1; /* add null */
}
/*
-** Convert a bignum into a string of decimal numbers
+** Convert a bignum into a string of numbers in given base
*/
-
-static Uint write_big(Wterm x, void (*write_func)(void *, char), void *arg)
+static Uint write_big(Wterm x, int base, void (*write_func)(void *, char),
+ void *arg)
{
Eterm* xp = big_val(x);
ErtsDigit* dx = BIG_V(xp);
@@ -1746,48 +1749,72 @@ static Uint write_big(Wterm x, void (*write_func)(void *, char), void *arg)
short sign = BIG_SIGN(xp);
ErtsDigit rem;
Uint n = 0;
- const Uint digits_per_Sint = get_digits_per_signed_int(10);
- const Sint largest_pow_of_base = get_largest_power_of_base(10);
+ const Uint digits_per_Sint = get_digits_per_signed_int(base);
+ const Sint largest_pow_of_base = get_largest_power_of_base(base);
if (xl == 1 && *dx < largest_pow_of_base) {
- rem = *dx;
- if (rem == 0) {
- (*write_func)(arg, '0'); n++;
- } else {
- while(rem) {
- (*write_func)(arg, (rem % 10) + '0'); n++;
- rem /= 10;
- }
- }
+ rem = *dx;
+ if (rem == 0) {
+ (*write_func)(arg, '0'); n++;
+ } else {
+ while(rem) {
+ int digit = rem % base;
+
+ if (digit < 10) {
+ (*write_func)(arg, digit + '0'); n++;
+ } else {
+ (*write_func)(arg, 'A' + (digit - 10)); n++;
+ }
+
+ rem /= base;
+ }
+ }
} else {
- ErtsDigit* tmp = (ErtsDigit*) erts_alloc(ERTS_ALC_T_TMP,
- sizeof(ErtsDigit)*xl);
- dsize_t tmpl = xl;
+ ErtsDigit* tmp = (ErtsDigit*) erts_alloc(ERTS_ALC_T_TMP,
+ sizeof(ErtsDigit) * xl);
+ dsize_t tmpl = xl;
- MOVE_DIGITS(tmp, dx, xl);
+ MOVE_DIGITS(tmp, dx, xl);
- while(1) {
+ while(1) {
tmpl = D_div(tmp, tmpl, largest_pow_of_base, tmp, &rem);
- if (tmpl == 1 && *tmp == 0) {
- while(rem) {
- (*write_func)(arg, (rem % 10)+'0'); n++;
- rem /= 10;
- }
- break;
- } else {
+
+ if (tmpl == 1 && *tmp == 0) {
+ while(rem) {
+ int digit = rem % base;
+
+ if (digit < 10) {
+ (*write_func)(arg, digit + '0'); n++;
+ } else {
+ (*write_func)(arg, 'A' + (digit - 10)); n++;
+ }
+
+ rem /= base;
+ }
+ break;
+ } else {
Uint i = digits_per_Sint;
- while(i--) {
- (*write_func)(arg, (rem % 10)+'0'); n++;
- rem /= 10;
- }
- }
- }
- erts_free(ERTS_ALC_T_TMP, (void *) tmp);
+
+ while(i--) {
+ int digit = rem % base;
+
+ if (digit < 10) {
+ (*write_func)(arg, digit + '0'); n++;
+ } else {
+ (*write_func)(arg, 'A' + (digit - 10)); n++;
+ }
+
+ rem /= base;
+ }
+ }
+ }
+ erts_free(ERTS_ALC_T_TMP, (void *) tmp);
}
if (sign) {
- (*write_func)(arg, '-'); n++;
+ (*write_func)(arg, '-'); n++;
}
+
return n;
}
@@ -1804,12 +1831,12 @@ write_list(void *arg, char c)
blp->hp += 2;
}
-Eterm erts_big_to_list(Eterm x, Eterm **hpp)
+Eterm erts_big_to_list(Eterm x, int base, Eterm **hpp)
{
struct big_list__ bl;
bl.hp = *hpp;
bl.res = NIL;
- write_big(x, write_list, (void *) &bl);
+ write_big(x, base, write_list, (void *) &bl);
*hpp = bl.hp;
return bl.res;
}
@@ -1820,11 +1847,11 @@ write_string(void *arg, char c)
*(--(*((char **) arg))) = c;
}
-char *erts_big_to_string(Wterm x, char *buf, Uint buf_sz)
+char *erts_big_to_string(Wterm x, int base, char *buf, Uint buf_sz)
{
char *big_str = buf + buf_sz - 1;
*big_str = '\0';
- write_big(x, write_string, (void *) &big_str);
+ write_big(x, base, write_string, (void*)&big_str);
ASSERT(buf <= big_str && big_str <= buf + buf_sz - 1);
return big_str;
}
@@ -1833,11 +1860,11 @@ char *erts_big_to_string(Wterm x, char *buf, Uint buf_sz)
* e.g. 1 bsl 64 -> "18446744073709551616"
*/
-Uint erts_big_to_binary_bytes(Eterm x, char *buf, Uint buf_sz)
+Uint erts_big_to_binary_bytes(Eterm x, int base, char *buf, Uint buf_sz)
{
char *big_str = buf + buf_sz;
Uint n;
- n = write_big(x, write_string, (void *) &big_str);
+ n = write_big(x, base, write_string, (void *) &big_str);
ASSERT(buf <= big_str && big_str <= buf + buf_sz);
return n;
}
@@ -2580,9 +2607,6 @@ static const double lg2_lookup[36-1] = {
4.32193, 4.39232, 4.45943, 4.52356, 4.58496, 4.64386, 4.70044, 4.75489,
4.80735, 4.85798, 4.90689, 4.9542, 5.0, 5.04439, 5.08746, 5.12928, 5.16993
};
-static ERTS_INLINE double lookup_log2(Uint base) {
- return lg2_lookup[base - 2];
-}
/*
* How many digits can fit into a signed int (Sint) for given base, we take
diff --git a/erts/emulator/beam/big.h b/erts/emulator/beam/big.h
index 7556205063..6e6d7b5a4b 100644
--- a/erts/emulator/beam/big.h
+++ b/erts/emulator/beam/big.h
@@ -119,10 +119,10 @@ typedef Uint dsize_t; /* Vector size type */
#endif
-int big_decimal_estimate(Wterm);
-Eterm erts_big_to_list(Eterm, Eterm**);
-char *erts_big_to_string(Wterm x, char *buf, Uint buf_sz);
-Uint erts_big_to_binary_bytes(Eterm x, char *buf, Uint buf_sz);
+int big_integer_estimate(Wterm, Uint base);
+Eterm erts_big_to_list(Eterm, int base, Eterm**);
+char *erts_big_to_string(Wterm x, int base, char *buf, Uint buf_sz);
+Uint erts_big_to_binary_bytes(Eterm x, int base, char *buf, Uint buf_sz);
Eterm small_times(Sint, Sint, Eterm*);
diff --git a/erts/emulator/beam/binary.c b/erts/emulator/beam/binary.c
index 6a349764b2..a18228b84a 100644
--- a/erts/emulator/beam/binary.c
+++ b/erts/emulator/beam/binary.c
@@ -322,40 +322,102 @@ BIF_RETTYPE binary_to_integer_2(BIF_ALIST_2)
}
+static Eterm integer_to_binary(Process *c_p, Eterm num, int base)
+{
+ Eterm res;
+
+ if (is_small(num)) {
+ char s[128];
+ char *c = s;
+ Uint digits;
+
+ digits = Sint_to_buf(signed_val(num), base, &c, sizeof(s));
+ res = new_binary(c_p, (byte*)c, digits);
+ } else {
+ const int DIGITS_PER_RED = 16;
+ Uint digits, n;
+ byte *bytes;
+
+ digits = big_integer_estimate(num, base);
+
+ if ((digits / DIGITS_PER_RED) > ERTS_BIF_REDS_LEFT(c_p)) {
+ ErtsSchedulerData *esdp = erts_get_scheduler_data();
+
+ /* This could take a very long time, tell the caller to reschedule
+ * us to a dirty CPU scheduler if we aren't already on one. */
+ if (esdp->type == ERTS_SCHED_NORMAL) {
+ return THE_NON_VALUE;
+ }
+ } else {
+ BUMP_REDS(c_p, digits / DIGITS_PER_RED);
+ }
+
+ bytes = (byte*)erts_alloc(ERTS_ALC_T_TMP, sizeof(byte) * digits);
+ n = erts_big_to_binary_bytes(num, base, (char*)bytes, digits);
+ res = new_binary(c_p, bytes + digits - n, n);
+ erts_free(ERTS_ALC_T_TMP, (void*)bytes);
+ }
+
+ return res;
+}
+
BIF_RETTYPE integer_to_binary_1(BIF_ALIST_1)
-{
- Uint size;
+{
Eterm res;
if (is_not_integer(BIF_ARG_1)) {
- BIF_ERROR(BIF_P, BADARG);
+ BIF_ERROR(BIF_P, BADARG);
}
- if (is_small(BIF_ARG_1)) {
- char *c;
- struct Sint_buf ibuf;
+ res = integer_to_binary(BIF_P, BIF_ARG_1, 10);
+
+ if (is_non_value(res)) {
+ Eterm args[1];
+ args[0] = BIF_ARG_1;
+ return erts_schedule_bif(BIF_P,
+ args,
+ BIF_I,
+ integer_to_binary_1,
+ ERTS_SCHED_DIRTY_CPU,
+ am_erlang,
+ am_integer_to_binary,
+ 1);
+ }
- /* Enhancement: If we can calculate the buffer size exactly
- * we could avoid an unnecessary copy of buffers.
- * Useful if size determination is faster than a copy.
- */
- c = Sint_to_buf(signed_val(BIF_ARG_1), &ibuf);
- size = sys_strlen(c);
- res = new_binary(BIF_P, (byte *)c, size);
- } else {
- byte* bytes;
- Uint n = 0;
+ return res;
+}
- /* Here we also have multiple copies of buffers
- * due to new_binary interface
- */
- size = big_decimal_estimate(BIF_ARG_1) - 1; /* remove null */
- bytes = (byte*) erts_alloc(ERTS_ALC_T_TMP, sizeof(byte)*size);
- n = erts_big_to_binary_bytes(BIF_ARG_1, (char *)bytes, size);
- res = new_binary(BIF_P, bytes + size - n, n);
- erts_free(ERTS_ALC_T_TMP, (void *) bytes);
+BIF_RETTYPE integer_to_binary_2(BIF_ALIST_2)
+{
+ Eterm res;
+ SWord base;
+
+ if (is_not_integer(BIF_ARG_1) || is_not_small(BIF_ARG_2)) {
+ BIF_ERROR(BIF_P, BADARG);
+ }
+
+ base = signed_val(BIF_ARG_2);
+ if (base < 2 || base > 36) {
+ BIF_ERROR(BIF_P, BADARG);
}
- BIF_RET(res);
+
+ res = integer_to_binary(BIF_P, BIF_ARG_1, base);
+
+ if (is_non_value(res)) {
+ Eterm args[2];
+ args[0] = BIF_ARG_1;
+ args[1] = BIF_ARG_2;
+ return erts_schedule_bif(BIF_P,
+ args,
+ BIF_I,
+ integer_to_binary_2,
+ ERTS_SCHED_DIRTY_CPU,
+ am_erlang,
+ am_integer_to_binary,
+ 2);
+ }
+
+ return res;
}
#define ERTS_B2L_BYTES_PER_REDUCTION 256
diff --git a/erts/emulator/beam/break.c b/erts/emulator/beam/break.c
index 9ff52c92b8..92009c2345 100644
--- a/erts/emulator/beam/break.c
+++ b/erts/emulator/beam/break.c
@@ -82,7 +82,7 @@ process_info(fmtfn_t to, void *to_arg)
* they are most likely just created and has invalid data
*/
if (!ERTS_PROC_IS_EXITING(p) && p->heap != NULL)
- print_process_info(to, to_arg, p);
+ print_process_info(to, to_arg, p, 0);
}
}
@@ -101,7 +101,7 @@ process_killer(void)
rp = erts_pix2proc(i);
if (rp && rp->i != ENULL) {
int br;
- print_process_info(ERTS_PRINT_STDOUT, NULL, rp);
+ print_process_info(ERTS_PRINT_STDOUT, NULL, rp, 0);
erts_printf("(k)ill (n)ext (r)eturn:\n");
while(1) {
if ((j = sys_get_key(0)) <= 0)
@@ -199,13 +199,14 @@ static void doit_print_monitor(ErtsMonitor *mon, void *vpcontext)
/* Display info about an individual Erlang process */
void
-print_process_info(fmtfn_t to, void *to_arg, Process *p)
+print_process_info(fmtfn_t to, void *to_arg, Process *p, ErtsProcLocks orig_locks)
{
int garbing = 0;
int running = 0;
Sint len;
struct saved_calls *scb;
erts_aint32_t state;
+ ErtsProcLocks locks = orig_locks;
/* display the PID */
erts_print(to, to_arg, "=proc:%T\n", p->common.id);
@@ -222,6 +223,22 @@ print_process_info(fmtfn_t to, void *to_arg, Process *p)
| ERTS_PSFLG_DIRTY_RUNNING))
running = 1;
+ if (!(locks & ERTS_PROC_LOCK_MAIN)) {
+ locks |= ERTS_PROC_LOCK_MAIN;
+ if (ERTS_IS_CRASH_DUMPING && running) {
+ if (erts_proc_trylock(p, locks)) {
+ /* crash dumping and main lock taken, this probably means that
+ the process is doing a GC on a dirty-scheduler... so we cannot
+ do erts_proc_sig_fetch as that would potentially cause a segfault */
+ locks = 0;
+ }
+ } else {
+ erts_proc_lock(p, locks);
+ }
+ } else {
+ ERTS_ASSERT(locks == ERTS_PROC_LOCK_MAIN && "Only main lock should be held");
+ }
+
/*
* If the process is registered as a global process, display the
* registered name
@@ -251,13 +268,19 @@ print_process_info(fmtfn_t to, void *to_arg, Process *p)
erts_print(to, to_arg, "Spawned by: %T\n", p->parent);
- erts_proc_lock(p, ERTS_PROC_LOCK_MSGQ);
- len = erts_proc_sig_fetch(p);
- erts_proc_unlock(p, ERTS_PROC_LOCK_MSGQ);
+ if (locks & ERTS_PROC_LOCK_MAIN) {
+ erts_proc_lock(p, ERTS_PROC_LOCK_MSGQ);
+ len = erts_proc_sig_fetch(p);
+ erts_proc_unlock(p, ERTS_PROC_LOCK_MSGQ);
+ } else {
+ len = p->sig_qs.len;
+ }
erts_print(to, to_arg, "Message queue length: %d\n", len);
- /* display the message queue only if there is anything in it */
- if (!ERTS_IS_CRASH_DUMPING && p->sig_qs.first != NULL && !garbing) {
+ /* display the message queue only if there is anything in it
+ and we can do it safely */
+ if (!ERTS_IS_CRASH_DUMPING && p->sig_qs.first != NULL && !garbing
+ && (locks & ERTS_PROC_LOCK_MAIN)) {
erts_print(to, to_arg, "Message queue: [");
ERTS_FOREACH_SIG_PRIVQS(
p, mp,
@@ -357,6 +380,8 @@ print_process_info(fmtfn_t to, void *to_arg, Process *p)
/* Display all states */
erts_print(to, to_arg, "Internal State: ");
erts_dump_extended_process_state(to, to_arg, state);
+
+ erts_proc_unlock(p, locks & ~orig_locks);
}
static void
diff --git a/erts/emulator/beam/erl_bif_info.c b/erts/emulator/beam/erl_bif_info.c
index 7fada0d548..6137edef1b 100644
--- a/erts/emulator/beam/erl_bif_info.c
+++ b/erts/emulator/beam/erl_bif_info.c
@@ -3139,6 +3139,8 @@ BIF_RETTYPE system_info_1(BIF_ALIST_1)
DECL_AM(tag);
BIF_RET(AM_tag);
#endif
+ } else if (ERTS_IS_ATOM_STR("system_logger", BIF_ARG_1)) {
+ BIF_RET(erts_get_system_logger());
}
BIF_ERROR(BIF_P, BADARG);
@@ -4608,6 +4610,7 @@ BIF_RETTYPE erts_debug_set_internal_state_2(BIF_ALIST_2)
}
}
else if (ERTS_IS_ATOM_STR("broken_halt", BIF_ARG_1)) {
+ erts_proc_unlock(BIF_P, ERTS_PROC_LOCK_MAIN);
broken_halt_test(BIF_ARG_2);
}
else if (ERTS_IS_ATOM_STR("unique_monotonic_integer_state", BIF_ARG_1)) {
diff --git a/erts/emulator/beam/erl_bif_port.c b/erts/emulator/beam/erl_bif_port.c
index 7fe4e02782..ed825d3dda 100644
--- a/erts/emulator/beam/erl_bif_port.c
+++ b/erts/emulator/beam/erl_bif_port.c
@@ -891,10 +891,6 @@ open_port(Process* p, Eterm name, Eterm settings, int *err_typep, int *err_nump)
driver = &spawn_driver;
} else if (*tp == am_fd) { /* An fd port */
- int n;
- struct Sint_buf sbuf;
- char* p;
-
if (arity != make_arityval(3)) {
goto badarg;
}
@@ -904,15 +900,9 @@ open_port(Process* p, Eterm name, Eterm settings, int *err_typep, int *err_nump)
opts.ifd = unsigned_val(tp[1]);
opts.ofd = unsigned_val(tp[2]);
- /* Syntesize name from input and output descriptor. */
- name_buf = erts_alloc(ERTS_ALC_T_TMP,
- 2*sizeof(struct Sint_buf) + 2);
- p = Sint_to_buf(opts.ifd, &sbuf);
- n = sys_strlen(p);
- sys_strncpy(name_buf, p, n);
- name_buf[n] = '/';
- p = Sint_to_buf(opts.ofd, &sbuf);
- sys_strcpy(name_buf+n+1, p);
+ /* Syntesize name from input and output descriptor. */
+ name_buf = erts_alloc(ERTS_ALC_T_TMP, 256);
+ erts_snprintf(name_buf, 256, "%i/%i", opts.ifd, opts.ofd);
driver = &fd_driver;
} else {
diff --git a/erts/emulator/beam/erl_db_util.c b/erts/emulator/beam/erl_db_util.c
index f1d47326b4..e2c029c244 100644
--- a/erts/emulator/beam/erl_db_util.c
+++ b/erts/emulator/beam/erl_db_util.c
@@ -2470,7 +2470,7 @@ restart:
case matchProcessDump: {
erts_dsprintf_buf_t *dsbufp = erts_create_tmp_dsbuf(0);
ASSERT(c_p == self);
- print_process_info(ERTS_PRINT_DSBUF, (void *) dsbufp, c_p);
+ print_process_info(ERTS_PRINT_DSBUF, (void *) dsbufp, c_p, ERTS_PROC_LOCK_MAIN);
*esp++ = new_binary(build_proc, (byte *)dsbufp->str,
dsbufp->str_len);
erts_destroy_tmp_dsbuf(dsbufp);
diff --git a/erts/emulator/beam/erl_gc.c b/erts/emulator/beam/erl_gc.c
index d5dfb096b1..3a50b294d1 100644
--- a/erts/emulator/beam/erl_gc.c
+++ b/erts/emulator/beam/erl_gc.c
@@ -2438,27 +2438,9 @@ erts_copy_one_frag(Eterm** hpp, ErlOffHeap* off_heap,
cpy_words:
ASSERT(sz >= cpy_sz);
sz -= cpy_sz;
- while (cpy_sz >= 8) {
- cpy_sz -= 8;
- *hp++ = *fhp++;
- *hp++ = *fhp++;
- *hp++ = *fhp++;
- *hp++ = *fhp++;
- *hp++ = *fhp++;
- *hp++ = *fhp++;
- *hp++ = *fhp++;
- *hp++ = *fhp++;
- }
- switch (cpy_sz) {
- case 7: *hp++ = *fhp++;
- case 6: *hp++ = *fhp++;
- case 5: *hp++ = *fhp++;
- case 4: *hp++ = *fhp++;
- case 3: *hp++ = *fhp++;
- case 2: *hp++ = *fhp++;
- case 1: *hp++ = *fhp++;
- default: break;
- }
+ sys_memcpy(hp, fhp, cpy_sz * sizeof(Eterm));
+ hp += cpy_sz;
+ fhp += cpy_sz;
if (oh) {
/* Add to offheap list */
oh->next = off_heap->first;
@@ -2477,7 +2459,7 @@ erts_copy_one_frag(Eterm** hpp, ErlOffHeap* off_heap,
*hpp = hp;
for (i = 0; i < nrefs; i++) {
- if (is_not_immed(refs[i]) && !erts_is_literal(refs[i],boxed_val(refs[i])))
+ if (is_not_immed(refs[i]) && !erts_is_literal(refs[i],ptr_val(refs[i])))
refs[i] = offset_ptr(refs[i], offs);
}
bp->off_heap.first = NULL;
diff --git a/erts/emulator/beam/erl_init.c b/erts/emulator/beam/erl_init.c
index 99e788c718..41bec17dfa 100644
--- a/erts/emulator/beam/erl_init.c
+++ b/erts/emulator/beam/erl_init.c
@@ -376,6 +376,27 @@ erl_init(int ncpu,
}
static Eterm
+erl_spawn_system_process(Process* parent, Eterm mod, Eterm func, Eterm args,
+ ErlSpawnOpts *so)
+{
+ Eterm res;
+ int arity;
+
+ ERTS_LC_ASSERT(ERTS_PROC_LOCK_MAIN & erts_proc_lc_my_proc_locks(parent));
+ arity = erts_list_length(args);
+
+ if (erts_find_function(mod, func, arity, erts_active_code_ix()) == NULL) {
+ erts_exit(ERTS_ERROR_EXIT, "No function %T:%T/%i\n", mod, func, arity);
+ }
+
+ so->flags |= SPO_SYSTEM_PROC;
+
+ res = erl_create_process(parent, mod, func, args, so);
+
+ return res;
+}
+
+static Eterm
erl_first_process_otp(char* modname, void* code, unsigned size, int argc, char** argv)
{
int i;
@@ -386,12 +407,6 @@ erl_first_process_otp(char* modname, void* code, unsigned size, int argc, char**
Process parent;
ErlSpawnOpts so;
Eterm env;
-
- start_mod = erts_atom_put((byte *) modname, sys_strlen(modname), ERTS_ATOM_ENC_LATIN1, 1);
- if (erts_find_function(start_mod, am_start, 2,
- erts_active_code_ix()) == NULL) {
- erts_exit(ERTS_ERROR_EXIT, "No function %s:start/2\n", modname);
- }
/*
* We need a dummy parent process to be able to call erl_create_process().
@@ -399,6 +414,7 @@ erl_first_process_otp(char* modname, void* code, unsigned size, int argc, char**
erts_init_empty_process(&parent);
erts_proc_lock(&parent, ERTS_PROC_LOCK_MAIN);
+
hp = HAlloc(&parent, argc*2 + 4);
args = NIL;
for (i = argc-1; i >= 0; i--) {
@@ -411,44 +427,73 @@ erl_first_process_otp(char* modname, void* code, unsigned size, int argc, char**
hp += 2;
args = CONS(hp, env, args);
- so.flags = erts_default_spo_flags|SPO_SYSTEM_PROC;
- res = erl_create_process(&parent, start_mod, am_start, args, &so);
+ start_mod = erts_atom_put((byte *) modname, sys_strlen(modname),
+ ERTS_ATOM_ENC_LATIN1, 1);
+
+ so.flags = erts_default_spo_flags;
+ res = erl_spawn_system_process(&parent, start_mod, am_start, args, &so);
+ ASSERT(is_internal_pid(res));
+
erts_proc_unlock(&parent, ERTS_PROC_LOCK_MAIN);
erts_cleanup_empty_process(&parent);
+
return res;
}
static Eterm
erl_system_process_otp(Eterm parent_pid, char* modname, int off_heap_msgq, int prio)
-{
- Eterm start_mod;
- Process* parent;
+{
+ Process *parent;
ErlSpawnOpts so;
- Eterm res;
-
- start_mod = erts_atom_put((byte *) modname, sys_strlen(modname), ERTS_ATOM_ENC_LATIN1, 1);
- if (erts_find_function(start_mod, am_start, 0,
- erts_active_code_ix()) == NULL) {
- erts_exit(ERTS_ERROR_EXIT, "No function %s:start/0\n", modname);
- }
+ Eterm mod, res;
parent = erts_pid2proc(NULL, 0, parent_pid, ERTS_PROC_LOCK_MAIN);
+ mod = erts_atom_put((byte *) modname, sys_strlen(modname),
+ ERTS_ATOM_ENC_LATIN1, 1);
+
+ so.flags = erts_default_spo_flags|SPO_USE_ARGS;
- so.flags = erts_default_spo_flags|SPO_SYSTEM_PROC|SPO_USE_ARGS;
- if (off_heap_msgq)
+ if (off_heap_msgq) {
so.flags |= SPO_OFF_HEAP_MSGQ;
- so.min_heap_size = H_MIN_SIZE;
- so.min_vheap_size = BIN_VH_MIN_SIZE;
- so.max_heap_size = H_MAX_SIZE;
- so.max_heap_flags = H_MAX_FLAGS;
- so.priority = prio;
- so.max_gen_gcs = (Uint16) erts_atomic32_read_nob(&erts_max_gen_gcs);
- so.scheduler = 0;
- res = erl_create_process(parent, start_mod, am_start, NIL, &so);
+ }
+
+ so.min_heap_size = H_MIN_SIZE;
+ so.min_vheap_size = BIN_VH_MIN_SIZE;
+ so.max_heap_size = H_MAX_SIZE;
+ so.max_heap_flags = H_MAX_FLAGS;
+ so.priority = prio;
+ so.max_gen_gcs = (Uint16) erts_atomic32_read_nob(&erts_max_gen_gcs);
+ so.scheduler = 0;
+
+ res = erl_spawn_system_process(parent, mod, am_start, NIL, &so);
+ ASSERT(is_internal_pid(res));
+
erts_proc_unlock(parent, ERTS_PROC_LOCK_MAIN);
+
return res;
}
+Eterm erts_internal_spawn_system_process_3(BIF_ALIST_3) {
+ Eterm mod, func, args, res;
+ ErlSpawnOpts so;
+
+ mod = BIF_ARG_1;
+ func = BIF_ARG_2;
+ args = BIF_ARG_3;
+
+ ASSERT(is_atom(mod));
+ ASSERT(is_atom(func));
+ ASSERT(erts_list_length(args) >= 0);
+
+ so.flags = erts_default_spo_flags;
+ res = erl_spawn_system_process(BIF_P, mod, func, args, &so);
+
+ if (is_non_value(res)) {
+ BIF_ERROR(BIF_P, so.error_code);
+ }
+
+ BIF_RET(res);
+}
Eterm
erts_preloaded(Process* p)
diff --git a/erts/emulator/beam/erl_printf_term.c b/erts/emulator/beam/erl_printf_term.c
index 990a01b96f..9cfb7fc681 100644
--- a/erts/emulator/beam/erl_printf_term.c
+++ b/erts/emulator/beam/erl_printf_term.c
@@ -364,13 +364,13 @@ print_term(fmtfn_t fn, void* arg, Eterm obj, long *dcount) {
int print_res;
char def_buf[64];
char *buf, *big_str;
- Uint sz = (Uint) big_decimal_estimate(wobj);
+ Uint sz = (Uint) big_integer_estimate(wobj, 10);
sz++;
if (sz <= 64)
buf = &def_buf[0];
else
buf = erts_alloc(ERTS_ALC_T_TMP, sz);
- big_str = erts_big_to_string(wobj, buf, sz);
+ big_str = erts_big_to_string(wobj, 10, buf, sz);
print_res = erts_printf_string(fn, arg, big_str);
if (buf != &def_buf[0])
erts_free(ERTS_ALC_T_TMP, (void *) buf);
diff --git a/erts/emulator/beam/erl_proc_sig_queue.c b/erts/emulator/beam/erl_proc_sig_queue.c
index f343e984f7..18418a76e1 100644
--- a/erts/emulator/beam/erl_proc_sig_queue.c
+++ b/erts/emulator/beam/erl_proc_sig_queue.c
@@ -3812,7 +3812,6 @@ clear_seq_trace_token(ErtsMessage *sig)
void
erts_proc_sig_clear_seq_trace_tokens(Process *c_p)
{
- ASSERT(erts_thr_progress_is_blocking());
erts_proc_sig_fetch(c_p);
ERTS_FOREACH_SIG_PRIVQS(c_p, sig, clear_seq_trace_token(sig));
}
diff --git a/erts/emulator/beam/erl_proc_sig_queue.h b/erts/emulator/beam/erl_proc_sig_queue.h
index 3fc2d06b2d..6b065a7add 100644
--- a/erts/emulator/beam/erl_proc_sig_queue.h
+++ b/erts/emulator/beam/erl_proc_sig_queue.h
@@ -989,8 +989,7 @@ erts_proc_sig_fetch(Process *proc)
Sint res = 0;
ErtsSignal *sig;
- ERTS_LC_ASSERT(erts_thr_progress_is_blocking()
- || ERTS_PROC_IS_EXITING(proc)
+ ERTS_LC_ASSERT(ERTS_PROC_IS_EXITING(proc)
|| ((erts_proc_lc_my_proc_locks(proc)
& (ERTS_PROC_LOCK_MAIN
| ERTS_PROC_LOCK_MSGQ))
diff --git a/erts/emulator/beam/erl_process.c b/erts/emulator/beam/erl_process.c
index 2427d87f66..19093ebfdd 100644
--- a/erts/emulator/beam/erl_process.c
+++ b/erts/emulator/beam/erl_process.c
@@ -92,10 +92,6 @@
#undef HARDDEBUG
#endif
-#ifdef HARDDEBUG
-#define HARDDEBUG_RUNQS
-#endif
-
#ifdef HIPE
#include "hipe_mode_switch.h" /* for hipe_init_process() */
#include "hipe_signal.h" /* for hipe_thread_signal_init() */
@@ -3300,6 +3296,46 @@ check_io_timer(void *null)
#define prepare_for_sys_schedule() 0
#endif
+#ifdef HARDDEBUG
+#define ERTS_HDBG_CHK_SLEEP_LIST(SL, L, F, FN) \
+ check_sleepers_list((SL), (L), (F), (FN))
+static void check_sleepers_list(ErtsSchedulerSleepList *sl,
+ int lock,
+ ErtsSchedulerSleepInfo *find,
+ ErtsSchedulerSleepInfo *find_not)
+{
+ ErtsSchedulerSleepInfo *last_out;
+ int found = 0;
+
+ if (lock)
+ erts_spin_lock(&sl->lock);
+
+ ERTS_ASSERT(!find_not || (!find_not->next && !find_not->prev));
+
+ last_out = sl->list;
+ if (last_out) {
+ ErtsSchedulerSleepInfo *tmp = last_out;
+ do {
+ ERTS_ASSERT(tmp->next);
+ ERTS_ASSERT(tmp->prev);
+ ERTS_ASSERT(tmp->next->prev == tmp);
+ ERTS_ASSERT(tmp->prev->next == tmp);
+ ERTS_ASSERT(tmp != find_not);
+ if (tmp == find)
+ found = !0;
+ tmp = tmp->next;
+
+ } while (tmp != last_out);
+ }
+ ERTS_ASSERT(!find || found);
+
+ if (lock)
+ erts_spin_unlock(&sl->lock);
+}
+#else
+#define ERTS_HDBG_CHK_SLEEP_LIST(SL, L, F, FN) ((void) 0)
+#endif
+
static void
scheduler_wait(int *fcalls, ErtsSchedulerData *esdp, ErtsRunQueue *rq)
{
@@ -3313,23 +3349,29 @@ scheduler_wait(int *fcalls, ErtsSchedulerData *esdp, ErtsRunQueue *rq)
ERTS_LC_ASSERT(erts_lc_runq_is_locked(rq));
- if (ERTS_RUNQ_IX_IS_DIRTY(rq->ix))
- erts_spin_lock(&rq->sleepers.lock);
flgs = sched_prep_spin_wait(ssi);
if (flgs & ERTS_SSI_FLG_SUSPENDED) {
/* Go suspend instead... */
- if (ERTS_RUNQ_IX_IS_DIRTY(rq->ix))
- erts_spin_unlock(&rq->sleepers.lock);
return;
}
if (ERTS_RUNQ_IX_IS_DIRTY(rq->ix)) {
- ssi->prev = NULL;
- ssi->next = rq->sleepers.list;
- if (rq->sleepers.list)
- rq->sleepers.list->prev = ssi;
- rq->sleepers.list = ssi;
- erts_spin_unlock(&rq->sleepers.lock);
+ erts_spin_lock(&rq->sleepers.lock);
+ ERTS_HDBG_CHK_SLEEP_LIST(&rq->sleepers, 0, NULL, ssi);
+ ASSERT(!ssi->next); /* Not in sleepers list */
+ ASSERT(!ssi->prev);
+ if (!rq->sleepers.list) {
+ ssi->next = ssi->prev = ssi;
+ rq->sleepers.list = ssi;
+ }
+ else {
+ ssi->prev = rq->sleepers.list;
+ ssi->next = rq->sleepers.list->next;
+ ssi->prev->next = ssi;
+ ssi->next->prev = ssi;
+ }
+ ERTS_HDBG_CHK_SLEEP_LIST(&rq->sleepers, 0, ssi, NULL);
+ erts_spin_unlock(&rq->sleepers.lock);
dirty_active(esdp, -1);
}
@@ -3470,8 +3512,28 @@ scheduler_wait(int *fcalls, ErtsSchedulerData *esdp, ErtsRunQueue *rq)
(ERTS_SSI_FLG_SUSPENDED
| ERTS_SSI_FLG_MSB_EXEC));
- if (ERTS_SCHEDULER_IS_DIRTY(esdp))
+ if (ERTS_SCHEDULER_IS_DIRTY(esdp)) {
dirty_sched_wall_time_change(esdp, working = 1);
+ erts_spin_lock(&rq->sleepers.lock);
+ ERTS_HDBG_CHK_SLEEP_LIST(&rq->sleepers, 0, ssi->next ? ssi : NULL, NULL);
+ if (ssi->next) { /* Still in list... */
+ if (ssi->next == ssi) {
+ ASSERT(rq->sleepers.list == ssi);
+ ASSERT(ssi->prev == ssi);
+ rq->sleepers.list = NULL;
+ }
+ else {
+ ASSERT(ssi->prev != ssi);
+ if (rq->sleepers.list == ssi)
+ rq->sleepers.list = ssi->next;
+ ssi->prev->next = ssi->next;
+ ssi->next->prev = ssi->prev;
+ }
+ ssi->next = ssi->prev = NULL;
+ }
+ ERTS_HDBG_CHK_SLEEP_LIST(&rq->sleepers, 0, NULL, ssi);
+ erts_spin_unlock(&rq->sleepers.lock);
+ }
else if (!thr_prgr_active) {
erts_thr_progress_active(erts_thr_prgr_data(esdp), thr_prgr_active = 1);
sched_wall_time_change(esdp, 1);
@@ -3559,56 +3621,44 @@ wake_scheduler(ErtsRunQueue *rq)
}
static void
-wake_dirty_schedulers(ErtsRunQueue *rq, int one)
+wake_dirty_scheduler(ErtsRunQueue *rq)
{
- ErtsSchedulerSleepInfo *ssi;
+ ErtsSchedulerSleepInfo *lo_ssi, *fo_ssi;
ErtsSchedulerSleepList *sl;
ASSERT(ERTS_RUNQ_IX_IS_DIRTY(rq->ix));
sl = &rq->sleepers;
erts_spin_lock(&sl->lock);
- ssi = sl->list;
- if (!ssi) {
+ ERTS_HDBG_CHK_SLEEP_LIST(&rq->sleepers, 0, NULL, NULL);
+ lo_ssi = sl->list;
+ if (!lo_ssi) {
erts_spin_unlock(&sl->lock);
- if (one)
- wake_scheduler(rq);
- } else if (one) {
+ wake_scheduler(rq);
+ }
+ else {
erts_aint32_t flgs;
- if (ssi->prev)
- ssi->prev->next = ssi->next;
- else {
- ASSERT(sl->list == ssi);
- sl->list = ssi->next;
+ fo_ssi = lo_ssi->next;
+ ASSERT(fo_ssi->prev == lo_ssi);
+ if (fo_ssi == lo_ssi) {
+ ASSERT(lo_ssi->prev == lo_ssi);
+ sl->list = NULL;
+ }
+ else {
+ ASSERT(lo_ssi->prev != lo_ssi);
+ lo_ssi->next = fo_ssi->next;
+ fo_ssi->next->prev = fo_ssi->prev;
}
- if (ssi->next)
- ssi->next->prev = ssi->prev;
-
- erts_spin_unlock(&sl->lock);
-
- ERTS_THR_MEMORY_BARRIER;
- flgs = ssi_flags_set_wake(ssi);
- erts_sched_finish_poke(ssi, flgs);
- } else {
- sl->list = NULL;
+ fo_ssi->next = fo_ssi->prev = NULL;
+ ERTS_HDBG_CHK_SLEEP_LIST(&rq->sleepers, 0, NULL, fo_ssi);
erts_spin_unlock(&sl->lock);
ERTS_THR_MEMORY_BARRIER;
- do {
- ErtsSchedulerSleepInfo *wake_ssi = ssi;
- ssi = ssi->next;
- erts_sched_finish_poke(wake_ssi, ssi_flags_set_wake(wake_ssi));
- } while (ssi);
+ flgs = ssi_flags_set_wake(fo_ssi);
+ erts_sched_finish_poke(fo_ssi, flgs);
}
}
-static void
-wake_dirty_scheduler(ErtsRunQueue *rq)
-{
- wake_dirty_schedulers(rq, 1);
-}
-
-
#define ERTS_NO_USED_RUNQS_SHIFT 16
#define ERTS_NO_RUNQS_MASK 0xffffU
@@ -5988,6 +6038,8 @@ erts_init_scheduling(int no_schedulers, int no_schedulers_online, int no_poll_th
for (ix = 0; ix < no_dirty_cpu_schedulers; ix++) {
ErtsSchedulerSleepInfo *ssi = &aligned_dirty_cpu_sched_sleep_info[ix].ssi;
erts_atomic32_init_nob(&ssi->flags, 0);
+ ssi->next = NULL;
+ ssi->prev = NULL;
ssi->event = NULL; /* initialized in sched_dirty_cpu_thread_func */
erts_atomic32_init_nob(&ssi->aux_work, 0);
}
@@ -5998,6 +6050,8 @@ erts_init_scheduling(int no_schedulers, int no_schedulers_online, int no_poll_th
for (ix = 0; ix < no_dirty_io_schedulers; ix++) {
ErtsSchedulerSleepInfo *ssi = &aligned_dirty_io_sched_sleep_info[ix].ssi;
erts_atomic32_init_nob(&ssi->flags, 0);
+ ssi->next = NULL;
+ ssi->prev = NULL;
ssi->event = NULL; /* initialized in sched_dirty_io_thread_func */
erts_atomic32_init_nob(&ssi->aux_work, 0);
}
@@ -7517,7 +7571,13 @@ suspend_scheduler(ErtsSchedulerData *esdp)
return;
}
+#ifdef HARDDEBUG
+ if (sched_type != ERTS_SCHED_NORMAL)
+ ERTS_HDBG_CHK_SLEEP_LIST(&esdp->run_queue->sleepers, !0, NULL, ssi);
+#endif
+
if (erts_atomic32_read_nob(&ssi->flags) & ERTS_SSI_FLG_MSB_EXEC) {
+
ASSERT(no == 1);
if (!msb_scheduler_type_switch(sched_type, esdp, no))
return;
diff --git a/erts/emulator/beam/erl_process.h b/erts/emulator/beam/erl_process.h
index a1b029adbe..0aa19e7bde 100644
--- a/erts/emulator/beam/erl_process.h
+++ b/erts/emulator/beam/erl_process.h
@@ -359,7 +359,7 @@ typedef struct ErtsSchedulerSleepInfo_ ErtsSchedulerSleepInfo;
typedef struct {
erts_spinlock_t lock;
- ErtsSchedulerSleepInfo *list;
+ ErtsSchedulerSleepInfo *list; /* circular lifo list; points to last out */
} ErtsSchedulerSleepList;
struct ErtsSchedulerSleepInfo_ {
diff --git a/erts/emulator/beam/erl_trace.c b/erts/emulator/beam/erl_trace.c
index 2350d4c02f..701fb38147 100644
--- a/erts/emulator/beam/erl_trace.c
+++ b/erts/emulator/beam/erl_trace.c
@@ -72,6 +72,7 @@ static ErtsTracer default_port_tracer;
static Eterm system_monitor;
static Eterm system_profile;
+static erts_aint_t system_logger;
#ifdef HAVE_ERTS_NOW_CPU
int erts_cpu_timestamp;
@@ -340,6 +341,7 @@ void erts_init_trace(void) {
default_port_trace_flags = F_INITIAL_TRACE_FLAGS;
default_port_tracer = erts_tracer_nil;
system_seq_tracer = erts_tracer_nil;
+ erts_atomic_init_nob(&system_logger, am_logger);
init_sys_msg_dispatcher();
init_tracer_nif();
}
@@ -2027,10 +2029,24 @@ enqueue_sys_msg(enum ErtsSysMsgType type,
erts_mtx_unlock(&smq_mtx);
}
+Eterm
+erts_get_system_logger(void)
+{
+ return (Eterm)erts_atomic_read_nob(&system_logger);
+}
+
+Eterm
+erts_set_system_logger(Eterm logger)
+{
+ if (logger != am_logger && logger != am_undefined && !is_internal_pid(logger))
+ return THE_NON_VALUE;
+ return (Eterm)erts_atomic_xchg_nob(&system_logger, logger);
+}
+
void
erts_queue_error_logger_message(Eterm from, Eterm msg, ErlHeapFragment *bp)
{
- enqueue_sys_msg(SYS_MSG_TYPE_ERRLGR, from, am_logger, msg, bp);
+ enqueue_sys_msg(SYS_MSG_TYPE_ERRLGR, from, erts_get_system_logger(), msg, bp);
}
void
@@ -2271,7 +2287,7 @@ sys_msg_dispatcher_func(void *unused)
}
break;
case SYS_MSG_TYPE_ERRLGR:
- receiver = am_logger;
+ receiver = smqp->to;
break;
default:
receiver = NIL;
@@ -2285,8 +2301,15 @@ sys_msg_dispatcher_func(void *unused)
if (is_internal_pid(receiver)) {
proc = erts_pid2proc(NULL, 0, receiver, proc_locks);
if (!proc) {
- /* Bad tracer */
- goto failure;
+ if (smqp->type == SYS_MSG_TYPE_ERRLGR) {
+ /* Bad logger process, send to kernel 'logger' process */
+ erts_set_system_logger(am_logger);
+ receiver = erts_get_system_logger();
+ goto logger;
+ } else {
+ /* Bad tracer */
+ goto failure;
+ }
}
else {
ErtsMessage *mp;
@@ -2299,9 +2322,9 @@ sys_msg_dispatcher_func(void *unused)
#endif
erts_proc_unlock(proc, proc_locks);
}
- }
- else if (receiver == am_logger) {
- proc = erts_whereis_process(NULL,0,receiver,proc_locks,0);
+ } else if (receiver == am_logger) {
+ logger:
+ proc = erts_whereis_process(NULL,0,am_logger,proc_locks,0);
if (!proc)
goto failure;
else if (smqp->from == proc->common.id)
@@ -2309,7 +2332,10 @@ sys_msg_dispatcher_func(void *unused)
else
goto queue_proc_msg;
}
- else if (is_internal_port(receiver)) {
+ else if (receiver == am_undefined) {
+ goto drop_sys_msg;
+ }
+ else if (is_internal_port(receiver)) {
port = erts_thr_id2port_sflgs(receiver,
ERTS_PORT_SFLGS_INVALID_TRACER_LOOKUP);
if (!port)
@@ -2366,7 +2392,7 @@ erts_foreach_sys_msg_in_q(void (*func)(Eterm,
to = erts_get_system_profile();
break;
case SYS_MSG_TYPE_ERRLGR:
- to = am_logger;
+ to = erts_get_system_logger();
break;
default:
to = NIL;
diff --git a/erts/emulator/beam/erl_trace.h b/erts/emulator/beam/erl_trace.h
index bccf31606e..b7844d1cb0 100644
--- a/erts/emulator/beam/erl_trace.h
+++ b/erts/emulator/beam/erl_trace.h
@@ -94,6 +94,8 @@ void erts_foreach_sys_msg_in_q(void (*func)(Eterm,
Eterm,
Eterm,
ErlHeapFragment *));
+Eterm erts_set_system_logger(Eterm);
+Eterm erts_get_system_logger(void);
void erts_queue_error_logger_message(Eterm, Eterm, ErlHeapFragment *);
void erts_send_sys_msg_proc(Eterm, Eterm, Eterm, ErlHeapFragment *);
diff --git a/erts/emulator/beam/global.h b/erts/emulator/beam/global.h
index 0631404599..36b753ca9c 100644
--- a/erts/emulator/beam/global.h
+++ b/erts/emulator/beam/global.h
@@ -962,7 +962,7 @@ void init_break_handler(void);
void erts_set_ignore_break(void);
void erts_replace_intr(void);
void process_info(fmtfn_t, void *);
-void print_process_info(fmtfn_t, void *, Process*);
+void print_process_info(fmtfn_t, void *, Process*, ErtsProcLocks);
void info(fmtfn_t, void *);
void loaded(fmtfn_t, void *);
void erts_print_base64(fmtfn_t to, void *to_arg, byte* src, Uint size);
@@ -1303,14 +1303,7 @@ Sint intlist_to_buf(Eterm, char*, Sint); /* most callers pass plain char*'s */
int erts_unicode_list_to_buf(Eterm list, byte *buf, Sint len, Sint* written);
Sint erts_unicode_list_to_buf_len(Eterm list);
-struct Sint_buf {
-#if defined(ARCH_64)
- char s[22];
-#else
- char s[12];
-#endif
-};
-char* Sint_to_buf(Sint, struct Sint_buf*);
+int Sint_to_buf(Sint num, int base, char **buf_p, size_t buf_size);
#define ERTS_IOLIST_STATE_INITER(C_P, OBJ) \
{(C_P), 0, 0, (OBJ), {NULL, NULL, NULL, ERTS_ALC_T_INVALID}, 0, 0}
diff --git a/erts/emulator/beam/utils.c b/erts/emulator/beam/utils.c
index d81bd89a48..a231638b50 100644
--- a/erts/emulator/beam/utils.c
+++ b/erts/emulator/beam/utils.c
@@ -3681,30 +3681,47 @@ erts_unicode_list_to_buf_len(Eterm list)
}
}
-/*
-** Convert an integer to a byte list
-** return pointer to converted stuff (need not to be at start of buf!)
-*/
-char* Sint_to_buf(Sint n, struct Sint_buf *buf)
+/* Prints an integer in the given base, returning the number of digits printed.
+ *
+ * (*buf) is a pointer to the buffer, and is set to the start of the string
+ * when returning. */
+int Sint_to_buf(Sint n, int base, char **buf, size_t buf_size)
{
- char* p = &buf->s[sizeof(buf->s)-1];
- int sign = 0;
-
- *p-- = '\0'; /* null terminate */
- if (n == 0)
- *p-- = '0';
- else if (n < 0) {
- sign = 1;
- n = -n;
+ char *p = &(*buf)[buf_size - 1];
+ int sign = 0, size = 0;
+
+ ASSERT(base >= 2 && base <= 36);
+
+ if (n == 0) {
+ *p-- = '0';
+ size++;
+ } else if (n < 0) {
+ sign = 1;
+ n = -n;
}
while (n != 0) {
- *p-- = (n % 10) + '0';
- n /= 10;
+ int digit = n % base;
+
+ if (digit < 10) {
+ *p-- = '0' + digit;
+ } else {
+ *p-- = 'A' + (digit - 10);
+ }
+
+ size++;
+
+ n /= base;
}
- if (sign)
- *p-- = '-';
- return p+1;
+
+ if (sign) {
+ *p-- = '-';
+ size++;
+ }
+
+ *buf = p + 1;
+
+ return size;
}
/* Build a list of integers in some safe memory area
@@ -4771,58 +4788,3 @@ erts_ptr_id(void *ptr)
return ptr;
}
-#ifdef DEBUG
-/*
- * Handy functions when using a debugger - don't use in the code!
- */
-
-void upp(byte *buf, size_t sz)
-{
- bin_write(ERTS_PRINT_STDERR, NULL, buf, sz);
-}
-
-void pat(Eterm atom)
-{
- upp(atom_tab(atom_val(atom))->name,
- atom_tab(atom_val(atom))->len);
-}
-
-
-void pinfo()
-{
- process_info(ERTS_PRINT_STDOUT, NULL);
-}
-
-
-void pp(p)
-Process *p;
-{
- if(p)
- print_process_info(ERTS_PRINT_STDERR, NULL, p);
-}
-
-void ppi(Eterm pid)
-{
- pp(erts_proc_lookup(pid));
-}
-
-void td(Eterm x)
-{
- erts_fprintf(stderr, "%T\n", x);
-}
-
-void
-ps(Process* p, Eterm* stop)
-{
- Eterm* sp = STACK_START(p) - 1;
-
- if (stop <= STACK_END(p)) {
- stop = STACK_END(p) + 1;
- }
-
- while(sp >= stop) {
- erts_printf("%p: %.75T\n", sp, *sp);
- sp--;
- }
-}
-#endif
diff --git a/erts/emulator/drivers/common/inet_drv.c b/erts/emulator/drivers/common/inet_drv.c
index 31c9ce2d0b..ed687b8d70 100644
--- a/erts/emulator/drivers/common/inet_drv.c
+++ b/erts/emulator/drivers/common/inet_drv.c
@@ -634,9 +634,13 @@ static size_t my_strnlen(const char *s, size_t maxlen)
* header length. To get the header length we use
* the pointer difference from the cmsg start pointer
* to the CMSG_DATA(cmsg) pointer.
+ *
+ * Some platforms (seen on ppc Linux 2.6.29-3.ydl61.3)
+ * may return 0 as the cmsg_len if the cmsg is to be ignored.
*/
#define LEN_CMSG_DATA(cmsg) \
- ((cmsg)->cmsg_len - ((char*)CMSG_DATA(cmsg) - (char*)(cmsg)))
+ ((cmsg)->cmsg_len < sizeof (struct cmsghdr) ? 0 : \
+ (cmsg)->cmsg_len - ((char*)CMSG_DATA(cmsg) - (char*)(cmsg)))
#define NXT_CMSG_HDR(cmsg) \
((struct cmsghdr*)(((char*)(cmsg)) + CMSG_SPACE(LEN_CMSG_DATA(cmsg))))
#endif
diff --git a/erts/emulator/nifs/common/prim_file_nif.c b/erts/emulator/nifs/common/prim_file_nif.c
index 5fff55b467..a78ee62677 100644
--- a/erts/emulator/nifs/common/prim_file_nif.c
+++ b/erts/emulator/nifs/common/prim_file_nif.c
@@ -38,7 +38,6 @@ static void unload(ErlNifEnv *env, void* priv_data);
static ErlNifResourceType *efile_resource_type;
-static ERL_NIF_TERM am_erts_prim_file;
static ERL_NIF_TERM am_close;
static ERL_NIF_TERM am_ok;
@@ -220,7 +219,6 @@ static int load(ErlNifEnv *env, void** priv_data, ERL_NIF_TERM prim_file_pid)
ASSERT(!"bad pid passed to prim_file_nif");
}
- am_erts_prim_file = enif_make_atom(env, "erts_prim_file");
am_close = enif_make_atom(env, "close");
am_ok = enif_make_atom(env, "ok");
diff --git a/erts/emulator/test/big_SUITE.erl b/erts/emulator/test/big_SUITE.erl
index 29508ffc7c..3b9b9e5989 100644
--- a/erts/emulator/test/big_SUITE.erl
+++ b/erts/emulator/test/big_SUITE.erl
@@ -168,7 +168,11 @@ eval({op,_,Op,A0,B0}, LFH) ->
Res = eval_op(Op, A, B),
erlang:garbage_collect(),
Res;
-eval({integer,_,I}, _) -> I;
+eval({integer,_,I}, _) ->
+ %% "Parasitic" ("symbiotic"?) test of squaring all numbers
+ %% found in the test data.
+ test_squaring(I),
+ I;
eval({call,_,{atom,_,Local},Args0}, LFH) ->
Args = eval_list(Args0, LFH),
LFH(Local, Args).
@@ -192,6 +196,18 @@ eval_op('bxor', A, B) -> A bxor B;
eval_op('bsl', A, B) -> A bsl B;
eval_op('bsr', A, B) -> A bsr B.
+test_squaring(I) ->
+ %% Multiplying an integer by itself is specially optimized, so we
+ %% should take special care to test squaring. The optimization
+ %% will kick in when the two operands have the same address.
+ Sqr = I * I,
+
+ %% This expression will be multiplied in the usual way, because
+ %% the the two operands for '*' are stored at different addresses.
+ Sqr = I * ((I + id(1)) - id(1)),
+
+ ok.
+
%% Built in test functions
fac(0) -> 1;
diff --git a/erts/emulator/test/num_bif_SUITE.erl b/erts/emulator/test/num_bif_SUITE.erl
index f15217814a..6b834705cf 100644
--- a/erts/emulator/test/num_bif_SUITE.erl
+++ b/erts/emulator/test/num_bif_SUITE.erl
@@ -504,6 +504,10 @@ t_integer_to_string(Config) when is_list(Config) ->
test_its("A", 10, 16),
test_its("D4BE", 54462, 16),
test_its("-D4BE", -54462, 16),
+ test_its("FFFFFFFFFF", 1099511627775, 16),
+ test_its("123456789ABCDEF123456789ABCDEF123456789ABCDEF",
+ 108977460683796539709587792812439445667270661579197935,
+ 16),
lists:foreach(fun(Value) ->
{'EXIT', {badarg, _}} =
@@ -515,12 +519,14 @@ t_integer_to_string(Config) when is_list(Config) ->
ok.
test_its(List,Int) ->
- Int = list_to_integer(List),
- Int = binary_to_integer(list_to_binary(List)).
+ List = integer_to_list(Int),
+ Binary = list_to_binary(List),
+ Binary = integer_to_binary(Int).
test_its(List,Int,Base) ->
- Int = list_to_integer(List, Base),
- Int = binary_to_integer(list_to_binary(List), Base).
+ List = integer_to_list(Int, Base),
+ Binary = list_to_binary(List),
+ Binary = integer_to_binary(Int, Base).
%% Tests binary_to_integer/1.
diff --git a/erts/emulator/test/persistent_term_SUITE.erl b/erts/emulator/test/persistent_term_SUITE.erl
index 58cd3276b0..58038e24b7 100644
--- a/erts/emulator/test/persistent_term_SUITE.erl
+++ b/erts/emulator/test/persistent_term_SUITE.erl
@@ -21,7 +21,7 @@
-module(persistent_term_SUITE).
-include_lib("common_test/include/ct.hrl").
--export([all/0,suite/0,
+-export([all/0,suite/0,init_per_suite/1,end_per_suite/1,
basic/1,purging/1,sharing/1,get_trapping/1,
info/1,info_trapping/1,killed_while_trapping/1,
off_heap_values/1,keys/1,collisions/1,
@@ -39,39 +39,49 @@ all() ->
killed_while_trapping,off_heap_values,keys,collisions,
init_restart].
+init_per_suite(Config) ->
+ %% Put a term in the dict so that we know that the testcases handle
+ %% stray terms left by stdlib or other test suites.
+ persistent_term:put(init_per_suite, {?MODULE}),
+ Config.
+
+end_per_suite(Config) ->
+ persistent_term:erase(init_per_suite),
+ Config.
+
basic(_Config) ->
Chk = chk(),
N = 777,
Seq = lists:seq(1, N),
- par(2, N, Seq),
- seq(3, Seq),
- seq(3, Seq), %Same values.
+ par(2, N, Seq, Chk),
+ seq(3, Seq, Chk),
+ seq(3, Seq, Chk), %Same values.
_ = [begin
Key = {?MODULE,{key,I}},
true = persistent_term:erase(Key),
false = persistent_term:erase(Key),
{'EXIT',{badarg,_}} = (catch persistent_term:get(Key))
end || I <- Seq],
- [] = [P || {{?MODULE,_},_}=P <- persistent_term:get()],
+ [] = [P || {{?MODULE,_},_}=P <- pget(Chk)],
chk(Chk).
-par(C, N, Seq) ->
+par(C, N, Seq, Chk) ->
_ = [spawn_link(fun() ->
ok = persistent_term:put({?MODULE,{key,I}},
{value,C*I})
end) || I <- Seq],
- Result = wait(N),
+ Result = wait(N, Chk),
_ = [begin
Double = C*I,
{{?MODULE,{key,I}},{value,Double}} = Res
end || {I,Res} <- lists:zip(Seq, Result)],
ok.
-seq(C, Seq) ->
+seq(C, Seq, Chk) ->
_ = [ok = persistent_term:put({?MODULE,{key,I}}, {value,C*I}) ||
I <- Seq],
- All = persistent_term:get(),
- All = [P || {{?MODULE,_},_}=P <- persistent_term:get()],
+ All = pget(Chk),
+ All = [P || {{?MODULE,_},_}=P <- All],
All = [{Key,persistent_term:get(Key)} || {Key,_} <- All],
Result = lists:sort(All),
_ = [begin
@@ -80,15 +90,15 @@ seq(C, Seq) ->
end || {I,Res} <- lists:zip(Seq, Result)],
ok.
-wait(N) ->
- All = [P || {{?MODULE,_},_}=P <- persistent_term:get()],
+wait(N, Chk) ->
+ All = [P || {{?MODULE,_},_}=P <- pget(Chk)],
case length(All) of
N ->
All = [{Key,persistent_term:get(Key)} || {Key,_} <- All],
lists:sort(All);
_ ->
receive after 10 -> ok end,
- wait(N)
+ wait(N, Chk)
end.
%% Make sure that terms that have been erased are copied into all
@@ -200,23 +210,23 @@ get_trapping(_Config) ->
_ -> 1000
end,
spawn_link(fun() -> get_trapping_create(N) end),
- All = do_get_trapping(N, []),
+ All = do_get_trapping(N, [], Chk),
N = get_trapping_check_result(lists:sort(All), 1),
erlang:garbage_collect(),
get_trapping_erase(N),
chk(Chk).
-do_get_trapping(N, Prev) ->
- case persistent_term:get() of
+do_get_trapping(N, Prev, Chk) ->
+ case pget(Chk) of
Prev when length(Prev) >= N ->
All = [P || {{?MODULE,{get_trapping,_}},_}=P <- Prev],
case length(All) of
N -> All;
- _ -> do_get_trapping(N, Prev)
+ _ -> do_get_trapping(N, Prev, Chk)
end;
New ->
receive after 1 -> ok end,
- do_get_trapping(N, New)
+ do_get_trapping(N, New, Chk)
end.
get_trapping_create(0) ->
@@ -331,25 +341,25 @@ info_trapping(_Config) ->
_ -> 1000
end,
spawn_link(fun() -> info_trapping_create(N) end),
- All = do_info_trapping(N, 0),
+ All = do_info_trapping(N, 0, Chk),
N = info_trapping_check_result(lists:sort(All), 1),
erlang:garbage_collect(),
info_trapping_erase(N),
chk(Chk).
-do_info_trapping(N, PrevMem) ->
+do_info_trapping(N, PrevMem, Chk) ->
case info_info() of
- {N,Mem} ->
+ {M,Mem} when M >= N ->
true = Mem >= PrevMem,
- All = [P || {{?MODULE,{info_trapping,_}},_}=P <- persistent_term:get()],
+ All = [P || {{?MODULE,{info_trapping,_}},_}=P <- pget(Chk)],
case length(All) of
N -> All;
- _ -> do_info_trapping(N, PrevMem)
+ _ -> do_info_trapping(N, PrevMem, Chk)
end;
{_,Mem} ->
true = Mem >= PrevMem,
receive after 1 -> ok end,
- do_info_trapping(N, Mem)
+ do_info_trapping(N, Mem, Chk)
end.
info_trapping_create(0) ->
@@ -462,17 +472,17 @@ collisions(_Config) ->
_ = [V = persistent_term:get(K) || {K,V} <- Kvs],
%% Now delete the persistent terms in random order.
- collisions_delete(lists:keysort(2, Kvs)),
+ collisions_delete(lists:keysort(2, Kvs), Chk),
chk(Chk).
-collisions_delete([{Key,Val}|Kvs]) ->
+collisions_delete([{Key,Val}|Kvs], Chk) ->
Val = persistent_term:get(Key),
true = persistent_term:erase(Key),
- true = lists:sort(persistent_term:get()) =:= lists:sort(Kvs),
+ true = lists:sort(pget(Chk)) =:= lists:sort(Kvs),
_ = [V = persistent_term:get(K) || {K,V} <- Kvs],
- collisions_delete(Kvs);
-collisions_delete([]) ->
+ collisions_delete(Kvs, Chk);
+collisions_delete([], _) ->
ok.
colliding_keys() ->
@@ -589,15 +599,16 @@ do_test_init_restart_cmd(File) ->
%% and after each test case.
chk() ->
- persistent_term:info().
+ {persistent_term:info(), persistent_term:get()}.
-chk(Chk) ->
- Chk = persistent_term:info(),
+chk({Info, _Initial} = Chk) ->
+ Info = persistent_term:info(),
Key = {?MODULE,?FUNCTION_NAME},
- ok = persistent_term:put(Key, {term,Chk}),
+ ok = persistent_term:put(Key, {term,Info}),
Term = persistent_term:get(Key),
true = persistent_term:erase(Key),
chk_not_stuck(Term),
+ [persistent_term:erase(K) || {K, _} <- pget(Chk)],
ok.
chk_not_stuck(Term) ->
@@ -612,3 +623,6 @@ chk_not_stuck(Term) ->
_ ->
ok
end.
+
+pget({_, Initial}) ->
+ persistent_term:get() -- Initial.
diff --git a/erts/emulator/test/process_SUITE.erl b/erts/emulator/test/process_SUITE.erl
index 57eb082d64..b23f77a0b2 100644
--- a/erts/emulator/test/process_SUITE.erl
+++ b/erts/emulator/test/process_SUITE.erl
@@ -2104,6 +2104,13 @@ spawn_opt_max_heap_size(_Config) ->
error_logger:add_report_handler(?MODULE, self()),
+ %% flush any prior messages in error_logger
+ Pid = spawn(fun() -> ok = nok end),
+ receive
+ {error, _, {emulator, _, [Pid|_]}} ->
+ flush()
+ end,
+
%% Test that numerical limit works
max_heap_size_test(1024, 1024, true, true),
@@ -2208,6 +2215,13 @@ receive_unexpected() ->
ok
end.
+flush() ->
+ receive
+ _M -> flush()
+ after 0 ->
+ ok
+ end.
+
%% error_logger report handler proxy
init(Pid) ->
{ok, Pid}.
diff --git a/erts/emulator/test/system_info_SUITE.erl b/erts/emulator/test/system_info_SUITE.erl
index 21ab6b378a..4e663fed7f 100644
--- a/erts/emulator/test/system_info_SUITE.erl
+++ b/erts/emulator/test/system_info_SUITE.erl
@@ -37,8 +37,9 @@
-export([process_count/1, system_version/1, misc_smoke_tests/1,
heap_size/1, wordsize/1, memory/1, ets_limit/1, atom_limit/1,
- ets_count/1,
- atom_count/1]).
+ ets_count/1, atom_count/1, system_logger/1]).
+
+-export([init/1, handle_event/2, handle_call/2]).
suite() ->
[{ct_hooks,[ts_install_cth]},
@@ -46,8 +47,8 @@ suite() ->
all() ->
[process_count, system_version, misc_smoke_tests,
- ets_count,
- heap_size, wordsize, memory, ets_limit, atom_limit, atom_count].
+ ets_count, heap_size, wordsize, memory, ets_limit, atom_limit, atom_count,
+ system_logger].
%%%
%%% The test cases -------------------------------------------------------------
@@ -573,3 +574,78 @@ atom_count(Config) when is_list(Config) ->
true = Limit >= Count2,
true = Count2 > Count1,
ok.
+
+
+system_logger(Config) when is_list(Config) ->
+
+ TC = self(),
+
+ ok = error_logger:add_report_handler(?MODULE, [TC]),
+
+ generate_log_event(),
+
+ flush(1, report_handler),
+
+ Initial = erlang:system_info(system_logger),
+
+ {Logger,_} = spawn_monitor(fun F() -> receive M -> TC ! {system_logger,M}, F() end end),
+
+ Initial = erlang:system_flag(system_logger, Logger),
+ Logger = erlang:system_info(system_logger),
+
+ generate_log_event(),
+ flush(1, system_logger),
+
+ Logger = erlang:system_flag(system_logger, Logger),
+
+ generate_log_event(),
+ flush(1, system_logger),
+
+ exit(Logger, die),
+ receive {'DOWN',_,_,_,_} -> ok end,
+
+ generate_log_event(),
+ flush(1, report_handler),
+
+ logger = erlang:system_info(system_logger),
+
+ logger = erlang:system_flag(system_logger, undefined),
+ generate_log_event(),
+ flush(),
+
+ undefined = erlang:system_flag(system_logger, Initial),
+
+ ok.
+
+flush() ->
+ receive
+ M ->
+ ct:fail({unexpected_message, M})
+ after 0 ->
+ ok
+ end.
+
+flush(0, _Pat) ->
+ flush();
+flush(Cnt, Pat) ->
+ receive
+ M when element(1,M) =:= Pat ->
+ ct:log("~p",[M]),
+ flush(Cnt-1, Pat)
+ after 500 ->
+ ct:fail({missing, Cnt, Pat})
+ end.
+
+generate_log_event() ->
+ {_Pid, Ref} = spawn_monitor(fun() -> ok = nok end),
+ receive {'DOWN', Ref, _, _, _} -> ok end.
+
+init([To]) ->
+ {ok, To}.
+
+handle_call(Msg, State) ->
+ {ok, Msg, State}.
+
+handle_event(Event, State) ->
+ State ! {report_handler, Event},
+ {ok, State}.