4
* Copyright Ericsson AB 2009-2010. All Rights Reserved.
6
* The contents of this file are subject to the Erlang Public License,
7
* Version 1.1, (the "License"); you may not use this file except in
8
* compliance with the License. You should have received a copy of the
9
* Erlang Public License along with this software. If not, it can be
10
* retrieved online at http://www.erlang.org/.
12
* Software distributed under the License is distributed on an "AS IS"
13
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
14
* the License for the specific language governing rights and limitations
1
19
#include "erl_nif.h"
5
23
#include "nif_mod.h"
25
#define CHECK(X) ((void)((X) || (check_abort(__LINE__),1)))
27
static void check_abort(unsigned line) __attribute__((noreturn));
29
static void check_abort(unsigned line)
31
enif_fprintf(stderr, "Test CHECK failed at %s:%u\r\n",
8
36
static int static_cntA; /* zero by default */
9
37
static int static_cntB = NIF_LIB_VER * 100;
11
static void add_call(ErlNifEnv* env, NifModPrivData* data, const char* func_name)
13
CallInfo* call = enif_alloc(env, sizeof(CallInfo)+strlen(func_name));
39
static ERL_NIF_TERM am_true;
40
static ERL_NIF_TERM am_null;
41
static ERL_NIF_TERM am_resource_type;
42
static ERL_NIF_TERM am_resource_dtor_A;
43
static ERL_NIF_TERM am_resource_dtor_B;
45
static NifModPrivData* priv_data(ErlNifEnv* env)
47
return (NifModPrivData*) enif_priv_data(env);
50
static void init(ErlNifEnv* env)
52
am_true = enif_make_atom(env, "true");
53
am_null = enif_make_atom(env, "null");
54
am_resource_type = enif_make_atom(env, "resource_type");
55
am_resource_dtor_A = enif_make_atom(env, "resource_dtor_A");
56
am_resource_dtor_B = enif_make_atom(env, "resource_dtor_B");
59
static void add_call_with_arg(ErlNifEnv* env, NifModPrivData* data, const char* func_name,
60
const char* arg, int arg_sz)
62
CallInfo* call = (CallInfo*)enif_alloc(sizeof(CallInfo)+strlen(func_name) + arg_sz);
14
63
strcpy(call->func_name, func_name);
15
64
call->lib_ver = NIF_LIB_VER;
16
65
call->static_cntA = ++static_cntA;
17
66
call->static_cntB = ++static_cntB;
67
call->arg_sz = arg_sz;
69
call->arg = call->func_name + strlen(func_name) + 1;
70
memcpy(call->arg, arg, arg_sz);
75
enif_mutex_lock(data->mtx);
18
76
call->next = data->call_history;
19
77
data->call_history = call;
22
#define ADD_CALL(FUNC_NAME) add_call(env, enif_get_data(env),FUNC_NAME)
24
static int load(ErlNifEnv* env, void** priv_data, ERL_NIF_TERM load_info)
26
NifModPrivData* data = enif_alloc(env, sizeof(NifModPrivData));
78
enif_mutex_unlock(data->mtx);
81
static void add_call(ErlNifEnv* env, NifModPrivData* data,const char* func_name)
83
add_call_with_arg(env, data, func_name, NULL, 0);
86
#define ADD_CALL(FUNC_NAME) add_call(env, priv_data(env),FUNC_NAME)
88
#define STRINGIFY_(X) #X
89
#define STRINGIFY(X) STRINGIFY_(X)
91
static void resource_dtor_A(ErlNifEnv* env, void* a)
93
const char dtor_name[] = "resource_dtor_A_v" STRINGIFY(NIF_LIB_VER);
95
add_call_with_arg(env, priv_data(env), dtor_name, (const char*)a,
96
enif_sizeof_resource(a));
99
static void resource_dtor_B(ErlNifEnv* env, void* a)
101
const char dtor_name[] = "resource_dtor_B_v" STRINGIFY(NIF_LIB_VER);
103
add_call_with_arg(env, priv_data(env), dtor_name, (const char*)a,
104
enif_sizeof_resource(a));
107
/* {resource_type, Ix|null, ErlNifResourceFlags in, "TypeName", dtor(A|B|null), ErlNifResourceFlags out}*/
108
static void open_resource_type(ErlNifEnv* env, ERL_NIF_TERM op_tpl)
110
NifModPrivData* data = priv_data(env);
111
const ERL_NIF_TERM* arr;
114
union { ErlNifResourceFlags e; int i; } flags, exp_res, got_res;
116
ErlNifResourceDtor* dtor;
117
ErlNifResourceType* got_ptr;
119
CHECK(enif_get_tuple(env, op_tpl, &arity, &arr));
121
CHECK(enif_is_identical(arr[0], am_resource_type));
122
CHECK(enif_get_int(env, arr[2], &flags.i));
123
CHECK(enif_get_string(env, arr[3], rt_name, sizeof(rt_name), ERL_NIF_LATIN1) > 0);
124
CHECK(enif_get_int(env, arr[5], &exp_res.i));
126
if (enif_is_identical(arr[4], am_null)) {
129
else if (enif_is_identical(arr[4], am_resource_dtor_A)) {
130
dtor = resource_dtor_A;
133
CHECK(enif_is_identical(arr[4], am_resource_dtor_B));
134
dtor = resource_dtor_B;
137
got_ptr = enif_open_resource_type(env, NULL, rt_name, dtor,
138
flags.e, &got_res.e);
140
if (enif_get_uint(env, arr[1], &ix) && ix < RT_MAX && got_ptr != NULL) {
141
data->rt_arr[ix] = got_ptr;
144
CHECK(enif_is_identical(arr[1], am_null));
145
CHECK(got_ptr == NULL);
147
CHECK(got_res.e == exp_res.e);
150
static void do_load_info(ErlNifEnv* env, ERL_NIF_TERM load_info)
152
NifModPrivData* data = priv_data(env);
153
ERL_NIF_TERM head, tail;
155
for (ix=0; ix<RT_MAX; ix++) {
156
data->rt_arr[ix] = NULL;
158
for (head = load_info; enif_get_list_cell(env, head, &head, &tail);
161
open_resource_type(env, head);
163
CHECK(enif_is_empty_list(env, head));
166
static int load(ErlNifEnv* env, void** priv, ERL_NIF_TERM load_info)
168
NifModPrivData* data;
171
data = (NifModPrivData*) enif_alloc(sizeof(NifModPrivData));
174
data->mtx = enif_mutex_create("nif_mod_priv_data");
28
175
data->ref_cnt = 1;
29
176
data->call_history = NULL;
30
178
add_call(env, data, "load");
37
static int reload(ErlNifEnv* env, void** priv_data, ERL_NIF_TERM load_info)
39
add_call(env, *priv_data, "reload");
43
static int upgrade(ErlNifEnv* env, void** priv_data, void** old_priv_data, ERL_NIF_TERM load_info)
45
NifModPrivData* data = *old_priv_data;
180
do_load_info(env, load_info);
185
static int reload(ErlNifEnv* env, void** priv, ERL_NIF_TERM load_info)
187
NifModPrivData* data = (NifModPrivData*) *priv;
189
add_call(env, data, "reload");
191
do_load_info(env, load_info);
195
static int upgrade(ErlNifEnv* env, void** priv, void** old_priv_data, ERL_NIF_TERM load_info)
197
NifModPrivData* data = (NifModPrivData*) *old_priv_data;
46
199
add_call(env, data, "upgrade");
48
*priv_data = *old_priv_data;
202
*priv = *old_priv_data;
203
do_load_info(env, load_info);
52
static void unload(ErlNifEnv* env, void* priv_data)
208
static void unload(ErlNifEnv* env, void* priv)
54
NifModPrivData* data = priv_data;
210
NifModPrivData* data = (NifModPrivData*) priv;
55
212
add_call(env, data, "unload");
56
if (--data->ref_cnt == 0) {
213
NifModPrivData_release(data);
61
static ERL_NIF_TERM lib_version(ErlNifEnv* env)
216
static ERL_NIF_TERM lib_version(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
63
218
ADD_CALL("lib_version");
64
219
return enif_make_int(env, NIF_LIB_VER);
67
static ERL_NIF_TERM call_history(ErlNifEnv* env)
69
NifModPrivData* data = (NifModPrivData*) enif_get_data(env);
70
ERL_NIF_TERM list = enif_make_list(env, 0); /* NIL */
72
while (data->call_history != NULL) {
73
CallInfo* call = data->call_history;
74
ERL_NIF_TERM tpl = enif_make_tuple(env, 2,
75
enif_make_atom(env,call->func_name),
76
enif_make_int(env,call->lib_ver));
77
list = enif_make_list_cell(env, tpl, list);
78
data->call_history = call->next;
84
static ERL_NIF_TERM get_priv_data_ptr(ErlNifEnv* env)
222
static ERL_NIF_TERM get_priv_data_ptr(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
86
224
ADD_CALL("get_priv_data_ptr");
87
return enif_make_ulong(env, (unsigned long)enif_get_data(env));
225
return enif_make_ulong(env, (unsigned long)priv_data(env));
228
static ERL_NIF_TERM make_new_resource(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
230
NifModPrivData* data = priv_data(env);
235
if (!enif_get_uint(env, argv[0], &ix) || ix >= RT_MAX
236
|| !enif_inspect_binary(env, argv[1], &ibin)) {
237
return enif_make_badarg(env);
239
a = (char*) enif_alloc_resource(data->rt_arr[ix], ibin.size);
240
memcpy(a, ibin.data, ibin.size);
241
ret = enif_make_resource(env, a);
242
enif_release_resource(a);
246
static ERL_NIF_TERM get_resource(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
248
NifModPrivData* data = priv_data(env);
252
if (!enif_get_uint(env, argv[0], &ix) || ix >= RT_MAX
253
|| !enif_get_resource(env, argv[1], data->rt_arr[ix], &a)
254
|| !enif_alloc_binary(enif_sizeof_resource(a), &obin)) {
255
return enif_make_badarg(env);
257
memcpy(obin.data, a, obin.size);
258
return enif_make_binary(env, &obin);
91
261
static ErlNifFunc nif_funcs[] =
93
263
{"lib_version", 0, lib_version},
94
{"call_history", 0, call_history},
95
{"get_priv_data_ptr", 0, get_priv_data_ptr}
264
{"get_priv_data_ptr", 0, get_priv_data_ptr},
265
{"make_new_resource", 2, make_new_resource},
266
{"get_resource", 2, get_resource}
98
269
#if NIF_LIB_VER != 3