Uint erts_msg_attached_data_size_aux(ErtsMessage *msg) { Sint sz; ASSERT(is_non_value(ERL_MESSAGE_TERM(msg))); ASSERT(msg->data.dist_ext); ASSERT(msg->data.dist_ext->heap_size < 0); sz = erts_decode_dist_ext_size(msg->data.dist_ext); if (sz < 0) { /* Bad external * We leave the message intact in this case as it's not worth the trouble * to make all callers remove it from queue. It will be detected again * and removed from message queue later anyway. */ return 0; } msg->data.dist_ext->heap_size = sz; if (is_not_nil(msg->m[1])) { ErlHeapFragment *heap_frag; heap_frag = erts_dist_ext_trailer(msg->data.dist_ext); sz += heap_frag->used_size; } return sz; }
Eterm erts_gc_after_bif_call(Process* p, Eterm result, Eterm* regs, Uint arity) { int cost; if (is_non_value(result)) { if (p->freason == TRAP) { #if HIPE if (regs == NULL) { regs = ERTS_PROC_GET_SCHDATA(p)->x_reg_array; } #endif cost = erts_garbage_collect(p, 0, regs, p->arity); } else { cost = erts_garbage_collect(p, 0, regs, arity); } } else { Eterm val[1]; val[0] = result; cost = erts_garbage_collect(p, 0, val, 1); result = val[0]; } BUMP_REDS(p, cost); return result; }
void erts_cleanup_messages(ErtsMessage *msgp) { ErtsMessage *mp = msgp; while (mp) { ErtsMessage *fmp; ErlHeapFragment *bp; if (is_non_value(ERL_MESSAGE_TERM(mp))) { if (is_not_immed(ERL_MESSAGE_TOKEN(mp))) { bp = (ErlHeapFragment *) mp->data.dist_ext->ext_endp; erts_cleanup_offheap(&bp->off_heap); } if (mp->data.dist_ext) erts_free_dist_ext_copy(mp->data.dist_ext); } else { if (mp->data.attached != ERTS_MSG_COMBINED_HFRAG) bp = mp->data.heap_frag; else { bp = mp->hfrag.next; erts_cleanup_offheap(&mp->hfrag.off_heap); } if (bp) free_message_buffer(bp); } fmp = mp; mp = mp->next; erts_free_message(fmp); } }
Uint erts_msg_attached_data_size_aux(ErtsMessage *msg) { Sint sz; ASSERT(is_non_value(ERL_MESSAGE_TERM(msg))); ASSERT(msg->data.dist_ext); ASSERT(msg->data.dist_ext->heap_size < 0); sz = erts_decode_dist_ext_size(msg->data.dist_ext); if (sz < 0) { /* Bad external; remove it */ if (is_not_nil(ERL_MESSAGE_TOKEN(msg))) { ErlHeapFragment *heap_frag; heap_frag = erts_dist_ext_trailer(msg->data.dist_ext); erts_cleanup_offheap(&heap_frag->off_heap); } erts_free_dist_ext_copy(msg->data.dist_ext); msg->data.dist_ext = NULL; return 0; } msg->data.dist_ext->heap_size = sz; if (is_not_nil(msg->m[1])) { ErlHeapFragment *heap_frag; heap_frag = erts_dist_ext_trailer(msg->data.dist_ext); sz += heap_frag->used_size; } return sz; }
Eterm erts_msg_distext2heap(Process *pp, ErtsProcLocks *plcksp, ErlHeapFragment **bpp, Eterm *tokenp, ErtsDistExternal *dist_extp) { Eterm msg; Uint tok_sz = 0; Eterm *hp = NULL; ErtsHeapFactory factory; Sint sz; *bpp = NULL; sz = erts_decode_dist_ext_size(dist_extp); if (sz < 0) goto decode_error; if (is_not_nil(*tokenp)) { ErlHeapFragment *heap_frag = erts_dist_ext_trailer(dist_extp); tok_sz = heap_frag->used_size; sz += tok_sz; } if (pp) { ErlOffHeap *ohp; hp = erts_alloc_message_heap(sz, bpp, &ohp, pp, plcksp); } else { *bpp = new_message_buffer(sz); hp = (*bpp)->mem; } erts_factory_message_init(&factory, pp, hp, *bpp); msg = erts_decode_dist_ext(&factory, dist_extp); if (is_non_value(msg)) goto decode_error; if (is_not_nil(*tokenp)) { ErlHeapFragment *heap_frag = erts_dist_ext_trailer(dist_extp); hp = erts_produce_heap(&factory, tok_sz, 0); *tokenp = copy_struct(*tokenp, tok_sz, &hp, factory.off_heap); erts_cleanup_offheap(&heap_frag->off_heap); } erts_free_dist_ext_copy(dist_extp); erts_factory_close(&factory); return msg; decode_error: if (is_not_nil(*tokenp)) { ErlHeapFragment *heap_frag = erts_dist_ext_trailer(dist_extp); erts_cleanup_offheap(&heap_frag->off_heap); } erts_free_dist_ext_copy(dist_extp); *bpp = NULL; return THE_NON_VALUE; }
BIF_RETTYPE lists_keysearch_3(Process* p, Eterm Key, Eterm Pos, Eterm List) { Eterm res; res = keyfind(BIF_lists_keysearch_3, p, Key, Pos, List); if (is_non_value(res) || is_not_tuple(res)) { return res; } else { /* Tuple */ Eterm* hp = HAlloc(p, 3); return TUPLE2(hp, am_value, res); } }
BIF_RETTYPE lists_keysearch_3(BIF_ALIST_3) { Eterm res; res = keyfind(BIF_lists_keysearch_3, BIF_P, BIF_ARG_1, BIF_ARG_2, BIF_ARG_3); if (is_non_value(res) || is_not_tuple(res)) { return res; } else { /* Tuple */ Eterm* hp = HAlloc(BIF_P, 3); return TUPLE2(hp, am_value, res); } }
/* * print_tagged_memory will print contents of given memory area and * display it as if it was tagged Erlang terms (which it hopefully * is). This function knows about forwarding pointers to be able to * print a heap during garbage collection. erts_printf("%T",val) * do not know about forwarding pointers though, so it will still * crash if they are encoutered... */ void print_tagged_memory(Eterm *pos, Eterm *end) { erts_printf("+-%s-+-%s-+\n",dashes,dashes); erts_printf("| 0x%0*lx - 0x%0*lx |\n", PTR_SIZE,(unsigned long)pos, PTR_SIZE,(unsigned long)(end - 1)); erts_printf("| %-*s | %-*s |\n",PTR_SIZE,"Address",PTR_SIZE,"Contents"); erts_printf("|-%s-|-%s-|\n",dashes,dashes); while( pos < end ) { Eterm val = pos[0]; erts_printf("| 0x%0*lx | 0x%0*lx | ", PTR_SIZE,(unsigned long)pos, PTR_SIZE,(unsigned long)val); ++pos; if( is_arity_value(val) ) { erts_printf("Arity(%lu)", arityval(val)); } else if( is_thing(val) ) { unsigned int ari = thing_arityval(val); erts_printf("Thing Arity(%u) Tag(%lu)", ari, thing_subtag(val)); while( ari ) { erts_printf("\n| 0x%0*lx | 0x%0*lx | THING", PTR_SIZE, (unsigned long)pos, PTR_SIZE, (unsigned long)*pos); ++pos; --ari; } } else { switch (primary_tag(val)) { case TAG_PRIMARY_BOXED: if (!is_header(*boxed_val(val))) { erts_printf("Moved -> 0x%0*lx\n",PTR_SIZE, (unsigned long)*boxed_val(val)); continue; } break; case TAG_PRIMARY_LIST: if (is_non_value(*list_val(val))) { erts_printf("Moved -> 0x%0*lx\n",PTR_SIZE, (unsigned long)*(list_val(val) + 1)); continue; } break; } erts_printf("%.30T", val); } erts_printf("\n"); } erts_printf("+-%s-+-%s-+\n",dashes,dashes); }
Uint erts_prep_msgq_for_inspection(Process *c_p, Process *rp, ErtsProcLocks rp_locks, ErtsMessageInfo *mip) { Uint tot_heap_size; ErtsMessage* mp; Sint i; int self_on_heap; /* * Prepare the message queue for inspection * by process_info(). * * * - Decode all messages on external format * - Remove all corrupt dist messages from queue * - Save pointer to, and heap size need of each * message in the mip array. * - Return total heap size need for all messages * that needs to be copied. * * If ERTS_INSPECT_MSGQ_KEEP_OH_MSGS == 0: * - In case off heap messages is disabled and * we are inspecting our own queue, move all * off heap data into the heap. */ self_on_heap = c_p == rp && !(c_p->flags & F_OFF_HEAP_MSGQ); tot_heap_size = 0; i = 0; mp = rp->msg.first; while (mp) { Eterm msg = ERL_MESSAGE_TERM(mp); mip[i].size = 0; if (is_non_value(msg)) { /* Dist message on external format; decode it... */ if (mp->data.attached) erts_decode_dist_message(rp, rp_locks, mp, ERTS_INSPECT_MSGQ_KEEP_OH_MSGS); msg = ERL_MESSAGE_TERM(mp); if (is_non_value(msg)) { ErtsMessage **mpp; ErtsMessage *bad_mp = mp; /* * Bad distribution message; remove * it from the queue... */ ASSERT(!mp->data.attached); mpp = i == 0 ? &rp->msg.first : &mip[i-1].msgp->next; ASSERT(*mpp == bad_mp); erts_msgq_update_internal_pointers(&rp->msg, mpp, &bad_mp->next); mp = mp->next; *mpp = mp; rp->msg.len--; bad_mp->next = NULL; erts_cleanup_messages(bad_mp); continue; } } ASSERT(is_value(msg)); #if ERTS_INSPECT_MSGQ_KEEP_OH_MSGS if (is_not_immed(msg) && (!self_on_heap || mp->data.attached)) { Uint sz = size_object(msg); mip[i].size = sz; tot_heap_size += sz; } #else if (self_on_heap) { if (mp->data.attached) { ErtsMessage *tmp = NULL; if (mp->data.attached != ERTS_MSG_COMBINED_HFRAG) { erts_link_mbuf_to_proc(rp, mp->data.heap_frag); mp->data.attached = NULL; } else { /* * Need to replace the message reference since * we will get references to the message data * from the heap... */ ErtsMessage **mpp; tmp = erts_alloc_message(0, NULL); sys_memcpy((void *) tmp->m, (void *) mp->m, sizeof(Eterm)*ERL_MESSAGE_REF_ARRAY_SZ); mpp = i == 0 ? &rp->msg.first : &mip[i-1].msgp->next; erts_msgq_replace_msg_ref(&rp->msg, tmp, mpp); erts_save_message_in_proc(rp, mp); mp = tmp; } } } else if (is_not_immed(msg)) { Uint sz = size_object(msg); mip[i].size = sz; tot_heap_size += sz; } #endif mip[i].msgp = mp; i++; mp = mp->next; } return tot_heap_size; }
int erts_decode_dist_message(Process *proc, ErtsProcLocks proc_locks, ErtsMessage *msgp, int force_off_heap) { ErtsHeapFactory factory; Eterm msg; ErlHeapFragment *bp; Sint need; int decode_in_heap_frag; decode_in_heap_frag = (force_off_heap || !(proc_locks & ERTS_PROC_LOCK_MAIN) || (proc->flags & F_OFF_HEAP_MSGQ)); if (msgp->data.dist_ext->heap_size >= 0) need = msgp->data.dist_ext->heap_size; else { need = erts_decode_dist_ext_size(msgp->data.dist_ext); if (need < 0) { /* bad msg; remove it... */ if (is_not_immed(ERL_MESSAGE_TOKEN(msgp))) { bp = erts_dist_ext_trailer(msgp->data.dist_ext); erts_cleanup_offheap(&bp->off_heap); } erts_free_dist_ext_copy(msgp->data.dist_ext); msgp->data.dist_ext = NULL; return 0; } msgp->data.dist_ext->heap_size = need; } if (is_not_immed(ERL_MESSAGE_TOKEN(msgp))) { bp = erts_dist_ext_trailer(msgp->data.dist_ext); need += bp->used_size; } if (decode_in_heap_frag) erts_factory_heap_frag_init(&factory, new_message_buffer(need)); else erts_factory_proc_prealloc_init(&factory, proc, need); ASSERT(msgp->data.dist_ext->heap_size >= 0); if (is_not_immed(ERL_MESSAGE_TOKEN(msgp))) { ErlHeapFragment *heap_frag; heap_frag = erts_dist_ext_trailer(msgp->data.dist_ext); ERL_MESSAGE_TOKEN(msgp) = copy_struct(ERL_MESSAGE_TOKEN(msgp), heap_frag->used_size, &factory.hp, factory.off_heap); erts_cleanup_offheap(&heap_frag->off_heap); } msg = erts_decode_dist_ext(&factory, msgp->data.dist_ext); ERL_MESSAGE_TERM(msgp) = msg; erts_free_dist_ext_copy(msgp->data.dist_ext); msgp->data.attached = NULL; if (is_non_value(msg)) { erts_factory_undo(&factory); return 0; } erts_factory_trim_and_close(&factory, msgp->m, ERL_MESSAGE_REF_ARRAY_SZ); ASSERT(!msgp->data.heap_frag); if (decode_in_heap_frag) msgp->data.heap_frag = factory.heap_frags; return 1; }
/* * Unregister a name * Return 0 if not registered * Otherwise returns 1 * */ int erts_unregister_name(Process *c_p, ErtsProcLocks c_p_locks, Port *c_prt, Eterm name) { int res = 0; RegProc r, *rp; Port *port = c_prt; ErtsProcLocks current_c_p_locks = 0; #ifdef ERTS_SMP /* * SMP note: If 'c_prt != NULL' and 'c_prt->reg->name == name', * we are *not* allowed to temporarily release the lock * on c_prt. */ if (!c_p) { c_p_locks = 0; } current_c_p_locks = c_p_locks; restart: reg_safe_write_lock(c_p, ¤t_c_p_locks); #endif r.name = name; if (is_non_value(name)) { /* Unregister current process name */ ASSERT(c_p); #ifdef ERTS_SMP if (current_c_p_locks != c_p_locks) { erts_smp_proc_lock(c_p, c_p_locks); current_c_p_locks = c_p_locks; } #endif if (c_p->common.u.alive.reg) { r.name = c_p->common.u.alive.reg->name; } else { /* Name got unregistered while main lock was released */ res = 0; goto done; } } if ((rp = (RegProc*) hash_get(&process_reg, (void*) &r)) != NULL) { if (rp->pt) { if (port != rp->pt) { #ifdef ERTS_SMP if (port) { ASSERT(port != c_prt); erts_port_release(port); port = NULL; } if (erts_smp_port_trylock(rp->pt) == EBUSY) { Eterm id = rp->pt->common.id; /* id read only... */ /* Unlock all locks, acquire port lock, and restart... */ if (current_c_p_locks) { erts_smp_proc_unlock(c_p, current_c_p_locks); current_c_p_locks = 0; } reg_write_unlock(); port = erts_id2port(id); goto restart; } #endif port = rp->pt; } ASSERT(rp->pt == port); ERTS_SMP_LC_ASSERT(erts_lc_is_port_locked(port)); rp->pt->common.u.alive.reg = NULL; if (IS_TRACED_FL(port, F_TRACE_PORTS)) { if (current_c_p_locks) { erts_smp_proc_unlock(c_p, current_c_p_locks); current_c_p_locks = 0; } trace_port(port, am_unregister, r.name); } } else if (rp->p) { #ifdef ERTS_SMP erts_proc_safelock(c_p, current_c_p_locks, c_p_locks, rp->p, (c_p == rp->p) ? current_c_p_locks : 0, ERTS_PROC_LOCK_MAIN); current_c_p_locks = c_p_locks; #endif rp->p->common.u.alive.reg = NULL; if (IS_TRACED_FL(rp->p, F_TRACE_PROCS)) { trace_proc(rp->p, (c_p == rp->p) ? c_p_locks : ERTS_PROC_LOCK_MAIN, rp->p, am_unregister, r.name); } #ifdef ERTS_SMP if (rp->p != c_p) { erts_smp_proc_unlock(rp->p, ERTS_PROC_LOCK_MAIN); } #endif } hash_erase(&process_reg, (void*) &r); res = 1; } done: reg_write_unlock(); if (c_prt != port) { if (port) { erts_port_release(port); } if (c_prt) { erts_smp_port_lock(c_prt); } } #ifdef ERTS_SMP if (c_p && !current_c_p_locks) { erts_smp_proc_lock(c_p, c_p_locks); } #endif return res; }
BIF_RETTYPE port_control_3(BIF_ALIST_3) { Port* p; Uint op; Eterm res = THE_NON_VALUE; /* Virtual schedule out calling process before lock wait */ if (IS_TRACED_FL(BIF_P, F_TRACE_SCHED_PROCS)) { trace_virtual_sched(BIF_P, am_out); } if (erts_system_profile_flags.runnable_procs && erts_system_profile_flags.exclusive) { profile_runnable_proc(BIF_P, am_inactive); } p = id_or_name2port(BIF_P, BIF_ARG_1); if (!p) { /* Schedule the process before exiting */ if (IS_TRACED_FL(BIF_P, F_TRACE_SCHED_PROCS)) { trace_virtual_sched(BIF_P, am_in); } if (erts_system_profile_flags.runnable_procs && erts_system_profile_flags.exclusive) { profile_runnable_proc(BIF_P, am_active); } BIF_ERROR(BIF_P, BADARG); } /* Trace the port for scheduling in */ if (IS_TRACED_FL(p, F_TRACE_SCHED_PORTS)) { trace_sched_ports_where(p, am_in, am_control); } if (erts_system_profile_flags.runnable_ports && !erts_port_is_scheduled(p)) { profile_runnable_port(p, am_active); } if (term_to_Uint(BIF_ARG_2, &op)) res = erts_port_control(BIF_P, p, op, BIF_ARG_3); /* Trace the port for scheduling out */ if (IS_TRACED_FL(p, F_TRACE_SCHED_PORTS)) { trace_sched_ports_where(p, am_out, am_control); } if (erts_system_profile_flags.runnable_ports && !erts_port_is_scheduled(p)) { profile_runnable_port(p, am_inactive); } erts_port_release(p); #ifdef ERTS_SMP ERTS_SMP_BIF_CHK_PENDING_EXIT(BIF_P, ERTS_PROC_LOCK_MAIN); #else ERTS_BIF_CHK_EXITED(BIF_P); #endif if (IS_TRACED_FL(BIF_P, F_TRACE_SCHED_PROCS)) { trace_virtual_sched(BIF_P, am_in); } if (erts_system_profile_flags.runnable_procs && erts_system_profile_flags.exclusive) { profile_runnable_proc(BIF_P, am_active); } if (is_non_value(res)) { BIF_ERROR(BIF_P, BADARG); } BIF_RET(res); }
Eterm erts_msg_distext2heap(Process *pp, ErtsProcLocks *plcksp, ErlHeapFragment **bpp, Eterm *tokenp, ErtsDistExternal *dist_extp) { Eterm msg; Uint tok_sz = 0; Eterm *hp = NULL; Eterm *hp_end = NULL; ErlOffHeap *ohp; Sint sz; *bpp = NULL; sz = erts_decode_dist_ext_size(dist_extp); if (sz < 0) goto decode_error; if (is_not_nil(*tokenp)) { ErlHeapFragment *heap_frag = erts_dist_ext_trailer(dist_extp); tok_sz = heap_frag->used_size; sz += tok_sz; } if (pp) hp = erts_alloc_message_heap(sz, bpp, &ohp, pp, plcksp); else { *bpp = new_message_buffer(sz); hp = (*bpp)->mem; ohp = &(*bpp)->off_heap; } hp_end = hp + sz; msg = erts_decode_dist_ext(&hp, ohp, dist_extp); if (is_non_value(msg)) goto decode_error; if (is_not_nil(*tokenp)) { ErlHeapFragment *heap_frag = erts_dist_ext_trailer(dist_extp); *tokenp = copy_struct(*tokenp, tok_sz, &hp, ohp); erts_cleanup_offheap(&heap_frag->off_heap); } erts_free_dist_ext_copy(dist_extp); if (hp_end != hp) { if (!(*bpp)) { HRelease(pp, hp_end, hp); } else { Uint final_size = hp - &(*bpp)->mem[0]; Eterm brefs[2] = {msg, *tokenp}; ASSERT(sz - (hp_end - hp) == final_size); *bpp = erts_resize_message_buffer(*bpp, final_size, &brefs[0], 2); msg = brefs[0]; *tokenp = brefs[1]; } } return msg; decode_error: if (is_not_nil(*tokenp)) { ErlHeapFragment *heap_frag = erts_dist_ext_trailer(dist_extp); erts_cleanup_offheap(&heap_frag->off_heap); } erts_free_dist_ext_copy(dist_extp); if (*bpp) { free_message_buffer(*bpp); *bpp = NULL; } else if (hp) { HRelease(pp, hp_end, hp); } return THE_NON_VALUE; }