static void dump_element(int to, void *to_arg, Eterm x) { if (is_list(x)) { erts_print(to, to_arg, "H" WORD_FMT, list_val(x)); } else if (is_boxed(x)) { erts_print(to, to_arg, "H" WORD_FMT, boxed_val(x)); } else if (is_immed(x)) { if (is_atom(x)) { unsigned char* s = atom_tab(atom_val(x))->name; int len = atom_tab(atom_val(x))->len; int i; erts_print(to, to_arg, "A%X:", atom_tab(atom_val(x))->len); for (i = 0; i < len; i++) { erts_putc(to, to_arg, *s++); } } else if (is_small(x)) { erts_print(to, to_arg, "I%T", x); } else if (is_pid(x)) { erts_print(to, to_arg, "P%T", x); } else if (is_port(x)) { erts_print(to, to_arg, "p<%bpu.%bpu>", port_channel_no(x), port_number(x)); } else if (is_nil(x)) { erts_putc(to, to_arg, 'N'); } } }
static void lookup_loc(FunctionInfo* fi, BeamInstr* orig_pc, BeamInstr* modp, int idx) { Eterm* line = (Eterm *) modp[MI_LINE_TABLE]; Eterm* low; Eterm* high; Eterm* mid; Eterm pc; if (line == 0) { return; } pc = (Eterm) (BeamInstr) orig_pc; fi->fname_ptr = (Eterm *) (BeamInstr) line[MI_LINE_FNAME_PTR]; low = (Eterm *) (BeamInstr) line[MI_LINE_FUNC_TAB+idx]; high = (Eterm *) (BeamInstr) line[MI_LINE_FUNC_TAB+idx+1]; while (high > low) { mid = low + (high-low) / 2; if (pc < mid[0]) { high = mid; } else if (pc < mid[1]) { int file; int index = mid - (Eterm *) (BeamInstr) line[MI_LINE_FUNC_TAB]; if (line[MI_LINE_LOC_SIZE] == 2) { Uint16* loc_table = (Uint16 *) (BeamInstr) line[MI_LINE_LOC_TAB]; fi->loc = loc_table[index]; } else { Uint32* loc_table = (Uint32 *) (BeamInstr) line[MI_LINE_LOC_TAB]; ASSERT(line[MI_LINE_LOC_SIZE] == 4); fi->loc = loc_table[index]; } if (fi->loc == LINE_INVALID_LOCATION) { return; } fi->needed += 3+2+3+2; file = LOC_FILE(fi->loc); if (file == 0) { /* Special case: Module name with ".erl" appended */ Atom* mod_atom = atom_tab(atom_val(fi->current[0])); fi->needed += 2*(mod_atom->len+4); } else { Atom* ap = atom_tab(atom_val((fi->fname_ptr)[file-1])); fi->needed += 2*ap->len; } return; } else { low = mid + 1; } } }
static void lookup_loc(FunctionInfo* fi, const BeamInstr* pc, BeamCodeHeader* code_hdr, int idx) { BeamCodeLineTab* lt = code_hdr->line_table; const BeamInstr** low; const BeamInstr** high; const BeamInstr** mid; if (lt == NULL) { return; } fi->fname_ptr = lt->fname_ptr; low = lt->func_tab[idx]; high = lt->func_tab[idx+1]; while (high > low) { mid = low + (high-low) / 2; if (pc < mid[0]) { high = mid; } else if (pc < mid[1]) { int file; int index = mid - lt->func_tab[0]; if (lt->loc_size == 2) { fi->loc = lt->loc_tab.p2[index]; } else { ASSERT(lt->loc_size == 4); fi->loc = lt->loc_tab.p4[index]; } if (fi->loc == LINE_INVALID_LOCATION) { return; } fi->needed += 3+2+3+2; file = LOC_FILE(fi->loc); if (file == 0) { /* Special case: Module name with ".erl" appended */ Atom* mod_atom = atom_tab(atom_val(fi->mfa->module)); fi->needed += 2*(mod_atom->len+4); } else { Atom* ap = atom_tab(atom_val((fi->fname_ptr)[file-1])); fi->needed += 2*ap->len; } return; } else { low = mid + 1; } } }
static HashValue node_table_hash(void *venp) { Uint32 cre = ((ErlNode *) venp)->creation; HashValue h = atom_tab(atom_val(((ErlNode *) venp)->sysname))->slot.bucket.hvalue; h *= PRIME0; h += cre & 0xff; #if MAX_CREATION >= (1 << 8) h *= PRIME1; h += (cre >> 8) & 0xff; #endif #if MAX_CREATION >= (1 << 16) h *= PRIME2; h += (cre >> 16) & 0xff; #endif #if MAX_CREATION >= (1 << 24) h *= PRIME3; h += (cre >> 24) & 0xff; #endif #if 0 /* XXX Problems in older versions of GCC */ #if MAX_CREATION >= (1UL << 32) #error "MAX_CREATION larger than size of expected creation storage (Uint32)" #endif #endif return h; }
static char *pick_list_or_atom(Eterm name_term) { char *name = NULL; ErlDrvSizeT name_len; if (is_atom(name_term)) { Atom *ap = atom_tab(atom_val(name_term)); if (ap->len == 0) { /* If io_lists with zero length is not allowed, then the empty atom shouldn't */ goto error; } name = erts_alloc(ERTS_ALC_T_DDLL_TMP_BUF, ap->len + 1); memcpy(name,ap->name,ap->len); name[ap->len] = '\0'; } else { if (erts_iolist_size(name_term, &name_len)) { goto error; } name = erts_alloc(ERTS_ALC_T_DDLL_TMP_BUF, name_len + 1); if (erts_iolist_to_buf(name_term, name, name_len) != 0) { goto error; } name[name_len] = '\0'; } return name; error: if (name != NULL) { erts_free(ERTS_ALC_T_DDLL_TMP_BUF, (void *) name); } return NULL; }
static void* dist_table_alloc(void *dep_tmpl) { Eterm chnl_nr; Eterm sysname; DistEntry *dep; erts_smp_rwmtx_opt_t rwmtx_opt = ERTS_SMP_RWMTX_OPT_DEFAULT_INITER; rwmtx_opt.type = ERTS_SMP_RWMTX_TYPE_FREQUENT_READ; sysname = ((DistEntry *) dep_tmpl)->sysname; chnl_nr = make_small((Uint) atom_val(sysname)); dep = (DistEntry *) erts_alloc(ERTS_ALC_T_DIST_ENTRY, sizeof(DistEntry)); dist_entries++; dep->prev = NULL; erts_refc_init(&dep->refc, -1); erts_smp_rwmtx_init_opt_x(&dep->rwmtx, &rwmtx_opt, "dist_entry", chnl_nr); dep->sysname = sysname; dep->cid = NIL; dep->connection_id = 0; dep->status = 0; dep->flags = 0; dep->version = 0; erts_smp_mtx_init_x(&dep->lnk_mtx, "dist_entry_links", chnl_nr); dep->node_links = NULL; dep->nlinks = NULL; dep->monitors = NULL; erts_smp_mtx_init_x(&dep->qlock, "dist_entry_out_queue", chnl_nr); dep->qflgs = 0; dep->qsize = 0; dep->out_queue.first = NULL; dep->out_queue.last = NULL; dep->suspended = NULL; dep->finalized_out_queue.first = NULL; dep->finalized_out_queue.last = NULL; erts_smp_atomic_init_nob(&dep->dist_cmd_scheduled, 0); erts_port_task_handle_init(&dep->dist_cmd); dep->send = NULL; dep->cache = NULL; /* Link in */ /* All new dist entries are "not connected". * erts_this_dist_entry is also always included among "not connected" */ dep->next = erts_not_connected_dist_entries; if(erts_not_connected_dist_entries) { ASSERT(erts_not_connected_dist_entries->prev == NULL); erts_not_connected_dist_entries->prev = dep; } erts_not_connected_dist_entries = dep; erts_no_of_not_connected_dist_entries++; return (void *) dep; }
static HashValue node_table_hash(void *venp) { Uint32 cre = ((ErlNode *) venp)->creation; HashValue h = atom_tab(atom_val(((ErlNode *) venp)->sysname))->slot.bucket.hvalue; return (h + cre) * PRIME0; }
int enif_get_atom_length(ErlNifEnv* env, Eterm atom, unsigned* len, ErlNifCharEncoding enc) { Atom* ap; ASSERT(enc == ERL_NIF_LATIN1); if (is_not_atom(atom)) return 0; ap = atom_tab(atom_val(atom)); *len = ap->len; return 1; }
void erts_print_nif_taints(int to, void* to_arg) { struct tainted_module_t* t; const char* delim = ""; for (t=first_tainted_module ; t!=NULL; t=t->next) { const Atom* atom = atom_tab(atom_val(t->module_atom)); erts_print(to,to_arg,"%s%.*s", delim, atom->len, atom->name); delim = ","; } erts_print(to,to_arg,"\n"); }
Module* erts_put_module(Eterm mod) { Module e; int index; ASSERT(is_atom(mod)); ERTS_SMP_LC_ASSERT(erts_initialized == 0 || erts_smp_is_system_blocked(0)); e.module = atom_val(mod); index = index_put(&module_table, (void*) &e); return (Module*) erts_index_lookup(&module_table, index); }
/* * Build a single {M,F,A,Loction} item to be part of * a stack trace. */ Eterm* erts_build_mfa_item(FunctionInfo* fi, Eterm* hp, Eterm args, Eterm* mfa_p) { BeamInstr* current = fi->current; Eterm loc = NIL; if (fi->loc != LINE_INVALID_LOCATION) { Eterm tuple; int line = LOC_LINE(fi->loc); int file = LOC_FILE(fi->loc); Eterm file_term = NIL; if (file == 0) { Atom* ap = atom_tab(atom_val(fi->current[0])); file_term = buf_to_intlist(&hp, ".erl", 4, NIL); file_term = buf_to_intlist(&hp, (char*)ap->name, ap->len, file_term); } else { Atom* ap = atom_tab(atom_val((fi->fname_ptr)[file-1])); file_term = buf_to_intlist(&hp, (char*)ap->name, ap->len, NIL); } tuple = TUPLE2(hp, am_line, make_small(line)); hp += 3; loc = CONS(hp, tuple, loc); hp += 2; tuple = TUPLE2(hp, am_file, file_term); hp += 3; loc = CONS(hp, tuple, loc); hp += 2; } if (is_list(args) || is_nil(args)) { *mfa_p = TUPLE4(hp, current[0], current[1], args, loc); } else { Eterm arity = make_small(current[2]); *mfa_p = TUPLE4(hp, current[0], current[1], arity, loc); } return hp + 5; }
static Module* put_module(Eterm mod, IndexTable* mod_tab) { Module e; int oldsz, newsz; Module* res; ASSERT(is_atom(mod)); e.module = atom_val(mod); oldsz = index_table_sz(mod_tab); res = (Module*) index_put_entry(mod_tab, (void*) &e); newsz = index_table_sz(mod_tab); erts_atomic_add_nob(&tot_module_bytes, (newsz - oldsz)); return res; }
Module* erts_get_module(Eterm mod) { Module e; int index; ASSERT(is_atom(mod)); e.module = atom_val(mod); index = index_get(&module_table, (void*) &e); if (index == -1) { return NULL; } else { return (Module*) erts_index_lookup(&module_table, index); } }
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; }
Module* erts_get_module(Eterm mod, ErtsCodeIndex code_ix) { Module e; int index; IndexTable* mod_tab; ASSERT(is_atom(mod)); mod_tab = &module_tables[code_ix]; e.module = atom_val(mod); index = index_get(mod_tab, (void*) &e); if (index == -1) { return NULL; } else { return (Module*) erts_index_lookup(mod_tab, index); } }
static void* dist_table_alloc(void *dep_tmpl) { DistEntry *dep; if(((DistEntry *) dep_tmpl) == erts_this_dist_entry) return dep_tmpl; dep = (DistEntry *) erts_alloc(ERTS_ALC_T_DIST_ENTRY, sizeof(DistEntry)); dist_entries++; dep->prev = NULL; erts_refc_init(&dep->refc, -1); dep->sysname = ((DistEntry *) dep_tmpl)->sysname; dep->cid = NIL; dep->nlinks = NULL; dep->node_links = NULL; dep->monitors = NULL; dep->status = 0; dep->flags = 0; dep->cache = NULL; dep->version = 0; #ifdef ERTS_SMP dep->mtxp = &dist_entry_mutexes[(atom_val(dep->sysname) % ERTS_NO_OF_DIST_ENTRY_MUTEXES)]; #endif /* Link in */ /* All new dist entries are "not connected" */ dep->next = erts_not_connected_dist_entries; if(erts_not_connected_dist_entries) { ASSERT(erts_not_connected_dist_entries->prev == NULL); erts_not_connected_dist_entries->prev = dep; } erts_not_connected_dist_entries = dep; erts_no_of_not_connected_dist_entries++; return (void *) dep; }
BIF_RETTYPE purge_module_1(BIF_ALIST_1) { int purge_res; if (is_not_atom(BIF_ARG_1)) { BIF_ERROR(BIF_P, BADARG); } erts_smp_proc_unlock(BIF_P, ERTS_PROC_LOCK_MAIN); erts_smp_block_system(0); erts_export_consolidate(); purge_res = purge_module(atom_val(BIF_ARG_1)); erts_smp_release_system(); erts_smp_proc_lock(BIF_P, ERTS_PROC_LOCK_MAIN); if (purge_res < 0) { BIF_ERROR(BIF_P, BADARG); } BIF_RET(am_true); }
static int errdesc_to_code(Eterm errdesc, int *code /* out */) { int i; if (is_atom(errdesc)) { Atom *ap = atom_tab(atom_val(errdesc)); for (i = 0; errcode_tab[i].atm != NULL; ++i) { int len = sys_strlen(errcode_tab[i].atm); if (len == ap->len && !sys_strncmp(errcode_tab[i].atm,(char *) ap->name,len)) { *code = errcode_tab[i].code; return 0; } } return -1; } else if (is_tuple(errdesc)) { Eterm *tp = tuple_val(errdesc); if (*tp != make_arityval(2) || tp[1] != am_open_error || is_not_small(tp[2])) { return -1; } *code = signed_val(tp[2]); return 0; } return -1; }
static int open_port(Process* p, Eterm name, Eterm settings, int *err_nump) { #define OPEN_PORT_ERROR(VAL) do { port_num = (VAL); goto do_return; } while (0) int i, port_num; Eterm option; Uint arity; Eterm* tp; Uint* nargs; erts_driver_t* driver; char* name_buf = NULL; SysDriverOpts opts; int binary_io; int soft_eof; Sint linebuf; Eterm edir = NIL; byte dir[MAXPATHLEN]; /* These are the defaults */ opts.packet_bytes = 0; opts.use_stdio = 1; opts.redir_stderr = 0; opts.read_write = 0; opts.hide_window = 0; opts.wd = NULL; opts.envir = NULL; opts.exit_status = 0; opts.overlapped_io = 0; opts.spawn_type = ERTS_SPAWN_ANY; opts.argv = NULL; binary_io = 0; soft_eof = 0; linebuf = 0; *err_nump = 0; if (is_not_list(settings) && is_not_nil(settings)) { goto badarg; } /* * Parse the settings. */ if (is_not_nil(settings)) { nargs = list_val(settings); while (1) { if (is_tuple_arity(*nargs, 2)) { tp = tuple_val(*nargs); arity = *tp++; option = *tp++; if (option == am_packet) { if (is_not_small(*tp)) { goto badarg; } opts.packet_bytes = signed_val(*tp); switch (opts.packet_bytes) { case 1: case 2: case 4: break; default: goto badarg; } } else if (option == am_line) { if (is_not_small(*tp)) { goto badarg; } linebuf = signed_val(*tp); if (linebuf <= 0) { goto badarg; } } else if (option == am_env) { byte* bytes; if ((bytes = convert_environment(p, *tp)) == NULL) { goto badarg; } opts.envir = (char *) bytes; } else if (option == am_args) { char **av; char **oav = opts.argv; if ((av = convert_args(*tp)) == NULL) { goto badarg; } opts.argv = av; if (oav) { opts.argv[0] = oav[0]; oav[0] = erts_default_arg0; free_args(oav); } } else if (option == am_arg0) { char *a0; if ((a0 = erts_convert_filename_to_native(*tp, ERTS_ALC_T_TMP, 1)) == NULL) { goto badarg; } if (opts.argv == NULL) { opts.argv = erts_alloc(ERTS_ALC_T_TMP, 2 * sizeof(char **)); opts.argv[0] = a0; opts.argv[1] = NULL; } else { if (opts.argv[0] != erts_default_arg0) { erts_free(ERTS_ALC_T_TMP, opts.argv[0]); } opts.argv[0] = a0; } } else if (option == am_cd) { edir = *tp; } else { goto badarg; } } else if (*nargs == am_stream) { opts.packet_bytes = 0; } else if (*nargs == am_use_stdio) { opts.use_stdio = 1; } else if (*nargs == am_stderr_to_stdout) { opts.redir_stderr = 1; } else if (*nargs == am_line) { linebuf = 512; } else if (*nargs == am_nouse_stdio) { opts.use_stdio = 0; } else if (*nargs == am_binary) { binary_io = 1; } else if (*nargs == am_in) { opts.read_write |= DO_READ; } else if (*nargs == am_out) { opts.read_write |= DO_WRITE; } else if (*nargs == am_eof) { soft_eof = 1; } else if (*nargs == am_hide) { opts.hide_window = 1; } else if (*nargs == am_exit_status) { opts.exit_status = 1; } else if (*nargs == am_overlapped_io) { opts.overlapped_io = 1; } else { goto badarg; } if (is_nil(*++nargs)) break; if (is_not_list(*nargs)) { goto badarg; } nargs = list_val(*nargs); } } if (opts.read_write == 0) /* implement default */ opts.read_write = DO_READ|DO_WRITE; /* Mutually exclusive arguments. */ if((linebuf && opts.packet_bytes) || (opts.redir_stderr && !opts.use_stdio)) { goto badarg; } /* * Parse the first argument and start the appropriate driver. */ if (is_atom(name) || (i = is_string(name))) { /* a vanilla port */ if (is_atom(name)) { name_buf = (char *) erts_alloc(ERTS_ALC_T_TMP, atom_tab(atom_val(name))->len+1); sys_memcpy((void *) name_buf, (void *) atom_tab(atom_val(name))->name, atom_tab(atom_val(name))->len); name_buf[atom_tab(atom_val(name))->len] = '\0'; } else { name_buf = (char *) erts_alloc(ERTS_ALC_T_TMP, i + 1); if (intlist_to_buf(name, name_buf, i) != i) erl_exit(1, "%s:%d: Internal error\n", __FILE__, __LINE__); name_buf[i] = '\0'; } driver = &vanilla_driver; } else { if (is_not_tuple(name)) { goto badarg; /* Not a process or fd port */ } tp = tuple_val(name); arity = *tp++; if (arity == make_arityval(0)) { goto badarg; } if (*tp == am_spawn || *tp == am_spawn_driver) { /* A process port */ if (arity != make_arityval(2)) { goto badarg; } name = tp[1]; if (is_atom(name)) { name_buf = (char *) erts_alloc(ERTS_ALC_T_TMP, atom_tab(atom_val(name))->len+1); sys_memcpy((void *) name_buf, (void *) atom_tab(atom_val(name))->name, atom_tab(atom_val(name))->len); name_buf[atom_tab(atom_val(name))->len] = '\0'; } else if ((i = is_string(name))) { name_buf = (char *) erts_alloc(ERTS_ALC_T_TMP, i + 1); if (intlist_to_buf(name, name_buf, i) != i) erl_exit(1, "%s:%d: Internal error\n", __FILE__, __LINE__); name_buf[i] = '\0'; } else { goto badarg; } if (*tp == am_spawn_driver) { opts.spawn_type = ERTS_SPAWN_DRIVER; } driver = &spawn_driver; } else if (*tp == am_spawn_executable) { /* A program */ /* * {spawn_executable,Progname} */ if (arity != make_arityval(2)) { goto badarg; } name = tp[1]; if ((name_buf = erts_convert_filename_to_native(name,ERTS_ALC_T_TMP,0)) == NULL) { goto badarg; } opts.spawn_type = ERTS_SPAWN_EXECUTABLE; driver = &spawn_driver; } else if (*tp == am_fd) { /* An fd port */ int n; struct Sint_buf sbuf; char* p; if (arity != make_arityval(3)) { goto badarg; } if (is_not_small(tp[1]) || is_not_small(tp[2])) { goto badarg; } opts.ifd = unsigned_val(tp[1]); opts.ofd = unsigned_val(tp[2]); /* Syntesize name from input and output descriptor. */ name_buf = erts_alloc(ERTS_ALC_T_TMP, 2*sizeof(struct Sint_buf) + 2); p = Sint_to_buf(opts.ifd, &sbuf); n = sys_strlen(p); sys_strncpy(name_buf, p, n); name_buf[n] = '/'; p = Sint_to_buf(opts.ofd, &sbuf); sys_strcpy(name_buf+n+1, p); driver = &fd_driver; } else { goto badarg; } } if ((driver != &spawn_driver && opts.argv != NULL) || (driver == &spawn_driver && opts.spawn_type != ERTS_SPAWN_EXECUTABLE && opts.argv != NULL)) { /* Argument vector only if explicit spawn_executable */ goto badarg; } if (edir != NIL) { /* A working directory is expressed differently if spawn_executable, i.e. Unicode is handles for spawn_executable... */ if (opts.spawn_type != ERTS_SPAWN_EXECUTABLE) { Eterm iolist; DeclareTmpHeap(heap,4,p); int r; UseTmpHeap(4,p); heap[0] = edir; heap[1] = make_list(heap+2); heap[2] = make_small(0); heap[3] = NIL; iolist = make_list(heap); r = io_list_to_buf(iolist, (char*) dir, MAXPATHLEN); UnUseTmpHeap(4,p); if (r < 0) { goto badarg; } opts.wd = (char *) dir; } else { if ((opts.wd = erts_convert_filename_to_native(edir,ERTS_ALC_T_TMP,0)) == NULL) { goto badarg; } } } if (driver != &spawn_driver && opts.exit_status) { goto badarg; } if (IS_TRACED_FL(p, F_TRACE_SCHED_PROCS)) { trace_virtual_sched(p, am_out); } erts_smp_proc_unlock(p, ERTS_PROC_LOCK_MAIN); port_num = erts_open_driver(driver, p->id, name_buf, &opts, err_nump); #ifdef USE_VM_PROBES if (port_num >= 0 && DTRACE_ENABLED(port_open)) { DTRACE_CHARBUF(process_str, DTRACE_TERM_BUF_SIZE); DTRACE_CHARBUF(port_str, DTRACE_TERM_BUF_SIZE); dtrace_proc_str(p, process_str); erts_snprintf(port_str, sizeof(port_str), "%T", erts_port[port_num].id); DTRACE3(port_open, process_str, name_buf, port_str); } #endif erts_smp_proc_lock(p, ERTS_PROC_LOCK_MAIN); if (port_num < 0) { DEBUGF(("open_driver returned %d(%d)\n", port_num, *err_nump)); if (IS_TRACED_FL(p, F_TRACE_SCHED_PROCS)) { trace_virtual_sched(p, am_in); } OPEN_PORT_ERROR(port_num); } if (IS_TRACED_FL(p, F_TRACE_SCHED_PROCS)) { trace_virtual_sched(p, am_in); } if (binary_io) { erts_port_status_bor_set(&erts_port[port_num], ERTS_PORT_SFLG_BINARY_IO); } if (soft_eof) { erts_port_status_bor_set(&erts_port[port_num], ERTS_PORT_SFLG_SOFT_EOF); } if (linebuf && erts_port[port_num].linebuf == NULL){ erts_port[port_num].linebuf = allocate_linebuf(linebuf); erts_port_status_bor_set(&erts_port[port_num], ERTS_PORT_SFLG_LINEBUF_IO); } do_return: if (name_buf) erts_free(ERTS_ALC_T_TMP, (void *) name_buf); if (opts.argv) { free_args(opts.argv); } if (opts.wd && opts.wd != ((char *)dir)) { erts_free(ERTS_ALC_T_TMP, (void *) opts.wd); } return port_num; badarg: *err_nump = BADARG; OPEN_PORT_ERROR(-3); goto do_return; #undef OPEN_PORT_ERROR }
static HashValue dist_table_hash(void *dep) { return atom_tab(atom_val(((DistEntry *) dep)->sysname))->slot.bucket.hvalue; }
constexpr std::uint64_t atom_val(const char* cstr, std::uint64_t interim = 0) { return (*cstr == '\0') ? interim : atom_val(cstr + 1, next_interim(interim, static_cast<size_t>(*cstr))); }
static Port * open_port(Process* p, Eterm name, Eterm settings, int *err_typep, int *err_nump) { Sint i; Eterm option; Uint arity; Eterm* tp; Uint* nargs; erts_driver_t* driver; char* name_buf = NULL; SysDriverOpts opts; Sint linebuf; Eterm edir = NIL; byte dir[MAXPATHLEN]; erts_aint32_t sflgs = 0; Port *port; /* These are the defaults */ opts.packet_bytes = 0; opts.use_stdio = 1; opts.redir_stderr = 0; opts.read_write = 0; opts.hide_window = 0; opts.wd = NULL; opts.envir = NULL; opts.exit_status = 0; opts.overlapped_io = 0; opts.spawn_type = ERTS_SPAWN_ANY; opts.argv = NULL; opts.parallelism = erts_port_parallelism; linebuf = 0; *err_nump = 0; if (is_not_list(settings) && is_not_nil(settings)) { goto badarg; } /* * Parse the settings. */ if (is_not_nil(settings)) { nargs = list_val(settings); while (1) { if (is_tuple_arity(*nargs, 2)) { tp = tuple_val(*nargs); arity = *tp++; option = *tp++; if (option == am_packet) { if (is_not_small(*tp)) { goto badarg; } opts.packet_bytes = signed_val(*tp); switch (opts.packet_bytes) { case 1: case 2: case 4: break; default: goto badarg; } } else if (option == am_line) { if (is_not_small(*tp)) { goto badarg; } linebuf = signed_val(*tp); if (linebuf <= 0) { goto badarg; } } else if (option == am_env) { byte* bytes; if ((bytes = convert_environment(p, *tp)) == NULL) { goto badarg; } opts.envir = (char *) bytes; } else if (option == am_args) { char **av; char **oav = opts.argv; if ((av = convert_args(*tp)) == NULL) { goto badarg; } opts.argv = av; if (oav) { opts.argv[0] = oav[0]; oav[0] = erts_default_arg0; free_args(oav); } } else if (option == am_arg0) { char *a0; if ((a0 = erts_convert_filename_to_native(*tp, NULL, 0, ERTS_ALC_T_TMP, 1, 1, NULL)) == NULL) { goto badarg; } if (opts.argv == NULL) { opts.argv = erts_alloc(ERTS_ALC_T_TMP, 2 * sizeof(char **)); opts.argv[0] = a0; opts.argv[1] = NULL; } else { if (opts.argv[0] != erts_default_arg0) { erts_free(ERTS_ALC_T_TMP, opts.argv[0]); } opts.argv[0] = a0; } } else if (option == am_cd) { edir = *tp; } else if (option == am_parallelism) { if (*tp == am_true) opts.parallelism = 1; else if (*tp == am_false) opts.parallelism = 0; else goto badarg; } else { goto badarg; } } else if (*nargs == am_stream) { opts.packet_bytes = 0; } else if (*nargs == am_use_stdio) { opts.use_stdio = 1; } else if (*nargs == am_stderr_to_stdout) { opts.redir_stderr = 1; } else if (*nargs == am_line) { linebuf = 512; } else if (*nargs == am_nouse_stdio) { opts.use_stdio = 0; } else if (*nargs == am_binary) { sflgs |= ERTS_PORT_SFLG_BINARY_IO; } else if (*nargs == am_in) { opts.read_write |= DO_READ; } else if (*nargs == am_out) { opts.read_write |= DO_WRITE; } else if (*nargs == am_eof) { sflgs |= ERTS_PORT_SFLG_SOFT_EOF; } else if (*nargs == am_hide) { opts.hide_window = 1; } else if (*nargs == am_exit_status) { opts.exit_status = 1; } else if (*nargs == am_overlapped_io) { opts.overlapped_io = 1; } else { goto badarg; } if (is_nil(*++nargs)) break; if (is_not_list(*nargs)) { goto badarg; } nargs = list_val(*nargs); } } if (opts.read_write == 0) /* implement default */ opts.read_write = DO_READ|DO_WRITE; /* Mutually exclusive arguments. */ if((linebuf && opts.packet_bytes) || (opts.redir_stderr && !opts.use_stdio)) { goto badarg; } /* * Parse the first argument and start the appropriate driver. */ if (is_atom(name) || (i = is_string(name))) { /* a vanilla port */ if (is_atom(name)) { name_buf = (char *) erts_alloc(ERTS_ALC_T_TMP, atom_tab(atom_val(name))->len+1); sys_memcpy((void *) name_buf, (void *) atom_tab(atom_val(name))->name, atom_tab(atom_val(name))->len); name_buf[atom_tab(atom_val(name))->len] = '\0'; } else { name_buf = (char *) erts_alloc(ERTS_ALC_T_TMP, i + 1); if (intlist_to_buf(name, name_buf, i) != i) erts_exit(ERTS_ERROR_EXIT, "%s:%d: Internal error\n", __FILE__, __LINE__); name_buf[i] = '\0'; } driver = &vanilla_driver; } else { if (is_not_tuple(name)) { goto badarg; /* Not a process or fd port */ } tp = tuple_val(name); arity = *tp++; if (arity == make_arityval(0)) { goto badarg; } if (*tp == am_spawn || *tp == am_spawn_driver || *tp == am_spawn_executable) { /* A process port */ int encoding; if (arity != make_arityval(2)) { goto badarg; } name = tp[1]; encoding = erts_get_native_filename_encoding(); /* Do not convert the command to utf-16le yet, do that in win32 specific code */ /* since the cmd is used for comparsion with drivers names and copied to port info */ if (encoding == ERL_FILENAME_WIN_WCHAR) { encoding = ERL_FILENAME_UTF8; } if ((name_buf = erts_convert_filename_to_encoding(name, NULL, 0, ERTS_ALC_T_TMP,0,1, encoding, NULL, 0)) == NULL) { goto badarg; } if (*tp == am_spawn_driver) { opts.spawn_type = ERTS_SPAWN_DRIVER; } else if (*tp == am_spawn_executable) { opts.spawn_type = ERTS_SPAWN_EXECUTABLE; } driver = &spawn_driver; } else if (*tp == am_fd) { /* An fd port */ int n; struct Sint_buf sbuf; char* p; if (arity != make_arityval(3)) { goto badarg; } if (is_not_small(tp[1]) || is_not_small(tp[2])) { goto badarg; } opts.ifd = unsigned_val(tp[1]); opts.ofd = unsigned_val(tp[2]); /* Syntesize name from input and output descriptor. */ name_buf = erts_alloc(ERTS_ALC_T_TMP, 2*sizeof(struct Sint_buf) + 2); p = Sint_to_buf(opts.ifd, &sbuf); n = sys_strlen(p); sys_strncpy(name_buf, p, n); name_buf[n] = '/'; p = Sint_to_buf(opts.ofd, &sbuf); sys_strcpy(name_buf+n+1, p); driver = &fd_driver; } else { goto badarg; } } if ((driver != &spawn_driver && opts.argv != NULL) || (driver == &spawn_driver && opts.spawn_type != ERTS_SPAWN_EXECUTABLE && opts.argv != NULL)) { /* Argument vector only if explicit spawn_executable */ goto badarg; } if (edir != NIL) { if ((opts.wd = erts_convert_filename_to_native(edir, NULL, 0, ERTS_ALC_T_TMP,0,1,NULL)) == NULL) { goto badarg; } } if (driver != &spawn_driver && opts.exit_status) { goto badarg; } if (IS_TRACED_FL(p, F_TRACE_SCHED_PROCS)) { trace_sched(p, ERTS_PROC_LOCK_MAIN, am_out); } erts_smp_proc_unlock(p, ERTS_PROC_LOCK_MAIN); port = erts_open_driver(driver, p->common.id, name_buf, &opts, err_typep, err_nump); #ifdef USE_VM_PROBES if (port && DTRACE_ENABLED(port_open)) { DTRACE_CHARBUF(process_str, DTRACE_TERM_BUF_SIZE); DTRACE_CHARBUF(port_str, DTRACE_TERM_BUF_SIZE); dtrace_proc_str(p, process_str); erts_snprintf(port_str, sizeof(DTRACE_CHARBUF_NAME(port_str)), "%T", port->common.id); DTRACE3(port_open, process_str, name_buf, port_str); } #endif if (port && IS_TRACED_FL(port, F_TRACE_PORTS)) trace_port(port, am_getting_linked, p->common.id); erts_smp_proc_lock(p, ERTS_PROC_LOCK_MAIN); if (IS_TRACED_FL(p, F_TRACE_SCHED_PROCS)) { trace_sched(p, ERTS_PROC_LOCK_MAIN, am_in); } if (!port) { DEBUGF(("open_driver returned (%d:%d)\n", err_typep ? *err_typep : 4711, err_nump ? *err_nump : 4711)); goto do_return; } if (linebuf && port->linebuf == NULL){ port->linebuf = allocate_linebuf(linebuf); sflgs |= ERTS_PORT_SFLG_LINEBUF_IO; } if (sflgs) erts_atomic32_read_bor_relb(&port->state, sflgs); do_return: if (name_buf) erts_free(ERTS_ALC_T_TMP, (void *) name_buf); if (opts.argv) { free_args(opts.argv); } if (opts.wd && opts.wd != ((char *)dir)) { erts_free(ERTS_ALC_T_TMP, (void *) opts.wd); } return port; badarg: if (err_typep) *err_typep = -3; if (err_nump) *err_nump = BADARG; port = NULL; goto do_return; }