static void insert_offheap(ErlOffHeap *oh, int type, Eterm id) { union erl_off_heap_ptr u; struct insert_offheap2_arg a; a.type = BIN_REF; for (u.hdr = oh->first; u.hdr; u.hdr = u.hdr->next) { switch (thing_subtag(u.hdr->thing_word)) { case REFC_BINARY_SUBTAG: if(IsMatchProgBinary(u.pb->val)) { InsertedBin *ib; int insert_bin = 1; for (ib = inserted_bins; ib; ib = ib->next) if(ib->bin_val == u.pb->val) { insert_bin = 0; break; } if (insert_bin) { #if HALFWORD_HEAP UWord val = (UWord) u.pb->val; DeclareTmpHeapNoproc(id_heap,BIG_UINT_HEAP_SIZE*2); /* extra place allocated */ #else DeclareTmpHeapNoproc(id_heap,BIG_UINT_HEAP_SIZE); #endif Uint *hp = &id_heap[0]; InsertedBin *nib; #if HALFWORD_HEAP int actual_need = BIG_UWORD_HEAP_SIZE(val); ASSERT(actual_need <= (BIG_UINT_HEAP_SIZE*2)); UseTmpHeapNoproc(actual_need); a.id = erts_bld_uword(&hp, NULL, (UWord) val); #else UseTmpHeapNoproc(BIG_UINT_HEAP_SIZE); a.id = erts_bld_uint(&hp, NULL, (Uint) u.pb->val); #endif erts_match_prog_foreach_offheap(u.pb->val, insert_offheap2, (void *) &a); nib = erts_alloc(ERTS_ALC_T_NC_TMP, sizeof(InsertedBin)); nib->bin_val = u.pb->val; nib->next = inserted_bins; inserted_bins = nib; #if HALFWORD_HEAP UnUseTmpHeapNoproc(actual_need); #else UnUseTmpHeapNoproc(BIG_UINT_HEAP_SIZE); #endif } } break; case FUN_SUBTAG: break; /* No need to */ default: ASSERT(is_external_header(u.hdr->thing_word)); insert_node(u.ext->node, type, id); break; } } }
static ERTS_INLINE int prepare_crash_dump(int secs) { #define NUFBUF (3) int i, max; char env[21]; /* enough to hold any 64-bit integer */ size_t envsz; /*DeclareTmpHeapNoproc(heap,NUFBUF);*/ /*Eterm *hp = heap;*/ /*Eterm list = NIL;*/ int has_heart = 0; UseTmpHeapNoproc(NUFBUF); if (ERTS_PREPARED_CRASH_DUMP) return 0; /* We have already been called */ /* Positive secs means an alarm must be set * 0 or negative means no alarm * * Set alarm before we try to write to a port * we don't want to hang on a port write with * no alarm. * */ #if 0 /*ose TBD!!!*/ if (secs >= 0) { alarm((unsigned int)secs); } #endif /* Make sure we unregister at epmd (unknown fd) and get at least one free filedescriptor (for erl_crash.dump) */ max = max_files; if (max < 1024) max = 1024; for (i = 3; i < max; i++) { close(i); } envsz = sizeof(env); i = erts_sys_getenv__("ERL_CRASH_DUMP_NICE", env, &envsz); if (i >= 0) { int nice_val; nice_val = i != 0 ? 0 : atoi(env); if (nice_val > 39) { nice_val = 39; } set_pri(nice_val); } UnUseTmpHeapNoproc(NUFBUF); #undef NUFBUF return has_heart; }
static void insert_delayed_delete_node(void *state, ErtsMonotonicTime timeout_pos, void *vnp) { DeclareTmpHeapNoproc(heap,3); UseTmpHeapNoproc(3); insert_node((ErlNode *) vnp, SYSTEM_REF, TUPLE2(&heap[0], AM_system, AM_delayed_delete_timer)); UnUseTmpHeapNoproc(3); }
static void insert_delayed_delete_dist_entry(void *state, ErtsMonotonicTime timeout_pos, void *vdep) { DeclareTmpHeapNoproc(heap,3); UseTmpHeapNoproc(3); insert_dist_entry((DistEntry *) vdep, SYSTEM_REF, TUPLE2(&heap[0], AM_system, AM_delayed_delete_timer), 0); UnUseTmpHeapNoproc(3); }
static void insert_bif_timer(Eterm receiver, Eterm msg, ErlHeapFragment *bp, void *arg) { if (bp) { DeclareTmpHeapNoproc(heap,3); UseTmpHeapNoproc(3); insert_offheap(&bp->off_heap, TIMER_REF, (is_internal_pid(receiver) ? receiver : TUPLE2(&heap[0], AM_process, receiver))); UnUseTmpHeapNoproc(3); } }
static ERTS_INLINE int prepare_crash_dump(int secs) { #define NUFBUF (3) int i; char env[21]; /* enough to hold any 64-bit integer */ size_t envsz; DeclareTmpHeapNoproc(heap,NUFBUF); Port *heart_port; Eterm *hp = heap; Eterm list = NIL; int has_heart = 0; UseTmpHeapNoproc(NUFBUF); if (ERTS_PREPARED_CRASH_DUMP) return 0; /* We have already been called */ heart_port = erts_get_heart_port(); /* Positive secs means an alarm must be set * 0 or negative means no alarm * * Set alarm before we try to write to a port * we don't want to hang on a port write with * no alarm. * */ if (secs >= 0) { alarm((unsigned int)secs); } /* close all viable sockets via emergency close callbacks. * Specifically we want to close epmd sockets. */ erts_emergency_close_ports(); if (heart_port) { has_heart = 1; list = CONS(hp, make_small(8), list); hp += 2; /* send to heart port, CMD = 8, i.e. prepare crash dump =o */ erts_port_output(NULL, ERTS_PORT_SIG_FLG_FORCE_IMM_CALL, heart_port, heart_port->common.id, list, NULL); } /* Make sure we have a fd for our crashdump file. */ close(crashdump_companion_cube_fd); envsz = sizeof(env); i = erts_sys_getenv__("ERL_CRASH_DUMP_NICE", env, &envsz); if (i >= 0) { int nice_val; nice_val = i != 0 ? 0 : atoi(env); if (nice_val > 39) { nice_val = 39; } erts_silence_warn_unused_result(nice(nice_val)); } UnUseTmpHeapNoproc(NUFBUF); #undef NUFBUF return has_heart; }
static void setup_reference_table(void) { ErlHeapFragment *hfp; DistEntry *dep; HashInfo hi; int i, max; DeclareTmpHeapNoproc(heap,3); inserted_bins = NULL; hash_get_info(&hi, &erts_node_table); referred_nodes = erts_alloc(ERTS_ALC_T_NC_TMP, hi.objs*sizeof(ReferredNode)); no_referred_nodes = 0; hash_foreach(&erts_node_table, init_referred_node, NULL); ASSERT(no_referred_nodes == hi.objs); hash_get_info(&hi, &erts_dist_table); referred_dists = erts_alloc(ERTS_ALC_T_NC_TMP, hi.objs*sizeof(ReferredDist)); no_referred_dists = 0; hash_foreach(&erts_dist_table, init_referred_dist, NULL); ASSERT(no_referred_dists == hi.objs); /* Go through the hole system, and build a table of all references to ErlNode and DistEntry structures */ erts_debug_callback_timer_foreach(try_delete_node, insert_delayed_delete_node, NULL); erts_debug_callback_timer_foreach(try_delete_dist_entry, insert_delayed_delete_dist_entry, NULL); UseTmpHeapNoproc(3); insert_node(erts_this_node, SYSTEM_REF, TUPLE2(&heap[0], AM_system, am_undefined)); UnUseTmpHeapNoproc(3); max = erts_ptab_max(&erts_proc); /* Insert all processes */ for (i = 0; i < max; i++) { Process *proc = erts_pix2proc(i); if (proc) { int mli; ErtsMessage *msg_list[] = { proc->msg.first, #ifdef ERTS_SMP proc->msg_inq.first, #endif proc->msg_frag}; /* Insert Heap */ insert_offheap(&(proc->off_heap), HEAP_REF, proc->common.id); /* Insert heap fragments buffers */ for(hfp = proc->mbuf; hfp; hfp = hfp->next) insert_offheap(&(hfp->off_heap), HEAP_REF, proc->common.id); /* Insert msg buffers */ for (mli = 0; mli < sizeof(msg_list)/sizeof(msg_list[0]); mli++) { ErtsMessage *msg; for (msg = msg_list[mli]; msg; msg = msg->next) { ErlHeapFragment *heap_frag = NULL; if (msg->data.attached) { if (msg->data.attached == ERTS_MSG_COMBINED_HFRAG) heap_frag = &msg->hfrag; else if (is_value(ERL_MESSAGE_TERM(msg))) heap_frag = msg->data.heap_frag; else { if (msg->data.dist_ext->dep) insert_dist_entry(msg->data.dist_ext->dep, HEAP_REF, proc->common.id, 0); if (is_not_nil(ERL_MESSAGE_TOKEN(msg))) heap_frag = erts_dist_ext_trailer(msg->data.dist_ext); } } while (heap_frag) { insert_offheap(&(heap_frag->off_heap), HEAP_REF, proc->common.id); heap_frag = heap_frag->next; } } } /* Insert links */ if (ERTS_P_LINKS(proc)) insert_links(ERTS_P_LINKS(proc), proc->common.id); if (ERTS_P_MONITORS(proc)) insert_monitors(ERTS_P_MONITORS(proc), proc->common.id); /* Insert controller */ { DistEntry *dep = ERTS_PROC_GET_DIST_ENTRY(proc); if (dep) insert_dist_entry(dep, CTRL_REF, proc->common.id, 0); } } } #ifdef ERTS_SMP erts_foreach_sys_msg_in_q(insert_sys_msg); #endif /* Insert all ports */ max = erts_ptab_max(&erts_port); for (i = 0; i < max; i++) { ErlOffHeap *ohp; erts_aint32_t state; Port *prt; prt = erts_pix2port(i); if (!prt) continue; state = erts_atomic32_read_nob(&prt->state); if (state & ERTS_PORT_SFLGS_DEAD) continue; /* Insert links */ if (ERTS_P_LINKS(prt)) insert_links(ERTS_P_LINKS(prt), prt->common.id); /* Insert monitors */ if (ERTS_P_MONITORS(prt)) insert_monitors(ERTS_P_MONITORS(prt), prt->common.id); /* Insert port data */ ohp = erts_port_data_offheap(prt); if (ohp) insert_offheap(ohp, HEAP_REF, prt->common.id); /* Insert controller */ if (prt->dist_entry) insert_dist_entry(prt->dist_entry, CTRL_REF, prt->common.id, 0); } { /* Add binaries stored elsewhere ... */ ErlOffHeap oh; ProcBin pb[2]; int i = 0; Binary *default_match_spec; Binary *default_meta_match_spec; oh.first = NULL; /* Only the ProcBin members thing_word, val and next will be inspected (by insert_offheap()) */ #undef ADD_BINARY #define ADD_BINARY(Bin) \ if ((Bin)) { \ pb[i].thing_word = REFC_BINARY_SUBTAG; \ pb[i].val = (Bin); \ pb[i].next = oh.first; \ oh.first = (struct erl_off_heap_header*) &pb[i]; \ i++; \ } erts_get_default_trace_pattern(NULL, &default_match_spec, &default_meta_match_spec, NULL, NULL); ADD_BINARY(default_match_spec); ADD_BINARY(default_meta_match_spec); insert_offheap(&oh, BIN_REF, AM_match_spec); #undef ADD_BINARY } /* Insert all dist links */ for(dep = erts_visible_dist_entries; dep; dep = dep->next) { if(dep->nlinks) insert_links2(dep->nlinks, dep->sysname); if(dep->node_links) insert_links(dep->node_links, dep->sysname); if(dep->monitors) insert_monitors(dep->monitors, dep->sysname); } for(dep = erts_hidden_dist_entries; dep; dep = dep->next) { if(dep->nlinks) insert_links2(dep->nlinks, dep->sysname); if(dep->node_links) insert_links(dep->node_links, dep->sysname); if(dep->monitors) insert_monitors(dep->monitors, dep->sysname); } /* Not connected dist entries should not have any links, but inspect them anyway */ for(dep = erts_not_connected_dist_entries; dep; dep = dep->next) { if(dep->nlinks) insert_links2(dep->nlinks, dep->sysname); if(dep->node_links) insert_links(dep->node_links, dep->sysname); if(dep->monitors) insert_monitors(dep->monitors, dep->sysname); } /* Insert all ets tables */ erts_db_foreach_table(insert_ets_table, NULL); /* Insert all bif timers */ erts_debug_bif_timer_foreach(insert_bif_timer, NULL); /* Insert node table (references to dist) */ hash_foreach(&erts_node_table, insert_erl_node, NULL); }
static ERTS_INLINE Eterm bld_unique_integer_term(Eterm **hpp, Uint *szp, Uint64 val0, Uint64 val1, int positive) { Uint hsz; Uint64 unique_val[2]; unique_val[0] = ((Uint64) val0); unique_val[0] |= ((Uint64) val1) << unique_data.r.o.left_shift; unique_val[1] = ((Uint64) val1) >> unique_data.r.o.right_shift; unique_val[1] &= unique_data.r.o.mask; if (positive) { unique_val[0]++; if (unique_val[0] == 0) unique_val[1]++; } else { ASSERT(MIN_SMALL < 0); if (unique_val[1] == 0 && unique_val[0] < ((Uint64) -1*((Sint64) MIN_SMALL))) { Sint64 s_unique_val = (Sint64) unique_val[0]; s_unique_val += MIN_SMALL; ASSERT(MIN_SMALL <= s_unique_val && s_unique_val < 0); if (szp) *szp = 0; if (!hpp) return THE_NON_VALUE; return make_small((Sint) s_unique_val); } if (unique_val[0] < ((Uint64) -1*((Sint64) MIN_SMALL))) { ASSERT(unique_val[1] != 0); unique_val[1] -= 1; } unique_val[0] += MIN_SMALL; } if (!unique_val[1]) { if (unique_val[0] <= MAX_SMALL) { if (szp) *szp = 0; if (!hpp) return THE_NON_VALUE; return make_small((Uint) unique_val[0]); } if (szp) *szp = ERTS_UINT64_HEAP_SIZE(unique_val[0]); if (!hpp) return THE_NON_VALUE; return erts_uint64_to_big(unique_val[0], hpp); } else { Eterm tmp, *tmp_hp, res; DeclareTmpHeapNoproc(local_heap, 2*ERTS_MAX_UNIQUE_INT_HEAP_SIZE); UseTmpHeapNoproc(2*ERTS_MAX_UNIQUE_INT_HEAP_SIZE); tmp_hp = local_heap; tmp = erts_uint64_array_to_big(&tmp_hp, 0, 2, unique_val); ASSERT(is_big(tmp)); hsz = big_arity(tmp) + 1; ASSERT(hsz <= ERTS_MAX_UNIQUE_INT_HEAP_SIZE); if (szp) *szp = hsz; if (!hpp) res = THE_NON_VALUE; else { int hix; Eterm *hp = *hpp; tmp_hp = big_val(tmp); for (hix = 0; hix < hsz; hix++) hp[hix] = tmp_hp[hix]; *hpp = hp + hsz; res = make_big(hp); } UnUseTmpHeapNoproc(2*ERTS_MAX_UNIQUE_INT_HEAP_SIZE); return res; } }
/* * Entry point called by the trace wrap functions in erl_bif_wrap.c * * The trace wrap functions are themselves called through the export * entries instead of the original BIF functions. */ Eterm erts_bif_trace(int bif_index, Process* p, Eterm* args, BeamInstr* I) { Eterm result; Eterm (*func)(Process*, Eterm*, BeamInstr*); Export* ep = bif_export[bif_index]; Uint32 flags = 0, flags_meta = 0; Eterm meta_tracer_pid = NIL; int applying = (I == &(ep->code[3])); /* Yup, the apply code for a bif * is actually in the * export entry */ BeamInstr *cp = p->cp; GenericBp* g; GenericBpData* bp = NULL; Uint bp_flags = 0; ERTS_SMP_CHK_HAVE_ONLY_MAIN_PROC_LOCK(p); g = (GenericBp *) ep->fake_op_func_info_for_hipe[1]; if (g) { bp = &g->data[erts_active_bp_ix()]; bp_flags = bp->flags; } /* * Make continuation pointer OK, it is not during direct BIF calls, * but it is correct during apply of bif. */ if (!applying) { p->cp = I; } if (bp_flags & (ERTS_BPF_LOCAL_TRACE|ERTS_BPF_GLOBAL_TRACE) && IS_TRACED_FL(p, F_TRACE_CALLS)) { int local = !!(bp_flags & ERTS_BPF_LOCAL_TRACE); flags = erts_call_trace(p, ep->code, bp->local_ms, args, local, &ERTS_TRACER_PROC(p)); } if (bp_flags & ERTS_BPF_META_TRACE) { Eterm tpid1, tpid2; tpid1 = tpid2 = (Eterm) erts_smp_atomic_read_nob(&bp->meta_pid->pid); flags_meta = erts_call_trace(p, ep->code, bp->meta_ms, args, 0, &tpid2); meta_tracer_pid = tpid2; if (tpid1 != tpid2) { erts_smp_atomic_set_nob(&bp->meta_pid->pid, tpid2); } } if (bp_flags & ERTS_BPF_TIME_TRACE_ACTIVE && IS_TRACED_FL(p, F_TRACE_CALLS) && erts_is_tracer_proc_valid(p)) { BeamInstr *pc = (BeamInstr *)ep->code+3; erts_trace_time_call(p, pc, bp->time); } /* Restore original continuation pointer (if changed). */ p->cp = cp; func = bif_table[bif_index].f; result = func(p, args, I); if (applying && (flags & MATCH_SET_RETURN_TO_TRACE)) { BeamInstr i_return_trace = beam_return_trace[0]; BeamInstr i_return_to_trace = beam_return_to_trace[0]; BeamInstr i_return_time_trace = beam_return_time_trace[0]; Eterm *cpp; /* Maybe advance cp to skip trace stack frames */ for (cpp = p->stop; ; cp = cp_val(*cpp++)) { if (*cp == i_return_trace) { /* Skip stack frame variables */ while (is_not_CP(*cpp)) cpp++; cpp += 2; /* Skip return_trace parameters */ } else if (*cp == i_return_time_trace) { /* Skip stack frame variables */ while (is_not_CP(*cpp)) cpp++; cpp += 1; /* Skip return_time_trace parameters */ } else if (*cp == i_return_to_trace) { /* A return_to trace message is going to be generated * by normal means, so we do not have to. */ cp = NULL; break; } else break; } } /* Try to get these in the order * they usually appear in normal code... */ if (is_non_value(result)) { Uint reason = p->freason; if (reason != TRAP) { Eterm class; Eterm value = p->fvalue; DeclareTmpHeapNoproc(nocatch,3); UseTmpHeapNoproc(3); /* Expand error value like in handle_error() */ if (reason & EXF_ARGLIST) { Eterm *tp; ASSERT(is_tuple(value)); tp = tuple_val(value); value = tp[1]; } if ((reason & EXF_THROWN) && (p->catches <= 0)) { value = TUPLE2(nocatch, am_nocatch, value); reason = EXC_ERROR; } /* Note: expand_error_value() could theoretically * allocate on the heap, but not for any error * returned by a BIF, and it would do no harm, * just be annoying. */ value = expand_error_value(p, reason, value); class = exception_tag[GET_EXC_CLASS(reason)]; if (flags_meta & MATCH_SET_EXCEPTION_TRACE) { erts_trace_exception(p, ep->code, class, value, &meta_tracer_pid); } if (flags & MATCH_SET_EXCEPTION_TRACE) { erts_trace_exception(p, ep->code, class, value, &ERTS_TRACER_PROC(p)); }