diff options
Diffstat (limited to 'erts')
46 files changed, 754 insertions, 371 deletions
diff --git a/erts/Makefile b/erts/Makefile index 60c70b6a2c..e62c896170 100644 --- a/erts/Makefile +++ b/erts/Makefile @@ -129,9 +129,13 @@ makefiles: .PHONY: release release: +ifeq ($(TYPE),) for t in $(TYPES); do \ ( cd emulator && $(MAKE) release TYPE=$$t ) || exit $$?; \ done +else + ( cd emulator && $(MAKE) release TYPE=$(TYPE) ) || exit $$?; +endif $(V_at)for d in $(ERTSDIRS) $(XINSTDIRS); do \ if test -d $$d; then \ ( cd $$d && $(MAKE) $@ ) || exit $$? ; \ diff --git a/erts/doc/src/tty.xml b/erts/doc/src/tty.xml index 51db1ba8e2..c33e082f4f 100644 --- a/erts/doc/src/tty.xml +++ b/erts/doc/src/tty.xml @@ -165,6 +165,10 @@ erl</pre> <cell align="left" valign="middle">C-y</cell> <cell align="left" valign="middle">Insert previously killed text</cell> </row> + <row> + <cell align="left" valign="middle">C-]</cell> + <cell align="left" valign="middle">Insert matching closing bracket</cell> + </row> <tcaption>tty Text Editing</tcaption> </table> </section> diff --git a/erts/emulator/beam/beam_emu.c b/erts/emulator/beam/beam_emu.c index d68d021679..ea01ce597d 100644 --- a/erts/emulator/beam/beam_emu.c +++ b/erts/emulator/beam/beam_emu.c @@ -1479,9 +1479,24 @@ next_catch(Process* c_p, Eterm *reg) { BeamInstr i_return_time_trace = beam_return_time_trace[0]; ptr = prev = c_p->stop; - ASSERT(is_CP(*ptr)); ASSERT(ptr <= STACK_START(c_p)); - if (ptr == STACK_START(c_p)) return NULL; + + /* This function is only called if we have active catch tags or have + * previously called a function that was exception-traced. As the exception + * trace flag isn't cleared after the traced function returns (and the + * catch tag inserted by it is gone), it's possible to land here with an + * empty stack, and the process should simply die when that happens. */ + if (ptr == STACK_START(c_p)) { + ASSERT(!active_catches && IS_TRACED_FL(c_p, F_EXCEPTION_TRACE)); + return NULL; + } + + /* + * Better safe than sorry here. In debug builds, produce a core + * dump if the top of the stack doesn't point to a continuation + * pointer. In other builds, ignore a non-CP at the top of stack. + */ + ASSERT(is_CP(*ptr)); if ((is_not_CP(*ptr) || (*cp_val(*ptr) != i_return_trace && *cp_val(*ptr) != i_return_to_trace && *cp_val(*ptr) != i_return_time_trace )) @@ -3252,20 +3267,23 @@ erts_is_builtin(Eterm Mod, Eterm Name, int arity) /* - * Return the current number of reductions for the given process. + * Return the current number of reductions consumed by the given process. * To get the total number of reductions, p->reds must be added. */ Uint -erts_current_reductions(Process *current, Process *p) +erts_current_reductions(Process *c_p, Process *p) { - if (current != p) { + Sint reds_left; + if (c_p != p || !(erts_atomic32_read_nob(&c_p->state) + & ERTS_PSFLG_RUNNING)) { return 0; - } else if (current->fcalls < 0 && ERTS_PROC_GET_SAVED_CALLS_BUF(current)) { - return current->fcalls + CONTEXT_REDS; + } else if (c_p->fcalls < 0 && ERTS_PROC_GET_SAVED_CALLS_BUF(c_p)) { + reds_left = c_p->fcalls + CONTEXT_REDS; } else { - return REDS_IN(current) - current->fcalls; + reds_left = c_p->fcalls; } + return REDS_IN(c_p) - reds_left; } int diff --git a/erts/emulator/beam/beam_load.c b/erts/emulator/beam/beam_load.c index 21740caa2c..941c3ebbbe 100644 --- a/erts/emulator/beam/beam_load.c +++ b/erts/emulator/beam/beam_load.c @@ -3145,6 +3145,13 @@ is_killed(LoaderState* stp, GenOpArg Reg, GenOpArg Live) Live.val <= Reg.val; } +static int +is_killed_by_call_fun(LoaderState* stp, GenOpArg Reg, GenOpArg Live) +{ + return Reg.type == TAG_x && Live.type == TAG_u && + Live.val+1 <= Reg.val; +} + /* * Test whether register Reg is killed by make_fun instruction that * creates the fun given by index idx. @@ -3347,19 +3354,12 @@ gen_get_binary2(LoaderState* stp, GenOpArg Fail, GenOpArg Ms, GenOpArg Live, NATIVE_ENDIAN(Flags); if (Size.type == TAG_a && Size.val == am_all) { - if (Ms.type == Dst.type && Ms.val == Dst.val) { - GENOP_NAME_ARITY(op, i_bs_get_binary_all_reuse, 3); - op->a[0] = Ms; - op->a[1] = Fail; - op->a[2] = Unit; - } else { - GENOP_NAME_ARITY(op, i_bs_get_binary_all2, 5); - op->a[0] = Ms; - op->a[1] = Fail; - op->a[2] = Live; - op->a[3] = Unit; - op->a[4] = Dst; - } + GENOP_NAME_ARITY(op, i_bs_get_binary_all2, 5); + op->a[0] = Ms; + op->a[1] = Fail; + op->a[2] = Live; + op->a[3] = Unit; + op->a[4] = Dst; } else if (Size.type == TAG_i) { GENOP_NAME_ARITY(op, i_bs_get_binary_imm2, 6); op->a[0] = Ms; diff --git a/erts/emulator/beam/bif.c b/erts/emulator/beam/bif.c index c102ddbee6..d0e2d9afc2 100644 --- a/erts/emulator/beam/bif.c +++ b/erts/emulator/beam/bif.c @@ -1915,7 +1915,7 @@ do_send(Process *p, Eterm to, Eterm msg, Eterm return_term, Eterm *refp, erts_dsprintf_buf_t *dsbufp = erts_create_logger_dsbuf(); erts_dsprintf(dsbufp, "Discarding message %T from %T to %T in an old " - "incarnation (%d) of this node (%d)\n", + "incarnation (%u) of this node (%u)\n", msg, p->common.id, to, @@ -1959,7 +1959,7 @@ do_send(Process *p, Eterm to, Eterm msg, Eterm return_term, Eterm *refp, erts_dsprintf_buf_t *dsbufp = erts_create_logger_dsbuf(); erts_dsprintf(dsbufp, "Discarding message %T from %T to %T in an old " - "incarnation (%d) of this node (%d)\n", + "incarnation (%u) of this node (%u)\n", msg, p->common.id, to, @@ -2463,6 +2463,7 @@ BIF_RETTYPE iolist_size_1(BIF_ALIST_1) ErtsIOListSizeContext* context = NULL; Eterm state_mref; int is_trap_at_L_iter_list; + ERTS_UNDEF(state_mref, THE_NON_VALUE); ESTACK_CHANGE_ALLOCATOR(s, ERTS_ALC_T_SAVED_ESTACK); #ifdef DEBUG iterations_until_trap = iterations_until_trap / 10; @@ -4313,7 +4314,7 @@ BIF_RETTYPE list_to_ref_1(BIF_ALIST_1) if(dep == erts_this_dist_entry) { ErtsMagicBinary *mb; Uint32 sid; - if (refn[0] > MAX_REFERENCE) goto bad; + if (refn[0] >= MAX_REFERENCE) goto bad; if (n != ERTS_REF_NUMBERS) goto bad; sid = erts_get_ref_numbers_thr_id(refn); if (sid > erts_no_schedulers) goto bad; diff --git a/erts/emulator/beam/big.c b/erts/emulator/beam/big.c index 522f50287a..7666f23a4f 100644 --- a/erts/emulator/beam/big.c +++ b/erts/emulator/beam/big.c @@ -2176,6 +2176,24 @@ term_to_Uint64(Eterm term, Uint64 *up) #endif } +int +term_to_Uint32(Eterm term, Uint32 *up) +{ +#if ERTS_SIZEOF_ETERM == 4 + return term_to_Uint(term,up); +#else + if (is_small(term)) { + Sint i = signed_val(term); + if (i >= 0) { + *up = (Uint32) i; + return 1; + } + } + *up = BADARG; + return 0; +#endif +} + int term_to_Sint(Eterm term, Sint *sp) { diff --git a/erts/emulator/beam/big.h b/erts/emulator/beam/big.h index ad19cce395..3fed076419 100644 --- a/erts/emulator/beam/big.h +++ b/erts/emulator/beam/big.h @@ -168,6 +168,8 @@ Eterm erts_uint64_array_to_big(Uint **, int, int, Uint64 *); int term_to_Uint64(Eterm, Uint64*); int term_to_Sint64(Eterm, Sint64*); #endif +int term_to_Uint32(Eterm, Uint32*); + Uint32 big_to_uint32(Eterm b); int term_equals_2pow32(Eterm); diff --git a/erts/emulator/beam/break.c b/erts/emulator/beam/break.c index 27bf2187c2..06d8c7cda8 100644 --- a/erts/emulator/beam/break.c +++ b/erts/emulator/beam/break.c @@ -39,6 +39,7 @@ #include "erl_hl_timer.h" #include "erl_thr_progress.h" #include "erl_proc_sig_queue.h" +#include "dist.h" /* Forward declarations -- should really appear somewhere else */ static void process_killer(void); @@ -74,6 +75,7 @@ port_info(fmtfn_t to, void *to_arg) void process_info(fmtfn_t to, void *to_arg) { + ErtsSchedulerData *esdp = erts_get_scheduler_data(); int i, max = erts_ptab_max(&erts_proc); for (i = 0; i < max; i++) { Process *p = erts_pix2proc(i); @@ -81,11 +83,35 @@ process_info(fmtfn_t to, void *to_arg) /* Do not include processes with no heap, * 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, 0); + if (p->heap != NULL) { + ErtsProcLocks locks = (p == esdp->current_process || + p == esdp->free_process) ? ERTS_PROC_LOCK_MAIN : 0; + print_process_info(to, to_arg, p, locks); + } } } + /* Look for FREE processes in the run-queues and dist entries. + These have been removed from the ptab but we still want them + in the crash dump for debugging. */ + + /* First loop through all run-queues */ + for (i = 0; i < erts_no_schedulers + ERTS_NUM_DIRTY_RUNQS; i++) { + ErtsRunQueue *rq = ERTS_RUNQ_IX(i); + int j; + for (j = 0; j < ERTS_NO_PROC_PRIO_QUEUES; j++) { + Process *p = rq->procs.prio[j].first; + while (p) { + if (ERTS_PSFLG_FREE & erts_atomic32_read_acqb(&p->state)) + print_process_info(to, to_arg, p, 0); + p = p->next; + } + } + } + + /* Then check all dist entries */ + erts_dist_print_procs_suspended_on_de(to, to_arg); + port_info(to, to_arg); } @@ -199,13 +225,14 @@ static int doit_print_monitor(ErtsMonitor *mon, void *vpcontext, Sint reds) } return 1; } - + /* Display info about an individual Erlang process */ void print_process_info(fmtfn_t to, void *to_arg, Process *p, ErtsProcLocks orig_locks) { int garbing = 0; int running = 0; + int exiting = 0; Sint len; struct saved_calls *scb; erts_aint32_t state; @@ -226,9 +253,12 @@ print_process_info(fmtfn_t to, void *to_arg, Process *p, ErtsProcLocks orig_lock | ERTS_PSFLG_DIRTY_RUNNING)) running = 1; + if (state & ERTS_PSFLG_EXITING) + exiting = 1; + if (!(locks & ERTS_PROC_LOCK_MAIN)) { locks |= ERTS_PROC_LOCK_MAIN; - if (ERTS_IS_CRASH_DUMPING && running) { + if (ERTS_IS_CRASH_DUMPING) { 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 @@ -246,7 +276,7 @@ print_process_info(fmtfn_t to, void *to_arg, Process *p, ErtsProcLocks orig_lock * If the process is registered as a global process, display the * registered name */ - if (p->common.u.alive.reg) + if (!ERTS_PROC_IS_EXITING(p) && p->common.u.alive.reg) erts_print(to, to_arg, "Name: %T\n", p->common.u.alive.reg->name); /* @@ -332,7 +362,7 @@ print_process_info(fmtfn_t to, void *to_arg, Process *p, ErtsProcLocks orig_lock } /* display the links only if there are any*/ - if (ERTS_P_LINKS(p) || ERTS_P_MONITORS(p) || ERTS_P_LT_MONITORS(p)) { + if (!exiting && (ERTS_P_LINKS(p) || ERTS_P_MONITORS(p) || ERTS_P_LT_MONITORS(p))) { PrintMonitorContext context = {1, to, to_arg}; erts_print(to, to_arg,"Link list: ["); erts_link_tree_foreach(ERTS_P_LINKS(p), doit_print_link, &context); diff --git a/erts/emulator/beam/bs_instrs.tab b/erts/emulator/beam/bs_instrs.tab index 652460a66d..9cad2b03c5 100644 --- a/erts/emulator/beam/bs_instrs.tab +++ b/erts/emulator/beam/bs_instrs.tab @@ -1136,7 +1136,6 @@ i_bs_get_utf16.execute(Fail, Flags, Dst) { } bs_context_to_binary := ctx_to_bin.fetch.execute; -i_bs_get_binary_all_reuse := ctx_to_bin.fetch_bin.execute; ctx_to_bin.head() { Eterm context; @@ -1159,16 +1158,6 @@ ctx_to_bin.fetch(Src) { } } -ctx_to_bin.fetch_bin(Src, Fail, Unit) { - context = $Src; - mb = ms_matchbuffer(context); - size = mb->size - mb->offset; - if (size % $Unit != 0) { - $FAIL($Fail); - } - offs = mb->offset; -} - ctx_to_bin.execute() { Uint hole_size; Uint orig = mb->orig; diff --git a/erts/emulator/beam/dist.c b/erts/emulator/beam/dist.c index ff5f766de7..8bbe6450eb 100644 --- a/erts/emulator/beam/dist.c +++ b/erts/emulator/beam/dist.c @@ -772,77 +772,25 @@ void init_dist(void) #define ErtsDistOutputBuf2Binary(OB) OB->bin -#ifdef DEBUG - -struct obuf_list; -struct obuf_list { - erts_refc_t refc; - struct obuf_list *next; - struct obuf_list *prev; -}; -#define obuf_list_size sizeof(struct obuf_list) -static struct obuf_list *erts_obuf_list = NULL; -static erts_mtx_t erts_obuf_list_mtx; - -static void -insert_obuf(struct obuf_list *obuf, erts_aint_t initial) { - erts_mtx_lock(&erts_obuf_list_mtx); - obuf->next = erts_obuf_list; - obuf->prev = NULL; - erts_refc_init(&obuf->refc, initial); - if (erts_obuf_list) - erts_obuf_list->prev = obuf; - erts_obuf_list = obuf; - erts_mtx_unlock(&erts_obuf_list_mtx); -} - -static void -remove_obuf(struct obuf_list *obuf) { - if (erts_refc_dectest(&obuf->refc, 0) == 0) { - erts_mtx_lock(&erts_obuf_list_mtx); - if (obuf->prev) { - obuf->prev->next = obuf->next; - } else { - erts_obuf_list = obuf->next; - } - if (obuf->next) obuf->next->prev = obuf->prev; - erts_mtx_unlock(&erts_obuf_list_mtx); - } -} - -void check_obuf(void); -void check_obuf(void) { - erts_mtx_lock(&erts_obuf_list_mtx); - ERTS_ASSERT(erts_obuf_list == NULL); - erts_mtx_unlock(&erts_obuf_list_mtx); -} -#else -#define insert_obuf(...) -#define remove_obuf(...) -#define obuf_list_size 0 -#endif - static ERTS_INLINE ErtsDistOutputBuf * alloc_dist_obuf(Uint size, Uint headers) { int i; ErtsDistOutputBuf *obuf; Uint obuf_size = sizeof(ErtsDistOutputBuf)*(headers) + - sizeof(byte)*size + obuf_list_size; + sizeof(byte)*size; Binary *bin = erts_bin_drv_alloc(obuf_size); - size += obuf_list_size; obuf = (ErtsDistOutputBuf *) &bin->orig_bytes[size]; erts_refc_add(&bin->intern.refc, headers - 1, 1); for (i = 0; i < headers; i++) { obuf[i].bin = bin; - obuf[i].extp = (byte *)&bin->orig_bytes[0] + obuf_list_size; + obuf[i].extp = (byte *)&bin->orig_bytes[0]; #ifdef DEBUG obuf[i].dbg_pattern = ERTS_DIST_OUTPUT_BUF_DBG_PATTERN; obuf[i].alloc_endp = obuf->extp + size; ASSERT(bin == ErtsDistOutputBuf2Binary(obuf)); #endif } - insert_obuf((struct obuf_list*)&bin->orig_bytes[0], headers); return obuf; } @@ -851,10 +799,7 @@ free_dist_obuf(ErtsDistOutputBuf *obuf) { Binary *bin = ErtsDistOutputBuf2Binary(obuf); ASSERT(obuf->dbg_pattern == ERTS_DIST_OUTPUT_BUF_DBG_PATTERN); - remove_obuf((struct obuf_list*)&bin->orig_bytes[0]); - if (erts_refc_dectest(&bin->intern.refc, 0) == 0) { - erts_bin_free(bin); - } + erts_bin_release(bin); } static ERTS_INLINE Sint @@ -1968,6 +1913,7 @@ int erts_net_message(Port *prt, goto invalid_message; } reason = tuple[5]; + edep = NULL; } if (is_not_ref(ref)) @@ -2014,12 +1960,14 @@ int erts_net_message(Port *prt, } token = NIL; reason = tuple[4]; + edep = NULL; } else if (type == DOP_EXIT_TT){ if (tuple_arity != 5) { goto invalid_message; } token = tuple[4]; reason = tuple[5]; + edep = NULL; } else if (type == DOP_PAYLOAD_EXIT) { if (tuple_arity != 3) { goto invalid_message; @@ -2067,12 +2015,14 @@ int erts_net_message(Port *prt, } reason = tuple[4]; token = NIL; + edep = NULL; } else if (type == DOP_EXIT2_TT) { if (tuple_arity != 5) { goto invalid_message; } token = tuple[4]; reason = tuple[5]; + edep = NULL; } else if (type == DOP_PAYLOAD_EXIT2) { if (tuple_arity != 3) { goto invalid_message; @@ -2430,8 +2380,8 @@ erts_dsig_send(ErtsDSigSendContext *ctx) case ERTS_DSIG_SEND_PHASE_FIN: { ASSERT(ctx->obuf->extp < ctx->obuf->ext_endp); - ASSERT(((byte*)&ctx->obuf->bin->orig_bytes[0]+obuf_list_size) <= ctx->obuf->extp - ctx->max_finalize_prepend); - ASSERT(ctx->obuf->ext_endp <= ((byte*)ctx->obuf->bin->orig_bytes+obuf_list_size) + ctx->data_size + ctx->dhdr_ext_size); + ASSERT(((byte*)&ctx->obuf->bin->orig_bytes[0]) <= ctx->obuf->extp - ctx->max_finalize_prepend); + ASSERT(ctx->obuf->ext_endp <= ((byte*)ctx->obuf->bin->orig_bytes) + ctx->data_size + ctx->dhdr_ext_size); ctx->data_size = ctx->obuf->ext_endp - ctx->obuf->extp; @@ -2935,7 +2885,9 @@ erts_dist_command(Port *prt, int initial_reds) ob = oq.first; ASSERT(ob); do { + obufsize += size_obuf(ob); reds = erts_encode_ext_dist_header_finalize(ob, dep, flags, reds); + obufsize -= size_obuf(ob); if (reds < 0) break; last_finalized = ob; @@ -2974,7 +2926,9 @@ erts_dist_command(Port *prt, int initial_reds) while (oq.first && !preempt) { ErtsDistOutputBuf *fob; Uint size; + obufsize += size_obuf(oq.first); reds = erts_encode_ext_dist_header_finalize(oq.first, dep, flags, reds); + obufsize -= size_obuf(oq.first); if (reds < 0) { preempt = 1; break; @@ -3407,14 +3361,13 @@ dist_ctrl_get_data_1(BIF_ALIST_1) { DistEntry *dep = ERTS_PROC_GET_DIST_ENTRY(BIF_P); const Sint initial_reds = ERTS_BIF_REDS_LEFT(BIF_P); - Sint reds = initial_reds; + Sint reds = initial_reds, obufsize = 0; ErtsDistOutputBuf *obuf; - Eterm *hp; + Eterm *hp, res; ProcBin *pb; erts_aint_t qsize; Uint32 conn_id, get_size; - Eterm res; - Uint hsz, bin_sz; + Uint hsz = 0, bin_sz; if (!dep) BIF_ERROR(BIF_P, EXC_NOTSUP); @@ -3466,7 +3419,9 @@ dist_ctrl_get_data_1(BIF_ALIST_1) } obuf = dep->tmp_out_queue.first; + obufsize += size_obuf(obuf); reds = erts_encode_ext_dist_header_finalize(obuf, dep, dep->flags, reds); + obufsize -= size_obuf(obuf); if (reds < 0) { erts_de_runlock(dep); ERTS_BIF_YIELD1(bif_export[BIF_dist_ctrl_get_data_1], @@ -3482,8 +3437,7 @@ dist_ctrl_get_data_1(BIF_ALIST_1) erts_de_runlock(dep); - bin_sz = obuf->ext_endp - obuf->extp; - hsz = PROC_BIN_SIZE; + bin_sz = obuf->ext_endp - obuf->extp + obuf->hdr_endp - obuf->hdrp; get_size = dep->opts & ERTS_DIST_CTRL_OPT_GET_SIZE; if (get_size) { @@ -3492,18 +3446,50 @@ dist_ctrl_get_data_1(BIF_ALIST_1) hsz += BIG_UINT_HEAP_SIZE; } - hp = HAlloc(BIF_P, hsz); - pb = (ProcBin *) (char *) hp; - pb->thing_word = HEADER_PROC_BIN; - pb->size = bin_sz; - pb->next = MSO(BIF_P).first; - MSO(BIF_P).first = (struct erl_off_heap_header*) pb; - pb->val = ErtsDistOutputBuf2Binary(obuf); - pb->bytes = (byte*) obuf->extp; - pb->flags = 0; - hp += PROC_BIN_SIZE; + if (!obuf->hdrp) { + hp = HAlloc(BIF_P, PROC_BIN_SIZE + hsz); + pb = (ProcBin *) (char *) hp; + pb->thing_word = HEADER_PROC_BIN; + pb->size = obuf->ext_endp - obuf->extp; + pb->next = MSO(BIF_P).first; + MSO(BIF_P).first = (struct erl_off_heap_header*) pb; + pb->val = ErtsDistOutputBuf2Binary(obuf); + pb->bytes = (byte*) obuf->extp; + pb->flags = 0; + res = make_binary(pb); + } else { + hp = HAlloc(BIF_P, PROC_BIN_SIZE * 2 + 4 + hsz); + pb = (ProcBin *) (char *) hp; + pb->thing_word = HEADER_PROC_BIN; + pb->size = obuf->ext_endp - obuf->extp; + pb->next = MSO(BIF_P).first; + MSO(BIF_P).first = (struct erl_off_heap_header*) pb; + pb->val = ErtsDistOutputBuf2Binary(obuf); + pb->bytes = (byte*) obuf->extp; + pb->flags = 0; + hp += PROC_BIN_SIZE; + + res = CONS(hp, make_binary(pb), NIL); + hp += 2; + + pb = (ProcBin *) (char *) hp; + pb->thing_word = HEADER_PROC_BIN; + pb->size = obuf->hdr_endp - obuf->hdrp; + pb->next = MSO(BIF_P).first; + MSO(BIF_P).first = (struct erl_off_heap_header*) pb; + pb->val = ErtsDistOutputBuf2Binary(obuf); + erts_refc_inc(&pb->val->intern.refc, 1); + pb->bytes = (byte*) obuf->hdrp; + pb->flags = 0; + hp += PROC_BIN_SIZE; + res = CONS(hp, make_binary(pb), res); + hp += 2; + } + + obufsize += size_obuf(obuf); + + qsize = erts_atomic_add_read_nob(&dep->qsize, (erts_aint_t) -obufsize); - qsize = erts_atomic_add_read_nob(&dep->qsize, -size_obuf(obuf)); ASSERT(qsize >= 0); if (qsize < erts_dist_buf_busy_limit/2 @@ -3518,8 +3504,6 @@ dist_ctrl_get_data_1(BIF_ALIST_1) } } - res = make_binary(pb); - if (get_size) { Eterm sz_term; if (IS_USMALL(0, bin_sz)) @@ -3764,12 +3748,10 @@ int distribution_info(fmtfn_t to, void *arg) /* Called by break handler */ BIF_RETTYPE setnode_2(BIF_ALIST_2) { Process *net_kernel; - Uint creation; + Uint32 creation; /* valid creation ? */ - if(!term_to_Uint(BIF_ARG_2, &creation)) - goto error; - if(creation > 3) + if(!term_to_Uint32(BIF_ARG_2, &creation)) goto error; /* valid node name ? */ @@ -3813,7 +3795,7 @@ BIF_RETTYPE setnode_2(BIF_ALIST_2) erts_proc_unlock(BIF_P, ERTS_PROC_LOCK_MAIN); erts_thr_progress_block(); inc_no_nodes(); - erts_set_this_node(BIF_ARG_1, (Uint32) creation); + erts_set_this_node(BIF_ARG_1, creation); erts_is_alive = 1; send_nodes_mon_msgs(NULL, am_nodeup, BIF_ARG_1, am_visible, NIL); erts_thr_progress_unblock(); @@ -4713,10 +4695,6 @@ init_nodes_monitors(void) { erts_mtx_init(&nodes_monitors_mtx, "nodes_monitors", NIL, ERTS_LOCK_FLAGS_PROPERTY_STATIC | ERTS_LOCK_FLAGS_CATEGORY_DISTRIBUTION); -#ifdef DEBUG - erts_mtx_init(&erts_obuf_list_mtx, "sad", NIL, - ERTS_LOCK_FLAGS_PROPERTY_STATIC | ERTS_LOCK_FLAGS_CATEGORY_DISTRIBUTION); -#endif nodes_monitors = NULL; no_nodes_monitors = 0; } @@ -5107,3 +5085,22 @@ erts_processes_monitoring_nodes(Process *c_p) return ctxt.res; } + +static void +print_suspended_on_de(fmtfn_t to, void *to_arg, DistEntry *dep) +{ + for (; dep; dep = dep->next) { + ErtsProcList *curr = erts_proclist_peek_first(dep->suspended); + while (curr) { + if (!is_internal_pid(curr->u.pid)) + print_process_info(to, to_arg, curr->u.p, 0); + curr = erts_proclist_peek_next(dep->suspended, curr); + } + } +} + +void +erts_dist_print_procs_suspended_on_de(fmtfn_t to, void *to_arg) { + print_suspended_on_de(to, to_arg, erts_hidden_dist_entries); + print_suspended_on_de(to, to_arg, erts_visible_dist_entries); +} diff --git a/erts/emulator/beam/dist.h b/erts/emulator/beam/dist.h index 5bd22cc31f..f953a2ab8c 100644 --- a/erts/emulator/beam/dist.h +++ b/erts/emulator/beam/dist.h @@ -54,11 +54,12 @@ #define DFLAG_DIST_MANDATORY (DFLAG_EXTENDED_REFERENCES \ | DFLAG_EXTENDED_PIDS_PORTS \ | DFLAG_UTF8_ATOMS \ - | DFLAG_NEW_FUN_TAGS) + | DFLAG_NEW_FUN_TAGS \ + | DFLAG_BIG_CREATION) /* * Additional optimistic flags when encoding toward pending connection. - * If remote node (erl_interface) does not supporting these then we may need + * If remote node (erl_interface) does not support these then we may need * to transcode messages enqueued before connection setup was finished. */ #define DFLAG_DIST_HOPEFULLY (DFLAG_EXPORT_PTR_TAG \ @@ -75,7 +76,6 @@ | DFLAG_SMALL_ATOM_TAGS \ | DFLAG_UTF8_ATOMS \ | DFLAG_MAP_TAG \ - | DFLAG_BIG_CREATION \ | DFLAG_SEND_SENDER \ | DFLAG_BIG_SEQTRACE_LABELS \ | DFLAG_EXIT_PAYLOAD \ @@ -319,5 +319,6 @@ extern int erts_dsig_prepare(ErtsDSigSendContext *, int, int); +void erts_dist_print_procs_suspended_on_de(fmtfn_t to, void *to_arg); int erts_auto_connect(DistEntry* dep, Process *proc, ErtsProcLocks proc_locks); #endif diff --git a/erts/emulator/beam/erl_bif_info.c b/erts/emulator/beam/erl_bif_info.c index de64f09a02..a7424bbcb8 100644 --- a/erts/emulator/beam/erl_bif_info.c +++ b/erts/emulator/beam/erl_bif_info.c @@ -2797,7 +2797,10 @@ BIF_RETTYPE system_info_1(BIF_ALIST_1) } else if (BIF_ARG_1 == am_threads) { return am_true; } else if (BIF_ARG_1 == am_creation) { - return make_small(erts_this_node->creation); + Uint hsz = 0; + erts_bld_uint(NULL, &hsz, erts_this_node->creation); + hp = hsz ? HAlloc(BIF_P, hsz) : NULL; + BIF_RET(erts_bld_uint(&hp, NULL, erts_this_node->creation)); } else if (BIF_ARG_1 == am_break_ignored) { extern int ignore_break; if (ignore_break) @@ -4439,6 +4442,7 @@ BIF_RETTYPE erts_debug_set_internal_state_2(BIF_ALIST_2) BIF_P->fcalls = reds; else BIF_P->fcalls = reds - CONTEXT_REDS; + BIF_P->scheduler_data->virtual_reds = 0; } BIF_RET(am_true); } diff --git a/erts/emulator/beam/erl_gc.c b/erts/emulator/beam/erl_gc.c index 9317850d96..67a73e4d57 100644 --- a/erts/emulator/beam/erl_gc.c +++ b/erts/emulator/beam/erl_gc.c @@ -577,7 +577,7 @@ force_reschedule: } static ERTS_FORCE_INLINE Uint -young_gen_usage(Process *p) +young_gen_usage(Process *p, Uint *ext_msg_usage) { Uint hsz; Eterm *aheap; @@ -604,7 +604,10 @@ young_gen_usage(Process *p) if (ERTS_SIG_IS_MSG(mp) && mp->data.attached && mp->data.attached != ERTS_MSG_COMBINED_HFRAG) { - hsz += erts_msg_attached_data_size(mp); + Uint sz = erts_msg_attached_data_size(mp); + if (ERTS_SIG_IS_EXTERNAL_MSG(mp)) + *ext_msg_usage += sz; + hsz += sz; } }); } @@ -676,6 +679,7 @@ garbage_collect(Process* p, ErlHeapFragment *live_hf_end, { Uint reclaimed_now = 0; Uint ygen_usage; + Uint ext_msg_usage = 0; Eterm gc_trace_end_tag; int reds; ErtsMonotonicTime start_time; @@ -698,7 +702,7 @@ garbage_collect(Process* p, ErlHeapFragment *live_hf_end, return delay_garbage_collection(p, live_hf_end, need, fcalls); } - ygen_usage = max_young_gen_usage ? max_young_gen_usage : young_gen_usage(p); + ygen_usage = max_young_gen_usage ? max_young_gen_usage : young_gen_usage(p, &ext_msg_usage); if (!ERTS_SCHEDULER_IS_DIRTY(esdp)) { check_for_possibly_long_gc(p, ygen_usage); @@ -739,7 +743,7 @@ garbage_collect(Process* p, ErlHeapFragment *live_hf_end, trace_gc(p, am_gc_minor_start, need, THE_NON_VALUE); } DTRACE2(gc_minor_start, pidbuf, need); - reds = minor_collection(p, live_hf_end, need, objv, nobj, + reds = minor_collection(p, live_hf_end, need + ext_msg_usage, objv, nobj, ygen_usage, &reclaimed_now); DTRACE2(gc_minor_end, pidbuf, reclaimed_now); if (reds == -1) { @@ -764,7 +768,7 @@ do_major_collection: trace_gc(p, am_gc_major_start, need, THE_NON_VALUE); } DTRACE2(gc_major_start, pidbuf, need); - reds = major_collection(p, live_hf_end, need, objv, nobj, + reds = major_collection(p, live_hf_end, need + ext_msg_usage, objv, nobj, ygen_usage, &reclaimed_now); if (ERTS_SCHEDULER_IS_DIRTY(esdp)) p->flags &= ~(F_DIRTY_MAJOR_GC|F_DIRTY_MINOR_GC); @@ -1101,6 +1105,7 @@ erts_garbage_collect_literals(Process* p, Eterm* literals, Eterm* old_htop; Uint n; Uint ygen_usage = 0; + Uint ext_msg_usage = 0; struct erl_off_heap_header** prev = NULL; Sint64 reds; int hibernated = !!(p->flags & F_HIBERNATED); @@ -1118,7 +1123,7 @@ erts_garbage_collect_literals(Process* p, Eterm* literals, p->flags &= ~F_DIRTY_CLA; else { Uint size = byte_lit_size/sizeof(Uint); - ygen_usage = young_gen_usage(p); + ygen_usage = young_gen_usage(p, &ext_msg_usage); if (hibernated) size = size*2 + 3*ygen_usage; else @@ -1130,7 +1135,7 @@ erts_garbage_collect_literals(Process* p, Eterm* literals, } } - reds = (Sint64) garbage_collect(p, ERTS_INVALID_HFRAG_PTR, 0, + reds = (Sint64) garbage_collect(p, ERTS_INVALID_HFRAG_PTR, ext_msg_usage, p->arg_reg, p->arity, fcalls, ygen_usage); if (ERTS_PROC_IS_EXITING(p)) { @@ -1348,6 +1353,9 @@ minor_collection(Process* p, ErlHeapFragment *live_hf_end, Eterm *mature = p->abandoned_heap ? p->abandoned_heap : p->heap; Uint mature_size = p->high_water - mature; Uint size_before = ygen_usage; +#ifdef DEBUG + Uint debug_tmp = 0; +#endif /* * Check if we have gone past the max heap size limit @@ -1484,7 +1492,7 @@ minor_collection(Process* p, ErlHeapFragment *live_hf_end, process from there */ ASSERT(!MAX_HEAP_SIZE_GET(p) || !(MAX_HEAP_SIZE_FLAGS_GET(p) & MAX_HEAP_SIZE_KILL) || - MAX_HEAP_SIZE_GET(p) > (young_gen_usage(p) + + MAX_HEAP_SIZE_GET(p) > (young_gen_usage(p, &debug_tmp) + (OLD_HEND(p) - OLD_HEAP(p)) + (HEAP_END(p) - HEAP_TOP(p)))); diff --git a/erts/emulator/beam/erl_init.c b/erts/emulator/beam/erl_init.c index 82d5140d1c..12750b9aa6 100644 --- a/erts/emulator/beam/erl_init.c +++ b/erts/emulator/beam/erl_init.c @@ -2417,17 +2417,12 @@ erts_exit_vv(int n, int flush_async, char *fmt, va_list args1, va_list args2) erts_exit_epilogue(); } -void check_obuf(void); __decl_noreturn void __noreturn erts_exit_epilogue(void) { int n = erts_exit_code; sys_tty_reset(n); -#ifdef DEBUG - check_obuf(); -#endif - if (n == ERTS_INTR_EXIT) exit(0); else if (n == ERTS_DUMP_EXIT) diff --git a/erts/emulator/beam/erl_lock_check.c b/erts/emulator/beam/erl_lock_check.c index 39eabb6710..3aab4828cc 100644 --- a/erts/emulator/beam/erl_lock_check.c +++ b/erts/emulator/beam/erl_lock_check.c @@ -164,8 +164,7 @@ static erts_lc_lock_order_t erts_lock_order[] = { { "os_monotonic_time", NULL }, { "erts_alloc_hard_debug", NULL }, { "hard_dbg_mseg", NULL }, - { "erts_mmap", NULL }, - { "sad", NULL} + { "erts_mmap", NULL } }; #define ERTS_LOCK_ORDER_SIZE \ diff --git a/erts/emulator/beam/erl_message.c b/erts/emulator/beam/erl_message.c index e350a20339..2a0fb9e2aa 100644 --- a/erts/emulator/beam/erl_message.c +++ b/erts/emulator/beam/erl_message.c @@ -1137,10 +1137,28 @@ change_to_off_heap: return res; } -void erts_factory_proc_init(ErtsHeapFactory* factory, - Process* p) +void erts_factory_proc_init(ErtsHeapFactory* factory, Process* p) { - erts_factory_proc_prealloc_init(factory, p, HEAP_LIMIT(p) - HEAP_TOP(p)); + /* This function does not use HAlloc to allocate on the heap + as we do not want to use INIT_HEAP_MEM on the allocated + heap as that completely destroys the DEBUG emulators + performance. */ + ErlHeapFragment *bp = p->mbuf; + factory->mode = FACTORY_HALLOC; + factory->p = p; + factory->hp_start = HEAP_TOP(p); + factory->hp = factory->hp_start; + factory->hp_end = HEAP_LIMIT(p); + factory->off_heap = &p->off_heap; + factory->message = NULL; + factory->off_heap_saved.first = p->off_heap.first; + factory->off_heap_saved.overhead = p->off_heap.overhead; + factory->heap_frags_saved = bp; + factory->heap_frags_saved_used = bp ? bp->used_size : 0; + factory->heap_frags = NULL; /* not used */ + factory->alloc_type = 0; /* not used */ + + HEAP_TOP(p) = HEAP_LIMIT(p); } void erts_factory_proc_prealloc_init(ErtsHeapFactory* factory, diff --git a/erts/emulator/beam/erl_message.h b/erts/emulator/beam/erl_message.h index e5f623a370..5bd25737a7 100644 --- a/erts/emulator/beam/erl_message.h +++ b/erts/emulator/beam/erl_message.h @@ -22,6 +22,7 @@ #define __ERL_MESSAGE_H__ #include "sys.h" +#include "erl_vm.h" #define ERTS_PROC_SIG_QUEUE_TYPE_ONLY #include "erl_proc_sig_queue.h" #undef ERTS_PROC_SIG_QUEUE_TYPE_ONLY @@ -117,6 +118,7 @@ erts_produce_heap(ErtsHeapFactory* factory, Uint need, Uint xtra) } res = factory->hp; factory->hp += need; + INIT_HEAP_MEM(res, need); return res; } diff --git a/erts/emulator/beam/erl_nif.h b/erts/emulator/beam/erl_nif.h index a599511c78..cc389a093f 100644 --- a/erts/emulator/beam/erl_nif.h +++ b/erts/emulator/beam/erl_nif.h @@ -59,12 +59,17 @@ */ #define ERL_NIF_MAJOR_VERSION 2 #define ERL_NIF_MINOR_VERSION 15 + /* - * WHEN CHANGING INTERFACE VERSION, also replace erts version below - * with ticket syntax like "erts-@OTP-12345@", or a temporary placeholder - * between two @ like "erts-@MyName@", if you don't know what a ticket is. + * WHEN CHANGING INTERFACE VERSION, also replace erts version below with + * a ticket number e.g. "erts-@OTP-12345@". The syntax is the same as for + * runtime dependencies so multiple tickets should be separated with ":", e.g. + * "erts-@OTP-12345:OTP-54321@". + * + * If you're not on the OTP team, you should use a placeholder like + * erts-@MyName@ instead. */ -#define ERL_NIF_MIN_ERTS_VERSION "erts-@OTP-15095 OTP-15640@ (OTP-22)" +#define ERL_NIF_MIN_ERTS_VERSION "erts-@OTP-15095:OTP-15640@" /* * The emulator will refuse to load a nif-lib with a major version diff --git a/erts/emulator/beam/erl_node_tables.c b/erts/emulator/beam/erl_node_tables.c index 1adb101e30..49dea8919b 100644 --- a/erts/emulator/beam/erl_node_tables.c +++ b/erts/emulator/beam/erl_node_tables.c @@ -977,7 +977,7 @@ static void print_node(void *venp, void *vpndp) if(pndp->sysname == NIL) { erts_print(pndp->to, pndp->to_arg, "Name: %T ", enp->sysname); } - erts_print(pndp->to, pndp->to_arg, " %d", enp->creation); + erts_print(pndp->to, pndp->to_arg, " %u", enp->creation); #ifdef DEBUG erts_print(pndp->to, pndp->to_arg, " (refc=%ld)", erts_refc_read(&enp->refc, 0)); @@ -1020,7 +1020,7 @@ void erts_print_node_info(fmtfn_t to, /* ----------------------------------------------------------------------- */ void -erts_set_this_node(Eterm sysname, Uint creation) +erts_set_this_node(Eterm sysname, Uint32 creation) { ERTS_LC_ASSERT(erts_thr_progress_is_blocking()); ASSERT(2 <= de_refc_read(erts_this_dist_entry, 2)); @@ -2295,7 +2295,7 @@ reference_table_term(Uint **hpp, ErlOffHeap *ohp, Uint *szp) tup = MK_2TUP(AM_ets, drp->id); } else { - ASSERT(!drp->ctrl_ref && drp->node_ref && !drp->signal_ref); + ASSERT(!drp->ctrl_ref && (drp->node_ref || drp->sequence_ref) && !drp->signal_ref); ASSERT(is_atom(drp->id)); tup = MK_2TUP(drp->id, MK_UINT(drp->creation)); tup = MK_2TUP(AM_node, tup); diff --git a/erts/emulator/beam/erl_node_tables.h b/erts/emulator/beam/erl_node_tables.h index 8153699596..c434926142 100644 --- a/erts/emulator/beam/erl_node_tables.h +++ b/erts/emulator/beam/erl_node_tables.h @@ -258,7 +258,7 @@ void erts_set_dist_entry_pending(DistEntry *); void erts_set_dist_entry_connected(DistEntry *, Eterm, Uint); ErlNode *erts_find_or_insert_node(Eterm, Uint32, Eterm); void erts_schedule_delete_node(ErlNode *); -void erts_set_this_node(Eterm, Uint); +void erts_set_this_node(Eterm, Uint32); Uint erts_node_table_size(void); void erts_init_node_tables(int); void erts_node_table_info(fmtfn_t, void *); diff --git a/erts/emulator/beam/erl_proc_sig_queue.c b/erts/emulator/beam/erl_proc_sig_queue.c index bd59c4afa3..4e9f177e51 100644 --- a/erts/emulator/beam/erl_proc_sig_queue.c +++ b/erts/emulator/beam/erl_proc_sig_queue.c @@ -611,7 +611,8 @@ proc_queue_signal(Process *c_p, Eterm pid, ErtsSignal *sig, int op) #endif return 1; } - ASSERT(esdp->pending_signal.dbg_from == esdp->current_process); + ASSERT(esdp->pending_signal.dbg_from == esdp->current_process || + esdp->pending_signal.dbg_from == esdp->free_process); if (pend_sig != sig) { /* Switch them and send previously pending signal instead */ Eterm pend_to = esdp->pending_signal.to; @@ -3973,6 +3974,9 @@ clear_seq_trace_token(ErtsMessage *sig) case ERTS_MON_TYPE_PROC: case ERTS_MON_TYPE_DIST_PROC: case ERTS_MON_TYPE_NODE: + case ERTS_MON_TYPE_NODES: + case ERTS_MON_TYPE_SUSPEND: + case ERTS_MON_TYPE_TIME_OFFSET: break; default: ERTS_INTERNAL_ERROR("Unexpected sig type"); @@ -3989,6 +3993,11 @@ clear_seq_trace_token(ErtsMessage *sig) case ERTS_SIG_Q_OP_LINK: case ERTS_SIG_Q_OP_UNLINK: case ERTS_SIG_Q_OP_TRACE_CHANGE_STATE: + case ERTS_SIG_Q_OP_GROUP_LEADER: + case ERTS_SIG_Q_OP_IS_ALIVE: + case ERTS_SIG_Q_OP_PROCESS_INFO: + case ERTS_SIG_Q_OP_SYNC_SUSPEND: + case ERTS_SIG_Q_OP_RPC: break; default: diff --git a/erts/emulator/beam/erl_process.c b/erts/emulator/beam/erl_process.c index f34289339f..9e662632b4 100644 --- a/erts/emulator/beam/erl_process.c +++ b/erts/emulator/beam/erl_process.c @@ -12090,9 +12090,11 @@ erts_proc_exit_handle_dist_monitor(ErtsMonitor *mon, void *vctxt, Sint reds) ErtsDSigSendContext ctx; ErtsMonLnkDist *dist; DistEntry *dep; - Eterm watcher; + Eterm watcher, ref, *hp; ErtsMonitorData *mdp = NULL; Eterm watched; + Uint watcher_sz, ref_sz; + ErtsHeapFactory factory; ASSERT(erts_monitor_is_target(mon) && mon->type == ERTS_MON_TYPE_DIST_PROC); @@ -12124,10 +12126,18 @@ erts_proc_exit_handle_dist_monitor(ErtsMonitor *mon, void *vctxt, Sint reds) case ERTS_DSIG_PREP_CONNECTED: if (dist->connection_id != ctx.connection_id) break; + erts_factory_proc_init(&factory, c_p); + watcher_sz = size_object(watcher); + hp = erts_produce_heap(&factory, watcher_sz, 0); + watcher = copy_struct(watcher, watcher_sz, &hp, factory.off_heap); + ref_sz = size_object(mdp->ref); + hp = erts_produce_heap(&factory, ref_sz, 0); + ref = copy_struct(mdp->ref, ref_sz, &hp, factory.off_heap); + erts_factory_close(&factory); code = erts_dsig_send_m_exit(&ctx, watcher, watched, - mdp->ref, + ref, reason); switch (code) { case ERTS_DSIG_SEND_CONTINUE: @@ -12332,13 +12342,15 @@ erts_proc_exit_handle_dist_link(ErtsLink *lnk, void *vctxt, Sint reds) { ErtsProcExitContext *ctxt = (ErtsProcExitContext *) vctxt; Process *c_p = ctxt->c_p; - Eterm reason = ctxt->reason; + Eterm reason = ctxt->reason, item, *hp; + Uint item_sz; int code; ErtsDSigSendContext ctx; ErtsMonLnkDist *dist; DistEntry *dep; ErtsLink *dlnk; ErtsLinkData *ldp = NULL; + ErtsHeapFactory factory; ASSERT(lnk->type == ERTS_LNK_TYPE_DIST_PROC); dlnk = erts_link_to_other(lnk, &ldp); @@ -12365,9 +12377,14 @@ erts_proc_exit_handle_dist_link(ErtsLink *lnk, void *vctxt, Sint reds) case ERTS_DSIG_PREP_CONNECTED: if (dist->connection_id != ctx.connection_id) break; + erts_factory_proc_init(&factory, c_p); + item_sz = size_object(lnk->other.item); + hp = erts_produce_heap(&factory, item_sz, 0); + item = copy_struct(lnk->other.item, item_sz, &hp, factory.off_heap); + erts_factory_close(&factory); code = erts_dsig_send_exit_tt(&ctx, c_p->common.id, - lnk->other.item, + item, reason, SEQ_TRACE_TOKEN(c_p)); switch (code) { @@ -12584,6 +12601,8 @@ erts_continue_exit_process(Process *p) if (p->u.terminate) { trap_state = p->u.terminate; + /* Re-set the reason as it may have been gc:ed */ + trap_state->reason = p->fvalue; } else { trap_state->phase = ERTS_CONTINUE_EXIT_TIMERS; trap_state->reason = p->fvalue; @@ -12661,11 +12680,11 @@ restart: p->flags &= ~F_USING_DB; } - erts_set_gc_state(p, 1); - trap_state->phase = ERTS_CONTINUE_EXIT_CLEAN_SYS_TASKS; case ERTS_CONTINUE_EXIT_CLEAN_SYS_TASKS: - + + /* We enable GC again as it can produce more sys-tasks */ + erts_set_gc_state(p, 1); state = erts_atomic32_read_acqb(&p->state); if ((state & ERTS_PSFLG_SYS_TASKS) || p->dirty_sys_tasks) { reds -= cleanup_sys_tasks(p, state, reds); @@ -12788,6 +12807,9 @@ restart: erts_deref_dist_entry(trap_state->dep); } + /* Disable GC so that reason does not get moved */ + erts_set_gc_state(p, 0); + trap_state->pectxt.c_p = p; trap_state->pectxt.reason = trap_state->reason; trap_state->pectxt.dist_links = NULL; @@ -12872,13 +12894,13 @@ restart: switch (result) { case ERTS_DSIG_SEND_OK: case ERTS_DSIG_SEND_TOO_LRG: /*SEND_SYSTEM_LIMIT*/ - case ERTS_DSIG_SEND_YIELD: /*SEND_YIELD_RETURN*/ break; + case ERTS_DSIG_SEND_YIELD: /*SEND_YIELD_RETURN*/ case ERTS_DSIG_SEND_CONTINUE: { /*SEND_YIELD_CONTINUE*/ goto yield; } } - erts_set_gc_state(p, 1); + trap_state->pectxt.dist_state = NIL; if (reds <= 0) goto yield; @@ -12917,11 +12939,12 @@ restart: * From this point on we are no longer allowed to yield * this process. */ - #ifdef DEBUG yield_allowed = 0; #endif + erts_set_gc_state(p, 1); + /* Set state to not active as we don't want this process to be scheduled in again after this. */ state = erts_atomic32_read_band_relb(&p->state, @@ -12960,7 +12983,7 @@ restart: erts_free(ERTS_ALC_T_CONT_EXIT_TRAP, trap_state); p->u.terminate = NULL; } - + ERTS_CHK_HAVE_ONLY_MAIN_PROC_LOCK(p); if (IS_TRACED_FL(p, F_TRACE_SCHED_EXIT)) diff --git a/erts/emulator/beam/erl_process.h b/erts/emulator/beam/erl_process.h index 4ffa022d5c..711b73417d 100644 --- a/erts/emulator/beam/erl_process.h +++ b/erts/emulator/beam/erl_process.h @@ -1322,9 +1322,6 @@ ERTS_GLB_INLINE void erts_heap_frag_shrink(Process* p, Eterm* hp) #endif /* inline */ Eterm* erts_heap_alloc(Process* p, Uint need, Uint xtra); -#ifdef CHECK_FOR_HOLES -Eterm* erts_set_hole_marker(Eterm* ptr, Uint sz); -#endif extern erts_rwmtx_t erts_cpu_bind_rwmtx; /* If any of the erts_system_monitor_* variables are set (enabled), diff --git a/erts/emulator/beam/erl_process_dump.c b/erts/emulator/beam/erl_process_dump.c index a164ed543e..71262061dd 100644 --- a/erts/emulator/beam/erl_process_dump.c +++ b/erts/emulator/beam/erl_process_dump.c @@ -121,12 +121,14 @@ Uint erts_process_memory(Process *p, int include_sigs_in_transit) size += sizeof(Process); - erts_link_tree_foreach(ERTS_P_LINKS(p), - link_size, (void *) &size); - erts_monitor_tree_foreach(ERTS_P_MONITORS(p), - monitor_size, (void *) &size); - erts_monitor_list_foreach(ERTS_P_LT_MONITORS(p), - monitor_size, (void *) &size); + if ((erts_atomic32_read_nob(&p->state) & ERTS_PSFLG_EXITING) == 0) { + erts_link_tree_foreach(ERTS_P_LINKS(p), + link_size, (void *) &size); + erts_monitor_tree_foreach(ERTS_P_MONITORS(p), + monitor_size, (void *) &size); + erts_monitor_list_foreach(ERTS_P_LT_MONITORS(p), + monitor_size, (void *) &size); + } size += (p->heap_sz + p->mbuf_sz) * sizeof(Eterm); if (p->abandoned_heap) size += (p->hend - p->heap) * sizeof(Eterm); diff --git a/erts/emulator/beam/erl_utils.h b/erts/emulator/beam/erl_utils.h index 880febba8b..430ac305c5 100644 --- a/erts/emulator/beam/erl_utils.h +++ b/erts/emulator/beam/erl_utils.h @@ -69,7 +69,6 @@ int erts_fit_in_bits_int32(Sint32); int erts_fit_in_bits_uint(Uint); Sint erts_list_length(Eterm); int erts_is_builtin(Eterm, Eterm, int); -Uint32 block_hash(byte *, unsigned, Uint32); Uint32 make_hash2(Eterm); Uint32 make_hash(Eterm); Uint32 make_internal_hash(Eterm, Uint32 salt); diff --git a/erts/emulator/beam/erl_vm.h b/erts/emulator/beam/erl_vm.h index 35eae18394..e623148587 100644 --- a/erts/emulator/beam/erl_vm.h +++ b/erts/emulator/beam/erl_vm.h @@ -67,9 +67,10 @@ (unsigned long)HEAP_TOP(p),(sz),__FILE__,__LINE__)), \ */ # ifdef CHECK_FOR_HOLES -# define INIT_HEAP_MEM(p,sz) erts_set_hole_marker(HEAP_TOP(p), (sz)) +Eterm* erts_set_hole_marker(Eterm* ptr, Uint sz); +# define INIT_HEAP_MEM(p,sz) erts_set_hole_marker(p, (sz)) # else -# define INIT_HEAP_MEM(p,sz) sys_memset(HEAP_TOP(p),0x01,(sz)*sizeof(Eterm*)) +# define INIT_HEAP_MEM(p,sz) sys_memset(p,0x01,(sz)*sizeof(Eterm*)) # endif #else # define INIT_HEAP_MEM(p,sz) ((void)0) @@ -91,7 +92,7 @@ ErtsHAllocLockCheck(p), \ (IS_FORCE_HEAP_FRAGS || (((HEAP_LIMIT(p) - HEAP_TOP(p)) < (sz))) \ ? erts_heap_alloc((p),(sz),(xtra)) \ - : (INIT_HEAP_MEM(p,sz), \ + : (INIT_HEAP_MEM(HEAP_TOP(p),sz), \ HEAP_TOP(p) = HEAP_TOP(p) + (sz), HEAP_TOP(p) - (sz)))) #define HAlloc(P, SZ) HAllocX(P,SZ,0) diff --git a/erts/emulator/beam/external.c b/erts/emulator/beam/external.c index 73eae614fa..471c1c3938 100644 --- a/erts/emulator/beam/external.c +++ b/erts/emulator/beam/external.c @@ -51,18 +51,17 @@ #define MAX_STRING_LEN 0xffff -/* MAX value for the creation field in pid, port and reference - for the local node and for the current external format. - - Larger creation values than this are allowed in external pid, port and refs - encoded with NEW_PID_EXT, NEW_PORT_EXT and NEWER_REFERENCE_EXT. - The point here is to prepare for future upgrade to 32-bit creation. - OTP-19 (erts-8.0) can handle big creation values from other (newer) nodes, - but do not use big creation values for the local node yet, - as we still may have to communicate with older nodes. +/* + * MAX value for the creation field in pid, port and reference + * for the old PID_EXT, PORT_EXT, REFERENCE_EXT and NEW_REFERENCE_EXT. + * Older nodes (OTP 19-21) will send us these so we must be able to decode them. + * + * From OTP 22 DFLAG_BIG_CREATION is mandatory so this node will always + * encode with new big 32-bit creations using NEW_PID_EXT, NEW_PORT_EXT + * and NEWER_REFERENCE_EXT. */ -#define ERTS_MAX_LOCAL_CREATION (3) -#define is_valid_creation(Cre) ((unsigned)(Cre) <= ERTS_MAX_LOCAL_CREATION) +#define ERTS_MAX_TINY_CREATION (3) +#define is_tiny_creation(Cre) ((unsigned)(Cre) <= ERTS_MAX_TINY_CREATION) #undef ERTS_DEBUG_USE_DIST_SEP #ifdef DEBUG @@ -2380,7 +2379,8 @@ enc_pid(ErtsAtomCacheMap *acmp, Eterm pid, byte* ep, Uint32 dflags) Eterm sysname = ((is_internal_pid(pid) && (dflags & DFLAG_INTERNAL_TAGS)) ? INTERNAL_LOCAL_SYSNAME : pid_node_name(pid)); Uint32 creation = pid_creation(pid); - byte* tagp = ep++; + + *ep++ = NEW_PID_EXT; /* insert atom here containing host and sysname */ ep = enc_atom(acmp, sysname, ep, dflags); @@ -2392,15 +2392,8 @@ enc_pid(ErtsAtomCacheMap *acmp, Eterm pid, byte* ep, Uint32 dflags) ep += 4; put_int32(os, ep); ep += 4; - if (creation <= ERTS_MAX_LOCAL_CREATION) { - *tagp = PID_EXT; - *ep++ = creation; - } else { - ASSERT(is_external_pid(pid)); - *tagp = NEW_PID_EXT; - put_int32(creation, ep); - ep += 4; - } + put_int32(creation, ep); + ep += 4; return ep; } @@ -2520,7 +2513,7 @@ dec_pid(ErtsDistExternal *edep, ErtsHeapFactory* factory, byte* ep, if (tag == PID_EXT) { cre = get_int8(ep); ep += 1; - if (!is_valid_creation(cre)) { + if (!is_tiny_creation(cre)) { return NULL; } } else { @@ -2781,25 +2774,18 @@ enc_term_int(TTBEncodeContext* ctx, ErtsAtomCacheMap *acmp, Eterm obj, byte* ep, Eterm sysname = (((dflags & DFLAG_INTERNAL_TAGS) && is_internal_ref(obj)) ? INTERNAL_LOCAL_SYSNAME : ref_node_name(obj)); Uint32 creation = ref_creation(obj); - byte* tagp = ep++; ASSERT(dflags & DFLAG_EXTENDED_REFERENCES); erts_magic_ref_save_bin(obj); + *ep++ = NEWER_REFERENCE_EXT; i = ref_no_numbers(obj); put_int16(i, ep); ep += 2; ep = enc_atom(acmp, sysname, ep, dflags); - if (creation <= ERTS_MAX_LOCAL_CREATION) { - *tagp = NEW_REFERENCE_EXT; - *ep++ = creation; - } else { - ASSERT(is_external_ref(obj)); - *tagp = NEWER_REFERENCE_EXT; - put_int32(creation, ep); - ep += 4; - } + put_int32(creation, ep); + ep += 4; ref_num = ref_numbers(obj); for (j = 0; j < i; j++) { put_int32(ref_num[j], ep); @@ -2812,21 +2798,14 @@ enc_term_int(TTBEncodeContext* ctx, ErtsAtomCacheMap *acmp, Eterm obj, byte* ep, Eterm sysname = (((dflags & DFLAG_INTERNAL_TAGS) && is_internal_port(obj)) ? INTERNAL_LOCAL_SYSNAME : port_node_name(obj)); Uint32 creation = port_creation(obj); - byte* tagp = ep++; + *ep++ = NEW_PORT_EXT; ep = enc_atom(acmp, sysname, ep, dflags); j = port_number(obj); put_int32(j, ep); ep += 4; - if (creation <= ERTS_MAX_LOCAL_CREATION) { - *tagp = PORT_EXT; - *ep++ = creation; - } else { - ASSERT(is_external_port(obj)); - *tagp = NEW_PORT_EXT; - put_int32(creation, ep); - ep += 4; - } + put_int32(creation, ep); + ep += 4; break; } case LIST_DEF: @@ -3521,7 +3500,7 @@ dec_term_atom_common: if (tag == PORT_EXT) { cre = get_int8(ep); ep++; - if (!is_valid_creation(cre)) { + if (!is_tiny_creation(cre)) { goto error; } } @@ -3568,7 +3547,7 @@ dec_term_atom_common: cre = get_int8(ep); ep += 1; - if (!is_valid_creation(cre)) { + if (!is_tiny_creation(cre)) { goto error; } goto ref_ext_common; @@ -3582,7 +3561,7 @@ dec_term_atom_common: cre = get_int8(ep); ep += 1; - if (!is_valid_creation(cre)) { + if (!is_tiny_creation(cre)) { goto error; } r0 = get_int32(ep); @@ -3600,7 +3579,7 @@ dec_term_atom_common: cre = get_int32(ep); ep += 4; - r0 = get_int32(ep); /* allow full word */ + r0 = get_int32(ep); ep += 4; ref_ext_common: { @@ -3611,6 +3590,13 @@ dec_term_atom_common: node = dec_get_node(sysname, cre, make_boxed(hp)); if(node == erts_this_node) { + if (r0 >= MAX_REFERENCE) { + /* + * Must reject local refs with more than 18 bits + * in first word as magic ref table relies on it. + */ + goto error; + } rtp = (ErtsORefThing *) hp; ref_num = &rtp->num[0]; @@ -4273,30 +4259,21 @@ encode_size_struct_int(TTBSizeContext* ctx, ErtsAtomCacheMap *acmp, Eterm obj, result += 1 + 4 + 1 + i; /* tag,size,sign,digits */ break; case EXTERNAL_PID_DEF: - if (external_pid_creation(obj) > ERTS_MAX_LOCAL_CREATION) - result += 3; - /*fall through*/ case PID_DEF: result += (1 + encode_size_struct2(acmp, pid_node_name(obj), dflags) + - 4 + 4 + 1); + 4 + 4 + 4); break; case EXTERNAL_REF_DEF: - if (external_ref_creation(obj) > ERTS_MAX_LOCAL_CREATION) - result += 3; - /*fall through*/ case REF_DEF: ASSERT(dflags & DFLAG_EXTENDED_REFERENCES); i = ref_no_numbers(obj); result += (1 + 2 + encode_size_struct2(acmp, ref_node_name(obj), dflags) + - 1 + 4*i); + 4 + 4*i); break; case EXTERNAL_PORT_DEF: - if (external_port_creation(obj) > ERTS_MAX_LOCAL_CREATION) - result += 3; - /*fall through*/ case PORT_DEF: result += (1 + encode_size_struct2(acmp, port_node_name(obj), dflags) + - 4 + 1); + 4 + 4); break; case LIST_DEF: { int is_str = is_external_string(obj, &m); diff --git a/erts/emulator/beam/msg_instrs.tab b/erts/emulator/beam/msg_instrs.tab index 6f8d1469ef..b08466c830 100644 --- a/erts/emulator/beam/msg_instrs.tab +++ b/erts/emulator/beam/msg_instrs.tab @@ -105,6 +105,7 @@ i_loop_rec(Dest) { $SET_CP_I_ABS(I); c_p->arity = 0; c_p->current = NULL; + c_p->fcalls = FCALLS; FCALLS -= erts_proc_sig_receive_helper(c_p, FCALLS, neg_o_reds, &msgp, &get_out); SWAPIN; diff --git a/erts/emulator/beam/ops.tab b/erts/emulator/beam/ops.tab index 6832e65b1b..7a125b0f67 100644 --- a/erts/emulator/beam/ops.tab +++ b/erts/emulator/beam/ops.tab @@ -338,7 +338,7 @@ swap_temp R1 R2 Tmp | line Loc | apply Live | is_killed_apply(Tmp, Live) => \ swap_temp R1 R2 Tmp | line Loc | apply_last Live D | is_killed_apply(Tmp, Live) => \ swap R1 R2 | line Loc | apply_last Live D -swap_temp R1 R2 Tmp | line Loc | call_fun Live | is_killed(Tmp, Live) => \ +swap_temp R1 R2 Tmp | line Loc | call_fun Live | is_killed_by_call_fun(Tmp, Live) => \ swap R1 R2 | line Loc | call_fun Live swap_temp R1 R2 Tmp | make_fun2 OldIndex=u | is_killed_by_make_fun(Tmp, OldIndex) => \ swap R1 R2 | make_fun2 OldIndex @@ -1262,7 +1262,6 @@ bs_get_binary2 Fail=f Ms=xy Live=u Sz=sq Unit=u Flags=u Dst=d => \ i_bs_get_binary_imm2 xy f? t W t d i_bs_get_binary2 xy f t? s t d i_bs_get_binary_all2 xy f? t t d -i_bs_get_binary_all_reuse xy f? t # Fetching float from binaries. bs_get_float2 Fail=f Ms=xy Live=u Sz=s Unit=u Flags=u Dst=d => \ diff --git a/erts/emulator/beam/utils.c b/erts/emulator/beam/utils.c index 36cfe0548e..0bbae65e28 100644 --- a/erts/emulator/beam/utils.c +++ b/erts/emulator/beam/utils.c @@ -1069,11 +1069,11 @@ do { \ #define HCONST 0x9e3779b9UL /* the golden ratio; an arbitrary value */ -Uint32 -block_hash(byte *k, unsigned length, Uint32 initval) +static Uint32 +block_hash(byte *k, Uint length, Uint32 initval) { Uint32 a,b,c; - unsigned len; + Uint len; /* Set up the internal state */ len = length; @@ -1749,7 +1749,7 @@ make_internal_hash(Eterm term, Uint32 salt) case SUB_BINARY_SUBTAG: { byte* bptr; - unsigned sz = binary_size(term); + Uint sz = binary_size(term); Uint32 con = HCONST_13 + hash; Uint bitoffs; Uint bitsize; diff --git a/erts/emulator/sys/common/erl_poll.c b/erts/emulator/sys/common/erl_poll.c index c71d23f58c..9662996039 100644 --- a/erts/emulator/sys/common/erl_poll.c +++ b/erts/emulator/sys/common/erl_poll.c @@ -2354,6 +2354,7 @@ uint32_t epoll_events(int kp_fd, int fd) fprintf(stderr,"failed to parse file %s on line %d, errno = %d\n", fname, line, errno); + fclose(f); return 0; } if (fd == ev_fd) { @@ -2408,6 +2409,7 @@ ERTS_POLL_EXPORT(erts_poll_get_selected_events)(ErtsPollSet *ps, if (fscanf(f,"pos:\t%x\nflags:\t%x", &pos, &flags) != 2) { fprintf(stderr,"failed to parse file %s, errno = %d\n", fname, errno); ASSERT(0); + fclose(f); return; } if (fscanf(f,"\nmnt_id:\t%x\n", &mnt_id)); @@ -2422,6 +2424,7 @@ ERTS_POLL_EXPORT(erts_poll_get_selected_events)(ErtsPollSet *ps, fprintf(stderr,"failed to parse file %s on line %d, errno = %d\n", fname, line, errno); ASSERT(0); + fclose(f); return; } if (fd == ps->wake_fds[0] || fd == ps->wake_fds[1]) @@ -2437,6 +2440,7 @@ ERTS_POLL_EXPORT(erts_poll_get_selected_events)(ErtsPollSet *ps, ev[fd] = (ERTS_POLL_EV_IN|ERTS_POLL_EV_OUT) & ERTS_POLL_EV_N2E(events); line++; } + fclose(f); #else for (fd = 0; fd < len; fd++) ev[fd] = ERTS_POLL_EV_NONE; diff --git a/erts/emulator/test/binary_SUITE.erl b/erts/emulator/test/binary_SUITE.erl index 1406ddc9dc..563d60cc3f 100644 --- a/erts/emulator/test/binary_SUITE.erl +++ b/erts/emulator/test/binary_SUITE.erl @@ -1703,13 +1703,16 @@ error_after_yield_bad_ext_term() -> BadAtomExt]). %% Invalid atom at the end cmp_old_impl(Config) when is_list(Config) -> - %% Compare results from new yielding implementations with - %% old non yielding implementations + %% This test was originally a comparison with the non yielding + %% implementation in R16B. Since OTP 22 we can't talk distribution with such + %% old nodes (< 19). The test case it kept but compares with previous major + %% version for semantic regression test. Cookie = atom_to_list(erlang:get_cookie()), - Rel = "r16b_latest", + Rel = (integer_to_list(list_to_integer(erlang:system_info(otp_release)) - 1) + ++ "_latest"), case test_server:is_release_available(Rel) of false -> - {skipped, "No "++Rel++" available"}; + {skipped, "No OTP "++Rel++" available"}; true -> {ok, Node} = test_server:start_node(list_to_atom(atom_to_list(?MODULE)++"_"++Rel), peer, diff --git a/erts/emulator/test/bs_match_misc_SUITE.erl b/erts/emulator/test/bs_match_misc_SUITE.erl index 17759d78f3..cae4eb54d2 100644 --- a/erts/emulator/test/bs_match_misc_SUITE.erl +++ b/erts/emulator/test/bs_match_misc_SUITE.erl @@ -24,7 +24,7 @@ kenneth/1,encode_binary/1,native/1,happi/1, size_var/1,wiger/1,x0_context/1,huge_float_field/1, writable_binary_matched/1,otp_7198/1,unordered_bindings/1, - float_middle_endian/1]). + float_middle_endian/1,unsafe_get_binary_reuse/1]). -include_lib("common_test/include/ct.hrl"). @@ -36,7 +36,8 @@ all() -> [bound_var, bound_tail, t_float, little_float, sean, kenneth, encode_binary, native, happi, size_var, wiger, x0_context, huge_float_field, writable_binary_matched, - otp_7198, unordered_bindings, float_middle_endian]. + otp_7198, unordered_bindings, float_middle_endian, + unsafe_get_binary_reuse]. %% Test matching of bound variables. @@ -556,5 +557,21 @@ unordered_bindings(CompressedLength, HashSize, PadLength, T) -> Padding:PadLength/binary,PadLength>> = T, {Content,Mac,Padding}. +%% ERL-901: A load-time optimization assumed that match contexts had no further +%% uses when a bs_get_binary2 overwrote the match context's register, and +%% figured it would be safe to reuse the match context's memory for the +%% resulting binary. +%% +%% This is no longer safe as of OTP 22, as a match context may be reused after +%% being passed to another function. +unsafe_get_binary_reuse(Config) when is_list(Config) -> + <<_First, Rest/binary>> = <<"hello">>, + ubgr_1(Rest), + <<Second,_/bits>> = Rest, + $e = Second, + ok. + +ubgr_1(<<_CP/utf8, Rest/binary>>) -> id(Rest); +ubgr_1(_) -> false. id(I) -> I. diff --git a/erts/emulator/test/distribution_SUITE.erl b/erts/emulator/test/distribution_SUITE.erl index 4f70b51aa0..449821e5ad 100644 --- a/erts/emulator/test/distribution_SUITE.erl +++ b/erts/emulator/test/distribution_SUITE.erl @@ -744,6 +744,7 @@ link_to_dead_new_node(Config) when is_list(Config) -> {'EXIT', Pid, noproc} -> ok; Other -> + stop_node(Node), ct:fail({unexpected_message, Other}) after 5000 -> ct:fail(nothing_received) @@ -1421,7 +1422,7 @@ message_latency_large_exit(Nodename, ReasonFun) -> FlushTrace = fun F() -> receive - {trace, Pid, _, _} = M -> + {trace, Pid, _, _} -> F() after 0 -> ok @@ -1455,8 +1456,14 @@ measure_latency_large_message(Nodename, DataFun) -> Echo = spawn(N, fun F() -> receive {From, Msg} -> From ! Msg, F() end end), - %% Test 32 MB and 320 MB and test the latency difference of sent messages - Payloads = [{I, <<0:(I * 32 * 1024 * 1024 * 8)>>} || I <- [1,10]], + case erlang:system_info(build_type) of + debug -> + %% Test 3.2 MB and 32 MB and test the latency difference of sent messages + Payloads = [{I, <<0:(I * 32 * 1024 * 8)>>} || I <- [1,10]]; + _ -> + %% Test 32 MB and 320 MB and test the latency difference of sent messages + Payloads = [{I, <<0:(I * 32 * 1024 * 1024 * 8)>>} || I <- [1,10]] + end, IndexTimes = [{I, measure_latency(DataFun, Dropper, Echo, P)} || {I, P} <- Payloads], @@ -1465,6 +1472,8 @@ measure_latency_large_message(Nodename, DataFun) -> ct:pal("~p",[IndexTimes]), + stop_node(N), + case {lists:max(Times), lists:min(Times)} of {Max, Min} when Max * 0.25 > Min -> ct:fail({incorrect_latency, IndexTimes}); @@ -1487,7 +1496,7 @@ measure_latency(DataFun, Dropper, Echo, Payload) -> end) || _ <- lists:seq(1,2)], [receive - {monitor, _Sender, busy_dist_port, _Info} = M -> + {monitor, _Sender, busy_dist_port, _Info} -> ok end || _ <- lists:seq(1,10)], @@ -1733,7 +1742,7 @@ bad_dist_fragments(Config) when is_list(Config) -> start_monitor(Offender,P), Exit2Victim = spawn(Victim, fun() -> receive ok -> ok end end), - send_bad_fragments(Offender, Victim, P,{?DOP_PAYLOAD_EXIT2,P,ExitVictim},2, + send_bad_fragments(Offender, Victim, P,{?DOP_PAYLOAD_EXIT2,P,Exit2Victim},2, [{hdr, 1, [132]}]), start_monitor(Offender,P), @@ -2428,17 +2437,22 @@ stop_node(Node) -> verify_nc(Node) -> P = self(), Ref = make_ref(), - spawn(Node, - fun() -> - R = erts_test_utils:check_node_dist(fun(E) -> E end), - P ! {Ref, R} - end), + Pid = spawn(Node, + fun() -> + R = erts_test_utils:check_node_dist(fun(E) -> E end), + P ! {Ref, R} + end), + MonRef = monitor(process, Pid), receive {Ref, ok} -> + demonitor(MonRef,[flush]), ok; {Ref, Error} -> - ct:log("~s",[Error]), - ct:fail(failed_nc_refc_check) + ct:log("~p",[Error]), + ct:fail(failed_nc_refc_check); + {'DOWN', MonRef, _, _, _} = Down -> + ct:log("~p",[Down]), + ct:fail(crashed_nc_refc_check) end. freeze_node(Node, MS) -> diff --git a/erts/emulator/test/dump_SUITE.erl b/erts/emulator/test/dump_SUITE.erl index d0237b78cc..3b860ebdf6 100644 --- a/erts/emulator/test/dump_SUITE.erl +++ b/erts/emulator/test/dump_SUITE.erl @@ -24,7 +24,7 @@ -export([all/0, suite/0, init_per_testcase/2, end_per_testcase/2]). --export([signal_abort/1]). +-export([signal_abort/1, exiting_dump/1, free_dump/1]). -export([load/0]). @@ -35,7 +35,7 @@ suite() -> {timetrap, {minutes, 2}}]. all() -> - [signal_abort]. + [signal_abort, exiting_dump, free_dump]. init_per_testcase(signal_abort, Config) -> SO = erlang:system_info(schedulers_online), @@ -48,7 +48,10 @@ init_per_testcase(signal_abort, Config) -> {skip, "the platform does not support scheduler dump"}; Dump -> Config - end. + end; +init_per_testcase(_, Config) -> + Config. + end_per_testcase(_, Config) -> Config. @@ -79,8 +82,6 @@ signal_abort(Config) -> {ok, Bin} = get_dump_when_done(Dump), - ct:log("~s",[Bin]), - {match, Matches} = re:run(Bin,"Current Process: <",[global]), ct:log("Found ~p",[Matches]), @@ -91,6 +92,85 @@ signal_abort(Config) -> ok. +load() -> + lists:seq(1,10000), + load(). + + +%% Test that crash dumping when a process is in the state EXITING works +exiting_dump(Config) when is_list(Config) -> + Dump = filename:join(proplists:get_value(priv_dir, Config),"signal_abort.dump"), + + {ok, Node} = start_node(Config), + + Self = self(), + + Pid = spawn_link(Node, + fun() -> + [begin + T = ets:new(hej,[]), + [ets:insert(T,{I,I}) || I <- lists:seq(1,1000)] + end || _ <- lists:seq(1,1000)], + Self ! ready, + receive ok -> ok end + end), + + true = rpc:call(Node, os, putenv, ["ERL_CRASH_DUMP",Dump]), + + receive ready -> unlink(Pid), Pid ! ok end, + + rpc:call(Node, erlang, halt, ["dump"]), + + {ok, Bin} = get_dump_when_done(Dump), + + {match, Matches} = re:run(Bin,"^State: Exiting", [global, multiline]), + + ct:log("Found ~p",[Matches]), + + true = length(Matches) == 1, + + file:delete(Dump), + + ok. + +%% Test that crash dumping when a process is in the state FREE works +free_dump(Config) when is_list(Config) -> + Dump = filename:join(proplists:get_value(priv_dir, Config),"signal_abort.dump"), + + {ok, Node} = start_node(Config), + + Self = self(), + + Pid = spawn_link(Node, + fun() -> + Self ! ready, + receive + ok -> + unlink(Self), + exit(lists:duplicate(1000,1000)) + end + end), + + true = rpc:call(Node, os, putenv, ["ERL_CRASH_DUMP",Dump]), + + [erlang:monitor(process, Pid) || _ <- lists:seq(1,10000)], + receive ready -> unlink(Pid), Pid ! ok end, + + rpc:call(Node, erlang, halt, ["dump"]), + + {ok, Bin} = get_dump_when_done(Dump), + + {match, Matches} = re:run(Bin,"^State: Non Existing", [global, multiline]), + + ct:log("Found ~p",[Matches]), + + true = length(Matches) == 1, + + file:delete(Dump), + + ok. + + get_dump_when_done(Dump) -> case file:read_file_info(Dump) of {ok, #file_info{ size = Sz }} -> @@ -104,15 +184,13 @@ get_dump_when_done(Dump, Sz) -> timer:sleep(1000), case file:read_file_info(Dump) of {ok, #file_info{ size = Sz }} -> - file:read_file(Dump); + {ok, Bin} = file:read_file(Dump), + ct:log("~s",[Bin]), + {ok, Bin}; {ok, #file_info{ size = NewSz }} -> get_dump_when_done(Dump, NewSz) end. -load() -> - lists:seq(1,10000), - load(). - start_node(Config) when is_list(Config) -> Pa = filename:dirname(code:which(?MODULE)), Name = list_to_atom(atom_to_list(?MODULE) diff --git a/erts/emulator/test/efile_SUITE.erl b/erts/emulator/test/efile_SUITE.erl index 7dcf302742..55c5343739 100644 --- a/erts/emulator/test/efile_SUITE.erl +++ b/erts/emulator/test/efile_SUITE.erl @@ -45,7 +45,12 @@ iter_max_files(Config) when is_list(Config) -> iter_max_files_1(Config) -> DataDir = proplists:get_value(data_dir,Config), TestFile = filename:join(DataDir, "existing_file"), - N = 10, + case erlang:system_info(debug_compiled) of + true -> + N = 5; + false -> + N = 10 + end, %% Run on a different node in order to make the test more stable. Dir = filename:dirname(code:which(?MODULE)), {ok,Node} = test_server:start_node(test_iter_max_files,slave, diff --git a/erts/emulator/test/erts_test_utils.erl b/erts/emulator/test/erts_test_utils.erl index 0c3ef3e0fc..e4e00a0a16 100644 --- a/erts/emulator/test/erts_test_utils.erl +++ b/erts/emulator/test/erts_test_utils.erl @@ -19,6 +19,7 @@ %% -module(erts_test_utils). +-compile(r16). %% %% THIS MODULE IS ALSO USED BY *OTHER* APPLICATIONS TEST CODE diff --git a/erts/emulator/test/fun_SUITE.erl b/erts/emulator/test/fun_SUITE.erl index 4042b58ff2..7f6caa08f1 100644 --- a/erts/emulator/test/fun_SUITE.erl +++ b/erts/emulator/test/fun_SUITE.erl @@ -592,7 +592,8 @@ refc_dist(Config) when is_list(Config) -> 3 = fun_refc(F2), true = erlang:garbage_collect(), 2 = fun_refc(F), - refc_dist_send(Node, F). + refc_dist_send(Node, F), + test_server:stop_node(Node). refc_dist_send(Node, F) -> Pid = spawn_link(Node, fun() -> receive @@ -682,6 +683,7 @@ t_arity(Config) when is_list(Config) -> 43 = spawn_call(Node, fun(X, Y) -> A+X+Y end), 1 = spawn_call(Node, fun(X, Y) -> X+Y end), 45 = spawn_call(Node, fun(X, Y, Z) -> A+X+Y+Z end), + test_server:stop_node(Node), ok. t_is_function2(Config) when is_list(Config) -> diff --git a/erts/emulator/test/map_SUITE.erl b/erts/emulator/test/map_SUITE.erl index d0a6763fe5..9ea59e1084 100644 --- a/erts/emulator/test/map_SUITE.erl +++ b/erts/emulator/test/map_SUITE.erl @@ -17,7 +17,7 @@ %% %CopyrightEnd% %% -module(map_SUITE). --export([all/0, suite/0]). +-export([all/0, suite/0, init_per_suite/1, end_per_suite/1]). -export([t_build_and_match_literals/1, t_build_and_match_literals_large/1, t_update_literals/1, t_update_literals_large/1, @@ -84,7 +84,10 @@ %% instruction-level tests t_has_map_fields/1, y_regs/1, - badmap_17/1]). + badmap_17/1, + + %%Bugs + t_large_unequal_bins_same_hash_bug/1]). -include_lib("stdlib/include/ms_transform.hrl"). @@ -149,7 +152,26 @@ all() -> [t_build_and_match_literals, t_build_and_match_literals_large, %% instruction-level tests t_has_map_fields, y_regs, - badmap_17]. + badmap_17, + + %% Bugs + t_large_unequal_bins_same_hash_bug]. + +init_per_suite(Config) -> + A0 = case application:start(sasl) of + ok -> [sasl]; + _ -> [] + end, + A = case application:start(os_mon) of + ok -> [os_mon|A0]; + _ -> A0 + end, + [{started_apps, A}|Config]. + +end_per_suite(Config) -> + As = proplists:get_value(started_apps, Config), + lists:foreach(fun (A) -> application:stop(A) end, As), + Config. %% tests @@ -3374,3 +3396,67 @@ fannerl() -> 104,2,97,9,97,16,70,63,184,100,97,32,0,0,0,104,2,97,10,97,16,70,63,169,174, 254,64,0,0,0,104,2,97,11,97,16,70,191,119,121,234,0,0,0,0,104,2,97,12,97, 16,70,63,149,12,170,128,0,0,0,104,2,97,13,97,16,70,191,144,193,191,0,0,0,0>>. + +%% This test case checks that the bug with ticket number OTP-15707 is +%% fixed. The bug could cause a crash or memory usage to grow until +%% the machine ran out of memory. +t_large_unequal_bins_same_hash_bug(Config) when is_list(Config) -> + run_when_enough_resources( + fun() -> + K1 = get_4GB_bin(1), + K2 = get_4GB_bin(2), + Map = make_map(500), + Map2 = maps:put(K1, 42, Map), + %% The map needed to contain at least 32 key-value pairs + %% at this point to get the crash or out of memory + %% problem on the next line + Map3 = maps:put(K2, 43, Map2), + %% The following line should avoid that the compiler + %% optimizes away the above + io:format("~p ~p~n", [erlang:phash2(Map3), maps:size(Map3)]) + end). + +make_map(0) -> + #{}; +make_map(Size) -> + maps:put(Size, Size, make_map(Size-1)). + +get_4GB_bin(Value) -> + List = lists:duplicate(65536, Value), + Bin = erlang:iolist_to_binary(List), + IOList4GB = duplicate_iolist(Bin, 16), + Bin4GB = erlang:iolist_to_binary(IOList4GB), + 4294967296 = size(Bin4GB), + Bin4GB. + +duplicate_iolist(IOList, 0) -> + IOList; +duplicate_iolist(IOList, NrOfTimes) -> + duplicate_iolist([IOList, IOList], NrOfTimes - 1). + +run_when_enough_resources(Fun) -> + case {total_memory(), erlang:system_info(wordsize)} of + {Mem, 8} when is_integer(Mem) andalso Mem >= 31 -> + Fun(); + {Mem, WordSize} -> + {skipped, + io_lib:format("Not enough resources (System Memory >= ~p, Word Size = ~p)", + [Mem, WordSize])} + end. + +total_memory() -> + %% Total memory in GB. + try + MemoryData = memsup:get_system_memory_data(), + case lists:keysearch(total_memory, 1, MemoryData) of + {value, {total_memory, TM}} -> + TM div (1024*1024*1024); + false -> + {value, {system_total_memory, STM}} = + lists:keysearch(system_total_memory, 1, MemoryData), + STM div (1024*1024*1024) + end + catch + _ : _ -> + undefined + end. diff --git a/erts/emulator/test/process_SUITE.erl b/erts/emulator/test/process_SUITE.erl index edf08ce0bd..b530ced566 100644 --- a/erts/emulator/test/process_SUITE.erl +++ b/erts/emulator/test/process_SUITE.erl @@ -44,6 +44,7 @@ process_info_garbage_collection/1, process_info_smoke_all/1, process_info_status_handled_signal/1, + process_info_reductions/1, bump_reductions/1, low_prio/1, binary_owner/1, yield/1, yield2/1, otp_4725/1, bad_register/1, garbage_collect/1, otp_6237/1, process_info_messages/1, process_flag_badarg/1, process_flag_heap_size/1, @@ -84,6 +85,7 @@ all() -> process_info_garbage_collection, process_info_smoke_all, process_info_status_handled_signal, + process_info_reductions, bump_reductions, low_prio, yield, yield2, otp_4725, bad_register, garbage_collect, process_info_messages, process_flag_badarg, process_flag_heap_size, @@ -133,6 +135,15 @@ init_per_group(_GroupName, Config) -> end_per_group(_GroupName, Config) -> Config. +init_per_testcase(Func, Config) + when Func =:= processes_default_tab; + Func =:= processes_this_tab -> + case erlang:system_info(debug_compiled) of + true -> + {skip, "Don't run in debug"}; + false -> + [{testcase, Func} | Config] + end; init_per_testcase(Func, Config) when is_atom(Func), is_list(Config) -> [{testcase, Func}|Config]. @@ -1084,6 +1095,46 @@ process_info_status_handled_signal(Config) when is_list(Config) -> false = erlang:is_process_alive(P), ok. +%% OTP-15709 +%% Provoke a bug where process_info(reductions) returned wrong result +%% because REDS_IN (def_arg_reg[5]) is read when the process in not running. +process_info_reductions(Config) when is_list(Config) -> + pi_reductions_tester(spawn_link(fun() -> pi_reductions_spinnloop() end)), + pi_reductions_tester(spawn_link(fun() -> pi_reductions_recvloop() end)), + ok. + +pi_reductions_tester(Pid) -> + {_, DiffList} = + lists:foldl(fun(_, {Prev, Acc}) -> + %% Add another item that force sending the request + %% as a signal, like 'current_function'. + PI = process_info(Pid, [reductions, current_function]), + [{reductions,Reds}, {current_function,_}] = PI, + Diff = Reds - Prev, + {Diff, true} = {Diff, (Diff >= 0)}, + {Diff, true} = {Diff, (Diff =< 1000*1000)}, + {Reds, [Diff | Acc]} + end, + {0, []}, + lists:seq(1,10)), + unlink(Pid), + exit(Pid,kill), + io:format("Reduction diffs: ~p\n", [DiffList]), + ok. + +pi_reductions_spinnloop() -> + %% 6 args to make use of def_arg_reg[5] which is also used as REDS_IN + pi_reductions_spinnloop(1, atom, "hej", self(), make_ref(), 3.14). + +pi_reductions_spinnloop(A,B,C,D,E,F) -> + pi_reductions_spinnloop(B,C,D,E,F,A). + +pi_reductions_recvloop() -> + receive + "a free lunch" -> false + end. + + %% Tests erlang:bump_reductions/1. bump_reductions(Config) when is_list(Config) -> erlang:garbage_collect(), diff --git a/erts/epmd/epmd.mk b/erts/epmd/epmd.mk index b1fd04dc04..f6889a7ff1 100644 --- a/erts/epmd/epmd.mk +++ b/erts/epmd/epmd.mk @@ -67,5 +67,5 @@ EPMD_NODE_TYPE=110 # Distribution format 5 contains the new md5 based handshake. EPMD_DIST_LOW=5 -EPMD_DIST_HIGH=5 +EPMD_DIST_HIGH=6 diff --git a/erts/epmd/src/epmd.h b/erts/epmd/src/epmd.h index cffcd4ae7a..7332294d3d 100644 --- a/erts/epmd/src/epmd.h +++ b/erts/epmd/src/epmd.h @@ -26,6 +26,7 @@ #define EPMD_ALIVE2_REQ 'x' #define EPMD_PORT2_REQ 'z' #define EPMD_ALIVE2_RESP 'y' +#define EPMD_ALIVE2_X_RESP 'v' #define EPMD_PORT2_RESP 'w' #define EPMD_NAMES_REQ 'n' diff --git a/erts/epmd/src/epmd_int.h b/erts/epmd/src/epmd_int.h index ed9bbdb8cd..a5156a142e 100644 --- a/erts/epmd/src/epmd_int.h +++ b/erts/epmd/src/epmd_int.h @@ -277,6 +277,12 @@ static const struct in6_addr in6addr_loopback = #define put_int16(i, s) {((unsigned char*)(s))[0] = ((i) >> 8) & 0xff; \ ((unsigned char*)(s))[1] = (i) & 0xff;} +#define put_int32(i, s) do {((char*)(s))[0] = (char)((i) >> 24) & 0xff; \ + ((char*)(s))[1] = (char)((i) >> 16) & 0xff; \ + ((char*)(s))[2] = (char)((i) >> 8) & 0xff; \ + ((char*)(s))[3] = (char)(i) & 0xff;} \ + while (0) + #if defined(__GNUC__) # define EPMD_INLINE __inline__ #elif defined(__WIN32__) @@ -307,10 +313,10 @@ struct enode { int fd; /* The socket in use */ unsigned short port; /* Port number of Erlang node */ char symname[MAXSYMLEN+1]; /* Name of the Erlang node */ - short creation; /* Started as a random number 1..3 */ + unsigned int cr_counter; /* Used to generate 'creation' numbers */ char nodetype; /* 77 = normal erlang node 72 = hidden (c-node */ char protocol; /* 0 = tcp/ipv4 */ - unsigned short highvsn; /* 0 = OTP-R3 erts-4.6.x, 1 = OTP-R4 erts-4.7.x*/ + unsigned short highvsn; /* 5: creation=1..3, 6: creation=1..(2^32-1)*/ unsigned short lowvsn; int extralen; char extra[MAXSYMLEN+1]; diff --git a/erts/epmd/src/epmd_srv.c b/erts/epmd/src/epmd_srv.c index 66c10a65bc..633ec71e5f 100644 --- a/erts/epmd/src/epmd_srv.c +++ b/erts/epmd/src/epmd_srv.c @@ -665,6 +665,21 @@ static int do_accept(EpmdVars *g,int listensock) return conn_open(g,msgsock); } +static void bump_creation(Node* node) +{ + if (++node->cr_counter == 0) + node->cr_counter = 1; +} +static unsigned int get_creation(Node* node) +{ + if (node->highvsn >= 6) { + return node->cr_counter; /* 1..(2^32-1)*/ + } + else { + return (node->cr_counter - 1) % 3 + 1; /* 1..3 */ + } +} + /* buf is actually one byte larger than bsize, giving place for null termination */ static void do_request(g, fd, s, buf, bsize) @@ -706,8 +721,10 @@ static void do_request(g, fd, s, buf, bsize) unsigned char protocol; unsigned short highvsn; unsigned short lowvsn; + unsigned int creation; int namelen; int extralen; + int replylen; char *name; char *extra; eport = get_int16(&buf[1]); @@ -737,17 +754,22 @@ static void do_request(g, fd, s, buf, bsize) extra = &buf[11+namelen+2]; extra[extralen]='\000'; - wbuf[0] = EPMD_ALIVE2_RESP; - if ((node = node_reg2(g, namelen, name, fd, eport, nodetype, protocol, - highvsn, lowvsn, extralen, extra)) == NULL) { - wbuf[1] = 1; /* error */ - put_int16(99, wbuf+2); - } else { - wbuf[1] = 0; /* ok */ - put_int16(node->creation, wbuf+2); - } + node = node_reg2(g, namelen, name, fd, eport, nodetype, protocol, + highvsn, lowvsn, extralen, extra); + creation = node ? get_creation(node) : 99; + wbuf[1] = node ? 0 : 1; /* ok | error */ + if (highvsn >= 6) { + wbuf[0] = EPMD_ALIVE2_X_RESP; + put_int32(creation, wbuf+2); + replylen = 6; + } + else { + wbuf[0] = EPMD_ALIVE2_RESP; + put_int16(creation, wbuf+2); + replylen = 4; + } - if (reply(g, fd, wbuf, 4) != 4) + if (!reply(g, fd, wbuf, replylen)) { node_unreg(g, name); dbg_tty_printf(g,1,"** failed to send ALIVE2_RESP for \"%s\"", @@ -807,7 +829,7 @@ static void do_request(g, fd, s, buf, bsize) offset += 2; memcpy(wbuf + offset,node->extra,node->extralen); offset += node->extralen; - if (reply(g, fd, wbuf, offset) != offset) + if (!reply(g, fd, wbuf, offset)) { dbg_tty_printf(g,1,"** failed to send PORT2_RESP (ok) for \"%s\"",name); return; @@ -817,7 +839,7 @@ static void do_request(g, fd, s, buf, bsize) } } wbuf[1] = 1; /* error */ - if (reply(g, fd, wbuf, 2) != 2) + if (!reply(g, fd, wbuf, 2)) { dbg_tty_printf(g,1,"** failed to send PORT2_RESP (error) for \"%s\"",name); return; @@ -835,7 +857,7 @@ static void do_request(g, fd, s, buf, bsize) i = htonl(g->port); memcpy(wbuf,&i,4); - if (reply(g, fd,wbuf,4) != 4) + if (!reply(g, fd,wbuf,4)) { dbg_tty_printf(g,1,"failed to send NAMES_RESP"); return; @@ -856,7 +878,7 @@ static void do_request(g, fd, s, buf, bsize) if (r < 0) goto failed_names_resp; len += r; - if (reply(g, fd, wbuf, len) != len) + if (!reply(g, fd, wbuf, len)) { failed_names_resp: dbg_tty_printf(g,1,"failed to send NAMES_RESP"); @@ -878,7 +900,7 @@ static void do_request(g, fd, s, buf, bsize) i = htonl(g->port); memcpy(wbuf,&i,4); - if (reply(g, fd,wbuf,4) != 4) + if (!reply(g, fd,wbuf,4)) { dbg_tty_printf(g,1,"failed to send DUMP_RESP"); return; @@ -899,7 +921,7 @@ static void do_request(g, fd, s, buf, bsize) if (r < 0) goto failed_dump_resp; len += r + 1; - if (reply(g, fd,wbuf,len) != len) + if (!reply(g, fd,wbuf,len)) { failed_dump_resp: dbg_tty_printf(g,1,"failed to send DUMP_RESP"); @@ -922,7 +944,7 @@ static void do_request(g, fd, s, buf, bsize) if (r < 0) goto failed_dump_resp2; len += r + 1; - if (reply(g, fd,wbuf,len) != len) + if (!reply(g, fd,wbuf,len)) { failed_dump_resp2: dbg_tty_printf(g,1,"failed to send DUMP_RESP"); @@ -942,12 +964,12 @@ static void do_request(g, fd, s, buf, bsize) if (!g->brutal_kill && (g->nodes.reg != NULL)) { dbg_printf(g,0,"Disallowed KILL_REQ, live nodes"); - if (reply(g, fd,"NO",2) != 2) + if (!reply(g, fd,"NO",2)) dbg_printf(g,0,"failed to send reply to KILL_REQ"); return; } - if (reply(g, fd,"OK",2) != 2) + if (!reply(g, fd,"OK",2)) dbg_printf(g,0,"failed to send reply to KILL_REQ"); dbg_tty_printf(g,1,"epmd killed"); conn_close_fd(g,fd); /* We never return to caller so close here */ @@ -977,7 +999,7 @@ static void do_request(g, fd, s, buf, bsize) if ((node_fd = node_unreg(g,name)) < 0) { - if (reply(g, fd,"NOEXIST",7) != 7) + if (!reply(g, fd,"NOEXIST",7)) { dbg_tty_printf(g,1,"failed to send STOP_RESP NOEXIST"); return; @@ -988,7 +1010,7 @@ static void do_request(g, fd, s, buf, bsize) conn_close_fd(g,node_fd); dbg_tty_printf(g,1,"epmd connection stopped"); - if (reply(g, fd,"STOPPED",7) != 7) + if (!reply(g, fd,"STOPPED",7)) { dbg_tty_printf(g,1,"failed to send STOP_RESP STOPPED"); return; @@ -1200,8 +1222,8 @@ static int node_unreg(EpmdVars *g,char *name) for (; node; prev = &node->next, node = node->next) if (is_same_str(node->symname, name)) { - dbg_tty_printf(g,1,"unregistering '%s:%d', port %d", - node->symname, node->creation, node->port); + dbg_tty_printf(g,1,"unregistering '%s:%u', port %d", + node->symname, get_creation(node), node->port); *prev = node->next; /* Link out from "reg" list */ @@ -1235,8 +1257,8 @@ static int node_unreg_sock(EpmdVars *g,int fd) for (; node; prev = &node->next, node = node->next) if (node->fd == fd) { - dbg_tty_printf(g,1,"unregistering '%s:%d', port %d", - node->symname, node->creation, node->port); + dbg_tty_printf(g,1,"unregistering '%s:%u', port %d", + node->symname, get_creation(node), node->port); *prev = node->next; /* Link out from "reg" list */ @@ -1264,19 +1286,8 @@ static int node_unreg_sock(EpmdVars *g,int fd) } /* - * Finding a node slot and a (name,creation) name is a bit tricky. - * We try in order - * - * 1. If the name was used before and we can reuse that slot but use - * a new "creation" digit in the range 1..3. - * - * 2. We try to find a new unused slot. - * - * 3. We try to use an used slot this isn't used any longer. - * FIXME: The criteria for *what* slot to steal should be improved. - * Perhaps use the oldest or something. + * Register a new node */ - static Node *node_reg2(EpmdVars *g, int namelen, char* name, @@ -1346,7 +1357,7 @@ static Node *node_reg2(EpmdVars *g, } /* Try to find the name in the used queue so that we - can change "creation" number 1..3 */ + can change "creation" number */ prev = NULL; @@ -1375,9 +1386,8 @@ static Node *node_reg2(EpmdVars *g, g->nodes.unreg_count--; - /* When reusing we change the "creation" number 1..3 */ - - node->creation = node->creation % 3 + 1; + /* When reusing we change the "creation" number */ + bump_creation(node); break; } @@ -1404,7 +1414,8 @@ static Node *node_reg2(EpmdVars *g, exit(1); } - node->creation = (current_time(g) % 3) + 1; /* "random" 1-3 */ + node->cr_counter = current_time(g); /* "random" */ + bump_creation(node); } } @@ -1423,11 +1434,11 @@ static Node *node_reg2(EpmdVars *g, select_fd_set(g, fd); if (highvsn == 0) { - dbg_tty_printf(g,1,"registering '%s:%d', port %d", - node->symname, node->creation, node->port); + dbg_tty_printf(g,1,"registering '%s:%u', port %d", + node->symname, get_creation(node), node->port); } else { - dbg_tty_printf(g,1,"registering '%s:%d', port %d", - node->symname, node->creation, node->port); + dbg_tty_printf(g,1,"registering '%s:%u', port %d", + node->symname, get_creation(node), node->port); dbg_tty_printf(g,1,"type %d proto %d highvsn %d lowvsn %d", nodetype, protocol, highvsn, lowvsn); } @@ -1448,7 +1459,9 @@ static time_t current_time(EpmdVars *g) static int reply(EpmdVars *g,int fd,char *buf,int len) { - int val; + char* p = buf; + int nbytes = len; + int val, ret; if (len < 0) { @@ -1459,15 +1472,27 @@ static int reply(EpmdVars *g,int fd,char *buf,int len) if (g->delay_write) /* Test of busy server */ sleep(g->delay_write); - val = write(fd,buf,len); - if (val < 0) - dbg_perror(g,"error in write"); - else if (val != len) - dbg_printf(g,0,"could only send %d bytes out of %d to fd %d",val,len,fd); + for (;;) { + val = write(fd, p, nbytes); + if (val == nbytes) { + ret = 1; + break; + } + if (val < 0) { + if (errno == EINTR) + continue; + dbg_perror(g,"error in write, errno=%d", errno); + ret = 0; + break; + } + dbg_printf(g,0,"could only send %d bytes out of %d to fd %d",val,nbytes,fd); + p += val; + nbytes -= val; + } dbg_print_buf(g,buf,len); - return val; + return ret; } @@ -1547,8 +1572,8 @@ static void print_names(EpmdVars *g) for (node = g->nodes.reg; node; node = node->next) { - fprintf(stderr,"***** active name \"%s#%d\" at port %d, fd = %d\r\n", - node->symname, node->creation, node->port, node->fd); + fprintf(stderr,"***** active name \"%s#%u\" at port %d, fd = %d\r\n", + node->symname, get_creation(node), node->port, node->fd); count ++; } @@ -1558,8 +1583,8 @@ static void print_names(EpmdVars *g) for (node = g->nodes.unreg; node; node = node->next) { - fprintf(stderr,"***** old/unused name \"%s#%d\"\r\n", - node->symname, node->creation); + fprintf(stderr,"***** old/unused name \"%s#%u\"\r\n", + node->symname, get_creation(node)); count ++; } diff --git a/erts/etc/unix/etp-commands.in b/erts/etc/unix/etp-commands.in index e8dc59156f..dc28107ef5 100644 --- a/erts/etc/unix/etp-commands.in +++ b/erts/etc/unix/etp-commands.in @@ -1453,8 +1453,10 @@ define etp-stack-preamble set $etp_stack_p = ($arg0)->stop set $etp_stack_end = ($arg0)->hend printf "%% Stacktrace (%u)\n", $etp_stack_end-$etp_stack_p - etp-1 ((Eterm)($arg0)->i) 0 - printf " (I)\n" + if ($arg0)->i != 0 + etp-1 ((Eterm)($arg0)->i) 0 + printf " (I)\n" + end if ($arg0)->cp != 0 etp-1 ((Eterm)($arg0)->cp) 0 printf " (cp)\n" diff --git a/erts/test/erl_print_SUITE.erl b/erts/test/erl_print_SUITE.erl index 463d890688..0a5987df88 100644 --- a/erts/test/erl_print_SUITE.erl +++ b/erts/test/erl_print_SUITE.erl @@ -324,6 +324,9 @@ run_case(Config, TestArgs, Fun) -> -define(PORT_EXT, 102). -define(PID_EXT, 103). -define(NEW_REFERENCE_EXT, 114). +-define(NEW_PID_EXT, $X). +-define(NEW_PORT_EXT, $Y). +-define(NEWER_REFERENCE_EXT, $Z). uint32_be(Uint) when is_integer(Uint), 0 =< Uint, Uint < 1 bsl 32 -> [(Uint bsr 24) band 16#ff, @@ -351,13 +354,13 @@ mk_pid({NodeName, Creation}, Number, Serial) when is_atom(NodeName) -> mk_pid({atom_to_list(NodeName), Creation}, Number, Serial); mk_pid({NodeName, Creation}, Number, Serial) -> case catch binary_to_term(list_to_binary([?VERSION_MAGIC, - ?PID_EXT, + ?NEW_PID_EXT, ?ATOM_EXT, uint16_be(length(NodeName)), NodeName, uint32_be(Number), uint32_be(Serial), - uint8(Creation)])) of + uint32_be(Creation)])) of Pid when is_pid(Pid) -> Pid; {'EXIT', {badarg, _}} -> @@ -370,12 +373,12 @@ mk_port({NodeName, Creation}, Number) when is_atom(NodeName) -> mk_port({atom_to_list(NodeName), Creation}, Number); mk_port({NodeName, Creation}, Number) -> case catch binary_to_term(list_to_binary([?VERSION_MAGIC, - ?PORT_EXT, + ?NEW_PORT_EXT, ?ATOM_EXT, uint16_be(length(NodeName)), NodeName, uint32_be(Number), - uint8(Creation)])) of + uint32_be(Creation)])) of Port when is_port(Port) -> Port; {'EXIT', {badarg, _}} -> @@ -388,33 +391,16 @@ mk_ref({NodeName, Creation}, Numbers) when is_atom(NodeName), is_integer(Creation), is_list(Numbers) -> mk_ref({atom_to_list(NodeName), Creation}, Numbers); -mk_ref({NodeName, Creation}, [Number]) when is_list(NodeName), - is_integer(Creation), - is_integer(Number) -> - case catch binary_to_term(list_to_binary([?VERSION_MAGIC, - ?REFERENCE_EXT, - ?ATOM_EXT, - uint16_be(length(NodeName)), - NodeName, - uint32_be(Number), - uint8(Creation)])) of - Ref when is_reference(Ref) -> - Ref; - {'EXIT', {badarg, _}} -> - exit({badarg, mk_ref, [{NodeName, Creation}, [Number]]}); - Other -> - exit({unexpected_binary_to_term_result, Other}) - end; mk_ref({NodeName, Creation}, Numbers) when is_list(NodeName), is_integer(Creation), is_list(Numbers) -> case catch binary_to_term(list_to_binary([?VERSION_MAGIC, - ?NEW_REFERENCE_EXT, + ?NEWER_REFERENCE_EXT, uint16_be(length(Numbers)), ?ATOM_EXT, uint16_be(length(NodeName)), NodeName, - uint8(Creation), + uint32_be(Creation), lists:map(fun (N) -> uint32_be(N) end, @@ -429,11 +415,10 @@ mk_ref({NodeName, Creation}, Numbers) when is_list(NodeName), my_cre() -> erlang:system_info(creation). -oth_cre(0) -> 1; -oth_cre(1) -> 2; -oth_cre(2) -> 3; -oth_cre(3) -> 1; -oth_cre(N) -> exit({invalid_creation, N}). +oth_cre(N) when N >= 0, N < (1 bsl 32) -> + (N rem ((1 bsl 32) - 1)) + 1; +oth_cre(N) -> + exit({invalid_creation, N}). str_1_bsl_10000() -> "19950631168807583848837421626835850838234968318861924548520089498529438830221946631919961684036194597899331129423209124271556491349413781117593785932096323957855730046793794526765246551266059895520550086918193311542508608460618104685509074866089624888090489894838009253941633257850621568309473902556912388065225096643874441046759871626985453222868538161694315775629640762836880760732228535091641476183956381458969463899410840960536267821064621427333394036525565649530603142680234969400335934316651459297773279665775606172582031407994198179607378245683762280037302885487251900834464581454650557929601414833921615734588139257095379769119277800826957735674444123062018757836325502728323789270710373802866393031428133241401624195671690574061419654342324638801248856147305207431992259611796250130992860241708340807605932320161268492288496255841312844061536738951487114256315111089745514203313820202931640957596464756010405845841566072044962867016515061920631004186422275908670900574606417856951911456055068251250406007519842261898059237118054444788072906395242548339221982707404473162376760846613033778706039803413197133493654622700563169937455508241780972810983291314403571877524768509857276937926433221599399876886660808368837838027643282775172273657572744784112294389733810861607423253291974813120197604178281965697475898164531258434135959862784130128185406283476649088690521047580882615823961985770122407044330583075869039319604603404973156583208672105913300903752823415539745394397715257455290510212310947321610753474825740775273986348298498340756937955646638621874569499279016572103701364433135817214311791398222983845847334440270964182851005072927748364550578634501100852987812389473928699540834346158807043959118985815145779177143619698728131459483783202081474982171858011389071228250905826817436220577475921417653715687725614904582904992461028630081535583308130101987675856234343538955409175623400844887526162643568648833519463720377293240094456246923254350400678027273837755376406726898636241037491410966718557050759098100246789880178271925953381282421954028302759408448955014676668389697996886241636313376393903373455801407636741877711055384225739499110186468219696581651485130494222369947714763069155468217682876200362777257723781365331611196811280792669481887201298643660768551639860534602297871557517947385246369446923087894265948217008051120322365496288169035739121368338393591756418733850510970271613915439590991598154654417336311656936031122249937969999226781732358023111862644575299135758175008199839236284615249881088960232244362173771618086357015468484058622329792853875623486556440536962622018963571028812361567512543338303270029097668650568557157505516727518899194129711337690149916181315171544007728650573189557450920330185304847113818315407324053319038462084036421763703911550639789000742853672196280903477974533320468368795868580237952218629120080742819551317948157624448298518461509704888027274721574688131594750409732115080498190455803416826949787141316063210686391511681774304792596709376". |