/* * Open a shared object */ int erts_sys_ddll_open(char *full_name, void **handle) { MODULE_ID mid; int len; int ret = ERL_DE_NO_ERROR; static char dlname[PATH_MAX + EXT_LEN + 1]; if ((mid = get_mid(full_name)) == NULL) { if ((len = sys_strlen(full_name)) > PATH_MAX-EXT_LEN-1) { ret = ERL_DE_LOAD_ERROR_NAME_TO_LONG; goto done; } sys_strcpy(dlname, full_name); sys_strcpy(dlname+len, FILE_EXT); if((mid = get_mid(dlname)) == NULL) { sys_strcpy(dlname+len, ALT_FILE_EXT); if((mid = get_mid(dlname)) == NULL) { ret = ERL_DE_DYNAMIC_ERROR_OFFSET - ((int) ModuleNotFound); goto done; } } } *handle = (void *) mid; done: return ret; }
/* * Open a shared object */ int erts_sys_ddll_open2(const char *full_name, void **handle, ErtsSysDdllError* err) { int len; char dlname[MAXPATHLEN + 1]; if ((len = sys_strlen(full_name)) >= MAXPATHLEN - EXT_LEN) { if (err != NULL) { err->str = "Library name too long"; } return ERL_DE_LOAD_ERROR_NAME_TO_LONG; } sys_strcpy(dlname, full_name); sys_strcpy(dlname+len, FILE_EXT); return erts_sys_ddll_open_noext(dlname, handle, err); }
static int __config_init( void ) { OSH_ERROR status = OSH_ERR_NONE; char temp_buf[1024]; static int global_test_rc = 0; sys_memset(&osh_config, 0, sizeof(osh_config)); osh_config.active = 0; if (gethostname(osh_config.hostname, sizeof(osh_config.hostname)) != 0) { sys_strcpy(osh_config.hostname, "localhost"); } osh_config.my_pe = INVALID_PE; osh_config.num_pe = INVALID_PE; osh_config.rc = &global_test_rc; /*NULL*/ /* * Seed the random-number generator with current time so that * the numbers will be different every time we run. */ osh_config.timer = (unsigned int)time( NULL ); srand( osh_config.timer ); PE_LIST_SET(DEFAULT_PE, osh_config.exec_mode.log_pe_list); osh_config.exec_mode.out_level = LOG_INFO; osh_config.exec_mode.out_file = stdout; osh_config.exec_mode.log_level = LOG_NONE; osh_config.exec_mode.log_file = NULL; sys_snprintf_safe(temp_buf, sizeof(temp_buf), "%s_%s_%04d.log", MODULE_NAME, osh_config.hostname, getpid()); osh_config.exec_mode.log_file_name = sys_strdup(temp_buf); return status; }
ErlDrvMutex * erl_drv_mutex_create(char *name) { #ifdef USE_THREADS ErlDrvMutex *dmtx = erts_alloc_fnf(ERTS_ALC_T_DRV_MTX, (sizeof(ErlDrvMutex) + (name ? sys_strlen(name) + 1 : 0))); if (dmtx) { ethr_mutex_opt opt = ETHR_MUTEX_OPT_DEFAULT_INITER; opt.posix_compliant = 1; if (ethr_mutex_init_opt(&dmtx->mtx, &opt) != 0) { erts_free(ERTS_ALC_T_DRV_MTX, (void *) dmtx); dmtx = NULL; } else if (!name) dmtx->name = no_name; else { dmtx->name = ((char *) dmtx) + sizeof(ErlDrvMutex); sys_strcpy(dmtx->name, name); } } return dmtx; #else return (ErlDrvMutex *) NULL; #endif }
ErlDrvCond * erl_drv_cond_create(char *name) { #ifdef USE_THREADS ErlDrvCond *dcnd = erts_alloc_fnf(ERTS_ALC_T_DRV_CND, (sizeof(ErlDrvCond) + (name ? sys_strlen(name) + 1 : 0))); if (dcnd) { ethr_cond_opt opt = ETHR_COND_OPT_DEFAULT_INITER; opt.posix_compliant = 1; if (ethr_cond_init_opt(&dcnd->cnd, &opt) != 0) { erts_free(ERTS_ALC_T_DRV_CND, (void *) dcnd); dcnd = NULL; } else if (!name) dcnd->name = no_name; else { dcnd->name = ((char *) dcnd) + sizeof(ErlDrvCond); sys_strcpy(dcnd->name, name); } } return dcnd; #else return (ErlDrvCond *) NULL; #endif }
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 }
Eterm erts_lc_dump_graph(void) { const char* basename = "lc_graph."; char filename[40]; lc_matrix_t* tot = &tot_lc_matrix; lc_thread_t* thr; int i, j, name_max = 0; FILE* ff; lc_lock_threads(); for (thr = lc_threads; thr; thr = thr->next) { collect_matrix(&thr->matrix); } lc_unlock_threads(); sys_strcpy(filename, basename); sys_get_pid(filename + strlen(basename), sizeof(filename) - strlen(basename)); ff = fopen(filename, "w"); if (!ff) return am_error; for (i = 1; i < ERTS_LOCK_ORDER_SIZE; i++) { int len = strlen(erts_lock_order[i].name); if (name_max < len) name_max = len; } fputs("%This file was generated by erts_debug:lc_graph()\n\n", ff); fputs("%{ThisLockName, ThisLockId, LockedDirectlyBeforeThis, LockedIndirectlyBeforeThis}\n", ff); fprintf(ff, "[{%*s, %2d}", name_max, "\"NO LOCK\"", 0); for (i = 1; i < ERTS_LOCK_ORDER_SIZE; i++) { char* delim = ""; fprintf(ff, ",\n {%*s, %2d, [", name_max, erts_lock_order[i].name, i); for (j = 0; j < ERTS_LOCK_ORDER_SIZE; j++) { if (tot->m[i][j] & 1) { fprintf(ff, "%s%d", delim, j); delim = ","; } } fprintf(ff, "], ["); delim = ""; for (j = 0; j < ERTS_LOCK_ORDER_SIZE; j++) { if (tot->m[i][j] == 2) { fprintf(ff, "%s%d", delim, j); delim = ","; } } fputs("]}", ff); } fputs("].", ff); fclose(ff); erts_fprintf(stderr, "Created file '%s' in current working directory\n", filename); return am_ok; }
/* * Open a shared object */ int erts_sys_ddll_open2(char *full_name, void **handle, ErtsSysDdllError* err) { #if defined(HAVE_DLOPEN) char* dlname; int len = sys_strlen(full_name); int ret; dlname = erts_alloc(ERTS_ALC_T_TMP, len + EXT_LEN + 1); sys_strcpy(dlname, full_name); sys_strcpy(dlname+len, FILE_EXT); ret = erts_sys_ddll_open_noext(dlname, handle, err); erts_free(ERTS_ALC_T_TMP, (void *) dlname); return ret; #else return ERL_DE_ERROR_NO_DDLL_FUNCTIONALITY; #endif }
/* * Open a shared object */ int erts_sys_ddll_open2(char *full_name, void **handle, ErtsSysDdllError* err) { int len; if (erts_sys_ddll_open_noext(full_name, handle, err) == ERL_DE_NO_ERROR) { return ERL_DE_NO_ERROR; } if ((len = sys_strlen(full_name)) > PATH_MAX-EXT_LEN) { return ERL_DE_LOAD_ERROR_NAME_TO_LONG; } else { static char dlname[PATH_MAX + 1]; sys_strcpy(dlname, full_name); sys_strcpy(dlname+len, FILE_EXT); if (erts_sys_ddll_open_noext(dlname, handle, err) == ERL_DE_NO_ERROR) { return ERL_DE_NO_ERROR; } sys_strcpy(dlname+len, ALT_FILE_EXT); return erts_sys_ddll_open_noext(dlname, handle, err); } }
int erts_sys_ddll_sym2(void *handle, char *func_name, void **function, ErtsSysDdllError* err) { FUNCPTR proc; static char statbuf[PREALLOC_BUFFER_SIZE]; char *buf = statbuf; int need; if ((proc = lookup(func_name)) == NULL) { if ((need = strlen(func_name)+2) > PREALLOC_BUFFER_SIZE) { buf = erts_alloc(ERTS_ALC_T_DDLL_TMP_BUF,need); } buf[0] = '_'; sys_strcpy(buf+1,func_name); proc = lookup(buf); if (buf != statbuf) { erts_free(ERTS_ALC_T_DDLL_TMP_BUF, buf); } if (proc == NULL) { return ERL_DE_LOOKUP_ERROR_NOT_FOUND; } } *function = (void *) proc; return ERL_DE_NO_ERROR; }
ErlDrvRWLock * erl_drv_rwlock_create(char *name) { #ifdef USE_THREADS ErlDrvRWLock *drwlck = erts_alloc_fnf(ERTS_ALC_T_DRV_RWLCK, (sizeof(ErlDrvRWLock) + (name ? sys_strlen(name) + 1 : 0))); if (drwlck) { if (ethr_rwmutex_init(&drwlck->rwmtx) != 0) { erts_free(ERTS_ALC_T_DRV_RWLCK, (void *) drwlck); drwlck = NULL; } else if (!name) drwlck->name = no_name; else { drwlck->name = ((char *) drwlck) + sizeof(ErlDrvRWLock); sys_strcpy(drwlck->name, name); } } return drwlck; #else return (ErlDrvRWLock *) NULL; #endif }
ErlDrvCond * erl_drv_cond_create(char *name) { #ifdef USE_THREADS ErlDrvCond *dcnd = erts_alloc_fnf(ERTS_ALC_T_DRV_CND, (sizeof(ErlDrvCond) + (name ? sys_strlen(name) + 1 : 0))); if (dcnd) { if (ethr_cond_init(&dcnd->cnd) != 0) { erts_free(ERTS_ALC_T_DRV_CND, (void *) dcnd); dcnd = NULL; } else if (!name) dcnd->name = no_name; else { dcnd->name = ((char *) dcnd) + sizeof(ErlDrvCond); sys_strcpy(dcnd->name, name); } } return dcnd; #else return (ErlDrvCond *) NULL; #endif }
ErlDrvMutex * erl_drv_mutex_create(char *name) { #ifdef USE_THREADS ErlDrvMutex *dmtx = erts_alloc_fnf(ERTS_ALC_T_DRV_MTX, (sizeof(ErlDrvMutex) + (name ? sys_strlen(name) + 1 : 0))); if (dmtx) { if (ethr_mutex_init(&dmtx->mtx) != 0) { erts_free(ERTS_ALC_T_DRV_MTX, (void *) dmtx); dmtx = NULL; } else if (!name) dmtx->name = no_name; else { dmtx->name = ((char *) dmtx) + sizeof(ErlDrvMutex); sys_strcpy(dmtx->name, name); } } return dmtx; #else return (ErlDrvMutex *) NULL; #endif }
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; }
int erl_drv_tsd_key_create(char *name, ErlDrvTSDKey *key) { char *name_copy; Uint old_used_tsd_keys_len; ErlDrvTSDKey res; if (!key) fatal_error(EINVAL, "erl_drv_tsd_key_create()"); if (!name) name_copy = no_name; else { name_copy = erts_alloc_fnf(ERTS_ALC_T_DRV_TSD, sizeof(char)*(strlen(name) + 1)); if (!name_copy) { *key = -1; return ENOMEM; } sys_strcpy(name_copy, name); } erts_mtx_lock(&tsd_mtx); *key = next_tsd_key; if (next_tsd_key < 0) res = ENOMEM; else { res = 0; ASSERT(!used_tsd_keys[next_tsd_key]); used_tsd_keys[next_tsd_key] = name_copy; if (max_used_tsd_key < next_tsd_key) max_used_tsd_key = next_tsd_key; if (max_used_tsd_key + 1 >= used_tsd_keys_len) { int i; old_used_tsd_keys_len = used_tsd_keys_len; if (used_tsd_keys_len + ERL_DRV_TSD_KEYS_INC >= INT_MAX) next_tsd_key = -1; else { char **new_used_tsd_keys; used_tsd_keys_len += ERL_DRV_TSD_KEYS_INC; new_used_tsd_keys = erts_realloc_fnf(ERTS_ALC_T_DRV_TSD, used_tsd_keys, (sizeof(char *) * used_tsd_keys_len)); if (!new_used_tsd_keys) next_tsd_key = -1; else { used_tsd_keys = new_used_tsd_keys; for (i = old_used_tsd_keys_len; i < used_tsd_keys_len; i++) used_tsd_keys[i] = NULL; } } } if (next_tsd_key >= 0) { do { next_tsd_key++; } while (used_tsd_keys[next_tsd_key]); } ASSERT(next_tsd_key < used_tsd_keys_len); } erts_mtx_unlock(&tsd_mtx); return res; }
static int do_load_driver_entry(DE_Handle *dh, char *path, char *name) { void *init_handle; int res; ErlDrvEntry *dp; assert_drv_list_rwlocked(); if ((res = erts_sys_ddll_open(path, &(dh->handle), NULL)) != ERL_DE_NO_ERROR) { return res; } if ((res = erts_sys_ddll_load_driver_init(dh->handle, &init_handle)) != ERL_DE_NO_ERROR) { res = ERL_DE_LOAD_ERROR_NO_INIT; goto error; } dp = erts_sys_ddll_call_init(init_handle); if (dp == NULL) { res = ERL_DE_LOAD_ERROR_FAILED_INIT; goto error; } switch (dp->extended_marker) { case ERL_DRV_EXTENDED_MARKER: if (dp->major_version < ERL_DRV_MIN_REQUIRED_MAJOR_VERSION_ON_LOAD || (ERL_DRV_EXTENDED_MAJOR_VERSION < dp->major_version || (ERL_DRV_EXTENDED_MAJOR_VERSION == dp->major_version && ERL_DRV_EXTENDED_MINOR_VERSION < dp->minor_version))) { /* Incompatible driver version */ res = ERL_DE_LOAD_ERROR_INCORRECT_VERSION; goto error; } break; default: /* Old driver; needs to be recompiled... */ res = ERL_DE_LOAD_ERROR_INCORRECT_VERSION; goto error; } if (strcmp(name, dp->driver_name) != 0) { res = ERL_DE_LOAD_ERROR_BAD_NAME; goto error; } erts_atomic_init_nob(&(dh->refc), (erts_aint_t) 0); erts_atomic32_init_nob(&dh->port_count, 0); dh->full_path = erts_alloc(ERTS_ALC_T_DDLL_HANDLE, sys_strlen(path) + 1); sys_strcpy(dh->full_path, path); dh->flags = 0; dh->status = ERL_DE_OK; if (erts_add_driver_entry(dp, dh, 1) != 0 /* io.c */) { /* * The init in the driver struct did not return 0 */ erts_free(ERTS_ALC_T_DDLL_HANDLE, dh->full_path); dh->full_path = NULL; res = ERL_DE_LOAD_ERROR_FAILED_INIT; goto error; } return ERL_DE_NO_ERROR; error: erts_sys_ddll_close(dh->handle); return res; }
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 }
/* * Try to load. If the driver is OK, add as LOADED. If the driver is * UNLOAD, possibly change to reload and add as LOADED, * there should be no other * LOADED tagged pid's. If the driver is RELOAD then add/increment as * LOADED (should be some LOADED pid). If the driver is not present, * really load and add as LOADED {ok,loaded} {ok,pending_driver} * {error, permanent} {error,load_error()} */ BIF_RETTYPE erl_ddll_try_load_3(BIF_ALIST_3) { Eterm path_term = BIF_ARG_1; Eterm name_term = BIF_ARG_2; Eterm options = BIF_ARG_3; char *path = NULL; Sint path_len; char *name = NULL; DE_Handle *dh; erts_driver_t *drv; int res; Eterm soft_error_term = NIL; Eterm ok_term = NIL; Eterm *hp; Eterm t; int monitor = 0; int reload = 0; Eterm l; Uint flags = 0; int kill_ports = 0; int do_build_load_error = 0; int build_this_load_error = 0; int encoding; for(l = options; is_list(l); l = CDR(list_val(l))) { Eterm opt = CAR(list_val(l)); Eterm *tp; if (is_not_tuple(opt)) { goto error; } tp = tuple_val(opt); if (*tp != make_arityval(2) || is_not_atom(tp[1])) { goto error; } switch (tp[1]) { case am_driver_options: { Eterm ll; for(ll = tp[2]; is_list(ll); ll = CDR(list_val(ll))) { Eterm dopt = CAR(list_val(ll)); if (dopt == am_kill_ports) { flags |= ERL_DE_FL_KILL_PORTS; } else { goto error; } } if (is_not_nil(ll)) { goto error; } } break; case am_monitor: if (tp[2] == am_pending_driver) { monitor = 1; } else if (tp[2] == am_pending ) { monitor = 2; } else { goto error; } break; case am_reload: if (tp[2] == am_pending_driver) { reload = 1; } else if (tp[2] == am_pending ) { reload = 2; } else { goto error; } break; default: goto error; } } if (is_not_nil(l)) { goto error; } if ((name = pick_list_or_atom(name_term)) == NULL) { goto error; } encoding = erts_get_native_filename_encoding(); if (encoding == ERL_FILENAME_WIN_WCHAR) { /* Do not convert the lib name to utf-16le yet, do that in win32 specific code */ /* since lib_name is used in error messages */ encoding = ERL_FILENAME_UTF8; } path = erts_convert_filename_to_encoding(path_term, NULL, 0, ERTS_ALC_T_DDLL_TMP_BUF, 1, 0, encoding, &path_len, sys_strlen(name) + 2); /* might need path separator */ if (!path) { goto error; } ASSERT(path_len > 0 && path[path_len-1] == 0); while (--path_len > 0 && (path[path_len-1] == '\\' || path[path_len-1] == '/')) ; path[path_len++] = '/'; sys_strcpy(path+path_len,name); erts_proc_unlock(BIF_P, ERTS_PROC_LOCK_MAIN); lock_drv_list(); if ((drv = lookup_driver(name)) != NULL) { if (drv->handle == NULL) { /* static_driver */ soft_error_term = am_linked_in_driver; goto soft_error; } else { dh = drv->handle; if (dh->status == ERL_DE_OK) { int is_last = is_last_user(dh, BIF_P); if (reload == 1 && !is_last) { /*Want reload if no other users, but there are others...*/ soft_error_term = am_pending_process; goto soft_error; } if (reload != 0) { DE_ProcEntry *old; if ((dh->flags & ERL_FL_CONSISTENT_MASK) != (flags & ERL_FL_CONSISTENT_MASK)) { soft_error_term = am_inconsistent; goto soft_error; } if ((old = find_proc_entry(dh, BIF_P, ERL_DE_PROC_LOADED)) == NULL) { soft_error_term = am_not_loaded_by_this_process; goto soft_error; } else { remove_proc_entry(dh, old); erts_ddll_dereference_driver(dh); erts_free(ERTS_ALC_T_DDLL_PROCESS, old); } /* Reload requested and granted */ dereference_all_processes(dh); set_driver_reloading(dh, BIF_P, path, name, flags); if (dh->flags & ERL_DE_FL_KILL_PORTS) { kill_ports = 1; } ok_term = (reload == 1) ? am_pending_driver : am_pending_process; } else { /* Already loaded and healthy (might be by me) */ if (sys_strcmp(dh->full_path, path) || (dh->flags & ERL_FL_CONSISTENT_MASK) != (flags & ERL_FL_CONSISTENT_MASK)) { soft_error_term = am_inconsistent; goto soft_error; } add_proc_loaded(dh, BIF_P); erts_ddll_reference_driver(dh); monitor = 0; ok_term = mkatom("already_loaded"); } } else if (dh->status == ERL_DE_UNLOAD || dh->status == ERL_DE_FORCE_UNLOAD) { /* pending driver */ if (reload != 0) { soft_error_term = am_not_loaded_by_this_process; goto soft_error; } if (sys_strcmp(dh->full_path, path) || (dh->flags & ERL_FL_CONSISTENT_MASK) != (flags & ERL_FL_CONSISTENT_MASK)) { soft_error_term = am_inconsistent; goto soft_error; } dh->status = ERL_DE_OK; notify_all(dh, drv->name, ERL_DE_PROC_AWAIT_UNLOAD, am_UP, am_unload_cancelled); add_proc_loaded(dh, BIF_P); erts_ddll_reference_driver(dh); monitor = 0; ok_term = mkatom("already_loaded"); } else if (dh->status == ERL_DE_RELOAD || dh->status == ERL_DE_FORCE_RELOAD) { if (reload != 0) { soft_error_term = am_pending_reload; goto soft_error; } if (sys_strcmp(dh->reload_full_path, path) || (dh->reload_flags & ERL_FL_CONSISTENT_MASK) != (flags & ERL_FL_CONSISTENT_MASK)) { soft_error_term = am_inconsistent; goto soft_error; } /* Load of granted unload... */ /* Don't reference, will happen after reload */ add_proc_loaded_deref(dh, BIF_P); ++monitor; ok_term = am_pending_driver; } else { /* ERL_DE_PERMANENT */ soft_error_term = am_permanent; goto soft_error; } } } else { /* driver non-existing */ if (reload != 0) { soft_error_term = am_not_loaded; goto soft_error; } if ((res = load_driver_entry(&dh, path, name)) != ERL_DE_NO_ERROR) { build_this_load_error = res; do_build_load_error = 1; soft_error_term = am_undefined; goto soft_error; } else { dh->flags = flags; add_proc_loaded(dh, BIF_P); first_ddll_reference(dh); monitor = 0; ok_term = mkatom("loaded"); } } assert_drv_list_rwlocked(); if (kill_ports) { /* Avoid closing the driver by referencing it */ erts_ddll_reference_driver(dh); ASSERT(dh->status == ERL_DE_RELOAD); dh->status = ERL_DE_FORCE_RELOAD; unlock_drv_list(); kill_ports_driver_unloaded(dh); /* Dereference, eventually causing driver destruction */ lock_drv_list(); erts_ddll_dereference_driver(dh); } erts_ddll_reference_driver(dh); unlock_drv_list(); erts_proc_lock(BIF_P, ERTS_PROC_LOCK_MAIN); lock_drv_list(); erts_ddll_dereference_driver(dh); BIF_P->flags |= F_USING_DDLL; if (monitor) { Eterm mref = add_monitor(BIF_P, dh, ERL_DE_PROC_AWAIT_LOAD); hp = HAlloc(BIF_P, 4); t = TUPLE3(hp, am_ok, ok_term, mref); } else { hp = HAlloc(BIF_P, 3); t = TUPLE2(hp, am_ok, ok_term); } unlock_drv_list(); erts_free(ERTS_ALC_T_DDLL_TMP_BUF, (void *) path); erts_free(ERTS_ALC_T_DDLL_TMP_BUF, (void *) name); ERTS_LC_ASSERT(ERTS_PROC_LOCK_MAIN & erts_proc_lc_my_proc_locks(BIF_P)); BIF_RET(t); soft_error: unlock_drv_list(); erts_proc_lock(BIF_P, ERTS_PROC_LOCK_MAIN); if (do_build_load_error) { soft_error_term = build_load_error(BIF_P, build_this_load_error); } hp = HAlloc(BIF_P, 3); t = TUPLE2(hp, am_error, soft_error_term); erts_free(ERTS_ALC_T_DDLL_TMP_BUF, (void *) path); erts_free(ERTS_ALC_T_DDLL_TMP_BUF, (void *) name); ERTS_LC_ASSERT(ERTS_PROC_LOCK_MAIN & erts_proc_lc_my_proc_locks(BIF_P)); BIF_RET(t); error: assert_drv_list_not_locked(); ERTS_LC_ASSERT(ERTS_PROC_LOCK_MAIN & erts_proc_lc_my_proc_locks(BIF_P)); if (path != NULL) { erts_free(ERTS_ALC_T_DDLL_TMP_BUF, (void *) path); } if (name != NULL) { erts_free(ERTS_ALC_T_DDLL_TMP_BUF, (void *) name); } BIF_ERROR(BIF_P, BADARG); }
/** * sys_strdup * * @brief * This function returns a newly allocated copy of string. * * @param[in] string This is a pointer to the original string. * * @retval pointer to new string - on success * @retval NULL - on failure ***************************************************************************/ char *sys_strdup(const char *string) { return string ? sys_strcpy((char *)sys_malloc(sys_strlen(string) + 1), string) : NULL; }