Esempio n. 1
0
BIF_RETTYPE module_loaded_1(BIF_ALIST_1)
{
    Module* modp;
    ErtsCodeIndex code_ix;
    Eterm res = am_false;

    if (is_not_atom(BIF_ARG_1)) {
	BIF_ERROR(BIF_P, BADARG);
    }
    code_ix = erts_active_code_ix();
    if ((modp = erts_get_module(BIF_ARG_1, code_ix)) != NULL) {
	if (modp->curr.code_hdr
	    && modp->curr.code_hdr->on_load_function_ptr == NULL) {
	    res = am_true;
	}
    }
    BIF_RET(res);
}
Esempio n. 2
0
BIF_RETTYPE
has_prepared_code_on_load_1(BIF_ALIST_1)
{
    Eterm res;
    ProcBin* pb;

    if (!ERTS_TERM_IS_MAGIC_BINARY(BIF_ARG_1)) {
    error:
	BIF_ERROR(BIF_P, BADARG);
    }

    pb = (ProcBin*) binary_val(BIF_ARG_1);
    res = erts_has_code_on_load(pb->val);
    if (res == NIL) {
	goto error;
    }
    BIF_RET(res);
}
Esempio n. 3
0
BIF_RETTYPE lists_reverse_2(BIF_ALIST_2)
{
    /* Handle legal and illegal non-lists quickly. */
    if (is_nil(BIF_ARG_1)) {
        BIF_RET(BIF_ARG_2);
    } else if (is_not_list(BIF_ARG_1)) {
        BIF_ERROR(BIF_P, BADARG);
    }

    /* We build the reversal on the unused part of the heap if possible to save
     * us the trouble of having to figure out the list size. We fall back to
     * lists_reverse_alloc when we run out of space. */
    if (HeapWordsLeft(BIF_P) > 8) {
        return lists_reverse_onheap(BIF_P, BIF_ARG_1, BIF_ARG_2);
    }

    return lists_reverse_alloc(BIF_P, BIF_ARG_1, BIF_ARG_2);
}
Esempio n. 4
0
BIF_RETTYPE erts_internal_port_info_2(BIF_ALIST_2)
{
    Eterm retval;
    Port* prt;

    if (is_internal_port(BIF_ARG_1) || is_atom(BIF_ARG_1)) {
	prt = sig_lookup_port(BIF_P, BIF_ARG_1);
	if (!prt)
	    BIF_RET(am_undefined);
    }
    else if (is_external_port(BIF_ARG_1)) {
	if (external_port_dist_entry(BIF_ARG_1) == erts_this_dist_entry)
	    BIF_RET(am_undefined);
	else
	    BIF_RET(am_badarg);
    }
    else {
	BIF_RET(am_badarg);
    }

    switch (erts_port_info(BIF_P, prt, BIF_ARG_2, &retval)) {
    case ERTS_PORT_OP_CALLER_EXIT:
    case ERTS_PORT_OP_BADARG:
	BIF_RET(am_badarg);
    case ERTS_PORT_OP_DROPPED:
	BIF_RET(am_undefined);
    case ERTS_PORT_OP_SCHEDULED:
	ASSERT(is_internal_ordinary_ref(retval));
	BIF_RET(retval);
    case ERTS_PORT_OP_DONE:
	ASSERT(is_not_internal_ref(retval));
	BIF_RET(retval);
    default:
	ERTS_INTERNAL_ERROR("Unexpected erts_port_info() result");
	BIF_RET(am_internal_error);
    }
}
Esempio n. 5
0
BIF_RETTYPE port_connect_2(BIF_ALIST_2)
{
    Port* prt;
    Process* rp;
    Eterm pid = BIF_ARG_2;

    if (is_not_internal_pid(pid)) {
    error:
	BIF_ERROR(BIF_P, BADARG);
    }
    prt = id_or_name2port(BIF_P, BIF_ARG_1);
    if (!prt) {
	goto error;
    }

    rp = erts_pid2proc(BIF_P, ERTS_PROC_LOCK_MAIN,
		       pid, ERTS_PROC_LOCK_LINK);
    if (!rp) {
	erts_smp_port_unlock(prt);
	ERTS_SMP_ASSERT_IS_NOT_EXITING(BIF_P);
	goto error;
    }

    erts_add_link(&(rp->nlinks), LINK_PID, prt->id);
    erts_add_link(&(prt->nlinks), LINK_PID, pid);

    erts_smp_proc_unlock(rp, ERTS_PROC_LOCK_LINK);

    prt->connected = pid; /* internal pid */
    erts_smp_port_unlock(prt);
#ifdef USE_VM_PROBES
    if (DTRACE_ENABLED(port_connect)) {
        DTRACE_CHARBUF(process_str, DTRACE_TERM_BUF_SIZE);
        DTRACE_CHARBUF(port_str, DTRACE_TERM_BUF_SIZE);
        DTRACE_CHARBUF(newprocess_str, DTRACE_TERM_BUF_SIZE);

        dtrace_pid_str(prt->connected, process_str);
        erts_snprintf(port_str, sizeof(port_str), "%T", prt->id);
        dtrace_proc_str(rp, newprocess_str);
        DTRACE4(port_connect, process_str, port_str, prt->name, newprocess_str);
    }
#endif
    BIF_RET(am_true);
}
Esempio n. 6
0
BIF_RETTYPE
erts_debug_copy_shared_1(BIF_ALIST_1)
{
    Process* p = BIF_P;
    Eterm term = BIF_ARG_1;
    Uint size;
    Eterm* hp;
    Eterm copy;
    erts_shcopy_t info;
    INITIALIZE_SHCOPY(info);

    size = copy_shared_calculate(term, &info);
    if (size > 0) {
      hp = HAlloc(p, size);
    }
    copy = copy_shared_perform(term, size, &info, &hp, &p->off_heap);
    DESTROY_SHCOPY(info);
    BIF_RET(copy);
}
Esempio n. 7
0
BIF_RETTYPE port_get_data_1(BIF_ALIST_1)
{
    BIF_RETTYPE res;
    Port* prt;
    Eterm portid = BIF_ARG_1;

    prt = id_or_name2port(BIF_P, portid);
    if (!prt) {
	BIF_ERROR(BIF_P, BADARG);
    }
    if (prt->bp == NULL) {	/* MUST be CONST! */
	res = prt->data;
    } else {
	Eterm* hp = HAlloc(BIF_P, prt->bp->used_size);
	res = copy_struct(prt->data, prt->bp->used_size, &hp, &MSO(BIF_P));
    }
    erts_smp_port_unlock(prt);
    BIF_RET(res);
}
Esempio n. 8
0
Eterm
os_putenv_2(Process* p, Eterm key, Eterm value)
{
    char def_buf[1024];
    char *buf = NULL;
    int sep_ix, i, key_len, value_len, tot_len;
    key_len = is_string(key);
    if (!key_len) {
    error:
	if (buf)
	    erts_free(ERTS_ALC_T_TMP, (void *) buf);
	BIF_ERROR(p, BADARG);
    }
    if (is_nil(value))
	value_len = 0;
    else {
	value_len = is_string(value);
	if (!value_len)
	    goto error;
    }
    tot_len = key_len + 1 + value_len + 1;
    if (tot_len <= sizeof(def_buf))
	buf = &def_buf[0];
    else
	buf = erts_alloc(ERTS_ALC_T_TMP, tot_len);
    i = intlist_to_buf(key, buf, key_len);
    if (i != key_len)
	erl_exit(1, "%s:%d: Internal error\n", __FILE__, __LINE__);	
    sep_ix = i;
    buf[i++] = '=';
    if (is_not_nil(value))
	i += intlist_to_buf(value, &buf[i], value_len);
    if (i != key_len + 1 + value_len)
	erl_exit(1, "%s:%d: Internal error\n", __FILE__, __LINE__);	
    buf[i] = '\0';
    if (erts_sys_putenv(buf, sep_ix)) {
	goto error;
    }
    if (buf != &def_buf[0])
	erts_free(ERTS_ALC_T_TMP, (void *) buf);
    BIF_RET(am_true);
}
Esempio n. 9
0
BIF_RETTYPE abs_1(BIF_ALIST_1)
{
    Eterm res;
    Sint i0, i;
    Eterm* hp;

    /* integer arguments */
    if (is_small(BIF_ARG_1)) {
	i0 = signed_val(BIF_ARG_1);
	i = ERTS_SMALL_ABS(i0);
	if (i0 == MIN_SMALL) {
	    hp = HAlloc(BIF_P, BIG_UINT_HEAP_SIZE);
	    BIF_RET(uint_to_big(i, hp));
	} else {
	    BIF_RET(make_small(i));
	}
    } else if (is_big(BIF_ARG_1)) {
	if (!big_sign(BIF_ARG_1)) {
	    BIF_RET(BIF_ARG_1);
	} else {
	    int sz = big_arity(BIF_ARG_1) + 1;
	    Uint* x;

	    hp = HAlloc(BIF_P, sz);	/* See note at beginning of file */
	    sz--;
	    res = make_big(hp);
	    x = big_val(BIF_ARG_1);
	    *hp++ = make_pos_bignum_header(sz);
	    x++;                          /* skip thing */
	    while(sz--)
		*hp++ = *x++;
	    BIF_RET(res);
	}
    } else if (is_float(BIF_ARG_1)) {
	FloatDef f;

	GET_DOUBLE(BIF_ARG_1, f);
	if (f.fd < 0.0) {
	    hp = HAlloc(BIF_P, FLOAT_SIZE_OBJECT);
	    f.fd = fabs(f.fd);
	    res = make_float(hp);
	    PUT_DOUBLE(f, hp);
	    BIF_RET(res);
	}
	else
	    BIF_RET(BIF_ARG_1);
    }
    BIF_ERROR(BIF_P, BADARG);
}
Esempio n. 10
0
BIF_RETTYPE os_putenv_2(BIF_ALIST_2)
{
    char def_buf_key[STATIC_BUF_SIZE];
    char def_buf_value[STATIC_BUF_SIZE];
    char *key_buf, *value_buf;

    key_buf = erts_convert_filename_to_native(BIF_ARG_1,def_buf_key,
					      STATIC_BUF_SIZE,
					      ERTS_ALC_T_TMP,0,0,NULL);
    if (!key_buf) {
	BIF_ERROR(BIF_P, BADARG);
    }
    value_buf = erts_convert_filename_to_native(BIF_ARG_2,def_buf_value,
						STATIC_BUF_SIZE,
						ERTS_ALC_T_TMP,1,0,
						NULL);
    if (!value_buf) {
	if (key_buf != def_buf_key) {
	    erts_free(ERTS_ALC_T_TMP, key_buf);
	}
	BIF_ERROR(BIF_P, BADARG);
    }
	    

    if (erts_sys_putenv(key_buf, value_buf)) {
	if (key_buf != def_buf_key) {
	    erts_free(ERTS_ALC_T_TMP, key_buf);
	}
	if (value_buf != def_buf_value) {
	    erts_free(ERTS_ALC_T_TMP, value_buf);
	}
	BIF_ERROR(BIF_P, BADARG);
    }
    if (key_buf != def_buf_key) {
	erts_free(ERTS_ALC_T_TMP, key_buf);
    }
    if (value_buf != def_buf_value) {
	erts_free(ERTS_ALC_T_TMP, value_buf);
    }
    BIF_RET(am_true);
}
Esempio n. 11
0
BIF_RETTYPE
check_old_code_1(BIF_ALIST_1)
{
    ErtsCodeIndex code_ix;
    Module* modp;
    Eterm res = am_false;

    if (is_not_atom(BIF_ARG_1)) {
	BIF_ERROR(BIF_P, BADARG);
    }
    code_ix = erts_active_code_ix();
    modp = erts_get_module(BIF_ARG_1, code_ix);
    if (modp != NULL) {
	erts_rlock_old_code(code_ix);
	if (modp->old.code_hdr) {
	    res = am_true;
	}
	erts_runlock_old_code(code_ix);
    }
    BIF_RET(res);
}
Esempio n. 12
0
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);
}
Esempio n. 13
0
BIF_RETTYPE os_unsetenv_1(BIF_ALIST_1)
{
    char *key_buf;
    char buf[STATIC_BUF_SIZE];

    key_buf = erts_convert_filename_to_native(BIF_ARG_1,buf,STATIC_BUF_SIZE,
					      ERTS_ALC_T_TMP,0,0,NULL);
    if (!key_buf) {
	BIF_ERROR(BIF_P, BADARG);
    }

    if (erts_sys_unsetenv(key_buf)) {
	if (key_buf != buf) {
	    erts_free(ERTS_ALC_T_TMP, key_buf);
	}
	BIF_ERROR(BIF_P, BADARG);
    }
    if (key_buf != buf) {
	erts_free(ERTS_ALC_T_TMP, key_buf);
    }
    BIF_RET(am_true);
}
Esempio n. 14
0
/* 
 * Return list of loaded drivers {ok,[string()]} 
 */
BIF_RETTYPE erl_ddll_loaded_drivers_0(BIF_ALIST_0)
{
    Eterm *hp;
    int need = 3;
    Eterm res = NIL;
    erts_driver_t *drv;
    lock_drv_list();
    for (drv = driver_list; drv; drv = drv->next) {
	need += sys_strlen(drv->name)*2+2;
    }
    hp = HAlloc(BIF_P, need);
    for (drv = driver_list; drv; drv = drv->next) {
	Eterm l;
	l = buf_to_intlist(&hp, drv->name, sys_strlen(drv->name), NIL);
	res = CONS(hp,l,res);
	hp += 2;
    }
    res = TUPLE2(hp,am_ok,res);
    /* hp += 3 */
    unlock_drv_list();
    BIF_RET(res);
}
Esempio n. 15
0
BIF_RETTYPE port_set_data_2(BIF_ALIST_2)
{
    /*
     * This is not a signal. See comment above.
     */
    erts_aint_t data;
    Port* prt;

    prt = data_lookup_port(BIF_P, BIF_ARG_1);
    if (!prt)
        BIF_ERROR(BIF_P, BADARG);

    if (is_immed(BIF_ARG_2)) {
	data = (erts_aint_t) BIF_ARG_2;
	ASSERT((data & 0x3) != 0);
    }
    else {
	ErtsPortDataHeap *pdhp;
	Uint hsize;
	Eterm *hp;

	hsize = size_object(BIF_ARG_2);
	pdhp = erts_alloc(ERTS_ALC_T_PORT_DATA_HEAP,
			  sizeof(ErtsPortDataHeap) + hsize*(sizeof(Eterm)-1));
	hp = &pdhp->heap[0];
	pdhp->off_heap.first = NULL;
	pdhp->off_heap.overhead = 0;
	pdhp->data = copy_struct(BIF_ARG_2, hsize, &hp, &pdhp->off_heap);
	data = (erts_aint_t) pdhp;
	ASSERT((data & 0x3) == 0);
    }

    data = erts_smp_atomic_xchg_wb(&prt->data, data);

    cleanup_old_port_data(data);

    BIF_RET(am_true);
}
Esempio n. 16
0
BIF_RETTYPE delete_module_1(BIF_ALIST_1)
{
    int res;

    if (is_not_atom(BIF_ARG_1))
	goto badarg;

    erts_smp_proc_unlock(BIF_P, ERTS_PROC_LOCK_MAIN);
    erts_smp_block_system(0);

    {
	Module *modp = erts_get_module(BIF_ARG_1);
	if (!modp) {
	    res = am_undefined;
	}
	else if (modp->old_code != 0) {
	    erts_dsprintf_buf_t *dsbufp = erts_create_logger_dsbuf();
	    erts_dsprintf(dsbufp, "Module %T must be purged before loading\n",
			  BIF_ARG_1);
	    erts_send_error_to_logger(BIF_P->group_leader, dsbufp);
	    res = am_badarg;
	}
	else {
	    delete_export_references(BIF_ARG_1);
	    delete_code(BIF_P, 0, modp);
	    res = am_true;
	}
    }

    erts_smp_release_system();
    erts_smp_proc_lock(BIF_P, ERTS_PROC_LOCK_MAIN);

    if (res == am_badarg) {
    badarg:
	BIF_ERROR(BIF_P, BADARG);
    }
    BIF_RET(res);
}
Esempio n. 17
0
BIF_RETTYPE hipe_bifs_show_term_1(BIF_ALIST_1)
{
    Eterm obj = BIF_ARG_1;

    printf("0x%0*lx\r\n", 2*(int)sizeof(long), obj);
    do {
	Eterm *objp;
	int i, ary;

	if (is_list(obj)) {
	    objp = list_val(obj);
	    ary = 2;
	} else if (is_boxed(obj)) {
	    Eterm header;

	    objp = boxed_val(obj);
	    header = objp[0];
	    if (is_thing(header))
		ary = thing_arityval(header);
	    else if (is_arity_value(header))
		ary = arityval(header);
	    else {
		printf("bad header %#lx\r\n", header);
		break;
	    }
	    ary += 1;
	} else
	    break;
	for (i = 0; i < ary; ++i)
	    printf("0x%0*lx: 0x%0*lx\r\n",
		   2*(int)sizeof(long), (unsigned long)&objp[i],
		   2*(int)sizeof(long), objp[i]);
    } while (0);
    erts_printf("%T", obj);
    printf("\r\n");
    BIF_RET(am_true);
}
Esempio n. 18
0
BIF_RETTYPE erts_internal_check_dirty_process_code_2(BIF_ALIST_2)
{
#if !defined(ERTS_DIRTY_SCHEDULERS)
    BIF_ERROR(BIF_P, EXC_NOTSUP);
#else
    Process *rp;
    int reds = 0;
    Eterm res;

    if (BIF_P != erts_dirty_process_code_checker)
	BIF_ERROR(BIF_P, EXC_NOTSUP);

    if (is_not_internal_pid(BIF_ARG_1))
	BIF_ERROR(BIF_P, BADARG);

    if (is_not_atom(BIF_ARG_2))
	BIF_ERROR(BIF_P, BADARG);

    rp = erts_pid2proc_not_running(BIF_P, ERTS_PROC_LOCK_MAIN,
				   BIF_ARG_1, ERTS_PROC_LOCK_MAIN);
    if (rp == ERTS_PROC_LOCK_BUSY)
	ERTS_BIF_YIELD2(bif_export[BIF_erts_internal_check_dirty_process_code_2],
			BIF_P, BIF_ARG_1, BIF_ARG_2);
    if (!rp)
	BIF_RET(am_false);
	
    res = erts_check_process_code(rp, BIF_ARG_2, &reds, BIF_P->fcalls);

    if (BIF_P != rp)
	erts_smp_proc_unlock(rp, ERTS_PROC_LOCK_MAIN);

    ASSERT(is_value(res));

    BIF_RET2(res, reds);
#endif
}
Esempio n. 19
0
BIF_RETTYPE hipe_bifs_stop_hrvtime_0(BIF_ALIST_0)
{
    stop_hrvtime();
    BIF_RET(am_true);
}
Esempio n. 20
0
BIF_RETTYPE hipe_bifs_trap_count_clear_0(BIF_ALIST_0)
{
    unsigned int count = hipe_trap_count;
    hipe_trap_count = 0;
    BIF_RET(make_small(count));
}
Esempio n. 21
0
BIF_RETTYPE hipe_bifs_trap_count_get_0(BIF_ALIST_0)
{
    BIF_RET(make_small(hipe_trap_count));
}
Esempio n. 22
0
/*
 * Backend for erl_ddll:format_error, handles all "soft" errors returned by builtins,
 * possibly by calling the system specific error handler
 */
BIF_RETTYPE erl_ddll_format_error_int_1(BIF_ALIST_1)
{
    Process *p = BIF_P;
    Eterm code_term = BIF_ARG_1;
    char *errstring = NULL;
    int errint;
    int len;
    Eterm ret = NIL;
    Eterm *hp;

    /* These errors can only appear in the erlang interface, not in the interface provided
       to drivers... */
    switch (code_term) {
    case am_inconsistent:
	errstring = "Driver name and/or driver options are inconsistent with "
	    "currently loaded driver";
	break;
    case am_linked_in_driver:
	errstring = "Driver is statically linked and "
	    "cannot be loaded/unloaded";
	break;
    case am_permanent:
	errstring = "DDLL driver is permanent an can not be unloaded/loaded";
	break;
    case am_not_loaded:
	errstring = "DDLL driver is not loaded";
	break;
    case am_not_loaded_by_this_process:
	errstring = "DDLL driver was not loaded by this process";
	break;
    case am_not_pending:
	errstring = "DDLL load not pending for this driver name";
	break;
    case am_already_loaded:
	errstring = "DDLL driver is already loaded successfully";
	break;
    case am_pending_reload:
	errstring = "Driver reloading is already pending";
	break;
    case am_pending_process:
	errstring = "Driver is loaded by others when attempting "
	    "option {reload, pending_driver}";
	break;
    default:
	/* A "real" error, we translate the atom to a code and translate the code 
	   to a string in the same manner as in the interface provided to drivers... */
	if (errdesc_to_code(code_term,&errint) != 0) {
	    goto error;
	}
	lock_drv_list();
	errstring = erts_ddll_error(errint);
	unlock_drv_list();
	break;
    }
    if (errstring == NULL) {
	goto error;
    }
    len = sys_strlen(errstring);
    hp = HAlloc(p, 2 * len);
    ret = buf_to_intlist(&hp, errstring, len, NIL);
    BIF_RET(ret);
 error:
    BIF_ERROR(p,BADARG);
} 
Esempio n. 23
0
/* 
 * More detailed info about loaded drivers: 
 * item is processes, driver_options, port_count, linked_in_driver, 
 * permanent, awaiting_load, awaiting_unload 
 */
BIF_RETTYPE erl_ddll_info_2(BIF_ALIST_2)
{
    Process *p = BIF_P;
    Eterm name_term = BIF_ARG_1;
    Eterm item = BIF_ARG_2;
    char *name = NULL;
    Eterm res = NIL;
    erts_driver_t *drv;
    ProcEntryInfo *pei = NULL;
    int num_pei;
    Eterm *hp;
    int i;
    Uint filter;
    int have_lock = 0;

    if ((name = pick_list_or_atom(name_term)) == NULL) {
	goto error;
    }

    if (!is_atom(item)) {
	goto error;
    }

    lock_drv_list();
    have_lock = 1;
    if ((drv = lookup_driver(name)) == NULL) {
	goto error;
    }
    
    switch (item) {
    case am_processes:
	filter = ERL_DE_PROC_LOADED;
	break;
    case am_driver_options:
	if (drv->handle == NULL) {
	    res = am_linked_in_driver;
	} else {
	    Uint start_flags = drv->handle->flags & ERL_FL_CONSISTENT_MASK;
	    /* Cheating, only one flag for now... */
	    if (start_flags & ERL_DE_FL_KILL_PORTS) {
		Eterm *myhp;
		myhp = HAlloc(p,2);
		res = CONS(myhp,am_kill_ports,NIL);
	    } else {
		res = NIL;
	    }
	}
	goto done;
    case am_port_count:
	if (drv->handle == NULL) {
	    res = am_linked_in_driver;
	} else if (drv->handle->status == ERL_DE_PERMANENT) {
	    res = am_permanent;
	} else {
	    res = make_small(erts_atomic32_read_nob(&drv->handle->port_count));
	}
	goto done;
    case am_linked_in_driver:
	if (drv->handle == NULL){
	    res = am_true;
	} else {
	    res = am_false;
	}
	goto done;
    case am_permanent:
	if (drv->handle != NULL && drv->handle->status == ERL_DE_PERMANENT) {
	    res = am_true;
	} else {
	    res = am_false;
	}
	goto done;
    case am_awaiting_load:
	filter = ERL_DE_PROC_AWAIT_LOAD;
	break;
    case am_awaiting_unload:
	filter = ERL_DE_PROC_AWAIT_UNLOAD;
	break;
    default:
	goto error;
    }

    if (drv->handle == NULL) {
	res = am_linked_in_driver;
	goto done;
    } else if (drv->handle->status == ERL_DE_PERMANENT) {
	res = am_permanent;
	goto done;
    }
    num_pei = build_proc_info(drv->handle, &pei, filter);
    if (!num_pei) {
	goto done;
    }
    hp = HAlloc(p,num_pei * (2+3));
    for (i = 0; i < num_pei; ++ i) {
	Eterm tpl = TUPLE2(hp,pei[i].pid,make_small(pei[i].count));
	hp += 3;
	res = CONS(hp,tpl,res);
	hp += 2;
    }    
 done:    
    unlock_drv_list();
    if (pei)
	erts_free(ERTS_ALC_T_DDLL_TMP_BUF, pei);
    erts_free(ERTS_ALC_T_DDLL_TMP_BUF, (void *) name);
    BIF_RET(res);
 error:
    if (name != NULL) {
	erts_free(ERTS_ALC_T_DDLL_TMP_BUF, (void *) name);
    }
    if (have_lock) {
	unlock_drv_list();
    }
    BIF_ERROR(p,BADARG);
}
Esempio n. 24
0
/* 
   You have to have loaded the driver and the pid state 
   is LOADED or AWAIT_LOAD. You will be removed from the list
   regardless of driver state.
   If the driver is loaded by someone else to, return is
   {ok, pending_process}
   If the driver is loaded but locked by a port, return is
   {ok, pending_driver}
   If the driver is loaded and free to unload (you're the last holding it)
   {ok, unloaded}
   If it's not loaded or not loaded by you
   {error, not_loaded} or {error, not_loaded_by_you}

   Internally, if its in state UNLOADING, just return {ok, pending_driver} and
   remove/decrement this pid (which should be an LOADED tagged one).
   If the state is RELOADING, this pid should be in list as LOADED tagged, 
   only AWAIT_LOAD would be possible but not allowed for unloading, remove it 
   and, if the last LOADED tagged, change from RELOAD to UNLOAD and notify
   any AWAIT_LOAD-waiters with {'DOWN', ref(), driver, name(), load_cancelled}
   If the driver made itself permanent, {'UP', ref(), driver, name(), permanent}
*/
Eterm erl_ddll_try_unload_2(BIF_ALIST_2)
{
    Eterm name_term = BIF_ARG_1;
    Eterm options = BIF_ARG_2;
    char *name = NULL;
    Eterm ok_term = NIL;
    Eterm soft_error_term = NIL;
    erts_driver_t *drv;
    DE_Handle *dh;
    DE_ProcEntry *pe;
    Eterm *hp;
    Eterm t;
    int monitor = 0;
    Eterm l;
    int kill_ports = 0;

    erts_proc_unlock(BIF_P, ERTS_PROC_LOCK_MAIN);

    for(l = options; is_list(l); l =  CDR(list_val(l))) {
	Eterm opt = CAR(list_val(l));
	Eterm *tp;
	if (is_not_tuple(opt)) {
	    if (opt == am_kill_ports) {
		kill_ports = 1;
		continue;
	    } else {
		goto error;
	    }
	}
	tp = tuple_val(opt);
	if (*tp != make_arityval(2) || tp[1] != am_monitor) {
	    goto error;
	}
	if (tp[2] == am_pending_driver) { 
	    monitor = 1;
	} else if (tp[2] == am_pending) {
	    monitor = 2;
	} else {
	    goto error;
	}
    }
    if (is_not_nil(l)) {
	goto error;
    }

    if ((name = pick_list_or_atom(name_term)) == NULL) {
	goto error;
    }

    lock_drv_list();

    if ((drv = lookup_driver(name)) == NULL) {
	soft_error_term = am_not_loaded;
	goto soft_error;
    }

    if (drv->handle == NULL) {
	soft_error_term = am_linked_in_driver;
	goto soft_error;
    } else if (drv->handle->status == ERL_DE_PERMANENT) {
	soft_error_term = am_permanent;
	goto soft_error;
    }	
    dh = drv->handle;
    if (dh->flags & ERL_DE_FL_KILL_PORTS) {
	kill_ports = 1;
    }
    if ((pe = find_proc_entry(dh, BIF_P, ERL_DE_PROC_LOADED)) == NULL) {
	if (num_procs(dh, ERL_DE_PROC_LOADED) > 0) {
	    soft_error_term = am_not_loaded_by_this_process;
	    goto soft_error;
	}
    } else {
	remove_proc_entry(dh, pe);
	if (!(pe->flags & ERL_DE_FL_DEREFERENCED)) {
	    erts_ddll_dereference_driver(dh);
	}
	erts_free(ERTS_ALC_T_DDLL_PROCESS, pe);
    }
    if (num_procs(dh, ERL_DE_PROC_LOADED) > 0) {
	ok_term = am_pending_process;
	--monitor;
	goto done;
    }
    if (dh->status == ERL_DE_RELOAD ||
	dh->status == ERL_DE_FORCE_RELOAD) {
	notify_all(dh, drv->name, 
		   ERL_DE_PROC_AWAIT_LOAD, am_DOWN, am_load_cancelled);
	erts_free(ERTS_ALC_T_DDLL_HANDLE,dh->reload_full_path);
	erts_free(ERTS_ALC_T_DDLL_HANDLE,dh->reload_driver_name);
	dh->reload_full_path = dh->reload_driver_name = NULL; 
	dh->reload_flags = 0;
    } 
    if (erts_atomic32_read_nob(&dh->port_count) > 0) {
	++kill_ports;
    }
    dh->status = ERL_DE_UNLOAD;
    ok_term = am_pending_driver;
done:
    assert_drv_list_rwlocked();
    if (kill_ports > 1) {
	/* Avoid closing the driver by referencing it */
	erts_ddll_reference_driver(dh);
	dh->status = ERL_DE_FORCE_UNLOAD;
	unlock_drv_list();
	kill_ports_driver_unloaded(dh);
	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);
    erts_free(ERTS_ALC_T_DDLL_TMP_BUF, (void *) name);
    BIF_P->flags |= F_USING_DDLL;
    if (monitor > 0) {
	Eterm mref = add_monitor(BIF_P, dh, ERL_DE_PROC_AWAIT_UNLOAD);
	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);
    }
    if (kill_ports > 1) {
	ERTS_BIF_CHK_EXITED(BIF_P); /* May be exited by port killing */
    }
    unlock_drv_list();
    BIF_RET(t);
 
soft_error:
    unlock_drv_list();
    erts_free(ERTS_ALC_T_DDLL_TMP_BUF, (void *) name);
    erts_proc_lock(BIF_P, ERTS_PROC_LOCK_MAIN);
    hp = HAlloc(BIF_P, 3);
    t = TUPLE2(hp, am_error, soft_error_term);
    BIF_RET(t);
 
 error: /* No lock fiddling before going here */
    assert_drv_list_not_locked();
    if (name != NULL) {
	erts_free(ERTS_ALC_T_DDLL_TMP_BUF, (void *) name);
    }
    erts_proc_lock(BIF_P, ERTS_PROC_LOCK_MAIN);
    BIF_ERROR(BIF_P, BADARG);
}
Esempio n. 25
0
/*
 * 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);
}
Esempio n. 26
0
BIF_RETTYPE finish_after_on_load_2(BIF_ALIST_2)
{
    ErtsCodeIndex code_ix;
    Module* modp;

    if (!erts_try_seize_code_write_permission(BIF_P)) {
	ERTS_BIF_YIELD2(bif_export[BIF_finish_after_on_load_2],
			BIF_P, BIF_ARG_1, BIF_ARG_2);
    }

    /* ToDo: Use code_ix staging instead of thread blocking */

    erts_smp_proc_unlock(BIF_P, ERTS_PROC_LOCK_MAIN);
    erts_smp_thr_progress_block();

    code_ix = erts_active_code_ix();
    modp = erts_get_module(BIF_ARG_1, code_ix);

    if (!modp || !modp->old.code_hdr) {
    error:
	erts_smp_thr_progress_unblock();
        erts_smp_proc_lock(BIF_P, ERTS_PROC_LOCK_MAIN);
	erts_release_code_write_permission();
	BIF_ERROR(BIF_P, BADARG);
    }
    if (modp->old.code_hdr->on_load_function_ptr == NULL) {
	goto error;
    }
    if (BIF_ARG_2 != am_false && BIF_ARG_2 != am_true) {
	goto error;
    }

    if (BIF_ARG_2 == am_true) {
	int i;
	struct erl_module_instance t;

	/*
	 * Swap old and new code.
	 */
	t = modp->curr;
	modp->curr = modp->old;
	modp->old = t;

	/*
	 * The on_load function succeded. Fix up export entries.
	 */
	for (i = 0; i < export_list_size(code_ix); i++) {
	    Export *ep = export_list(i,code_ix);
	    if (ep == NULL || ep->code[0] != BIF_ARG_1) {
		continue;
	    }
	    if (ep->code[4] != 0) {
		ep->addressv[code_ix] = (void *) ep->code[4];
		ep->code[4] = 0;
	    } else {
		if (ep->addressv[code_ix] == ep->code+3 &&
		    ep->code[3] == (BeamInstr) em_apply_bif) {
		    continue;
		}
		ep->addressv[code_ix] = ep->code+3;
		ep->code[3] = (BeamInstr) em_call_error_handler;
	    }
	}
	modp->curr.code_hdr->on_load_function_ptr = NULL;
	set_default_trace_pattern(BIF_ARG_1);
    } else if (BIF_ARG_2 == am_false) {
	int i;

	/*
	 * The on_load function failed. Remove references to the
	 * code that is about to be purged from the export entries.
	 */

	for (i = 0; i < export_list_size(code_ix); i++) {
	    Export *ep = export_list(i,code_ix);
	    if (ep == NULL || ep->code[0] != BIF_ARG_1) {
		continue;
	    }
	    if (ep->code[3] == (BeamInstr) em_apply_bif) {
		continue;
	    }
	    ep->code[4] = 0;
	}
    }
    erts_smp_thr_progress_unblock();
    erts_smp_proc_lock(BIF_P, ERTS_PROC_LOCK_MAIN);
    erts_release_code_write_permission();
    BIF_RET(am_true);
}
Esempio n. 27
0
BIF_RETTYPE hipe_bifs_nstack_used_size_0(BIF_ALIST_0)
{
    BIF_RET(make_small(hipe_nstack_used(BIF_P)));
}
Esempio n. 28
0
File: erl_nif.c Progetto: a5an0/otp
BIF_RETTYPE load_nif_2(BIF_ALIST_2)
{
    static const char bad_lib[] = "bad_lib";
    static const char reload[] = "reload";
    static const char upgrade[] = "upgrade";
    char* lib_name = NULL;
    void* handle = NULL;
    void* init_func;
    ErlNifEntry* entry = NULL;
    ErlNifEnv env;
    int len, i, err;
    Module* mod;
    Eterm mod_atom;
    Eterm f_atom;
    BeamInstr* caller;
    ErtsSysDdllError errdesc = ERTS_SYS_DDLL_ERROR_INIT;
    Eterm ret = am_ok;
    int veto;
    struct erl_module_nif* lib = NULL;

    len = list_length(BIF_ARG_1);
    if (len < 0) {
	BIF_ERROR(BIF_P, BADARG);
    }
    lib_name = (char *) erts_alloc(ERTS_ALC_T_TMP, len + 1);

    if (intlist_to_buf(BIF_ARG_1, lib_name, len) != len) {
	erts_free(ERTS_ALC_T_TMP, lib_name);
	BIF_ERROR(BIF_P, BADARG);
    }
    lib_name[len] = '\0';

    /* Block system (is this the right place to do it?) */
    erts_smp_proc_unlock(BIF_P, ERTS_PROC_LOCK_MAIN);
    erts_smp_thr_progress_block();

    /* Find calling module */
    ASSERT(BIF_P->current != NULL);
    ASSERT(BIF_P->current[0] == am_erlang
	   && BIF_P->current[1] == am_load_nif 
	   && BIF_P->current[2] == 2);
    caller = find_function_from_pc(BIF_P->cp);
    ASSERT(caller != NULL);
    mod_atom = caller[0];
    ASSERT(is_atom(mod_atom));
    mod=erts_get_module(mod_atom);
    ASSERT(mod != NULL);

    if (!in_area(caller, mod->code, mod->code_length)) {
	ASSERT(in_area(caller, mod->old_code, mod->old_code_length));

	ret = load_nif_error(BIF_P, "old_code", "Calling load_nif from old "
			     "module '%T' not allowed", mod_atom);
    }    
    else if ((err=erts_sys_ddll_open2(lib_name, &handle, &errdesc)) != ERL_DE_NO_ERROR) {
	const char slogan[] = "Failed to load NIF library";
	if (strstr(errdesc.str, lib_name) != NULL) {
	    ret = load_nif_error(BIF_P, "load_failed", "%s: '%s'", slogan, errdesc.str);
	}
	else {
	    ret = load_nif_error(BIF_P, "load_failed", "%s %s: '%s'", slogan, lib_name, errdesc.str);
	}
    }
    else if (erts_sys_ddll_load_nif_init(handle, &init_func, &errdesc) != ERL_DE_NO_ERROR) {
	ret  = load_nif_error(BIF_P, bad_lib, "Failed to find library init"
			      " function: '%s'", errdesc.str);
	
    }
    else if ((add_taint(mod_atom),
	      (entry = erts_sys_ddll_call_nif_init(init_func)) == NULL)) {
	ret = load_nif_error(BIF_P, bad_lib, "Library init-call unsuccessful");
    }
    else if (entry->major != ERL_NIF_MAJOR_VERSION
	     || entry->minor > ERL_NIF_MINOR_VERSION) {
	
	ret = load_nif_error(BIF_P, bad_lib, "Library version (%d.%d) not compatible (with %d.%d).",
			     entry->major, entry->minor, ERL_NIF_MAJOR_VERSION, ERL_NIF_MINOR_VERSION);
    }   
    else if (entry->minor >= 1
	     && sys_strcmp(entry->vm_variant, ERL_NIF_VM_VARIANT) != 0) {
	ret = load_nif_error(BIF_P, bad_lib, "Library (%s) not compiled for "
			     "this vm variant (%s).",
			     entry->vm_variant, ERL_NIF_VM_VARIANT);
    }
    else if (!erts_is_atom_str((char*)entry->name, mod_atom)) {
	ret = load_nif_error(BIF_P, bad_lib, "Library module name '%s' does not"
			     " match calling module '%T'", entry->name, mod_atom);
    }
    else {
	/*erts_fprintf(stderr, "Found module %T\r\n", mod_atom);*/
    
	for (i=0; i < entry->num_of_funcs && ret==am_ok; i++) {
	    BeamInstr** code_pp;
	    ErlNifFunc* f = &entry->funcs[i];
	    if (!erts_atom_get(f->name, sys_strlen(f->name), &f_atom)
		|| (code_pp = get_func_pp(mod->code, f_atom, f->arity))==NULL) { 
		ret = load_nif_error(BIF_P,bad_lib,"Function not found %T:%s/%u",
				     mod_atom, f->name, f->arity);
	    }    
	    else if (code_pp[1] - code_pp[0] < (5+3)) {
		ret = load_nif_error(BIF_P,bad_lib,"No explicit call to load_nif"
				     " in module (%T:%s/%u to small)",
				     mod_atom, entry->funcs[i].name, entry->funcs[i].arity);
	    }
	    /*erts_fprintf(stderr, "Found NIF %T:%s/%u\r\n",
			 mod_atom, entry->funcs[i].name, entry->funcs[i].arity);*/
	}
    }

    if (ret != am_ok) {
	goto error;
    }

    /* Call load, reload or upgrade:
     */


    lib = erts_alloc(ERTS_ALC_T_NIF, sizeof(struct erl_module_nif));
    lib->handle = handle;
    lib->entry = entry;
    erts_refc_init(&lib->rt_cnt, 0);
    erts_refc_init(&lib->rt_dtor_cnt, 0);
    lib->mod = mod;
    env.mod_nif = lib;
    if (mod->nif != NULL) { /* Reload */
	int k;
        lib->priv_data = mod->nif->priv_data;

	ASSERT(mod->nif->entry != NULL);
	if (entry->reload == NULL) {
	    ret = load_nif_error(BIF_P,reload,"Reload not supported by this NIF library.");
	    goto error;
	}
	/* Check that no NIF is removed */
	for (k=0; k < mod->nif->entry->num_of_funcs; k++) {
	    ErlNifFunc* old_func = &mod->nif->entry->funcs[k];
	    for (i=0; i < entry->num_of_funcs; i++) {
		if (old_func->arity == entry->funcs[i].arity
		    && sys_strcmp(old_func->name, entry->funcs[i].name) == 0) {			   
		    break;
		}
	    }
	    if (i == entry->num_of_funcs) {
		ret = load_nif_error(BIF_P,reload,"Reloaded library missing "
				     "function %T:%s/%u\r\n", mod_atom,
				     old_func->name, old_func->arity);
		goto error;
	    }
	}       
	erts_pre_nif(&env, BIF_P, lib);
	veto = entry->reload(&env, &lib->priv_data, BIF_ARG_2);
	erts_post_nif(&env);
	if (veto) {
	    ret = load_nif_error(BIF_P, reload, "Library reload-call unsuccessful.");
	}
	else {
	    mod->nif->entry = NULL; /* to prevent 'unload' callback */
	    erts_unload_nif(mod->nif);
	}
    }
    else {
	lib->priv_data = NULL;
	if (mod->old_nif != NULL) { /* Upgrade */
	    void* prev_old_data = mod->old_nif->priv_data;
	    if (entry->upgrade == NULL) {
		ret = load_nif_error(BIF_P, upgrade, "Upgrade not supported by this NIF library.");
		goto error;
	    }
	    erts_pre_nif(&env, BIF_P, lib);
	    veto = entry->upgrade(&env, &lib->priv_data, &mod->old_nif->priv_data, BIF_ARG_2);
	    erts_post_nif(&env);
	    if (veto) {
		mod->old_nif->priv_data = prev_old_data;
		ret = load_nif_error(BIF_P, upgrade, "Library upgrade-call unsuccessful.");
	    }
	    /*else if (mod->old_nif->priv_data != prev_old_data) {
		refresh_cached_nif_data(mod->old_code, mod->old_nif);
	    }*/
	}
	else if (entry->load != NULL) { /* Initial load */
	    erts_pre_nif(&env, BIF_P, lib);
	    veto = entry->load(&env, &lib->priv_data, BIF_ARG_2);
	    erts_post_nif(&env);
	    if (veto) {
		ret = load_nif_error(BIF_P, "load", "Library load-call unsuccessful.");
	    }
	}
    }
    if (ret == am_ok) {
	/*
	** Everything ok, patch the beam code with op_call_nif
	*/
        mod->nif = lib; 
	for (i=0; i < entry->num_of_funcs; i++)
	{
	    BeamInstr* code_ptr;
	    erts_atom_get(entry->funcs[i].name, sys_strlen(entry->funcs[i].name), &f_atom); 
	    code_ptr = *get_func_pp(mod->code, f_atom, entry->funcs[i].arity); 
	    
	    if (code_ptr[1] == 0) {
		code_ptr[5+0] = (BeamInstr) BeamOp(op_call_nif);
	    }
	    else { /* Function traced, patch the original instruction word */
		BpData** bps = (BpData**) code_ptr[1];
		BpData*  bp  = (BpData*) bps[erts_bp_sched2ix()];
	        bp->orig_instr = (BeamInstr) BeamOp(op_call_nif);
	    }	    
	    code_ptr[5+1] = (BeamInstr) entry->funcs[i].fptr;
	    code_ptr[5+2] = (BeamInstr) lib;
	}
    }
    else {
    error:
	ASSERT(ret != am_ok);
        if (lib != NULL) {
	    erts_free(ERTS_ALC_T_NIF, lib);
	}
	if (handle != NULL) {
	    erts_sys_ddll_close(handle);
	}
	erts_sys_ddll_free_error(&errdesc);
    }

    erts_smp_thr_progress_unblock();
    erts_smp_proc_lock(BIF_P, ERTS_PROC_LOCK_MAIN);
    erts_free(ERTS_ALC_T_TMP, lib_name);
    BIF_RET(ret);
}
Esempio n. 29
0
BIF_RETTYPE
erts_debug_disassemble_1(BIF_ALIST_1)
{
    Process* p = BIF_P;
    Eterm addr = BIF_ARG_1;
    erts_dsprintf_buf_t *dsbufp;
    Eterm* hp;
    Eterm* tp;
    Eterm bin;
    Eterm mfa;
    ErtsCodeMFA *cmfa = NULL;
    BeamCodeHeader* code_hdr;
    BeamInstr *code_ptr;
    BeamInstr instr;
    BeamInstr uaddr;
    Uint hsz;
    int i;

    if (term_to_UWord(addr, &uaddr)) {
	code_ptr = (BeamInstr *) uaddr;
	if ((cmfa = find_function_from_pc(code_ptr)) == NULL) {
	    BIF_RET(am_false);
	}
    } else if (is_tuple(addr)) {
	ErtsCodeIndex code_ix;
	Module* modp;
	Eterm mod;
	Eterm name;
	Export* ep;
	Sint arity;
	int n;

	tp = tuple_val(addr);
	if (tp[0] != make_arityval(3)) {
	error:
	    BIF_ERROR(p, BADARG);
	}
	mod = tp[1];
	name = tp[2];
	if (!is_atom(mod) || !is_atom(name) || !is_small(tp[3])) {
	    goto error;
	}
	arity = signed_val(tp[3]);
	code_ix = erts_active_code_ix();
	modp = erts_get_module(mod, code_ix);

	/*
	 * Try the export entry first to allow disassembly of special functions
	 * such as erts_debug:apply/4.  Then search for it in the module.
	 */
	if ((ep = erts_find_function(mod, name, arity, code_ix)) != NULL) {
	    /* XXX: add "&& ep->address != ep->code" condition?
	     * Consider a traced function.
	     * Its ep will have ep->address == ep->code.
	     * erts_find_function() will return the non-NULL ep.
	     * Below we'll try to derive a code_ptr from ep->address.
	     * But this code_ptr will point to the start of the Export,
	     * not the function's func_info instruction. BOOM !?
	     */
	    cmfa = erts_code_to_codemfa(ep->addressv[code_ix]);
	} else if (modp == NULL || (code_hdr = modp->curr.code_hdr) == NULL) {
	    BIF_RET(am_undef);
	} else {
	    n = code_hdr->num_functions;
	    for (i = 0; i < n; i++) {
		cmfa = &code_hdr->functions[i]->mfa;
		if (cmfa->function == name && cmfa->arity == arity) {
		    break;
		}
	    }
	    if (i == n) {
		BIF_RET(am_undef);
	    }
	}
        code_ptr = (BeamInstr*)erts_code_to_codeinfo(erts_codemfa_to_code(cmfa));
    } else {
	goto error;
    }

    dsbufp = erts_create_tmp_dsbuf(0);
    erts_print(ERTS_PRINT_DSBUF, (void *) dsbufp, HEXF ": ", code_ptr);
    instr = (BeamInstr) code_ptr[0];
    for (i = 0; i < NUM_SPECIFIC_OPS; i++) {
	if (BeamIsOpCode(instr, i) && opc[i].name[0] != '\0') {
	    code_ptr += print_op(ERTS_PRINT_DSBUF, (void *) dsbufp,
				 i, opc[i].sz-1, code_ptr) + 1;
	    break;
	}
    }
    if (i >= NUM_SPECIFIC_OPS) {
	erts_print(ERTS_PRINT_DSBUF, (void *) dsbufp,
		   "unknown " HEXF "\n", instr);
	code_ptr++;
    }
    bin = new_binary(p, (byte *) dsbufp->str, dsbufp->str_len);
    erts_destroy_tmp_dsbuf(dsbufp);
    hsz = 4+4;
    (void) erts_bld_uword(NULL, &hsz, (BeamInstr) code_ptr);
    hp = HAlloc(p, hsz);
    addr = erts_bld_uword(&hp, NULL, (BeamInstr) code_ptr);
    ASSERT(is_atom(cmfa->module) || is_nil(cmfa->module));
    ASSERT(is_atom(cmfa->function) || is_nil(cmfa->function));
    mfa = TUPLE3(hp, cmfa->module, cmfa->function,
                 make_small(cmfa->arity));
    hp += 4;
    return TUPLE3(hp, addr, bin, mfa);
}
Esempio n. 30
0
Eterm
load_module_2(BIF_ALIST_2)
{
    Eterm   reason;
    Eterm*  hp;
    int      i;
    int      sz;
    byte*    code;
    int trace_pattern_is_on;
    Binary *match_spec;
    Binary *meta_match_spec;
    struct trace_pattern_flags trace_pattern_flags;
    Eterm meta_tracer_pid;
    Eterm res;
    byte* temp_alloc = NULL;

    if (is_not_atom(BIF_ARG_1)) {
    error:
	erts_free_aligned_binary_bytes(temp_alloc);
	BIF_ERROR(BIF_P, BADARG);
    }
    if ((code = erts_get_aligned_binary_bytes(BIF_ARG_2, &temp_alloc)) == NULL) {
	goto error;
    }
    erts_smp_proc_unlock(BIF_P, ERTS_PROC_LOCK_MAIN);
    erts_smp_block_system(0);

    erts_export_consolidate();

    hp = HAlloc(BIF_P, 3);
    sz = binary_size(BIF_ARG_2);
    if ((i = erts_load_module(BIF_P, 0,
			      BIF_P->group_leader, &BIF_ARG_1, code, sz)) < 0) { 
	switch (i) {
	case -1: reason = am_badfile; break; 
	case -2: reason = am_nofile; break;
	case -3: reason = am_not_purged; break;
	case -4:
	    reason = am_atom_put("native_code", sizeof("native_code")-1);
	    break;
	default: reason = am_badfile; break;
	}
	res = TUPLE2(hp, am_error, reason);
	goto done;
    }

    erts_get_default_trace_pattern(&trace_pattern_is_on,
				   &match_spec,
				   &meta_match_spec,
				   &trace_pattern_flags,
				   &meta_tracer_pid);
    if (trace_pattern_is_on) {
	Eterm mfa[1];
	mfa[0] = BIF_ARG_1;
	(void) erts_set_trace_pattern(mfa, 1, 
				      match_spec, 
				      meta_match_spec,
				      1, trace_pattern_flags, 
				      meta_tracer_pid);
    }

    res = TUPLE2(hp, am_module, BIF_ARG_1);

 done:
    erts_free_aligned_binary_bytes(temp_alloc);
    erts_smp_release_system();
    erts_smp_proc_lock(BIF_P, ERTS_PROC_LOCK_MAIN);

    BIF_RET(res);
}