/* * %CopyrightBegin% * * Copyright Ericsson AB 2016-2018. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * %CopyrightEnd% */ #ifdef HAVE_CONFIG_H # include "config.h" #endif #define ERTS_WANT_NFUNC_SCHED_INTERNALS__ #include "global.h" #include "erl_process.h" #include "bif.h" #include "erl_nfunc_sched.h" #include "erl_trace.h" NifExport * erts_new_proc_nif_export(Process *c_p, int argc) { size_t size; int i; NifExport *nep, *old_nep; size = sizeof(NifExport) + (argc-1)*sizeof(Eterm); nep = erts_alloc(ERTS_ALC_T_NIF_TRAP_EXPORT, size); for (i = 0; i < ERTS_NUM_CODE_IX; i++) nep->exp.addressv[i] = &nep->exp.beam[0]; nep->argc = -1; /* unused marker */ nep->argv_size = argc; nep->trace = NULL; old_nep = ERTS_PROC_SET_NIF_TRAP_EXPORT(c_p, nep); if (old_nep) { ASSERT(!nep->trace); erts_free(ERTS_ALC_T_NIF_TRAP_EXPORT, old_nep); } return nep; } void erts_destroy_nif_export(Process *p) { NifExport *nep = ERTS_PROC_SET_NIF_TRAP_EXPORT(p, NULL); if (nep) { if (nep->m) erts_nif_export_cleanup_nif_mod(nep); erts_free(ERTS_ALC_T_NIF_TRAP_EXPORT, nep); } } void erts_nif_export_save_trace(Process *c_p, NifExport *nep, int applying, Export* ep, BeamInstr *cp, Uint32 flags, Uint32 flags_meta, BeamInstr* I, ErtsTracer meta_tracer) { NifExportTrace *netp; ASSERT(nep && nep->argc >= 0); ASSERT(!nep->trace); netp = erts_alloc(ERTS_ALC_T_NIF_EXP_TRACE, sizeof(NifExportTrace)); netp->applying = applying; netp->ep = ep; netp->cp = cp; netp->flags = flags; netp->flags_meta = flags_meta; netp->I = I; netp->meta_tracer = NIL; erts_tracer_update(&netp->meta_tracer, meta_tracer); nep->trace = netp; } void erts_nif_export_restore_trace(Process *c_p, Eterm result, NifExport *nep) { NifExportTrace *netp = nep->trace; nep->trace = NULL; erts_bif_trace_epilogue(c_p, result, netp->applying, netp->ep, netp->cp, netp->flags, netp->flags_meta, netp->I, netp->meta_tracer); erts_tracer_update(&netp->meta_tracer, NIL); erts_free(ERTS_ALC_T_NIF_EXP_TRACE, netp); } NifExport * erts_nif_export_schedule(Process *c_p, Process *dirty_shadow_proc, ErtsCodeMFA *mfa, BeamInstr *pc, BeamInstr instr, void *dfunc, void *ifunc, Eterm mod, Eterm func, int argc, const Eterm *argv) { Process *used_proc; ErtsSchedulerData *esdp; Eterm* reg; NifExport* nep; int i; ERTS_LC_ASSERT(erts_proc_lc_my_proc_locks(c_p) & ERTS_PROC_LOCK_MAIN); if (dirty_shadow_proc) { esdp = erts_get_scheduler_data(); ASSERT(esdp && ERTS_SCHEDULER_IS_DIRTY(esdp)); used_proc = dirty_shadow_proc; } else { esdp = erts_proc_sched_data(c_p); ASSERT(esdp && !ERTS_SCHEDULER_IS_DIRTY(esdp)); used_proc = c_p; ERTS_VBUMP_ALL_REDS(c_p); } reg = esdp->x_reg_array; if (mfa) nep = erts_get_proc_nif_export(c_p, (int) mfa->arity); else { /* If no mfa, this is not the first schedule... */ nep = ERTS_PROC_GET_NIF_TRAP_EXPORT(c_p); ASSERT(nep && nep->argc >= 0); } if (nep->argc < 0) { /* * First schedule; save things that might * need to be restored... */ for (i = 0; i < (int) mfa->arity; i++) nep->argv[i] = reg[i]; nep->pc = pc; nep->cp = c_p->cp; nep->mfa = mfa; nep->current = c_p->current; ASSERT(argc >= 0); nep->argc = (int) mfa->arity; nep->m = NULL; ASSERT(!erts_check_nif_export_in_area(c_p, (char *) nep, (sizeof(NifExport) + (sizeof(Eterm) *(nep->argc-1))))); } /* Copy new arguments into register array if necessary... */ if (reg != argv) { for (i = 0; i < argc; i++) reg[i] = argv[i]; } ASSERT(is_atom(mod) && is_atom(func)); nep->exp.info.mfa.module = mod; nep->exp.info.mfa.function = func; nep->exp.info.mfa.arity = (Uint) argc; nep->exp.beam[0] = (BeamInstr) instr; /* call_nif || apply_bif */ nep->exp.beam[1] = (BeamInstr) dfunc; nep->func = ifunc; used_proc->arity = argc; used_proc->freason = TRAP; used_proc->i = (BeamInstr*) nep->exp.addressv[0]; return nep; }