BIF_RETTYPE open_port_2(BIF_ALIST_2) { Port *port; Eterm port_id; char *str; int err_type, err_num; port = open_port(BIF_P, BIF_ARG_1, BIF_ARG_2, &err_type, &err_num); if (!port) { if (err_type == -3) { ASSERT(err_num == BADARG || err_num == SYSTEM_LIMIT); BIF_ERROR(BIF_P, err_num); } else if (err_type == -2) { str = erl_errno_id(err_num); } else { str = "einval"; } BIF_P->fvalue = erts_atom_put((byte *) str, strlen(str), ERTS_ATOM_ENC_LATIN1, 1); BIF_ERROR(BIF_P, EXC_ERROR); } erts_smp_proc_lock(BIF_P, ERTS_PROC_LOCK_LINK); port_id = port->common.id; erts_add_link(&ERTS_P_LINKS(port), LINK_PID, BIF_P->common.id); erts_add_link(&ERTS_P_LINKS(BIF_P), LINK_PID, port_id); erts_smp_proc_unlock(BIF_P, ERTS_PROC_LOCK_LINK); erts_port_release(port); BIF_RET(port_id); }
Uint erts_process_memory(Process *p, int include_sigs_in_transit) { Uint size = 0; struct saved_calls *scb; size += sizeof(Process); 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); if (p->old_hend && p->old_heap) size += (p->old_hend - p->old_heap) * sizeof(Eterm); if (!include_sigs_in_transit) { /* * Size of message queue! * * Note that this assumes that any part of message * queue located in middle queue have been moved * into the inner queue prior to this call. * process_info() management ensures this is done- */ ErtsMessage *mp; for (mp = p->sig_qs.first; mp; mp = mp->next) { ASSERT(ERTS_SIG_IS_MSG((ErtsSignal *) mp)); size += sizeof(ErtsMessage); if (mp->data.attached) size += erts_msg_attached_data_size(mp) * sizeof(Eterm); } } else { /* * Size of message queue plus size of all signals * in transit to the process! */ erts_proc_lock(p, ERTS_PROC_LOCK_MSGQ); erts_proc_sig_fetch(p); erts_proc_unlock(p, ERTS_PROC_LOCK_MSGQ); ERTS_FOREACH_SIG_PRIVQS( p, mp, { size += sizeof(ErtsMessage); if (ERTS_SIG_IS_NON_MSG((ErtsSignal *) mp)) size += erts_proc_sig_signal_size((ErtsSignal *) mp); else if (mp->data.attached) size += erts_msg_attached_data_size(mp) * sizeof(Eterm); }); }
Uint erts_process_memory(Process *p, int incl_msg_inq) { ErtsMessage *mp; Uint size = 0; struct saved_calls *scb; size += sizeof(Process); if (incl_msg_inq) ERTS_MSGQ_MV_INQ2PRIVQ(p); erts_doforall_links(ERTS_P_LINKS(p), &erts_one_link_size, &size); erts_doforall_monitors(ERTS_P_MONITORS(p), &erts_one_mon_size, &size); size += (p->heap_sz + p->mbuf_sz) * sizeof(Eterm); if (p->abandoned_heap) size += (p->hend - p->heap) * sizeof(Eterm); if (p->old_hend && p->old_heap) size += (p->old_hend - p->old_heap) * sizeof(Eterm); size += p->msg.len * sizeof(ErtsMessage); for (mp = p->msg.first; mp; mp = mp->next) if (mp->data.attached) size += erts_msg_attached_data_size(mp)*sizeof(Eterm); if (p->arg_reg != p->def_arg_reg) { size += p->arity * sizeof(p->arg_reg[0]); } if (erts_atomic_read_nob(&p->psd) != (erts_aint_t) NULL) size += sizeof(ErtsPSD); scb = ERTS_PROC_GET_SAVED_CALLS_BUF(p); if (scb) { size += (sizeof(struct saved_calls) + (scb->len-1) * sizeof(scb->ct[0])); } size += erts_dicts_mem_size(p); return size; }
BIF_RETTYPE erts_internal_open_port_2(BIF_ALIST_2) { Port *port; Eterm res; char *str; int err_type, err_num; port = open_port(BIF_P, BIF_ARG_1, BIF_ARG_2, &err_type, &err_num); if (!port) { if (err_type == -3) { ASSERT(err_num == BADARG || err_num == SYSTEM_LIMIT); if (err_num == BADARG) res = am_badarg; else if (err_num == SYSTEM_LIMIT) res = am_system_limit; else /* this is only here to silence gcc, it should not happen */ BIF_ERROR(BIF_P, EXC_INTERNAL_ERROR); } else if (err_type == -2) { str = erl_errno_id(err_num); res = erts_atom_put((byte *) str, strlen(str), ERTS_ATOM_ENC_LATIN1, 1); } else { res = am_einval; } BIF_RET(res); } if (port->drv_ptr->flags & ERL_DRV_FLAG_USE_INIT_ACK) { /* Copied from erl_port_task.c */ port->async_open_port = erts_alloc(ERTS_ALC_T_PRTSD, sizeof(*port->async_open_port)); erts_make_ref_in_array(port->async_open_port->ref); port->async_open_port->to = BIF_P->common.id; erts_smp_proc_lock(BIF_P, ERTS_PROC_LOCKS_MSG_RECEIVE | ERTS_PROC_LOCK_LINK); if (ERTS_PROC_PENDING_EXIT(BIF_P)) { /* need to exit caller instead */ erts_smp_proc_unlock(BIF_P, ERTS_PROC_LOCKS_MSG_RECEIVE | ERTS_PROC_LOCK_LINK); KILL_CATCHES(BIF_P); BIF_P->freason = EXC_EXIT; erts_port_release(port); BIF_RET(am_badarg); } ERTS_SMP_MSGQ_MV_INQ2PRIVQ(BIF_P); BIF_P->msg.save = BIF_P->msg.last; erts_smp_proc_unlock(BIF_P, ERTS_PROC_LOCKS_MSG_RECEIVE); res = erts_proc_store_ref(BIF_P, port->async_open_port->ref); } else { res = port->common.id; erts_smp_proc_lock(BIF_P, ERTS_PROC_LOCK_LINK); } erts_add_link(&ERTS_P_LINKS(port), LINK_PID, BIF_P->common.id); erts_add_link(&ERTS_P_LINKS(BIF_P), LINK_PID, port->common.id); if (IS_TRACED_FL(BIF_P, F_TRACE_PROCS)) trace_proc(BIF_P, ERTS_PROC_LOCK_MAIN|ERTS_PROC_LOCK_LINK, BIF_P, am_link, port->common.id); erts_smp_proc_unlock(BIF_P, ERTS_PROC_LOCK_LINK); erts_port_release(port); BIF_RET(res); }
/* Display info about an individual Erlang process */ void print_process_info(int to, void *to_arg, Process *p) { time_t approx_started; int garbing = 0; int running = 0; struct saved_calls *scb; erts_aint32_t state; /* display the PID */ erts_print(to, to_arg, "=proc:%T\n", p->common.id); /* Display the state */ erts_print(to, to_arg, "State: "); state = erts_smp_atomic32_read_acqb(&p->state); erts_dump_process_state(to, to_arg, state); if (state & ERTS_PSFLG_GC) { garbing = 1; running = 1; } else if (state & ERTS_PSFLG_RUNNING) running = 1; /* * If the process is registered as a global process, display the * registered name */ if (p->common.u.alive.reg) erts_print(to, to_arg, "Name: %T\n", p->common.u.alive.reg->name); /* * Display the initial function name */ erts_print(to, to_arg, "Spawned as: %T:%T/%bpu\n", p->u.initial[INITIAL_MOD], p->u.initial[INITIAL_FUN], p->u.initial[INITIAL_ARI]); if (p->current != NULL) { if (running) { erts_print(to, to_arg, "Last scheduled in for: "); } else { erts_print(to, to_arg, "Current call: "); } erts_print(to, to_arg, "%T:%T/%bpu\n", p->current[0], p->current[1], p->current[2]); } erts_print(to, to_arg, "Spawned by: %T\n", p->parent); approx_started = (time_t) p->approx_started; erts_print(to, to_arg, "Started: %s", ctime(&approx_started)); ERTS_SMP_MSGQ_MV_INQ2PRIVQ(p); erts_print(to, to_arg, "Message queue length: %d\n", p->msg.len); /* display the message queue only if there is anything in it */ if (!ERTS_IS_CRASH_DUMPING && p->msg.first != NULL && !garbing) { ErlMessage* mp; erts_print(to, to_arg, "Message queue: ["); for (mp = p->msg.first; mp; mp = mp->next) erts_print(to, to_arg, mp->next ? "%T," : "%T", ERL_MESSAGE_TERM(mp)); erts_print(to, to_arg, "]\n"); } { int frags = 0; ErlHeapFragment *m = p->mbuf; while (m != NULL) { frags++; m = m->next; } erts_print(to, to_arg, "Number of heap fragments: %d\n", frags); } erts_print(to, to_arg, "Heap fragment data: %beu\n", MBUF_SIZE(p)); scb = ERTS_PROC_GET_SAVED_CALLS_BUF(p); if (scb) { int i, j; erts_print(to, to_arg, "Last calls:"); for (i = 0; i < scb->n; i++) { erts_print(to, to_arg, " "); j = scb->cur - i - 1; if (j < 0) j += scb->len; if (scb->ct[j] == &exp_send) erts_print(to, to_arg, "send"); else if (scb->ct[j] == &exp_receive) erts_print(to, to_arg, "'receive'"); else if (scb->ct[j] == &exp_timeout) erts_print(to, to_arg, "timeout"); else erts_print(to, to_arg, "%T:%T/%bpu\n", scb->ct[j]->code[0], scb->ct[j]->code[1], scb->ct[j]->code[2]); } erts_print(to, to_arg, "\n"); } /* display the links only if there are any*/ if (ERTS_P_LINKS(p) || ERTS_P_MONITORS(p)) { PrintMonitorContext context = {1,to}; erts_print(to, to_arg,"Link list: ["); erts_doforall_links(ERTS_P_LINKS(p), &doit_print_link, &context); erts_doforall_monitors(ERTS_P_MONITORS(p), &doit_print_monitor, &context); erts_print(to, to_arg,"]\n"); } if (!ERTS_IS_CRASH_DUMPING) { /* and the dictionary */ if (p->dictionary != NULL && !garbing) { erts_print(to, to_arg, "Dictionary: "); erts_dictionary_dump(to, to_arg, p->dictionary); erts_print(to, to_arg, "\n"); } } /* print the number of reductions etc */ erts_print(to, to_arg, "Reductions: %beu\n", p->reds); erts_print(to, to_arg, "Stack+heap: %beu\n", p->heap_sz); erts_print(to, to_arg, "OldHeap: %bpu\n", (OLD_HEAP(p) == NULL) ? 0 : (OLD_HEND(p) - OLD_HEAP(p)) ); erts_print(to, to_arg, "Heap unused: %bpu\n", (p->hend - p->htop)); erts_print(to, to_arg, "OldHeap unused: %bpu\n", (OLD_HEAP(p) == NULL) ? 0 : (OLD_HEND(p) - OLD_HTOP(p)) ); erts_print(to, to_arg, "Memory: %beu\n", erts_process_memory(p)); if (garbing) { print_garb_info(to, to_arg, p); } if (ERTS_IS_CRASH_DUMPING) { erts_program_counter_info(to, to_arg, p); } else { erts_print(to, to_arg, "Stack dump:\n"); #ifdef ERTS_SMP if (!garbing) #endif erts_stack_dump(to, to_arg, p); } /* Display all states */ erts_print(to, to_arg, "Internal State: "); erts_dump_extended_process_state(to, to_arg, state); }
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); }
BIF_RETTYPE erts_internal_open_port_2(BIF_ALIST_2) { BIF_RETTYPE ret; Port *port; Eterm res; char *str; int err_type, err_num; ErtsLinkData *ldp; ErtsLink *lnk; port = open_port(BIF_P, BIF_ARG_1, BIF_ARG_2, &err_type, &err_num); if (!port) { if (err_type == -3) { ASSERT(err_num == BADARG || err_num == SYSTEM_LIMIT); if (err_num == BADARG) res = am_badarg; else if (err_num == SYSTEM_LIMIT) res = am_system_limit; else /* this is only here to silence gcc, it should not happen */ BIF_ERROR(BIF_P, EXC_INTERNAL_ERROR); } else if (err_type == -2) { str = erl_errno_id(err_num); res = erts_atom_put((byte *) str, sys_strlen(str), ERTS_ATOM_ENC_LATIN1, 1); } else { res = am_einval; } BIF_RET(res); } ldp = erts_link_create(ERTS_LNK_TYPE_PORT, BIF_P->common.id, port->common.id); ASSERT(ldp->a.other.item == port->common.id); ASSERT(ldp->b.other.item == BIF_P->common.id); /* * This link should not already be present, but can potentially * due to id wrapping... */ lnk = erts_link_tree_lookup_insert(&ERTS_P_LINKS(BIF_P), &ldp->a); erts_link_tree_insert(&ERTS_P_LINKS(port), &ldp->b); if (port->drv_ptr->flags & ERL_DRV_FLAG_USE_INIT_ACK) { /* Copied from erl_port_task.c */ port->async_open_port = erts_alloc(ERTS_ALC_T_PRTSD, sizeof(*port->async_open_port)); erts_make_ref_in_array(port->async_open_port->ref); port->async_open_port->to = BIF_P->common.id; /* * We unconditionaly *must* do a receive on a message * containing the reference after this... */ ERTS_RECV_MARK_SAVE(BIF_P); ERTS_RECV_MARK_SET(BIF_P); res = erts_proc_store_ref(BIF_P, port->async_open_port->ref); } else { res = port->common.id; } if (IS_TRACED_FL(BIF_P, F_TRACE_PROCS)) trace_proc(BIF_P, ERTS_PROC_LOCK_MAIN, BIF_P, am_link, port->common.id); ERTS_BIF_PREP_RET(ret, res); erts_port_release(port); if (lnk) erts_link_release(lnk); return ret; }