From 28cd2d1c3829071c817639599ff0ac00f6c4d3ed Mon Sep 17 00:00:00 2001 From: Sverker Eriksson Date: Wed, 17 Feb 2010 16:41:25 +0000 Subject: 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. --- erts/example/matrix_nif.c | 210 ++++++++++++++++++++++++++++++++++++++++++++ erts/example/matrix_nif.erl | 44 ++++++++++ 2 files changed, 254 insertions(+) create mode 100644 erts/example/matrix_nif.c create mode 100644 erts/example/matrix_nif.erl (limited to 'erts') diff --git a/erts/example/matrix_nif.c b/erts/example/matrix_nif.c new file mode 100644 index 0000000000..c5e01dade5 --- /dev/null +++ b/erts/example/matrix_nif.c @@ -0,0 +1,210 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 2010. All Rights Reserved. + * + * 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 online 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. + * + * %CopyrightEnd% + */ +/* + * Purpose: Simple example of NIFs using resource objects to implement functions + * for matrix calculations. + */ + +#include "erl_nif.h" + +#include +#include + +typedef struct +{ + unsigned nrows; + unsigned ncols; + double* data; +}Matrix; + +#define POS(MX, ROW, COL) ((MX)->data[(ROW)* (MX)->ncols + (COL)]) + +static int get_number(ErlNifEnv* env, ERL_NIF_TERM term, double* dp); +static Matrix* alloc_matrix(ErlNifEnv* env, unsigned nrows, unsigned ncols); +static void matrix_dtor(ErlNifEnv* env, void* obj); + + +static ErlNifResourceType* resource_type = NULL; + +static int load(ErlNifEnv* env, void** priv_data, ERL_NIF_TERM load_info) +{ + ErlNifResourceType* rt = enif_open_resource_type(env, "matrix_nif_example", + matrix_dtor, + ERL_NIF_RT_CREATE, NULL); + if (rt == NULL) { + return -1; + } + assert(resource_type == NULL); + resource_type = rt; + return 0; +} + +static ERL_NIF_TERM create(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) +{ + /* create(Nrows, Ncolumns, [[first row],[second row],...,[last row]]) -> Matrix */ + unsigned nrows, ncols; + unsigned i, j; + ERL_NIF_TERM list, row, ret; + Matrix* mx = NULL; + + if (!enif_get_uint(env, argv[0], &nrows) || nrows < 1 || + !enif_get_uint(env, argv[1], &ncols) || ncols < 1) { + + goto badarg; + } + mx = alloc_matrix(env, nrows, ncols); + list = argv[2]; + for (i = 0; i float() */ + Matrix* mx; + unsigned i, j; + if (!enif_get_resource(env, argv[0], resource_type, (void**)&mx) || + !enif_get_uint(env, argv[1], &i) || (--i >= mx->nrows) || + !enif_get_uint(env, argv[2], &j) || (--j >= mx->ncols)) { + return enif_make_badarg(env); + } + return enif_make_double(env, POS(mx, i,j)); +} + +static ERL_NIF_TERM add(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) +{ + /* add(Matrix_A, Matrix_B) -> Matrix_Sum */ + unsigned i, j; + ERL_NIF_TERM ret; + Matrix* mxA = NULL; + Matrix* mxB = NULL; + Matrix* mxS = NULL; + + if (!enif_get_resource(env, argv[0], resource_type, (void**)&mxA) || + !enif_get_resource(env, argv[1], resource_type, (void**)&mxB) || + mxA->nrows != mxB->nrows || + mxB->ncols != mxB->ncols) { + + return enif_make_badarg(env); + } + mxS = alloc_matrix(env, mxA->nrows, mxA->ncols); + for (i = 0; i < mxA->nrows; i++) { + for (j = 0; j < mxA->ncols; j++) { + POS(mxS, i, j) = POS(mxA, i, j) + POS(mxB, i, j); + } + } + ret = enif_make_resource(env, mxS); + enif_release_resource(env, mxS); + return ret; +} + +static ERL_NIF_TERM size_of(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) +{ + /* size(Matrix) -> {Nrows, Ncols} */ + Matrix* mx; + if (!enif_get_resource(env, argv[0], resource_type, (void**)&mx)) { + return enif_make_badarg(env); + } + return enif_make_tuple2(env, enif_make_uint(env, mx->nrows), + enif_make_uint(env, mx->ncols)); +} + +static ERL_NIF_TERM to_term(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) +{ + /* to_term(Matrix) -> [[first row], [second row], ...,[last row]] */ + unsigned i, j; + ERL_NIF_TERM res; + Matrix* mx = NULL; + + if (!enif_get_resource(env, argv[0], resource_type, (void**)&mx)) { + return enif_make_badarg(env); + } + res = enif_make_list(env, 0); + for (i = mx->nrows; i-- > 0; ) { + ERL_NIF_TERM row = enif_make_list(env, 0); + for (j = mx->ncols; j-- > 0; ) { + row = enif_make_list_cell(env, enif_make_double(env, POS(mx,i,j)), + row); + } + res = enif_make_list_cell(env, row, res); + } + return res; +} + +static int get_number(ErlNifEnv* env, ERL_NIF_TERM term, double* dp) +{ + long i; + return enif_get_double(env, term, dp) || + (enif_get_long(env, term, &i) && (*dp=(double)i, 1)); +} + +static Matrix* alloc_matrix(ErlNifEnv* env, unsigned nrows, unsigned ncols) +{ + Matrix* mx = enif_alloc_resource(env, resource_type, sizeof(Matrix)); + mx->nrows = nrows; + mx->ncols = ncols; + mx->data = enif_alloc(env, nrows*ncols*sizeof(double)); + return mx; +} + +static void matrix_dtor(ErlNifEnv* env, void* obj) +{ + Matrix* mx = (Matrix*) obj; + enif_free(env, mx->data); + mx->data = NULL; +} + +static ErlNifFunc nif_funcs[] = +{ + {"create", 3, create}, + {"pos", 3, pos}, + {"add", 2, add}, + {"size_of", 1, size_of}, + {"to_term", 1, to_term} +}; + +ERL_NIF_INIT(matrix_nif,nif_funcs,load,NULL,NULL,NULL); + diff --git a/erts/example/matrix_nif.erl b/erts/example/matrix_nif.erl new file mode 100644 index 0000000000..9008977e01 --- /dev/null +++ b/erts/example/matrix_nif.erl @@ -0,0 +1,44 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2010. All Rights Reserved. +%% +%% 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 online 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. +%% +%% %CopyrightEnd% +%% + +%% +%% Purpose: Simple example of NIFs using resource objects to implement functions +%% for matrix calculations. + +-module(matrix_nif). + +-export([create/3, pos/3, add/2, size_of/1, to_term/1]). + +-define(nif, nif_error(?LINE)). + +-on_load(on_load/0). + +on_load() -> + erlang:load_nif("./matrix_nif", 0). + +%% NIFs +create(_Rows, _Cols, _RowList) -> ?nif. +pos(_Mx, _Row, _Col) -> ?nif. +add(_MxA, _MxB) -> ?nif. +size_of(_Mx) -> ?nif. +to_term(_Mx) -> ?nif. + +nif_error(Line) -> + erlang:error({"NIF not implemented in matrix_nif at line", Line}). + -- cgit v1.2.3