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; } }