posix_errno_t efile_altname(ErlNifEnv *env, const efile_path_t *path, ERL_NIF_TERM *result) { ErlNifBinary result_bin; ASSERT_PATH_FORMAT(path); if(is_path_root(path)) { /* Root paths can't be queried so we'll just return them as they are. */ if(!enif_alloc_binary(path->size, &result_bin)) { return ENOMEM; } sys_memcpy(result_bin.data, path->data, path->size); } else { WIN32_FIND_DATAW data; HANDLE handle; WCHAR *name_buffer; int name_length; /* Reject path wildcards. */ if(wcspbrk(&((const WCHAR*)path->data)[LP_PREFIX_LENGTH], L"?*")) { return ENOENT; } handle = FindFirstFileW((const WCHAR*)path->data, &data); if(handle == INVALID_HANDLE_VALUE) { return windows_to_posix_errno(GetLastError()); } FindClose(handle); name_length = wcslen(data.cAlternateFileName); if(name_length > 0) { name_buffer = data.cAlternateFileName; } else { name_length = wcslen(data.cFileName); name_buffer = data.cFileName; } /* Include NUL-terminator; it will be removed after normalization. */ name_length += 1; if(!enif_alloc_binary(name_length * sizeof(WCHAR), &result_bin)) { return ENOMEM; } sys_memcpy(result_bin.data, name_buffer, name_length * sizeof(WCHAR)); } if(!normalize_path_result(&result_bin)) { enif_release_binary(&result_bin); return ENOMEM; } (*result) = enif_make_binary(env, &result_bin); return 0; }
posix_errno_t efile_list_dir(ErlNifEnv *env, const efile_path_t *path, ERL_NIF_TERM *result) { ERL_NIF_TERM list_head; WIN32_FIND_DATAW data; HANDLE search_handle; WCHAR *search_path; DWORD last_error; ASSERT_PATH_FORMAT(path); search_path = enif_alloc(path->size + 2 * sizeof(WCHAR)); if(search_path == NULL) { return ENOMEM; } sys_memcpy(search_path, path->data, path->size); search_path[PATH_LENGTH(path) + 0] = L'\\'; search_path[PATH_LENGTH(path) + 1] = L'*'; search_path[PATH_LENGTH(path) + 2] = L'\0'; search_handle = FindFirstFileW(search_path, &data); last_error = GetLastError(); enif_free(search_path); if(search_handle == INVALID_HANDLE_VALUE) { return windows_to_posix_errno(last_error); } list_head = enif_make_list(env, 0); do { int name_length = wcslen(data.cFileName); if(!is_ignored_name(name_length, data.cFileName)) { unsigned char *name_bytes; ERL_NIF_TERM name_term; size_t name_size; name_size = name_length * sizeof(WCHAR); name_bytes = enif_make_new_binary(env, name_size, &name_term); sys_memcpy(name_bytes, data.cFileName, name_size); list_head = enif_make_list_cell(env, name_term, list_head); } } while(FindNextFileW(search_handle, &data)); FindClose(search_handle); (*result) = list_head; return 0; }
static void subtract_ctx_move(ErtsSubtractContext *from, ErtsSubtractContext *to) { int uses_result_cdr = 0; to->stage = from->stage; to->lhs_original = from->lhs_original; to->rhs_original = from->rhs_original; to->lhs_remaining = from->lhs_remaining; to->rhs_remaining = from->rhs_remaining; to->iterator = from->iterator; to->result = from->result; switch (to->stage) { case SUBTRACT_STAGE_NAIVE_LHS: sys_memcpy(to->u.lhs_elements, from->u.lhs_elements, sizeof(Eterm) * to->lhs_remaining); break; case SUBTRACT_STAGE_NAIVE_RHS: sys_memcpy(to->u.rhs_elements, from->u.rhs_elements, sizeof(Eterm) * to->rhs_remaining); uses_result_cdr = 1; break; case SUBTRACT_STAGE_SET_FINISH: uses_result_cdr = 1; /* FALL THROUGH */ case SUBTRACT_STAGE_SET_BUILD: to->u.rhs_set.alloc_start = from->u.rhs_set.alloc_start; to->u.rhs_set.alloc = from->u.rhs_set.alloc; to->u.rhs_set.tree = from->u.rhs_set.tree; break; default: break; } if (uses_result_cdr) { if (from->result_cdr == &from->result) { to->result_cdr = &to->result; } else { to->result_cdr = from->result_cdr; } } }
Export * erts_suspend_process_on_pending_purge_lambda(Process *c_p) { erts_smp_mtx_lock(&purge_state.mtx); if (is_value(purge_state.module)) { /* * The process c_p is about to call a fun in the code * that we are trying to purge. Suspend it and call * erts_code_purger:pending_purge_lambda/3. The process * will be resumed when the purge completes or aborts, * and will then try to do the call again. */ if (purge_state.sp_ix >= purge_state.sp_size) { Eterm *sprocs; purge_state.sp_size += 100; sprocs = erts_alloc(ERTS_ALC_T_PURGE_DATA, (sizeof(ErlFunEntry *) * purge_state.sp_size)); sys_memcpy((void *) sprocs, (void *) purge_state.sprocs, purge_state.sp_ix*sizeof(ErlFunEntry *)); if (purge_state.sprocs != &purge_state.def_sprocs[0]) erts_free(ERTS_ALC_T_PURGE_DATA, purge_state.sprocs); purge_state.sprocs = sprocs; } purge_state.sprocs[purge_state.sp_ix++] = c_p->common.id; erts_suspend(c_p, ERTS_PROC_LOCK_MAIN, NULL); ERTS_VBUMP_ALL_REDS(c_p); } erts_smp_mtx_unlock(&purge_state.mtx); return purge_state.pending_purge_lambda; }
static ERTS_INLINE erts_tse_t * tse_fetch(erts_pix_lock_t *pix_lock) { erts_tse_t *tse = erts_tse_fetch(); if (!tse->udata) { erts_proc_lock_queues_t *qs; #if ERTS_PROC_LOCK_SPINLOCK_IMPL && !ERTS_PROC_LOCK_ATOMIC_IMPL if (pix_lock) erts_pix_unlock(pix_lock); #endif erts_smp_spin_lock(&qs_lock); qs = queue_free_list; if (qs) { queue_free_list = queue_free_list->next; erts_smp_spin_unlock(&qs_lock); } else { erts_smp_spin_unlock(&qs_lock); qs = erts_alloc(ERTS_ALC_T_PROC_LCK_QS, sizeof(erts_proc_lock_queues_t)); sys_memcpy((void *) qs, (void *) &zeroqs, sizeof(erts_proc_lock_queues_t)); } tse->udata = qs; #if ERTS_PROC_LOCK_SPINLOCK_IMPL && !ERTS_PROC_LOCK_ATOMIC_IMPL if (pix_lock) erts_pix_lock(pix_lock); #endif } tse->uflgs = 0; return tse; }
unsigned beam_catches_cons(BeamInstr *cp, unsigned cdr) { int i; struct bc_pool* p = &bccix[erts_staging_code_ix()]; ASSERT(p->is_staging); /* * Allocate from free_list while it is non-empty. * If free_list is empty, allocate at high_mark. */ if (p->free_list >= 0) { i = p->free_list; p->free_list = p->beam_catches[i].cdr; } else { if (p->high_mark >= p->tabsize) { /* No free slots and table is full: realloc table */ beam_catch_t* prev_vec = p->beam_catches; unsigned newsize = p->tabsize*2; p->beam_catches = erts_alloc(ERTS_ALC_T_CODE, newsize*sizeof(beam_catch_t)); sys_memcpy(p->beam_catches, prev_vec, p->tabsize*sizeof(beam_catch_t)); gc_old_vec(prev_vec); p->tabsize = newsize; } i = p->high_mark++; } p->beam_catches[i].cp = cp; p->beam_catches[i].cdr = cdr; return i; }
/*===========================================================================*/ void init_prsiolib(scanning_character_info_type *pair) { /*-------------------------------------------------------*/ charinfo.current_ch_lno = charinfo.current_ch_pos = charinfo.lookahead_ch_lno = charinfo.lookahead_ch_pos = 0; charinfo.current_ch = charinfo.lookahead_ch = ' '; sys_memcpy(pair,&charinfo,sizeof(scanning_character_info_type)); /*-------------------------------------------------------*/ }
int erl_drv_thread_create(char *name, ErlDrvTid *tid, void* (*func)(void*), void* arg, ErlDrvThreadOpts *opts) { #ifdef USE_THREADS int res; struct ErlDrvTid_ *dtid; ethr_thr_opts ethr_opts; ethr_thr_opts *use_opts; if (!opts) use_opts = NULL; else { sys_memcpy((void *) ðr_opts, (void *) &def_ethr_opts, sizeof(ethr_thr_opts)); ethr_opts.suggested_stack_size = opts->suggested_stack_size; use_opts = ðr_opts; } dtid = erts_alloc_fnf(ERTS_ALC_T_DRV_TID, (sizeof(struct ErlDrvTid_) + (name ? sys_strlen(name) + 1 : 0))); if (!dtid) return ENOMEM; dtid->drv_thr = 1; dtid->func = func; dtid->arg = arg; dtid->tsd = NULL; dtid->tsd_len = 0; if (!name) dtid->name = no_name; else { dtid->name = ((char *) dtid) + sizeof(struct ErlDrvTid_); sys_strcpy(dtid->name, name); } #ifdef ERTS_ENABLE_LOCK_COUNT res = erts_lcnt_thr_create(&dtid->tid, erl_drv_thread_wrapper, dtid, use_opts); #else res = ethr_thr_create(&dtid->tid, erl_drv_thread_wrapper, dtid, use_opts); #endif if (res != 0) { erts_free(ERTS_ALC_T_DRV_TID, dtid); return res; } *tid = (ErlDrvTid) dtid; return 0; #else return ENOTSUP; #endif }
static ErtsIOQBinary *alloc_binary(Uint size, char *source, void **iov_base, int driver) { if (driver) { ErlDrvBinary *bin = driver_alloc_binary(size); if (!bin) return NULL; sys_memcpy(bin->orig_bytes, source, size); *iov_base = bin->orig_bytes; return (ErtsIOQBinary *)bin; } else { /* This clause can be triggered in enif_ioq_enq_binary is used */ Binary *bin = erts_bin_nrml_alloc(size); if (!bin) return NULL; erts_refc_init(&bin->intern.refc, 1); sys_memcpy(bin->orig_bytes, source, size); *iov_base = bin->orig_bytes; return (ErtsIOQBinary *)bin; } }
/* Put elements from vec at q head */ int erts_ioq_pushqv(ErtsIOQueue *q, ErtsIOVec* vec, Uint skipbytes) { int n; Uint len; Uint size = vec->common.size - skipbytes; SysIOVec* iov; ErtsIOQBinary** binv; ErtsIOQBinary* b; if (q == NULL) return -1; ASSERT(vec->common.size >= skipbytes); if (vec->common.size <= skipbytes) return 0; n = skip(vec, skipbytes, &iov, &binv, &len); if (n < 0) return n; if (q->v_head - n < q->v_start) if (expandq(q, n, 0)) return -1; /* Queue and reference all binaries (remove zero length items) */ iov += (n-1); /* move to end */ binv += (n-1); /* move to end */ while(n--) { if ((len = iov->iov_len) > 0) { if ((b = *binv) == NULL) { /* special case create binary ! */ if (q->driver) { ErlDrvBinary *bin = driver_alloc_binary(len); if (!bin) return -1; sys_memcpy(bin->orig_bytes, iov->iov_base, len); b = (ErtsIOQBinary *)bin; q->v_head->iov_base = bin->orig_bytes; } *--q->b_head = b; q->v_head--; q->v_head->iov_len = len; } else { if (q->driver) driver_binary_inc_refc(&b->driver); else erts_refc_inc(&b->nif.intern.refc, 1); *--q->b_head = b; *--q->v_head = *iov; } } iov--; binv--; } q->size += size; /* update total size in queue */ return 0; }
void *erts_sys_aligned_realloc(UWord alignment, void *ptr, UWord size, UWord old_size) { void *new_ptr = erts_sys_aligned_alloc(alignment, size); if (new_ptr) { UWord copy_size = old_size < size ? old_size : size; sys_memcpy(new_ptr, ptr, (size_t) copy_size); erts_sys_aligned_free(alignment, ptr); } return new_ptr; }
static int ssl_tls_erl(void* arg, unsigned type, unsigned major, unsigned minor, const char* buf, int len, const char* prefix, int plen) { struct packet_callback_args* pca = (struct packet_callback_args*) arg; Eterm* hp; Eterm ver; Eterm bin = new_binary(pca->p, NULL, plen+len); byte* bin_ptr = binary_bytes(bin); sys_memcpy(bin_ptr+plen, buf, len); if (plen) { sys_memcpy(bin_ptr, prefix, plen); } /* {ssl_tls,NIL,ContentType,{Major,Minor},Bin} */ hp = HAlloc(pca->p, 3+6); ver = TUPLE2(hp, make_small(major), make_small(minor)); hp += 3; pca->res = TUPLE5(hp, am_ssl_tls, NIL, make_small(type), ver, bin); return 1; }
Allctr_t * erts_afalc_start(AFAllctr_t *afallctr, AFAllctrInit_t *afinit, AllctrInit_t *init) { struct { int dummy; AFAllctr_t allctr; } zero = {0}; /* The struct with a dummy element first is used in order to avoid (an incorrect) gcc warning. gcc warns if {0} is used as initializer of a struct when the first member is a struct (not if, for example, the third member is a struct). */ Allctr_t *allctr = (Allctr_t *) afallctr; sys_memcpy((void *) afallctr, (void *) &zero.allctr, sizeof(AFAllctr_t)); allctr->mbc_header_size = sizeof(Carrier_t); allctr->min_mbc_size = MIN_MBC_SZ; allctr->min_mbc_first_free_size = MIN_MBC_FIRST_FREE_SZ; allctr->min_block_size = sizeof(AFFreeBlock_t); allctr->vsn_str = ERTS_ALC_AF_ALLOC_VSN_STR; /* Callback functions */ allctr->get_free_block = get_free_block; allctr->link_free_block = link_free_block; allctr->unlink_free_block = unlink_free_block; allctr->info_options = info_options; allctr->get_next_mbc_size = NULL; allctr->creating_mbc = NULL; allctr->destroying_mbc = NULL; allctr->add_mbc = NULL; allctr->remove_mbc = NULL; allctr->largest_fblk_in_mbc = NULL; allctr->init_atoms = init_atoms; #ifdef ERTS_ALLOC_UTIL_HARD_DEBUG allctr->check_block = NULL; allctr->check_mbc = NULL; #endif allctr->atoms_initialized = 0; if (!erts_alcu_start(allctr, init)) return NULL; return allctr; }
int enif_get_atom(ErlNifEnv* env, Eterm atom, char* buf, unsigned len, ErlNifCharEncoding encoding) { Atom* ap; ASSERT(encoding == ERL_NIF_LATIN1); if (is_not_atom(atom)) { return 0; } ap = atom_tab(atom_val(atom)); if (ap->len+1 > len) { return 0; } sys_memcpy(buf, ap->name, ap->len); buf[ap->len] = '\0'; return ap->len + 1; }
Allctr_t * erts_aoffalc_start(AOFFAllctr_t *alc, AOFFAllctrInit_t* aoffinit, AllctrInit_t *init) { AOFFAllctr_t nulled_state = {{0}}; /* {{0}} is used instead of {0}, in order to avoid (an incorrect) gcc warning. gcc warns if {0} is used as initializer of a struct when the first member is a struct (not if, for example, the third member is a struct). */ Allctr_t *allctr = (Allctr_t *) alc; sys_memcpy((void *) alc, (void *) &nulled_state, sizeof(AOFFAllctr_t)); allctr->mbc_header_size = sizeof(Carrier_t); allctr->min_mbc_size = MIN_MBC_SZ; allctr->min_mbc_first_free_size = MIN_MBC_FIRST_FREE_SZ; allctr->min_block_size = sizeof(AOFF_RBTree_t); allctr->vsn_str = ERTS_ALC_AOFF_ALLOC_VSN_STR; /* Callback functions */ allctr->get_free_block = aoff_get_free_block; allctr->link_free_block = aoff_link_free_block; allctr->unlink_free_block = aoff_unlink_free_block; allctr->info_options = info_options; allctr->get_next_mbc_size = NULL; allctr->creating_mbc = NULL; allctr->destroying_mbc = NULL; allctr->init_atoms = init_atoms; #ifdef ERTS_ALLOC_UTIL_HARD_DEBUG allctr->check_block = NULL; allctr->check_mbc = NULL; #endif allctr->atoms_initialized = 0; if (!erts_alcu_start(allctr, init)) return NULL; return allctr; }
void hipe_inc_nstack(Process *p) { unsigned old_size = p->hipe.nstend - p->hipe.nstack; unsigned new_size = hipe_next_nstack_size(old_size); Eterm *new_nstack = erts_alloc(ERTS_ALC_T_HIPE, new_size*sizeof(Eterm)); unsigned used_size = p->hipe.nstend - p->hipe.nsp; sys_memcpy(new_nstack+new_size-used_size, p->hipe.nsp, used_size*sizeof(Eterm)); if (p->hipe.nstgraylim) p->hipe.nstgraylim = new_nstack + new_size - (p->hipe.nstend - p->hipe.nstgraylim); if (p->hipe.nstblacklim) p->hipe.nstblacklim = new_nstack + new_size - (p->hipe.nstend - p->hipe.nstblacklim); if (p->hipe.nstack) erts_free(ERTS_ALC_T_HIPE, p->hipe.nstack); p->hipe.nstack = new_nstack; p->hipe.nstend = new_nstack + new_size; p->hipe.nsp = new_nstack + new_size - used_size; }
void erts_purge_state_add_fun(ErlFunEntry *fe) { ASSERT(is_value(purge_state.module)); if (purge_state.fe_ix >= purge_state.fe_size) { ErlFunEntry **funs; purge_state.fe_size += 100; funs = erts_alloc(ERTS_ALC_T_PURGE_DATA, sizeof(ErlFunEntry *)*purge_state.fe_size); sys_memcpy((void *) funs, (void *) purge_state.funs, purge_state.fe_ix*sizeof(ErlFunEntry *)); if (purge_state.funs != &purge_state.def_funs[0]) erts_free(ERTS_ALC_T_PURGE_DATA, purge_state.funs); purge_state.funs = funs; } purge_state.funs[purge_state.fe_ix++] = fe; }
/*===========================================================================*/ void add_xref_item(char *look,char code) { cross_reference_entry_type item; int nch; /*-------------------------------------------------------*/ if (!xref_map) return; if (((*look)=='$')&&(isascii(*(look+1)))&&(isdigit(*(look+1)))) return; if ((*look)==NUMBER_TABLE_PREFIX_CHAR) return; item.linnum=last_token_gotten_from_linnum; item.pos=last_token_gotten_from_pos; nch=strlen(look); if (nch>XREF_IDENT_MAXNCH_P) nch=XREF_IDENT_MAXNCH_P; sys_memcpy(item.name,look,nch); while (nch<XREF_IDENT_MAXNCH_P) *(item.name+(nch++)) = ' '; item.refcode=code; fwrite(&item,sizeof(cross_reference_entry_type),(size_t) 1,xreffile); /*-------------------------------------------------------*/ }
static Eterm http_bld_string(struct packet_callback_args* pca, Uint **hpp, Uint *szp, const char *str, Sint len) { Eterm res = THE_NON_VALUE; Uint size; int make_subbin; if (pca->string_as_bin) { size = heap_bin_size(len); make_subbin = (size > ERL_SUB_BIN_SIZE && in_area(str, pca->aligned_ptr, pca->bin_sz)); if (szp) { *szp += make_subbin ? ERL_SUB_BIN_SIZE : size; } if (hpp) { res = make_binary(*hpp); if (make_subbin) { ErlSubBin* bin = (ErlSubBin*) *hpp; bin->thing_word = HEADER_SUB_BIN; bin->size = len; bin->offs = pca->bin_offs + ((byte*)str - pca->aligned_ptr); bin->orig = pca->orig; bin->bitoffs = pca->bin_bitoffs; bin->bitsize = 0; bin->is_writable = 0; *hpp += ERL_SUB_BIN_SIZE; } else { ErlHeapBin* bin = (ErlHeapBin*) *hpp; bin->thing_word = header_heap_bin(len); bin->size = len; sys_memcpy(bin->data, str, len); *hpp += size; } } } else { res = erts_bld_string_n(hpp, szp, str, len); } return res; }
int erts_sys_getenv__(char *key, char *value, size_t *size) { int res; char *orig_value = getenv(key); if (!orig_value) res = -1; else { size_t len = sys_strlen(orig_value); if (len >= *size) { *size = len + 1; res = 1; } else { *size = len; sys_memcpy((void *) value, (void *) orig_value, len+1); res = 0; } } return res; }
static BIF_RETTYPE iol2v_yield(iol2v_state_t *state) { if (is_nil(state->magic_reference)) { iol2v_state_t *boxed_state; Binary *magic_binary; Eterm *hp; magic_binary = erts_create_magic_binary_x(sizeof(*state), &iol2v_state_destructor, ERTS_ALC_T_BINARY, 1); boxed_state = ERTS_MAGIC_BIN_UNALIGNED_DATA(magic_binary); sys_memcpy(boxed_state, state, sizeof(*state)); hp = HAlloc(boxed_state->process, ERTS_MAGIC_REF_THING_SIZE); boxed_state->magic_reference = erts_mk_magic_ref(&hp, &MSO(boxed_state->process), magic_binary); state = boxed_state; } ERTS_BIF_YIELD1(bif_export[BIF_iolist_to_iovec_1], state->process, state->magic_reference); }
void erts_mtrace_install_wrapper_functions(void) { if (erts_mtrace_enabled) { int i; /* Install trace functions */ ERTS_CT_ASSERT(sizeof(erts_allctrs) == sizeof(real_allctrs)); sys_memcpy((void *) real_allctrs, (void *) erts_allctrs, sizeof(erts_allctrs)); for (i = ERTS_ALC_A_MIN; i <= ERTS_ALC_A_MAX; i++) { erts_allctrs[i].alloc = mtrace_alloc; erts_allctrs[i].realloc = mtrace_realloc; erts_allctrs[i].free = mtrace_free; erts_allctrs[i].extra = (void *) &real_allctrs[i]; } mtrace_wrapper.lock = mtrace_pre_lock; mtrace_wrapper.unlock = mtrace_pre_unlock; erts_allctr_wrapper_prelock_init(&mtrace_wrapper); } }
/**************************************************************************** * Place for Test Item functions ***************************************************************************/ static int test_item1(void) { int rc = TC_PASS; TE_MEM mstat; sys_memcpy(&mstat, &(osh_config.mstat), sizeof(osh_config.mstat)); get_mstat(&(osh_config.mstat)); log_trace(OSH_TE, "Memory Usage (%s):\t" "before start_pes(): %lld resident: %lld\t" "after start_pes(): %lld resident: %lld\t" "difference: %+lld resident: %+lld\n", __memory_unit_size_str, mstat.vm_size / __memory_unit_size, mstat.vm_rss / __memory_unit_size, osh_config.mstat.vm_size / __memory_unit_size, osh_config.mstat.vm_rss / __memory_unit_size, (osh_config.mstat.vm_size - mstat.vm_size) / __memory_unit_size, (osh_config.mstat.vm_rss - mstat.vm_rss) / __memory_unit_size ); return rc; }
posix_errno_t efile_list_dir(ErlNifEnv *env, const efile_path_t *path, ERL_NIF_TERM *result) { ERL_NIF_TERM list_head; struct dirent *dir_entry; DIR *dir_stream; dir_stream = opendir((const char*)path->data); if(dir_stream == NULL) { posix_errno_t saved_errno = errno; *result = enif_make_list(env, 0); return saved_errno; } list_head = enif_make_list(env, 0); dir_entry = readdir(dir_stream); while(dir_entry != NULL) { int name_length = strlen(dir_entry->d_name); if(!is_ignored_name(name_length, dir_entry->d_name)) { unsigned char *name_bytes; ERL_NIF_TERM name_term; name_bytes = enif_make_new_binary(env, name_length, &name_term); sys_memcpy(name_bytes, dir_entry->d_name, name_length); list_head = enif_make_list_cell(env, name_term, list_head); } dir_entry = readdir(dir_stream); } (*result) = list_head; closedir(dir_stream); return 0; }
int enif_realloc_binary(ErlNifBinary* bin, size_t size) { if (bin->ref_bin != NULL) { Binary* oldbin; Binary* newbin; oldbin = (Binary*) bin->ref_bin; newbin = (Binary *) erts_bin_realloc_fnf(oldbin, size); if (!newbin) { return 0; } newbin->orig_size = size; bin->ref_bin = newbin; bin->data = (unsigned char*) newbin->orig_bytes; bin->size = size; } else { unsigned char* old_data = bin->data; size_t cpy_sz = (size < bin->size ? size : bin->size); enif_alloc_binary(size, bin); sys_memcpy(bin->data, old_data, cpy_sz); } return 1; }
Eterm erts_instr_get_stat(Process *proc, Eterm what, int begin_max_period) { int i, len, max, min, allctr; Eterm *names, *values, res; Uint arr_size, stat_size, hsz, *hszp, *hp, **hpp; Stat_t *stat_src, *stat; if (!erts_instr_stat) return am_false; if (!atoms_initialized) init_atoms(); if (what == am.total) { min = 0; max = 0; allctr = 0; stat_size = sizeof(Stat_t); stat_src = &stats->tot; if (!am_tot) init_am_tot(); names = am_tot; } else if (what == am.allocators) { min = ERTS_ALC_A_MIN; max = ERTS_ALC_A_MAX; allctr = 1; stat_size = sizeof(Stat_t)*(ERTS_ALC_A_MAX+1); stat_src = stats->a; if (!am_a) init_am_a(); names = am_a; } else if (what == am.classes) { min = ERTS_ALC_C_MIN; max = ERTS_ALC_C_MAX; allctr = 0; stat_size = sizeof(Stat_t)*(ERTS_ALC_C_MAX+1); stat_src = stats->c; if (!am_c) init_am_c(); names = &am_c[ERTS_ALC_C_MIN]; } else if (what == am.types) { min = ERTS_ALC_N_MIN; max = ERTS_ALC_N_MAX; allctr = 0; stat_size = sizeof(Stat_t)*(ERTS_ALC_N_MAX+1); stat_src = stats->n; if (!am_n) init_am_n(); names = &am_n[ERTS_ALC_N_MIN]; } else { return THE_NON_VALUE; } stat = (Stat_t *) erts_alloc(ERTS_ALC_T_TMP, stat_size); arr_size = (max - min + 1)*sizeof(Eterm); if (allctr) names = (Eterm *) erts_alloc(ERTS_ALC_T_TMP, arr_size); values = (Eterm *) erts_alloc(ERTS_ALC_T_TMP, arr_size); erts_mtx_lock(&instr_mutex); update_max_ever_values(stat_src, min, max); sys_memcpy((void *) stat, (void *) stat_src, stat_size); if (begin_max_period) begin_new_max_period(stat_src, min, max); erts_mtx_unlock(&instr_mutex); hsz = 0; hszp = &hsz; hpp = NULL; restart_bld: len = 0; for (i = min; i <= max; i++) { if (!allctr || erts_allctrs_info[i].enabled) { Eterm s[2]; if (allctr) names[len] = am_a[i]; s[0] = bld_tuple(hpp, hszp, 4, am.sizes, bld_uint(hpp, hszp, stat[i].size), bld_uint(hpp, hszp, stat[i].max_size), bld_uint(hpp, hszp, stat[i].max_size_ever)); s[1] = bld_tuple(hpp, hszp, 4, am.blocks, bld_uint(hpp, hszp, stat[i].blocks), bld_uint(hpp, hszp, stat[i].max_blocks), bld_uint(hpp, hszp, stat[i].max_blocks_ever)); values[len] = bld_list(hpp, hszp, 2, s); len++; } } res = bld_2tup_list(hpp, hszp, len, names, values); if (!hpp) { hp = HAlloc(proc, hsz); hszp = NULL; hpp = &hp; goto restart_bld; } erts_free(ERTS_ALC_T_TMP, (void *) stat); erts_free(ERTS_ALC_T_TMP, (void *) values); if (allctr) erts_free(ERTS_ALC_T_TMP, (void *) names); return res; }
Uint erts_instr_init(int stat, int map_stat) { Uint extra_sz; int i; am_tot = NULL; am_n = NULL; am_c = NULL; am_a = NULL; erts_instr_memory_map = 0; erts_instr_stat = 0; atoms_initialized = 0; if (!stat && !map_stat) return 0; stats = erts_alloc(ERTS_ALC_T_INSTR_INFO, sizeof(struct stats_)); erts_mtx_init(&instr_mutex, "instr"); mem_anchor = NULL; /* Install instrumentation functions */ ERTS_CT_ASSERT(sizeof(erts_allctrs) == sizeof(real_allctrs)); sys_memcpy((void *)real_allctrs,(void *)erts_allctrs,sizeof(erts_allctrs)); sys_memzero((void *) &stats->tot, sizeof(Stat_t)); sys_memzero((void *) stats->a, sizeof(Stat_t)*(ERTS_ALC_A_MAX+1)); sys_memzero((void *) stats->c, sizeof(Stat_t)*(ERTS_ALC_C_MAX+1)); sys_memzero((void *) stats->n, sizeof(Stat_t)*(ERTS_ALC_N_MAX+1)); for (i = ERTS_ALC_A_MIN; i <= ERTS_ALC_A_MAX; i++) { if (erts_allctrs_info[i].enabled) stats->ap[i] = &stats->a[i]; else stats->ap[i] = &stats->a[ERTS_ALC_A_SYSTEM]; } if (map_stat) { erts_mtx_init(&instr_x_mutex, "instr_x"); erts_instr_memory_map = 1; erts_instr_stat = 1; for (i = ERTS_ALC_A_MIN; i <= ERTS_ALC_A_MAX; i++) { erts_allctrs[i].alloc = map_stat_alloc; erts_allctrs[i].realloc = map_stat_realloc; erts_allctrs[i].free = map_stat_free; erts_allctrs[i].extra = (void *) &real_allctrs[i]; } instr_wrapper.lock = map_stat_pre_lock; instr_wrapper.unlock = map_stat_pre_unlock; extra_sz = MAP_STAT_BLOCK_HEADER_SIZE; } else { erts_instr_stat = 1; for (i = ERTS_ALC_A_MIN; i <= ERTS_ALC_A_MAX; i++) { erts_allctrs[i].alloc = stat_alloc; erts_allctrs[i].realloc = stat_realloc; erts_allctrs[i].free = stat_free; erts_allctrs[i].extra = (void *) &real_allctrs[i]; } instr_wrapper.lock = stat_pre_lock; instr_wrapper.unlock = stat_pre_unlock; extra_sz = STAT_BLOCK_HEADER_SIZE; } erts_allctr_wrapper_prelock_init(&instr_wrapper); return extra_sz; }
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; }
/* Copy a message to the message area. */ Eterm copy_struct_lazy(Process *from, Eterm orig, Uint offs) { Eterm obj; Eterm dest; #ifdef INCREMENTAL int alloc_old = 0; #else int total_need = 0; #endif VERBOSE(DEBUG_MESSAGES, ("COPY START; %T is sending a message @ 0x%016x\n%T\n", from->id, orig, orig)); #ifndef INCREMENTAL copy_start: #endif MA_STACK_PUSH(src,orig); MA_STACK_PUSH(dst,&dest); MA_STACK_PUSH(offset,offs); while (ma_src_top > 0) { obj = MA_STACK_POP(src); /* copy_struct_lazy should never be called with something that * do not need to be copied. Within the loop, nothing that do * not need copying should be placed in the src-stack. */ ASSERT(!NO_COPY(obj)); switch (primary_tag(obj)) { case TAG_PRIMARY_LIST: { Eterm *hp; Eterm *objp; GlobalAlloc(from,2,hp); objp = list_val(obj); MA_STACK_UPDATE(dst,MA_STACK_POP(offset),make_list(hp)); MA_STACK_POP(dst); /* TODO: Byt ordningen nedan så att CDR pushas först. */ if (NO_COPY(*objp)) { hp[0] = *objp; #ifdef INCREMENTAL if (ptr_within(ptr_val(*objp),inc_fromspc,inc_fromend)) INC_STORE(gray,hp,2); #endif } else { MA_STACK_PUSH(src,*objp); MA_STACK_PUSH(dst,hp); MA_STACK_PUSH(offset,0); } objp++; if (NO_COPY(*objp)) { hp[1] = *objp; #ifdef INCREMENTAL if (ptr_within(ptr_val(*objp),inc_fromspc,inc_fromend)) INC_STORE(gray,hp,2); #endif } else { MA_STACK_PUSH(src,*objp); MA_STACK_PUSH(dst,hp); MA_STACK_PUSH(offset,1); } continue; } case TAG_PRIMARY_BOXED: { Eterm *objp = boxed_val(obj); switch (*objp & _TAG_HEADER_MASK) { case ARITYVAL_SUBTAG: { Uint ari = arityval(*objp); Uint i; Eterm *hp; GlobalAlloc(from,ari + 1,hp); /* A GC above might invalidate the value of objp */ objp = boxed_val(obj); MA_STACK_UPDATE(dst,MA_STACK_POP(offset),make_tuple(hp)); MA_STACK_POP(dst); *hp = *objp++; for (i = 1; i <= ari; i++) { switch (primary_tag(*objp)) { case TAG_PRIMARY_LIST: case TAG_PRIMARY_BOXED: if (NO_COPY(*objp)) { hp[i] = *objp; #ifdef INCREMENTAL if (ptr_within(ptr_val(*objp), inc_fromspc,inc_fromend)) INC_STORE(gray,hp,BOXED_NEED(hp,*hp)); #endif objp++; } else { MA_STACK_PUSH(src,*objp++); MA_STACK_PUSH(dst,hp); MA_STACK_PUSH(offset,i); } break; default: hp[i] = *objp++; } } continue; } case REFC_BINARY_SUBTAG: { ProcBin *pb; Uint i = thing_arityval(*objp) + 1; Eterm *hp; GlobalAlloc(from,i,hp); /* A GC above might invalidate the value of objp */ objp = boxed_val(obj); MA_STACK_UPDATE(dst,MA_STACK_POP(offset),make_binary(hp)); MA_STACK_POP(dst); pb = (ProcBin*) hp; while (i--) { *hp++ = *objp++; } erts_refc_inc(&pb->val->refc, 2); pb->next = erts_global_offheap.mso; erts_global_offheap.mso = pb; erts_global_offheap.overhead += pb->size / sizeof(Eterm); continue; } case FUN_SUBTAG: { ErlFunThing *funp = (ErlFunThing*) objp; Uint i = thing_arityval(*objp) + 1; Uint j = i + 1 + funp->num_free; Uint k = i; Eterm *hp, *hp_start; GlobalAlloc(from,j,hp); /* A GC above might invalidate the value of objp */ objp = boxed_val(obj); hp_start = hp; MA_STACK_UPDATE(dst,MA_STACK_POP(offset),make_fun(hp)); MA_STACK_POP(dst); funp = (ErlFunThing*) hp; while (i--) { *hp++ = *objp++; } #ifndef HYBRID // FIND ME! funp->next = erts_global_offheap.funs; erts_global_offheap.funs = funp; erts_refc_inc(&funp->fe->refc, 2); #endif for (i = k; i < j; i++) { switch (primary_tag(*objp)) { case TAG_PRIMARY_LIST: case TAG_PRIMARY_BOXED: if (NO_COPY(*objp)) { #ifdef INCREMENTAL if (ptr_within(ptr_val(*objp), inc_fromspc,inc_fromend)) INC_STORE(gray,hp,BOXED_NEED(hp,*hp)); #endif *hp++ = *objp++; } else { MA_STACK_PUSH(src,*objp++); MA_STACK_PUSH(dst,hp_start); MA_STACK_PUSH(offset,i); hp++; } break; default: *hp++ = *objp++; } } continue; } case EXTERNAL_PID_SUBTAG: case EXTERNAL_PORT_SUBTAG: case EXTERNAL_REF_SUBTAG: { ExternalThing *etp; Uint i = thing_arityval(*objp) + 1; Eterm *hp; GlobalAlloc(from,i,hp); /* A GC above might invalidate the value of objp */ objp = boxed_val(obj); MA_STACK_UPDATE(dst,MA_STACK_POP(offset),make_external(hp)); MA_STACK_POP(dst); etp = (ExternalThing*) hp; while (i--) { *hp++ = *objp++; } etp->next = erts_global_offheap.externals; erts_global_offheap.externals = etp; erts_refc_inc(&etp->node->refc, 2); continue; } case SUB_BINARY_SUBTAG: { ErlSubBin *sb = (ErlSubBin *) objp; Eterm *hp; Eterm res_binary; Eterm real_bin = sb->orig; Uint bit_offset = sb->bitoffs; Uint bit_size = sb -> bitsize; Uint sub_offset = sb->offs; size_t size = sb->size; Uint extra_bytes; Uint real_size; Uint sub_binary_heapneed; if ((bit_size + bit_offset) > 8) { extra_bytes = 2; sub_binary_heapneed = ERL_SUB_BIN_SIZE; } else if ((bit_size + bit_offset) > 0) { extra_bytes = 1; sub_binary_heapneed = ERL_SUB_BIN_SIZE; } else { extra_bytes = 0; sub_binary_heapneed = 0; } real_size = size+extra_bytes; objp = binary_val(real_bin); if (thing_subtag(*objp) == HEAP_BINARY_SUBTAG) { ErlHeapBin *from_bin; ErlHeapBin *to_bin; Uint i = heap_bin_size(real_size); GlobalAlloc(from,i+sub_binary_heapneed,hp); from_bin = (ErlHeapBin *) objp; to_bin = (ErlHeapBin *) hp; to_bin->thing_word = header_heap_bin(real_size); to_bin->size = real_size; sys_memcpy(to_bin->data, ((byte *)from_bin->data) + sub_offset, real_size); res_binary = make_binary(to_bin); hp += i; } else { ProcBin *from_bin; ProcBin *to_bin; ASSERT(thing_subtag(*objp) == REFC_BINARY_SUBTAG); from_bin = (ProcBin *) objp; erts_refc_inc(&from_bin->val->refc, 2); GlobalAlloc(from,PROC_BIN_SIZE+sub_binary_heapneed,hp); to_bin = (ProcBin *) hp; to_bin->thing_word = HEADER_PROC_BIN; to_bin->size = real_size; to_bin->val = from_bin->val; to_bin->bytes = from_bin->bytes + sub_offset; to_bin->next = erts_global_offheap.mso; erts_global_offheap.mso = to_bin; erts_global_offheap.overhead += to_bin->size / sizeof(Eterm); res_binary=make_binary(to_bin); hp += PROC_BIN_SIZE; } if (extra_bytes != 0) { ErlSubBin* res; res = (ErlSubBin *) hp; res->thing_word = HEADER_SUB_BIN; res->size = size; res->bitsize = bit_size; res->bitoffs = bit_offset; res->offs = 0; res->is_writable = 0; res->orig = res_binary; res_binary = make_binary(hp); } MA_STACK_UPDATE(dst,MA_STACK_POP(offset),res_binary); MA_STACK_POP(dst); continue; } case BIN_MATCHSTATE_SUBTAG: erl_exit(ERTS_ABORT_EXIT, "copy_struct_lazy: matchstate term not allowed"); default: { Uint size = thing_arityval(*objp) + 1; Eterm *hp; GlobalAlloc(from,size,hp); /* A GC above might invalidate the value of objp */ objp = boxed_val(obj); MA_STACK_UPDATE(dst,MA_STACK_POP(offset),make_boxed(hp)); MA_STACK_POP(dst); while (size--) { *hp++ = *objp++; } continue; } } continue; } case TAG_PRIMARY_HEADER: ASSERT((obj & _TAG_HEADER_MASK) == ARITYVAL_SUBTAG); { Eterm *objp = &obj; Uint ari = arityval(obj); Uint i; Eterm *hp; GlobalAlloc(from,ari + 1,hp); MA_STACK_UPDATE(dst,MA_STACK_POP(offset),make_tuple(hp)); MA_STACK_POP(dst); *hp = *objp++; for (i = 1; i <= ari; i++) { switch (primary_tag(*objp)) { case TAG_PRIMARY_LIST: case TAG_PRIMARY_BOXED: if (NO_COPY(*objp)) { #ifdef INCREMENTAL if (ptr_within(ptr_val(*objp),inc_fromspc,inc_fromend)) INC_STORE(gray,hp,ari + 1); #endif hp[i] = *objp++; } else { MA_STACK_PUSH(src,*objp++); MA_STACK_PUSH(dst,hp); MA_STACK_PUSH(offset,i); } break; default: hp[i] = *objp++; } } continue; } default: erl_exit(ERTS_ABORT_EXIT, "%s, line %d: Internal error in copy_struct_lazy: 0x%08x\n", __FILE__, __LINE__,obj); } } VERBOSE(DEBUG_MESSAGES, ("Copy allocated @ 0x%08lx:\n%T\n", (unsigned long)ptr_val(dest),dest)); ma_gc_flags &= ~GC_CYCLE_START; ASSERT(eq(orig, dest)); ASSERT(ma_src_top == 0); ASSERT(ma_dst_top == 0); ASSERT(ma_offset_top == 0); return dest; }
/* * Copy a structure to a heap. */ Eterm copy_struct(Eterm obj, Uint sz, Eterm** hpp, ErlOffHeap* off_heap) { char* hstart; Uint hsize; Eterm* htop; Eterm* hbot; Eterm* hp; Eterm* objp; Eterm* tp; Eterm res; Eterm elem; Eterm* tailp; Eterm* argp; Eterm* const_tuple; Eterm hdr; int i; #ifdef DEBUG Eterm org_obj = obj; Uint org_sz = sz; #endif if (IS_CONST(obj)) return obj; hp = htop = *hpp; hbot = htop + sz; hstart = (char *)htop; hsize = (char*) hbot - hstart; const_tuple = 0; /* Copy the object onto the heap */ switch (primary_tag(obj)) { case TAG_PRIMARY_LIST: argp = &res; goto L_copy_list; case TAG_PRIMARY_BOXED: argp = &res; goto L_copy_boxed; default: erl_exit(ERTS_ABORT_EXIT, "%s, line %d: Internal error in copy_struct: 0x%08x\n", __FILE__, __LINE__,obj); } L_copy: while (hp != htop) { obj = *hp; switch (primary_tag(obj)) { case TAG_PRIMARY_IMMED1: hp++; break; case TAG_PRIMARY_LIST: objp = list_val(obj); if (in_area(objp,hstart,hsize)) { hp++; break; } argp = hp++; /* Fall through */ L_copy_list: tailp = argp; while (is_list(obj)) { objp = list_val(obj); tp = tailp; elem = *objp; if (IS_CONST(elem)) { *(hbot-2) = elem; tailp = hbot-1; hbot -= 2; } else { *htop = elem; tailp = htop+1; htop += 2; } *tp = make_list(tailp - 1); obj = *(objp+1); } switch (primary_tag(obj)) { case TAG_PRIMARY_IMMED1: *tailp = obj; goto L_copy; case TAG_PRIMARY_BOXED: argp = tailp; goto L_copy_boxed; default: erl_exit(ERTS_ABORT_EXIT, "%s, line %d: Internal error in copy_struct: 0x%08x\n", __FILE__, __LINE__,obj); } case TAG_PRIMARY_BOXED: if (in_area(boxed_val(obj),hstart,hsize)) { hp++; break; } argp = hp++; L_copy_boxed: objp = boxed_val(obj); hdr = *objp; switch (hdr & _TAG_HEADER_MASK) { case ARITYVAL_SUBTAG: { int const_flag = 1; /* assume constant tuple */ i = arityval(hdr); *argp = make_tuple(htop); tp = htop; /* tp is pointer to new arity value */ *htop++ = *objp++; /* copy arity value */ while (i--) { elem = *objp++; if (!IS_CONST(elem)) { const_flag = 0; } *htop++ = elem; } if (const_flag) { const_tuple = tp; /* this is the latest const_tuple */ } } break; case REFC_BINARY_SUBTAG: { ProcBin* pb; pb = (ProcBin *) objp; if (pb->flags) { erts_emasculate_writable_binary(pb); } i = thing_arityval(*objp) + 1; hbot -= i; tp = hbot; while (i--) { *tp++ = *objp++; } *argp = make_binary(hbot); pb = (ProcBin*) hbot; erts_refc_inc(&pb->val->refc, 2); pb->next = off_heap->mso; pb->flags = 0; off_heap->mso = pb; off_heap->overhead += pb->size / sizeof(Eterm); } break; case SUB_BINARY_SUBTAG: { ErlSubBin* sb = (ErlSubBin *) objp; Eterm real_bin = sb->orig; Uint bit_offset = sb->bitoffs; Uint bit_size = sb -> bitsize; Uint offset = sb->offs; size_t size = sb->size; Uint extra_bytes; Uint real_size; if ((bit_size + bit_offset) > 8) { extra_bytes = 2; } else if ((bit_size + bit_offset) > 0) { extra_bytes = 1; } else { extra_bytes = 0; } real_size = size+extra_bytes; objp = binary_val(real_bin); if (thing_subtag(*objp) == HEAP_BINARY_SUBTAG) { ErlHeapBin* from = (ErlHeapBin *) objp; ErlHeapBin* to; i = heap_bin_size(real_size); hbot -= i; to = (ErlHeapBin *) hbot; to->thing_word = header_heap_bin(real_size); to->size = real_size; sys_memcpy(to->data, ((byte *)from->data)+offset, real_size); } else { ProcBin* from = (ProcBin *) objp; ProcBin* to; ASSERT(thing_subtag(*objp) == REFC_BINARY_SUBTAG); if (from->flags) { erts_emasculate_writable_binary(from); } hbot -= PROC_BIN_SIZE; to = (ProcBin *) hbot; to->thing_word = HEADER_PROC_BIN; to->size = real_size; to->val = from->val; erts_refc_inc(&to->val->refc, 2); to->bytes = from->bytes + offset; to->next = off_heap->mso; to->flags = 0; off_heap->mso = to; off_heap->overhead += to->size / sizeof(Eterm); } *argp = make_binary(hbot); if (extra_bytes != 0) { ErlSubBin* res; hbot -= ERL_SUB_BIN_SIZE; res = (ErlSubBin *) hbot; res->thing_word = HEADER_SUB_BIN; res->size = size; res->bitsize = bit_size; res->bitoffs = bit_offset; res->offs = 0; res->is_writable = 0; res->orig = *argp; *argp = make_binary(hbot); } break; } break; case FUN_SUBTAG: { ErlFunThing* funp = (ErlFunThing *) objp; i = thing_arityval(hdr) + 2 + funp->num_free; tp = htop; while (i--) { *htop++ = *objp++; } #ifndef HYBRID /* FIND ME! */ funp = (ErlFunThing *) tp; funp->next = off_heap->funs; off_heap->funs = funp; erts_refc_inc(&funp->fe->refc, 2); #endif *argp = make_fun(tp); } break; case EXTERNAL_PID_SUBTAG: case EXTERNAL_PORT_SUBTAG: case EXTERNAL_REF_SUBTAG: { ExternalThing *etp = (ExternalThing *) htop; i = thing_arityval(hdr) + 1; tp = htop; while (i--) { *htop++ = *objp++; } etp->next = off_heap->externals; off_heap->externals = etp; erts_refc_inc(&etp->node->refc, 2); *argp = make_external(tp); } break; case BIN_MATCHSTATE_SUBTAG: erl_exit(ERTS_ABORT_EXIT, "copy_struct: matchstate term not allowed"); default: i = thing_arityval(hdr)+1; hbot -= i; tp = hbot; *argp = make_boxed(hbot); while (i--) { *tp++ = *objp++; } } break; case TAG_PRIMARY_HEADER: if (header_is_thing(obj) || hp == const_tuple) { hp += header_arity(obj) + 1; } else { hp++; } break; } } #ifdef DEBUG if (htop != hbot) erl_exit(ERTS_ABORT_EXIT, "Internal error in copy_struct() when copying %T:" " htop=%p != hbot=%p (sz=%bpu)\n", org_obj, htop, hbot, org_sz); #else if (htop > hbot) { erl_exit(ERTS_ABORT_EXIT, "Internal error in copy_struct(): htop, hbot overrun\n"); } #endif *hpp = (Eterm *) (hstart+hsize); return res; }