Skip to content

Commit 28cd2d1

Browse files
sverkerErlang/OTP
authored and
Erlang/OTP
committed
OTP-8335 NIF improvements:
Driver API for multi-threading made available for NIFs. Support for mempory managed (garbage collected) resource objects. A way to pass "pointers" to native data structures between C and Erlang in a safe way. Support for references, floats and term comparison. Various new functions, like enif_inspect_iolist_as_binary, enif_make_sub_binary, enif_get_string, enif_get_atom, enif_make_tuple_from_array, enif_make_list_from_array, enif_make_existing_atom.
1 parent 64d4c5a commit 28cd2d1

File tree

2 files changed

+254
-0
lines changed

2 files changed

+254
-0
lines changed

erts/example/matrix_nif.c

+210
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,210 @@
1+
/*
2+
* %CopyrightBegin%
3+
*
4+
* Copyright Ericsson AB 2010. All Rights Reserved.
5+
*
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/.
11+
*
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
15+
* under the License.
16+
*
17+
* %CopyrightEnd%
18+
*/
19+
/*
20+
* Purpose: Simple example of NIFs using resource objects to implement functions
21+
* for matrix calculations.
22+
*/
23+
24+
#include "erl_nif.h"
25+
26+
#include <stddef.h>
27+
#include <assert.h>
28+
29+
typedef struct
30+
{
31+
unsigned nrows;
32+
unsigned ncols;
33+
double* data;
34+
}Matrix;
35+
36+
#define POS(MX, ROW, COL) ((MX)->data[(ROW)* (MX)->ncols + (COL)])
37+
38+
static int get_number(ErlNifEnv* env, ERL_NIF_TERM term, double* dp);
39+
static Matrix* alloc_matrix(ErlNifEnv* env, unsigned nrows, unsigned ncols);
40+
static void matrix_dtor(ErlNifEnv* env, void* obj);
41+
42+
43+
static ErlNifResourceType* resource_type = NULL;
44+
45+
static int load(ErlNifEnv* env, void** priv_data, ERL_NIF_TERM load_info)
46+
{
47+
ErlNifResourceType* rt = enif_open_resource_type(env, "matrix_nif_example",
48+
matrix_dtor,
49+
ERL_NIF_RT_CREATE, NULL);
50+
if (rt == NULL) {
51+
return -1;
52+
}
53+
assert(resource_type == NULL);
54+
resource_type = rt;
55+
return 0;
56+
}
57+
58+
static ERL_NIF_TERM create(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
59+
{
60+
/* create(Nrows, Ncolumns, [[first row],[second row],...,[last row]]) -> Matrix */
61+
unsigned nrows, ncols;
62+
unsigned i, j;
63+
ERL_NIF_TERM list, row, ret;
64+
Matrix* mx = NULL;
65+
66+
if (!enif_get_uint(env, argv[0], &nrows) || nrows < 1 ||
67+
!enif_get_uint(env, argv[1], &ncols) || ncols < 1) {
68+
69+
goto badarg;
70+
}
71+
mx = alloc_matrix(env, nrows, ncols);
72+
list = argv[2];
73+
for (i = 0; i<nrows; i++) {
74+
if (!enif_get_list_cell(env, list, &row, &list)) {
75+
goto badarg;
76+
}
77+
for (j = 0; j<ncols; j++) {
78+
ERL_NIF_TERM v;
79+
if (!enif_get_list_cell(env, row, &v, &row) ||
80+
!get_number(env, v, &POS(mx,i,j))) {
81+
goto badarg;
82+
}
83+
}
84+
if (!enif_is_empty_list(env, row)) {
85+
goto badarg;
86+
}
87+
}
88+
if (!enif_is_empty_list(env, list)) {
89+
goto badarg;
90+
}
91+
92+
ret = enif_make_resource(env, mx);
93+
enif_release_resource(env, mx);
94+
return ret;
95+
96+
badarg:
97+
if (mx != NULL) {
98+
enif_release_resource(env,mx);
99+
}
100+
return enif_make_badarg(env);
101+
}
102+
103+
104+
static ERL_NIF_TERM pos(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
105+
{
106+
/* pos(Matrix, Row, Column) -> float() */
107+
Matrix* mx;
108+
unsigned i, j;
109+
if (!enif_get_resource(env, argv[0], resource_type, (void**)&mx) ||
110+
!enif_get_uint(env, argv[1], &i) || (--i >= mx->nrows) ||
111+
!enif_get_uint(env, argv[2], &j) || (--j >= mx->ncols)) {
112+
return enif_make_badarg(env);
113+
}
114+
return enif_make_double(env, POS(mx, i,j));
115+
}
116+
117+
static ERL_NIF_TERM add(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
118+
{
119+
/* add(Matrix_A, Matrix_B) -> Matrix_Sum */
120+
unsigned i, j;
121+
ERL_NIF_TERM ret;
122+
Matrix* mxA = NULL;
123+
Matrix* mxB = NULL;
124+
Matrix* mxS = NULL;
125+
126+
if (!enif_get_resource(env, argv[0], resource_type, (void**)&mxA) ||
127+
!enif_get_resource(env, argv[1], resource_type, (void**)&mxB) ||
128+
mxA->nrows != mxB->nrows ||
129+
mxB->ncols != mxB->ncols) {
130+
131+
return enif_make_badarg(env);
132+
}
133+
mxS = alloc_matrix(env, mxA->nrows, mxA->ncols);
134+
for (i = 0; i < mxA->nrows; i++) {
135+
for (j = 0; j < mxA->ncols; j++) {
136+
POS(mxS, i, j) = POS(mxA, i, j) + POS(mxB, i, j);
137+
}
138+
}
139+
ret = enif_make_resource(env, mxS);
140+
enif_release_resource(env, mxS);
141+
return ret;
142+
}
143+
144+
static ERL_NIF_TERM size_of(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
145+
{
146+
/* size(Matrix) -> {Nrows, Ncols} */
147+
Matrix* mx;
148+
if (!enif_get_resource(env, argv[0], resource_type, (void**)&mx)) {
149+
return enif_make_badarg(env);
150+
}
151+
return enif_make_tuple2(env, enif_make_uint(env, mx->nrows),
152+
enif_make_uint(env, mx->ncols));
153+
}
154+
155+
static ERL_NIF_TERM to_term(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
156+
{
157+
/* to_term(Matrix) -> [[first row], [second row], ...,[last row]] */
158+
unsigned i, j;
159+
ERL_NIF_TERM res;
160+
Matrix* mx = NULL;
161+
162+
if (!enif_get_resource(env, argv[0], resource_type, (void**)&mx)) {
163+
return enif_make_badarg(env);
164+
}
165+
res = enif_make_list(env, 0);
166+
for (i = mx->nrows; i-- > 0; ) {
167+
ERL_NIF_TERM row = enif_make_list(env, 0);
168+
for (j = mx->ncols; j-- > 0; ) {
169+
row = enif_make_list_cell(env, enif_make_double(env, POS(mx,i,j)),
170+
row);
171+
}
172+
res = enif_make_list_cell(env, row, res);
173+
}
174+
return res;
175+
}
176+
177+
static int get_number(ErlNifEnv* env, ERL_NIF_TERM term, double* dp)
178+
{
179+
long i;
180+
return enif_get_double(env, term, dp) ||
181+
(enif_get_long(env, term, &i) && (*dp=(double)i, 1));
182+
}
183+
184+
static Matrix* alloc_matrix(ErlNifEnv* env, unsigned nrows, unsigned ncols)
185+
{
186+
Matrix* mx = enif_alloc_resource(env, resource_type, sizeof(Matrix));
187+
mx->nrows = nrows;
188+
mx->ncols = ncols;
189+
mx->data = enif_alloc(env, nrows*ncols*sizeof(double));
190+
return mx;
191+
}
192+
193+
static void matrix_dtor(ErlNifEnv* env, void* obj)
194+
{
195+
Matrix* mx = (Matrix*) obj;
196+
enif_free(env, mx->data);
197+
mx->data = NULL;
198+
}
199+
200+
static ErlNifFunc nif_funcs[] =
201+
{
202+
{"create", 3, create},
203+
{"pos", 3, pos},
204+
{"add", 2, add},
205+
{"size_of", 1, size_of},
206+
{"to_term", 1, to_term}
207+
};
208+
209+
ERL_NIF_INIT(matrix_nif,nif_funcs,load,NULL,NULL,NULL);
210+

erts/example/matrix_nif.erl

+44
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
%%
2+
%% %CopyrightBegin%
3+
%%
4+
%% Copyright Ericsson AB 2010. All Rights Reserved.
5+
%%
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/.
11+
%%
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
15+
%% under the License.
16+
%%
17+
%% %CopyrightEnd%
18+
%%
19+
20+
%%
21+
%% Purpose: Simple example of NIFs using resource objects to implement functions
22+
%% for matrix calculations.
23+
24+
-module(matrix_nif).
25+
26+
-export([create/3, pos/3, add/2, size_of/1, to_term/1]).
27+
28+
-define(nif, nif_error(?LINE)).
29+
30+
-on_load(on_load/0).
31+
32+
on_load() ->
33+
erlang:load_nif("./matrix_nif", 0).
34+
35+
%% NIFs
36+
create(_Rows, _Cols, _RowList) -> ?nif.
37+
pos(_Mx, _Row, _Col) -> ?nif.
38+
add(_MxA, _MxB) -> ?nif.
39+
size_of(_Mx) -> ?nif.
40+
to_term(_Mx) -> ?nif.
41+
42+
nif_error(Line) ->
43+
erlang:error({"NIF not implemented in matrix_nif at line", Line}).
44+

0 commit comments

Comments
 (0)