Eterm hipe_build_stacktrace(Process *p, struct StackTrace *s) { int depth, i; Uint heap_size; Eterm *hp, *hp_end, mfa, m, f, head, *next_p, next; const void *ra; unsigned int a; depth = s->depth; if (depth < 1) return NIL; heap_size = 6 * depth; /* each [{M,F,A}|_] is 2+4 == 6 words */ hp = HAlloc(p, heap_size); hp_end = hp + heap_size; head = NIL; next_p = &head; for (i = 0; i < depth; ++i) { ra = (const void*)s->trace[i]; if (!hipe_find_mfa_from_ra(ra, &m, &f, &a)) continue; mfa = TUPLE3(hp, m, f, make_small(a)); hp += 4; next = CONS(hp, mfa, NIL); *next_p = next; next_p = &CDR(list_val(next)); hp += 2; } HRelease(p, hp_end, hp); return head; }
void erts_factory_close(ErtsHeapFactory* factory) { ErlHeapFragment* bp; switch (factory->mode) { case FACTORY_HALLOC: HRelease(factory->p, factory->hp_end, factory->hp); break; case FACTORY_HEAP_FRAGS: bp = factory->heap_frags; if (bp) { ASSERT(factory->hp >= bp->mem); ASSERT(factory->hp <= factory->hp_end); ASSERT(factory->hp_end == bp->mem + bp->alloc_size); bp->used_size = factory->hp - bp->mem; } break; case FACTORY_TMP: erts_factory_undo(factory); break; case FACTORY_STATIC: break; case FACTORY_CLOSED: break; default: ASSERT(!"Invalid factory mode"); } factory->mode = FACTORY_CLOSED; }
static void reserve_heap(ErtsHeapFactory* factory, Uint need, Uint xtra) { ErlHeapFragment* bp; switch (factory->mode) { case FACTORY_HALLOC: HRelease(factory->p, factory->hp_end, factory->hp); factory->hp = HAllocX(factory->p, need, xtra); factory->hp_end = factory->hp + need; return; case FACTORY_MESSAGE: if (!factory->heap_frags) { ASSERT(factory->message->data.attached == ERTS_MSG_COMBINED_HFRAG); bp = &factory->message->hfrag; } else { /* Fall through */ case FACTORY_HEAP_FRAGS: case FACTORY_TMP: bp = factory->heap_frags; } if (bp) { ASSERT(factory->hp > bp->mem); ASSERT(factory->hp <= factory->hp_end); ASSERT(factory->hp_end == bp->mem + bp->alloc_size); bp->used_size = factory->hp - bp->mem; } bp = (ErlHeapFragment*) ERTS_HEAP_ALLOC(factory->alloc_type, ERTS_HEAP_FRAG_SIZE(need+xtra)); bp->next = factory->heap_frags; factory->heap_frags = bp; bp->alloc_size = need + xtra; bp->used_size = need; bp->off_heap.first = NULL; bp->off_heap.overhead = 0; factory->hp = bp->mem; factory->hp_end = bp->mem + bp->alloc_size; return; case FACTORY_STATIC: case FACTORY_CLOSED: default: ASSERT(!"Invalid factory mode"); } }
void erts_factory_close(ErtsHeapFactory* factory) { ErlHeapFragment* bp; switch (factory->mode) { case FACTORY_HALLOC: HRelease(factory->p, factory->hp_end, factory->hp); break; case FACTORY_MESSAGE: if (!factory->heap_frags) { if (factory->message->data.attached == ERTS_MSG_COMBINED_HFRAG) bp = &factory->message->hfrag; else bp = NULL; } else { if (factory->message->data.attached == ERTS_MSG_COMBINED_HFRAG) factory->message->hfrag.next = factory->heap_frags; else factory->message->data.heap_frag = factory->heap_frags; /* Fall through */ case FACTORY_HEAP_FRAGS: bp = factory->heap_frags; } if (bp) { ASSERT(factory->hp >= bp->mem); ASSERT(factory->hp <= factory->hp_end); ASSERT(factory->hp_end == bp->mem + bp->alloc_size); bp->used_size = factory->hp - bp->mem; } break; case FACTORY_TMP: erts_factory_undo(factory); break; case FACTORY_STATIC: break; case FACTORY_CLOSED: break; default: ASSERT(!"Invalid factory mode"); } factory->mode = FACTORY_CLOSED; }
void erts_reserve_heap__(ErtsHeapFactory* factory, Uint need, Uint xtra) { /* internal... */ ErlHeapFragment* bp; switch (factory->mode) { case FACTORY_HALLOC: HRelease(factory->p, factory->hp_end, factory->hp); factory->hp = HAllocX(factory->p, need, xtra); factory->hp_end = factory->hp + need; return; case FACTORY_MESSAGE: { int replace_oh; int replace_msg_hfrag; if (!factory->heap_frags) { ASSERT(factory->message->data.attached == ERTS_MSG_COMBINED_HFRAG); bp = &factory->message->hfrag; } else { /* Fall through */ case FACTORY_HEAP_FRAGS: case FACTORY_TMP: bp = factory->heap_frags; } replace_oh = 0; replace_msg_hfrag = 0; if (bp) { ASSERT(factory->hp >= bp->mem); ASSERT(factory->hp <= factory->hp_end); ASSERT(factory->hp_end == bp->mem + bp->alloc_size); bp->used_size = factory->hp - bp->mem; if (!bp->used_size && factory->heap_frags) { factory->heap_frags = bp->next; bp->next = NULL; ASSERT(!bp->off_heap.first); if (factory->off_heap == &bp->off_heap) replace_oh = !0; if (factory->message && factory->message->data.heap_frag == bp) replace_msg_hfrag = !0; free_message_buffer(bp); } } bp = (ErlHeapFragment*) ERTS_HEAP_ALLOC(factory->alloc_type, ERTS_HEAP_FRAG_SIZE(need+xtra)); bp->next = factory->heap_frags; factory->heap_frags = bp; bp->alloc_size = need + xtra; bp->used_size = need + xtra; bp->off_heap.first = NULL; bp->off_heap.overhead = 0; if (replace_oh) { factory->off_heap = &bp->off_heap; factory->off_heap_saved.first = factory->off_heap->first; factory->off_heap_saved.overhead = factory->off_heap->overhead; } if (replace_msg_hfrag) factory->message->data.heap_frag = bp; factory->hp = bp->mem; factory->hp_end = bp->mem + bp->alloc_size; return; } case FACTORY_STATIC: case FACTORY_CLOSED: default: ASSERT(!"Invalid factory mode"); } }
static BIF_RETTYPE port_call(Process* c_p, Eterm arg1, Eterm arg2, Eterm arg3) { Uint op; Port *p; Uint size; byte *bytes; byte *endp; ErlDrvSizeT real_size; erts_driver_t *drv; byte port_input[256]; /* Default input buffer to encode in */ byte port_result[256]; /* Buffer for result from port. */ byte* port_resp; /* Pointer to result buffer. */ char *prc; ErlDrvSSizeT ret; Eterm res; Sint result_size; Eterm *hp; Eterm *hp_end; /* To satisfy hybrid heap architecture */ unsigned ret_flags = 0U; int fpe_was_unmasked; bytes = &port_input[0]; port_resp = port_result; /* trace of port scheduling with virtual process descheduling * lock wait */ if (IS_TRACED_FL(c_p, F_TRACE_SCHED_PROCS)) { trace_virtual_sched(c_p, am_out); } if (erts_system_profile_flags.runnable_procs && erts_system_profile_flags.exclusive) { profile_runnable_proc(c_p, am_inactive); } p = id_or_name2port(c_p, arg1); if (!p) { error: if (port_resp != port_result && !(ret_flags & DRIVER_CALL_KEEP_BUFFER)) { driver_free(port_resp); } if (bytes != &port_input[0]) erts_free(ERTS_ALC_T_PORT_CALL_BUF, bytes); /* Need to virtual schedule in the process if there * was an error. */ if (IS_TRACED_FL(c_p, F_TRACE_SCHED_PROCS)) { trace_virtual_sched(c_p, am_in); } if (erts_system_profile_flags.runnable_procs && erts_system_profile_flags.exclusive) { profile_runnable_proc(c_p, am_active); } if (p) erts_port_release(p); #ifdef ERTS_SMP ERTS_SMP_BIF_CHK_PENDING_EXIT(c_p, ERTS_PROC_LOCK_MAIN); #else ERTS_BIF_CHK_EXITED(c_p); #endif BIF_ERROR(c_p, BADARG); } if ((drv = p->drv_ptr) == NULL) { goto error; } if (drv->call == NULL) { goto error; } if (!term_to_Uint(arg2, &op)) { goto error; } p->caller = c_p->id; /* Lock taken, virtual schedule of port */ if (IS_TRACED_FL(p, F_TRACE_SCHED_PORTS)) { trace_sched_ports_where(p, am_in, am_call); } if (erts_system_profile_flags.runnable_ports && !erts_port_is_scheduled(p)) { profile_runnable_port(p, am_active); } size = erts_encode_ext_size(arg3); if (size > sizeof(port_input)) bytes = erts_alloc(ERTS_ALC_T_PORT_CALL_BUF, size); endp = bytes; erts_encode_ext(arg3, &endp); real_size = endp - bytes; if (real_size > size) { erl_exit(1, "%s, line %d: buffer overflow: %d word(s)\n", __FILE__, __LINE__, endp - (bytes + size)); } erts_smp_proc_unlock(c_p, ERTS_PROC_LOCK_MAIN); #ifdef USE_VM_PROBES if (DTRACE_ENABLED(driver_call)) { DTRACE_CHARBUF(process_str, DTRACE_TERM_BUF_SIZE); DTRACE_CHARBUF(port_str, DTRACE_TERM_BUF_SIZE); dtrace_pid_str(p->connected, process_str); dtrace_port_str(p, port_str); DTRACE5(driver_call, process_str, port_str, p->name, op, real_size); } #endif prc = (char *) port_resp; fpe_was_unmasked = erts_block_fpe(); ret = drv->call((ErlDrvData)p->drv_data, (unsigned) op, (char *) bytes, (int) real_size, &prc, (int) sizeof(port_result), &ret_flags); erts_unblock_fpe(fpe_was_unmasked); if (IS_TRACED_FL(p, F_TRACE_SCHED_PORTS)) { trace_sched_ports_where(p, am_out, am_call); } if (erts_system_profile_flags.runnable_ports && !erts_port_is_scheduled(p)) { profile_runnable_port(p, am_inactive); } port_resp = (byte *) prc; p->caller = NIL; erts_smp_proc_lock(c_p, ERTS_PROC_LOCK_MAIN); #ifdef HARDDEBUG { ErlDrvSizeT z; printf("real_size = %ld,%d, ret = %ld,%d\r\n", (unsigned long) real_size, (int) real_size, (unsigned long)ret, (int) ret); printf("["); for(z = 0; z < real_size; ++z) { printf("%d, ",(int) bytes[z]); } printf("]\r\n"); printf("["); for(z = 0; z < ret; ++z) { printf("%d, ",(int) port_resp[z]); } printf("]\r\n"); } #endif if (ret <= 0 || port_resp[0] != VERSION_MAGIC) { /* Error or a binary without magic/ with wrong magic */ goto error; } result_size = erts_decode_ext_size(port_resp, ret); if (result_size < 0) { goto error; } hp = HAlloc(c_p, result_size); hp_end = hp + result_size; endp = port_resp; res = erts_decode_ext(&hp, &MSO(c_p), &endp); if (res == THE_NON_VALUE) { goto error; } HRelease(c_p, hp_end, hp); if (port_resp != port_result && !(ret_flags & DRIVER_CALL_KEEP_BUFFER)) { driver_free(port_resp); } if (bytes != &port_input[0]) erts_free(ERTS_ALC_T_PORT_CALL_BUF, bytes); if (p) erts_port_release(p); #ifdef ERTS_SMP ERTS_SMP_BIF_CHK_PENDING_EXIT(c_p, ERTS_PROC_LOCK_MAIN); #else ERTS_BIF_CHK_EXITED(c_p); #endif if (IS_TRACED_FL(c_p, F_TRACE_SCHED_PROCS)) { trace_virtual_sched(c_p, am_in); } if (erts_system_profile_flags.runnable_procs && erts_system_profile_flags.exclusive) { profile_runnable_proc(c_p, am_active); } return 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; }