aboutsummaryrefslogtreecommitdiffstats
path: root/erts/emulator/test/nif_SUITE_data
diff options
context:
space:
mode:
authorSverker Eriksson <[email protected]>2010-02-11 13:30:32 +0000
committerErlang/OTP <[email protected]>2010-02-11 13:30:32 +0000
commit2a96208cb00220f963e723ae0530492c5c70df27 (patch)
tree1a0150d8a404a19fa69da48bb49fad95e701454c /erts/emulator/test/nif_SUITE_data
parent94a5a2832200fa5061d31e64c0eb8315c3215e0a (diff)
downloadotp-2a96208cb00220f963e723ae0530492c5c70df27.tar.gz
otp-2a96208cb00220f963e723ae0530492c5c70df27.tar.bz2
otp-2a96208cb00220f963e723ae0530492c5c70df27.zip
OTP-8335 Even more NIF features
Diffstat (limited to 'erts/emulator/test/nif_SUITE_data')
-rw-r--r--erts/emulator/test/nif_SUITE_data/Makefile.src13
-rw-r--r--erts/emulator/test/nif_SUITE_data/head.txt5
-rw-r--r--erts/emulator/test/nif_SUITE_data/nif_SUITE.c388
-rw-r--r--erts/emulator/test/nif_SUITE_data/nif_mod.c203
-rw-r--r--erts/emulator/test/nif_SUITE_data/nif_mod.erl10
-rw-r--r--erts/emulator/test/nif_SUITE_data/nif_mod.h5
-rw-r--r--erts/emulator/test/nif_SUITE_data/tail.txt5
-rw-r--r--erts/emulator/test/nif_SUITE_data/testcase_driver.h59
-rw-r--r--erts/emulator/test/nif_SUITE_data/tester.c73
-rw-r--r--erts/emulator/test/nif_SUITE_data/tester.erl13
10 files changed, 714 insertions, 60 deletions
diff --git a/erts/emulator/test/nif_SUITE_data/Makefile.src b/erts/emulator/test/nif_SUITE_data/Makefile.src
index 6a8b4f1245..ab4ff77add 100644
--- a/erts/emulator/test/nif_SUITE_data/Makefile.src
+++ b/erts/emulator/test/nif_SUITE_data/Makefile.src
@@ -4,11 +4,22 @@ NIF_LIBS = nif_SUITE.1@dll@ \
nif_mod.2@dll@ \
nif_mod.3@dll@
-all: $(NIF_LIBS)
+all: $(NIF_LIBS) basic@dll@ rwlock@dll@ tsd@dll@
@SHLIB_RULES@
$(NIF_LIBS): nif_SUITE.c nif_mod.c nif_mod.h
+basic@dll@: tester.c testcase_driver.h
+rwlock@dll@: tester.c testcase_driver.h
+
+tsd@dll@: tester.c testcase_driver.h
+
+DRIVER_DIR = ../erl_drv_thread_SUITE_data
+
+basic.c rwlock.c tsd.c: $(DRIVER_DIR)/$@
+ cat head.txt > $@
+ cat $(DRIVER_DIR)/$@ | sed -e 's/erl_drv_/enif_/g' -e 's/driver_/enif_/g' -e 's/ErlDrv/ErlNif/g' >> $@
+ cat tail.txt >> $@
diff --git a/erts/emulator/test/nif_SUITE_data/head.txt b/erts/emulator/test/nif_SUITE_data/head.txt
new file mode 100644
index 0000000000..4b9b44276f
--- /dev/null
+++ b/erts/emulator/test/nif_SUITE_data/head.txt
@@ -0,0 +1,5 @@
+/* Do NOT edit this file!!!
+**
+** This is a NIF'ified COPY of the original in ../erl_drv_thread_SUITE_data/
+*/
+
diff --git a/erts/emulator/test/nif_SUITE_data/nif_SUITE.c b/erts/emulator/test/nif_SUITE_data/nif_SUITE.c
index 4532062dce..7d05a9a880 100644
--- a/erts/emulator/test/nif_SUITE_data/nif_SUITE.c
+++ b/erts/emulator/test/nif_SUITE_data/nif_SUITE.c
@@ -15,6 +15,7 @@ typedef struct
int ref_cnt;
CallInfo* call_history;
NifModPrivData* nif_mod;
+ union { ErlNifResourceType* t; long l; } rt_arr[2];
}PrivData;
void add_call(ErlNifEnv* env, PrivData* data, const char* func_name)
@@ -26,12 +27,29 @@ void add_call(ErlNifEnv* env, PrivData* data, const char* func_name)
call->static_cntA = ++static_cntA;
call->static_cntB = ++static_cntB;
data->call_history = call;
+ call->arg = NULL;
+ call->arg_sz = 0;
}
#define ADD_CALL(FUNC_NAME) add_call(env, enif_get_data(env),FUNC_NAME)
+static void* resource_dtor_last = NULL;
+static unsigned resource_dtor_last_sz = 0;
+static char resource_dtor_last_data[20];
+static int resource_dtor_cnt = 0;
+
+static void resource_dtor(ErlNifEnv* env, void* obj)
+{
+ resource_dtor_last = obj;
+ resource_dtor_cnt++;
+ resource_dtor_last_sz = enif_sizeof_resource(env, obj);
+ assert(resource_dtor_last_sz <= sizeof(resource_dtor_last_data));
+ memcpy(resource_dtor_last_data, obj, resource_dtor_last_sz);
+}
+
static int load(ErlNifEnv* env, void** priv_data, ERL_NIF_TERM load_info)
{
+ /*ERL_NIF_TERM head, tail;*/
PrivData* data = enif_alloc(env, sizeof(PrivData));
assert(data != NULL);
data->ref_cnt = 1;
@@ -39,7 +57,26 @@ static int load(ErlNifEnv* env, void** priv_data, ERL_NIF_TERM load_info)
data->nif_mod = NULL;
add_call(env, data, "load");
-
+
+ /*
+ head = load_info;
+ data->rt_cnt = 0;
+ for (head=load_info; enif_get_list_cell(env,load_info,&head,&tail);
+ head=tail) {
+ char buf[20];
+ int n = enif_get_string(env,head,buf,sizeof(buf));
+ assert(n > 0);
+ assert(i < sizeof(data->rt_arr)/sizeof(*data->rt_arr));
+ data->rt_arr[data->rt_cnt++].t = enif_create_resource_type(env,buf,resource_dtor,
+ ERL_NIF_RT_CREATE,NULL);
+ }
+ assert(enif_is_empty_list(env,head));
+ */
+ data->rt_arr[0].t = enif_open_resource_type(env,"Gold",resource_dtor,
+ ERL_NIF_RT_CREATE,NULL);
+ data->rt_arr[1].t = enif_open_resource_type(env,"Silver",resource_dtor,
+ ERL_NIF_RT_CREATE,NULL);
+
*priv_data = data;
return 0;
}
@@ -80,11 +117,19 @@ static ERL_NIF_TERM make_call_history(ErlNifEnv* env, CallInfo** headp)
while (*headp != NULL) {
CallInfo* call = *headp;
- ERL_NIF_TERM tpl = enif_make_tuple(env, 4,
- enif_make_atom(env,call->func_name),
- enif_make_int(env,call->lib_ver),
- enif_make_int(env,call->static_cntA),
- enif_make_int(env,call->static_cntB));
+ ERL_NIF_TERM func_term = enif_make_atom(env,call->func_name);
+ ERL_NIF_TERM tpl;
+ if (call->arg != NULL) {
+ ErlNifBinary arg_bin;
+ enif_alloc_binary(env, call->arg_sz, &arg_bin);
+ memcpy(arg_bin.data, call->arg, call->arg_sz);
+ func_term = enif_make_tuple2(env, func_term,
+ enif_make_binary(env, &arg_bin));
+ }
+ tpl = enif_make_tuple4(env, func_term,
+ enif_make_int(env,call->lib_ver),
+ enif_make_int(env,call->static_cntA),
+ enif_make_int(env,call->static_cntB));
list = enif_make_list_cell(env, tpl, list);
*headp = call->next;
enif_free(env,call);
@@ -117,11 +162,14 @@ static ERL_NIF_TERM hold_nif_mod_priv_data(ErlNifEnv* env, int argc, const ERL_N
static ERL_NIF_TERM nif_mod_call_history(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{
PrivData* data = (PrivData*) enif_get_data(env);
-
+ ERL_NIF_TERM ret;
if (data->nif_mod == NULL) {
- return enif_make_string(env,"nif_mod pointer is NULL");
+ return enif_make_string(env,"nif_mod pointer is NULL", ERL_NIF_LATIN1);
}
- return make_call_history(env,&data->nif_mod->call_history);
+ enif_mutex_lock(data->nif_mod->mtx);
+ ret = make_call_history(env, &data->nif_mod->call_history);
+ enif_mutex_unlock(data->nif_mod->mtx);
+ return ret;
}
static ERL_NIF_TERM list_seq(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
@@ -150,12 +198,34 @@ static int test_int(ErlNifEnv* env, int i1)
return 1;
}
+static int test_uint(ErlNifEnv* env, unsigned i1)
+{
+ unsigned i2 = 0;
+ ERL_NIF_TERM int_term = enif_make_uint(env, i1);
+ if (!enif_get_uint(env,int_term, &i2) || i1 != i2) {
+ fprintf(stderr, "test_uint(%u) ...FAILED i2=%u\r\n", i1, i2);
+ return 0;
+ }
+ return 1;
+}
+
+static int test_long(ErlNifEnv* env, long i1)
+{
+ long i2 = 0;
+ ERL_NIF_TERM int_term = enif_make_long(env, i1);
+ if (!enif_get_long(env,int_term, &i2) || i1 != i2) {
+ fprintf(stderr, "test_long(%ld) ...FAILED i2=%ld\r\n", i1, i2);
+ return 0;
+ }
+ return 1;
+}
+
static int test_ulong(ErlNifEnv* env, unsigned long i1)
{
unsigned long i2 = 0;
ERL_NIF_TERM int_term = enif_make_ulong(env, i1);
if (!enif_get_ulong(env,int_term, &i2) || i1 != i2) {
- fprintf(stderr, "SVERK: test_ulong(%lu) ...FAILED i2=%lu\r\n", i1, i2);
+ fprintf(stderr, "test_ulong(%lu) ...FAILED i2=%lu\r\n", i1, i2);
return 0;
}
return 1;
@@ -166,7 +236,7 @@ static int test_double(ErlNifEnv* env, double d1)
double d2 = 0;
ERL_NIF_TERM term = enif_make_double(env, d1);
if (!enif_get_double(env,term, &d2) || d1 != d2) {
- fprintf(stderr, "SVERK: test_double(%e) ...FAILED i2=%e\r\n", d1, d2);
+ fprintf(stderr, "test_double(%e) ...FAILED i2=%e\r\n", d1, d2);
return 0;
}
return 1;
@@ -180,32 +250,59 @@ static int test_double(ErlNifEnv* env, double d1)
static ERL_NIF_TERM type_test(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{
int i;
- unsigned long u;
+ int sint;
+ unsigned uint;
+ long slong;
+ unsigned long ulong;
double d;
ERL_NIF_TERM atom, ref1, ref2;
- i = INT_MIN;
+ sint = INT_MIN;
do {
- if (!test_int(env,i)) {
+ if (!test_int(env,sint)) {
goto error;
}
- i += ~i / 3 + 1;
- } while (i < 0);
- i = INT_MAX;
+ sint += ~sint / 3 + 1;
+ } while (sint < 0);
+ sint = INT_MAX;
do {
- if (!test_int(env,i)) {
+ if (!test_int(env,sint)) {
goto error;
}
- i -= i / 3 + 1;
- } while (i >= 0);
+ sint -= sint / 3 + 1;
+ } while (sint >= 0);
- u = ULONG_MAX;
+ slong = LONG_MIN;
+ do {
+ if (!test_long(env,slong)) {
+ goto error;
+ }
+ slong += ~slong / 3 + 1;
+ } while (slong < 0);
+ slong = LONG_MAX;
+ do {
+ if (!test_long(env,slong)) {
+ goto error;
+ }
+ slong -= slong / 3 + 1;
+ } while (slong >= 0);
+
+
+ uint = UINT_MAX;
for (;;) {
- if (!test_ulong(env,u)) {
+ if (!test_uint(env,uint)) {
}
- if (u == 0) break;
- u -= u / 3 + 1;
+ if (uint == 0) break;
+ uint -= uint / 3 + 1;
+ }
+ ulong = ULONG_MAX;
+ for (;;) {
+ if (!test_ulong(env,ulong)) {
+
+ }
+ if (ulong == 0) break;
+ ulong -= ulong / 3 + 1;
}
if (MAX_SMALL < INT_MAX) { /* 32-bit */
@@ -219,11 +316,17 @@ static ERL_NIF_TERM type_test(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[
goto error;
}
}
+ for (i=-10 ; i <= 10; i++) {
+ if (!test_uint(env,MAX_SMALL+i)) {
+ goto error;
+ }
+ }
}
assert((MAX_SMALL < INT_MAX) == (MIN_SMALL > INT_MIN));
- for (u=0 ; u < 10; u++) {
- if (!test_ulong(env,MAX_SMALL+u) || !test_ulong(env,MAX_SMALL-u)) {
+ for (i=-10 ; i < 10; i++) {
+ if (!test_long(env,MAX_SMALL+i) || !test_ulong(env,MAX_SMALL+i) ||
+ !test_long(env,MIN_SMALL+i)) {
goto error;
}
}
@@ -236,12 +339,12 @@ static ERL_NIF_TERM type_test(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[
if (!enif_make_existing_atom(env,"nif_SUITE", &atom)
|| !enif_is_identical(env,atom,enif_make_atom(env,"nif_SUITE"))) {
- fprintf(stderr, "SVERK: nif_SUITE not an atom?\r\n");
+ fprintf(stderr, "nif_SUITE not an atom?\r\n");
goto error;
}
for (i=2; i; i--) {
if (enif_make_existing_atom(env,"nif_SUITE_pink_unicorn", &atom)) {
- fprintf(stderr, "SVERK: pink unicorn exist?\r\n");
+ fprintf(stderr, "pink unicorn exist?\r\n");
goto error;
}
}
@@ -249,7 +352,8 @@ static ERL_NIF_TERM type_test(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[
ref2 = enif_make_ref(env);
if (!enif_is_ref(env,ref1) || !enif_is_ref(env,ref2)
|| enif_is_identical(env,ref1,ref2) || enif_compare(env,ref1,ref2)==0) {
- fprintf(stderr, "SVERK: strange refs?\r\n");
+ fprintf(stderr, "strange refs?\r\n");
+ goto error;
}
return enif_make_atom(env,"ok");
@@ -260,7 +364,7 @@ error:
static ERL_NIF_TERM tuple_2_list(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{
int arity = -1;
- ERL_NIF_TERM* ptr;
+ const ERL_NIF_TERM* ptr;
ERL_NIF_TERM list = enif_make_list(env,0);
if (argc!=1 || !enif_get_tuple(env,argv[0],&arity,&ptr)) {
@@ -304,6 +408,213 @@ badarg:
return enif_make_badarg(env);
}
+static ERL_NIF_TERM clone_bin(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{
+ ErlNifBinary ibin;
+ if (enif_inspect_binary(env,argv[0],&ibin)) {
+ ErlNifBinary obin;
+ enif_alloc_binary(env,ibin.size,&obin);
+ memcpy(obin.data,ibin.data,ibin.size);
+ /*enif_release_binary(env,&ibin);*/
+ return enif_make_binary(env,&obin);
+ }
+ else {
+ return enif_make_badarg(env);
+ }
+}
+
+static ERL_NIF_TERM make_sub_bin(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{
+ int pos, size;
+ if (!enif_get_int(env,argv[1],&pos) || !enif_get_int(env,argv[2],&size)) {
+ return enif_make_badarg(env);
+ }
+ return enif_make_sub_binary(env,argv[0],pos,size);
+}
+
+static ERL_NIF_TERM string_to_bin(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{
+ ErlNifBinary obin;
+ unsigned size;
+ int n;
+ if (!enif_get_int(env,argv[1],(int*)&size)
+ || !enif_alloc_binary(env,size,&obin)) {
+ return enif_make_badarg(env);
+ }
+ n = enif_get_string(env, argv[0], (char*)obin.data, size, ERL_NIF_LATIN1);
+ return enif_make_tuple(env, 2, enif_make_int(env,n),
+ enif_make_binary(env,&obin));
+}
+
+static ERL_NIF_TERM atom_to_bin(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{
+ ErlNifBinary obin;
+ unsigned size;
+ int n;
+ if (!enif_get_int(env,argv[1],(int*)&size)
+ || !enif_alloc_binary(env,size,&obin)) {
+ return enif_make_badarg(env);
+ }
+ n = enif_get_atom(env, argv[0], (char*)obin.data, size);
+ return enif_make_tuple(env, 2, enif_make_int(env,n),
+ enif_make_binary(env,&obin));
+}
+
+static ERL_NIF_TERM macros(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{
+ const ERL_NIF_TERM* a;
+ ERL_NIF_TERM lists, tuples;
+ int arity;
+ if (!enif_get_tuple(env, argv[0], &arity, &a) || arity != 9) {
+ return enif_make_badarg(env);
+ }
+
+ lists = enif_make_list(env,9,
+ enif_make_list1(env,a[0]),
+ enif_make_list2(env,a[0],a[1]),
+ enif_make_list3(env,a[0],a[1],a[2]),
+ enif_make_list4(env,a[0],a[1],a[2],a[3]),
+ enif_make_list5(env,a[0],a[1],a[2],a[3],a[4]),
+ enif_make_list6(env,a[0],a[1],a[2],a[3],a[4],a[5]),
+ enif_make_list7(env,a[0],a[1],a[2],a[3],a[4],a[5],a[6]),
+ enif_make_list8(env,a[0],a[1],a[2],a[3],a[4],a[5],a[6],a[7]),
+ enif_make_list9(env,a[0],a[1],a[2],a[3],a[4],a[5],a[6],a[7],a[8]));
+ tuples = enif_make_list(env,9,
+ enif_make_tuple1(env,a[0]),
+ enif_make_tuple2(env,a[0],a[1]),
+ enif_make_tuple3(env,a[0],a[1],a[2]),
+ enif_make_tuple4(env,a[0],a[1],a[2],a[3]),
+ enif_make_tuple5(env,a[0],a[1],a[2],a[3],a[4]),
+ enif_make_tuple6(env,a[0],a[1],a[2],a[3],a[4],a[5]),
+ enif_make_tuple7(env,a[0],a[1],a[2],a[3],a[4],a[5],a[6]),
+ enif_make_tuple8(env,a[0],a[1],a[2],a[3],a[4],a[5],a[6],a[7]),
+ enif_make_tuple9(env,a[0],a[1],a[2],a[3],a[4],a[5],a[6],a[7],a[8]));
+ return enif_make_tuple2(env,lists,tuples);
+}
+
+static ERL_NIF_TERM tuple_2_list_and_tuple(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{
+ const ERL_NIF_TERM* arr;
+ int arity;
+ if (!enif_get_tuple(env,argv[0],&arity,&arr)) {
+ return enif_make_badarg(env);
+ }
+ return enif_make_tuple2(env,
+ enif_make_list_from_array(env, arr, arity),
+ enif_make_tuple_from_array(env, arr, arity));
+}
+
+static ERL_NIF_TERM iolist_2_bin(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{
+ ErlNifBinary obin;
+ if (!enif_inspect_iolist_as_binary(env, argv[0], &obin)) {
+ return enif_make_badarg(env);
+ }
+ return enif_make_binary(env,&obin);
+}
+
+static ERL_NIF_TERM last_resource_dtor_call(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{
+ ErlNifBinary bin;
+ ERL_NIF_TERM ret;
+ if (resource_dtor_last != NULL) {
+ enif_alloc_binary(env, resource_dtor_last_sz, &bin);
+ memcpy(bin.data, resource_dtor_last_data, resource_dtor_last_sz);
+ ret = enif_make_tuple3(env,
+ enif_make_long(env, (long)resource_dtor_last),
+ enif_make_binary(env, &bin),
+ enif_make_int(env, resource_dtor_cnt));
+ }
+ else {
+ ret = enif_make_list(env,0);
+ }
+ resource_dtor_last = NULL;
+ resource_dtor_last_sz = 0;
+ resource_dtor_cnt = 0;
+ return ret;
+}
+
+static ERL_NIF_TERM get_resource_type(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{
+ PrivData* data = (PrivData*) enif_get_data(env);
+ int ix;
+
+ if (!enif_get_int(env, argv[0], &ix) || ix >= 2) {
+ return enif_make_badarg(env);
+ }
+ return enif_make_long(env, data->rt_arr[ix].l);
+}
+
+static ERL_NIF_TERM alloc_resource(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{
+ ErlNifBinary data_bin;
+ union { ErlNifResourceType* t; long l;} type;
+ union { void* p; long l;} data;
+ if (!enif_get_long(env, argv[0], &type.l)
+ || !enif_inspect_binary(env, argv[1], &data_bin)
+ || (data.p = enif_alloc_resource(env, type.t, data_bin.size))==NULL) {
+
+ return enif_make_badarg(env);
+ }
+ memcpy(data.p, data_bin.data, data_bin.size);
+ return enif_make_long(env, data.l);
+}
+
+static ERL_NIF_TERM make_resource(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{
+ union { void* p; long l; } data;
+ if (!enif_get_long(env, argv[0], &data.l)) {
+ return enif_make_badarg(env);
+ }
+ return enif_make_resource(env, data.p);
+}
+
+static ERL_NIF_TERM make_new_resource(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{
+ ErlNifBinary data_bin;
+ union { ErlNifResourceType* t; long l;} type;
+ void* data;
+ ERL_NIF_TERM ret;
+ if (!enif_get_long(env, argv[0], &type.l)
+ || !enif_inspect_binary(env, argv[1], &data_bin)
+ || (data = enif_alloc_resource(env, type.t, data_bin.size))==NULL) {
+
+ return enif_make_badarg(env);
+ }
+ ret = enif_make_resource(env, data);
+ memcpy(data, data_bin.data, data_bin.size);
+ enif_release_resource(env, data);
+ return ret;
+}
+
+static ERL_NIF_TERM get_resource(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{
+ ErlNifBinary data_bin;
+ union { ErlNifResourceType* t; long l; } type;
+ union { void* p; long l; } data;
+
+ if (!enif_get_long(env, argv[0], &type.l)
+ || !enif_get_resource(env, argv[1], type.t, &data.p)) {
+ return enif_make_badarg(env);
+ }
+
+ enif_alloc_binary(env, enif_sizeof_resource(env,data.p), &data_bin);
+ memcpy(data_bin.data, data.p, data_bin.size);
+ return enif_make_tuple2(env, enif_make_long(env,data.l),
+ enif_make_binary(env, &data_bin));
+}
+
+static ERL_NIF_TERM release_resource(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{
+ union { void* p; long l; } data;
+ if (!enif_get_long(env, argv[0], &data.l)) {
+ return enif_make_badarg(env);
+ }
+ enif_release_resource(env, data.p);
+ return enif_make_atom(env,"ok");
+}
+
+
static ErlNifFunc nif_funcs[] =
{
{"lib_version", 0, lib_version},
@@ -315,7 +626,22 @@ static ErlNifFunc nif_funcs[] =
{"tuple_2_list", 1, tuple_2_list},
{"is_identical",2,is_identical},
{"compare",2,compare},
- {"many_args_100", 100, many_args_100}
+ {"many_args_100", 100, many_args_100},
+ {"clone_bin", 1, clone_bin},
+ {"make_sub_bin", 3, make_sub_bin},
+ {"string_to_bin", 2, string_to_bin},
+ {"atom_to_bin", 2, atom_to_bin},
+ {"macros", 1, macros},
+ {"tuple_2_list_and_tuple",1,tuple_2_list_and_tuple},
+ {"iolist_2_bin", 1, iolist_2_bin},
+ {"get_resource_type", 1, get_resource_type},
+ {"alloc_resource", 2, alloc_resource},
+ {"make_resource", 1, make_resource},
+ {"get_resource", 2, get_resource},
+ {"release_resource", 1, release_resource},
+ {"last_resource_dtor_call", 0, last_resource_dtor_call},
+ {"make_new_resource", 2, make_new_resource}
+
};
ERL_NIF_INIT(nif_SUITE,nif_funcs,load,reload,upgrade,unload)
diff --git a/erts/emulator/test/nif_SUITE_data/nif_mod.c b/erts/emulator/test/nif_SUITE_data/nif_mod.c
index 2f2267cf78..c075b74c57 100644
--- a/erts/emulator/test/nif_SUITE_data/nif_mod.c
+++ b/erts/emulator/test/nif_SUITE_data/nif_mod.c
@@ -1,51 +1,182 @@
#include "erl_nif.h"
#include <string.h>
-#include <assert.h>
+#include <stdio.h>
#include "nif_mod.h"
+#define CHECK(X) ((void)((X) || (check_abort(__LINE__),1)))
+#ifdef __GNUC__
+static void check_abort(unsigned line) __attribute__((noreturn));
+#endif
+static void check_abort(unsigned line)
+{
+ enif_fprintf(stderr, "Test CHECK failed at %s:%u\r\n",
+ __FILE__, line);
+ abort();
+}
static int static_cntA; /* zero by default */
static int static_cntB = NIF_LIB_VER * 100;
-static void add_call(ErlNifEnv* env, NifModPrivData* data, const char* func_name)
+static ERL_NIF_TERM am_true;
+static ERL_NIF_TERM am_null;
+static ERL_NIF_TERM am_resource_type;
+static ERL_NIF_TERM am_resource_dtor_A;
+static ERL_NIF_TERM am_resource_dtor_B;
+
+static void init(ErlNifEnv* env)
+{
+ am_true = enif_make_atom(env, "true");
+ am_null = enif_make_atom(env, "null");
+ am_resource_type = enif_make_atom(env, "resource_type");
+ am_resource_dtor_A = enif_make_atom(env, "resource_dtor_A");
+ am_resource_dtor_B = enif_make_atom(env, "resource_dtor_B");
+}
+
+static void add_call_with_arg(ErlNifEnv* env, NifModPrivData* data, const char* func_name,
+ const char* arg, int arg_sz)
{
- CallInfo* call = enif_alloc(env, sizeof(CallInfo)+strlen(func_name));
+ CallInfo* call = enif_alloc(env, sizeof(CallInfo)+strlen(func_name) + arg_sz);
strcpy(call->func_name, func_name);
call->lib_ver = NIF_LIB_VER;
call->static_cntA = ++static_cntA;
call->static_cntB = ++static_cntB;
+ call->arg_sz = arg_sz;
+ if (arg != NULL) {
+ call->arg = call->func_name + strlen(func_name) + 1;
+ memcpy(call->arg, arg, arg_sz);
+ }
+ else {
+ call->arg = NULL;
+ }
+ enif_mutex_lock(data->mtx);
call->next = data->call_history;
data->call_history = call;
+ enif_mutex_unlock(data->mtx);
+}
+
+static void add_call(ErlNifEnv* env, NifModPrivData* data,const char* func_name)
+{
+ add_call_with_arg(env, data, func_name, NULL, 0);
+}
+
+#define ADD_CALL(FUNC_NAME) add_call(env, enif_priv_data(env),FUNC_NAME)
+
+#define STRINGIFY_(X) #X
+#define STRINGIFY(X) STRINGIFY_(X)
+
+static void resource_dtor_A(ErlNifEnv* env, void* a)
+{
+ const char dtor_name[] = "resource_dtor_A_v" STRINGIFY(NIF_LIB_VER);
+
+ add_call_with_arg(env, enif_priv_data(env), dtor_name,
+ a, enif_sizeof_resource(env, a));
+}
+
+static void resource_dtor_B(ErlNifEnv* env, void* a)
+{
+ const char dtor_name[] = "resource_dtor_B_v" STRINGIFY(NIF_LIB_VER);
+
+ add_call_with_arg(env, enif_priv_data(env), dtor_name,
+ a, enif_sizeof_resource(env, a));
+}
+
+/* {resource_type, Ix|null, ErlNifResourceFlags in, "TypeName", dtor(A|B|null), ErlNifResourceFlags out}*/
+static void open_resource_type(ErlNifEnv* env, ERL_NIF_TERM op_tpl)
+{
+ NifModPrivData* data = enif_priv_data(env);
+ const ERL_NIF_TERM* arr;
+ int arity;
+ char rt_name[30];
+ union { enum ErlNifResourceFlags e; int i; } flags, exp_res, got_res;
+ unsigned ix;
+ ErlNifResourceDtor* dtor;
+ ErlNifResourceType* got_ptr;
+
+ CHECK(enif_get_tuple(env, op_tpl, &arity, &arr));
+ CHECK(arity == 6);
+ CHECK(enif_is_identical(env, arr[0], am_resource_type));
+ CHECK(enif_get_int(env, arr[2], &flags.i));
+ CHECK(enif_get_string(env, arr[3], rt_name, sizeof(rt_name), ERL_NIF_LATIN1) > 0);
+ CHECK(enif_get_int(env, arr[5], &exp_res.i));
+
+ if (enif_is_identical(env, arr[4], am_null)) {
+ dtor = NULL;
+ }
+ else if (enif_is_identical(env, arr[4], am_resource_dtor_A)) {
+ dtor = resource_dtor_A;
+ }
+ else {
+ CHECK(enif_is_identical(env, arr[4], am_resource_dtor_B));
+ dtor = resource_dtor_B;
+ }
+
+ got_ptr = enif_open_resource_type(env, rt_name, dtor,
+ flags.e, &got_res.e);
+
+ if (enif_get_uint(env, arr[1], &ix) && ix < RT_MAX && got_ptr != NULL) {
+ data->rt_arr[ix] = got_ptr;
+ }
+ else {
+ CHECK(enif_is_identical(env, arr[1], am_null));
+ CHECK(got_ptr == NULL);
+ }
+ CHECK(got_res.e == exp_res.e);
}
-#define ADD_CALL(FUNC_NAME) add_call(env, enif_get_data(env),FUNC_NAME)
+static void do_load_info(ErlNifEnv* env, ERL_NIF_TERM load_info)
+{
+ NifModPrivData* data = enif_priv_data(env);
+ ERL_NIF_TERM head, tail;
+ unsigned ix;
+ for (ix=0; ix<RT_MAX; ix++) {
+ data->rt_arr[ix] = NULL;
+ }
+ for (head = load_info; enif_get_list_cell(env, head, &head, &tail);
+ head = tail) {
+
+ open_resource_type(env, head);
+ }
+ CHECK(enif_is_empty_list(env, head));
+}
static int load(ErlNifEnv* env, void** priv_data, ERL_NIF_TERM load_info)
{
- NifModPrivData* data = enif_alloc(env, sizeof(NifModPrivData));
- assert(data != NULL);
+ NifModPrivData* data;
+
+ init(env);
+ data = enif_alloc(env, sizeof(NifModPrivData));
+ CHECK(data != NULL);
+ *priv_data = data;
+ data->mtx = enif_mutex_create("nif_mod_priv_data");
data->ref_cnt = 1;
data->call_history = NULL;
add_call(env, data, "load");
- data->calls = 0;
- *priv_data = data;
+ do_load_info(env, load_info);
+ data->calls = 0;
return 0;
}
static int reload(ErlNifEnv* env, void** priv_data, ERL_NIF_TERM load_info)
{
+ init(env);
add_call(env, *priv_data, "reload");
+
+ do_load_info(env, load_info);
return 0;
}
static int upgrade(ErlNifEnv* env, void** priv_data, void** old_priv_data, ERL_NIF_TERM load_info)
{
NifModPrivData* data = *old_priv_data;
+ init(env);
add_call(env, data, "upgrade");
data->ref_cnt++;
+
*priv_data = *old_priv_data;
+ do_load_info(env, load_info);
+
return 0;
}
@@ -53,9 +184,13 @@ static void unload(ErlNifEnv* env, void* priv_data)
{
NifModPrivData* data = priv_data;
add_call(env, data, "unload");
+ enif_mutex_lock(data->mtx);
if (--data->ref_cnt == 0) {
+ enif_mutex_unlock(data->mtx);
+ enif_mutex_destroy(data->mtx);
enif_free(env, data);
}
+ enif_mutex_unlock(data->mtx);
}
static ERL_NIF_TERM lib_version(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
@@ -64,35 +199,51 @@ static ERL_NIF_TERM lib_version(ErlNifEnv* env, int argc, const ERL_NIF_TERM arg
return enif_make_int(env, NIF_LIB_VER);
}
-static ERL_NIF_TERM call_history(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+static ERL_NIF_TERM get_priv_data_ptr(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{
- NifModPrivData* data = (NifModPrivData*) enif_get_data(env);
- ERL_NIF_TERM list = enif_make_list(env, 0); /* NIL */
+ ADD_CALL("get_priv_data_ptr");
+ return enif_make_ulong(env, (unsigned long)enif_priv_data(env));
+}
- while (data->call_history != NULL) {
- CallInfo* call = data->call_history;
- ERL_NIF_TERM tpl = enif_make_tuple(env, 2,
- enif_make_atom(env,call->func_name),
- enif_make_int(env,call->lib_ver));
- list = enif_make_list_cell(env, tpl, list);
- data->call_history = call->next;
- enif_free(env,call);
+static ERL_NIF_TERM make_new_resource(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{
+ NifModPrivData* data = (NifModPrivData*) enif_priv_data(env);
+ ErlNifBinary ibin;
+ char* a;
+ ERL_NIF_TERM ret;
+ unsigned ix;
+ if (!enif_get_uint(env, argv[0], &ix) || ix >= RT_MAX
+ || !enif_inspect_binary(env, argv[1], &ibin)) {
+ return enif_make_badarg(env);
}
- return list;
+ a = enif_alloc_resource(env, data->rt_arr[ix], ibin.size);
+ memcpy(a, ibin.data, ibin.size);
+ ret = enif_make_resource(env, a);
+ enif_release_resource(env, a);
+ return ret;
}
-static ERL_NIF_TERM get_priv_data_ptr(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+static ERL_NIF_TERM get_resource(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{
- ADD_CALL("get_priv_data_ptr");
- return enif_make_ulong(env, (unsigned long)enif_get_data(env));
+ NifModPrivData* data = (NifModPrivData*) enif_priv_data(env);
+ ErlNifBinary obin;
+ unsigned ix;
+ void* a;
+ if (!enif_get_uint(env, argv[0], &ix) || ix >= RT_MAX
+ || !enif_get_resource(env, argv[1], data->rt_arr[ix], &a)
+ || !enif_alloc_binary(env, enif_sizeof_resource(env, a), &obin)) {
+ return enif_make_badarg(env);
+ }
+ memcpy(obin.data, a, obin.size);
+ return enif_make_binary(env, &obin);
}
-
static ErlNifFunc nif_funcs[] =
{
{"lib_version", 0, lib_version},
- {"call_history", 0, call_history},
- {"get_priv_data_ptr", 0, get_priv_data_ptr}
+ {"get_priv_data_ptr", 0, get_priv_data_ptr},
+ {"make_new_resource", 2, make_new_resource},
+ {"get_resource", 2, get_resource}
};
#if NIF_LIB_VER != 3
diff --git a/erts/emulator/test/nif_SUITE_data/nif_mod.erl b/erts/emulator/test/nif_SUITE_data/nif_mod.erl
index 93da6590a0..7888a589e7 100644
--- a/erts/emulator/test/nif_SUITE_data/nif_mod.erl
+++ b/erts/emulator/test/nif_SUITE_data/nif_mod.erl
@@ -21,15 +21,19 @@
-include("test_server.hrl").
--export([load_nif_lib/2, start/0, lib_version/0, call_history/0, get_priv_data_ptr/0]).
+-export([load_nif_lib/2, load_nif_lib/3, start/0, lib_version/0, call_history/0,
+ get_priv_data_ptr/0, make_new_resource/2, get_resource/2]).
-export([loop/0, upgrade/1]).
-define(nif_stub,nif_stub_error(?LINE)).
load_nif_lib(Config, Ver) ->
+ load_nif_lib(Config, Ver, []).
+
+load_nif_lib(Config, Ver, LoadInfo) ->
?line Path = ?config(data_dir, Config),
- erlang:load_nif(filename:join(Path,libname(Ver)), 0).
+ erlang:load_nif(filename:join(Path,libname(Ver)), LoadInfo).
libname(no_init) -> libname(3);
libname(Ver) when is_integer(Ver) ->
@@ -59,6 +63,8 @@ lib_version() -> % NIF
call_history() -> ?nif_stub.
get_priv_data_ptr() -> ?nif_stub.
+make_new_resource(_,_) -> ?nif_stub.
+get_resource(_,_) -> ?nif_stub.
nif_stub_error(Line) ->
exit({nif_not_loaded,module,?MODULE,line,Line}).
diff --git a/erts/emulator/test/nif_SUITE_data/nif_mod.h b/erts/emulator/test/nif_SUITE_data/nif_mod.h
index 2dfdc75176..0eaf91d6e1 100644
--- a/erts/emulator/test/nif_SUITE_data/nif_mod.h
+++ b/erts/emulator/test/nif_SUITE_data/nif_mod.h
@@ -4,14 +4,19 @@ typedef struct call_info_t
unsigned lib_ver;
int static_cntA;
int static_cntB;
+ char* arg;
+ int arg_sz;
char func_name[1]; /* must be last */
}CallInfo;
+#define RT_MAX 5
typedef struct
{
+ ErlNifMutex* mtx;
int calls;
int ref_cnt;
CallInfo* call_history;
+ ErlNifResourceType* rt_arr[RT_MAX];
}NifModPrivData;
diff --git a/erts/emulator/test/nif_SUITE_data/tail.txt b/erts/emulator/test/nif_SUITE_data/tail.txt
new file mode 100644
index 0000000000..7f06c118c1
--- /dev/null
+++ b/erts/emulator/test/nif_SUITE_data/tail.txt
@@ -0,0 +1,5 @@
+
+
+#include "tester.c" /* poor mans linker */
+
+
diff --git a/erts/emulator/test/nif_SUITE_data/testcase_driver.h b/erts/emulator/test/nif_SUITE_data/testcase_driver.h
new file mode 100644
index 0000000000..98339e4746
--- /dev/null
+++ b/erts/emulator/test/nif_SUITE_data/testcase_driver.h
@@ -0,0 +1,59 @@
+/* ``The contents of this file are subject to the Erlang Public License,
+ * Version 1.1, (the "License"); you may not use this file except in
+ * compliance with the License. You should have received a copy of the
+ * Erlang Public License along with this software. If not, it can be
+ * retrieved via the world wide web at http://www.erlang.org/.
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * The Initial Developer of the Original Code is Ericsson Utvecklings AB.
+ * Portions created by Ericsson are Copyright 1999, Ericsson Utvecklings
+ * AB. All Rights Reserved.''
+ *
+ * $Id$
+ */
+
+#ifndef TESTCASE_DRIVER_H__
+#define TESTCASE_DRIVER_H__
+
+#include "erl_nif.h"
+#include <stdlib.h>
+#include <stdio.h>
+
+typedef struct {
+ char *testcase_name;
+ char *command;
+ int command_len;
+ void *extra;
+} TestCaseState_t;
+
+#define ASSERT_CLNUP(TCS, B, CLN) \
+do { \
+ if (!(B)) { \
+ CLN; \
+ testcase_assertion_failed((TCS), __FILE__, __LINE__, #B); \
+ } \
+} while (0)
+
+#define ASSERT(TCS, B) ASSERT_CLNUP(TCS, B, (void) 0)
+
+
+void testcase_printf(TestCaseState_t *tcs, char *frmt, ...);
+void testcase_succeeded(TestCaseState_t *tcs, char *frmt, ...);
+void testcase_skipped(TestCaseState_t *tcs, char *frmt, ...);
+void testcase_failed(TestCaseState_t *tcs, char *frmt, ...);
+int testcase_assertion_failed(TestCaseState_t *tcs, char *file, int line,
+ char *assertion);
+void *testcase_alloc(size_t size);
+void *testcase_realloc(void *ptr, size_t size);
+void testcase_free(void *ptr);
+
+
+char *testcase_name(void);
+void testcase_run(TestCaseState_t *tcs);
+void testcase_cleanup(TestCaseState_t *tcs);
+
+#endif
diff --git a/erts/emulator/test/nif_SUITE_data/tester.c b/erts/emulator/test/nif_SUITE_data/tester.c
new file mode 100644
index 0000000000..08466d0f18
--- /dev/null
+++ b/erts/emulator/test/nif_SUITE_data/tester.c
@@ -0,0 +1,73 @@
+#include "erl_nif.h"
+
+#include <stdio.h>
+#include <stdarg.h>
+
+void testcase_printf(TestCaseState_t *tcs, char *frmt, ...)
+{
+ va_list va;
+ va_start(va, frmt);
+ vfprintf(stderr, frmt, va);
+ va_end(va);
+ fprintf(stderr, "\r");
+}
+
+void testcase_succeeded(TestCaseState_t *tcs, char *frmt, ...)
+{
+}
+
+void testcase_skipped(TestCaseState_t *tcs, char *frmt, ...)
+{
+}
+
+void testcase_failed(TestCaseState_t *tcs, char *frmt, ...)
+{
+ va_list va;
+ va_start(va, frmt);
+ vfprintf(stderr, frmt, va);
+ va_end(va);
+ abort();
+}
+
+int testcase_assertion_failed(TestCaseState_t *tcs, char *file, int line,
+ char *assertion)
+{
+ testcase_failed(tcs, "ASSERTION '%s' FAILED at %s:%d\r\n",
+ assertion, file, line);
+ abort();
+ return 0; /*?*/
+}
+
+void *testcase_alloc(size_t size)
+{
+ return malloc(size);
+}
+void *testcase_realloc(void *ptr, size_t size)
+{
+ return realloc(ptr, size);
+}
+void testcase_free(void *ptr)
+{
+ free(ptr);
+}
+
+void testcase_run(TestCaseState_t *tcs);
+
+static int reload(ErlNifEnv* env, void** priv_data, ERL_NIF_TERM load_info)
+{
+ return 0;
+}
+
+static ERL_NIF_TERM run(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{
+ testcase_run(NULL);
+ return enif_make_atom(env, "ok");
+}
+
+static ErlNifFunc nif_funcs[] =
+{
+ {"run", 0, run}
+};
+
+ERL_NIF_INIT(tester,nif_funcs,NULL,reload,NULL,NULL)
+
diff --git a/erts/emulator/test/nif_SUITE_data/tester.erl b/erts/emulator/test/nif_SUITE_data/tester.erl
new file mode 100644
index 0000000000..9df2158200
--- /dev/null
+++ b/erts/emulator/test/nif_SUITE_data/tester.erl
@@ -0,0 +1,13 @@
+-module(tester).
+
+-include("test_server.hrl").
+
+-export([load_nif_lib/2, run/0]).
+
+
+load_nif_lib(Config, LibName) ->
+ ?line Path = ?config(data_dir, Config),
+ erlang:load_nif(filename:join(Path,LibName), []).
+
+run() ->
+ exit({nif_not_loaded,?MODULE,?LINE}).