From 7149d49992fb1a13c6753638733b59015c28c0a5 Mon Sep 17 00:00:00 2001 From: Lukas Larsson Date: Mon, 25 Mar 2019 11:45:50 +0100 Subject: erts: Fix so that exit/down terms stay alive When the GC is run or the link/monitor node is deleted, the terms associated with it will also be deallocated so we have to make sure that we don't do any GCs and that all link/monitor nodes are copied onto the heap before the node is deallocated. --- erts/emulator/beam/erl_process.c | 43 ++++++++++++++++++++++++++++++---------- 1 file changed, 33 insertions(+), 10 deletions(-) (limited to 'erts') diff --git a/erts/emulator/beam/erl_process.c b/erts/emulator/beam/erl_process.c index f34289339f..6a0c5bde58 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; @@ -12878,7 +12900,7 @@ restart: 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)) -- cgit v1.2.3