From 933304e3dcce052eff6d36c37b708949e53597c3 Mon Sep 17 00:00:00 2001 From: Sverker Eriksson Date: Wed, 28 Apr 2010 10:21:36 +0000 Subject: OTP-8474 NIF improvements after R13B04 New NIF API function enif_make_new_binary --- system/doc/tutorial/complex6.erl | 11 +++ system/doc/tutorial/complex6_nif.c | 32 +++++++++ system/doc/tutorial/nif.xmlsrc | 136 +++++++++++++++++++++++++++++++++++++ system/doc/tutorial/part.xml | 9 +-- system/doc/tutorial/xmlfiles.mk | 13 ++-- 5 files changed, 191 insertions(+), 10 deletions(-) create mode 100644 system/doc/tutorial/complex6.erl create mode 100644 system/doc/tutorial/complex6_nif.c create mode 100644 system/doc/tutorial/nif.xmlsrc (limited to 'system/doc/tutorial') diff --git a/system/doc/tutorial/complex6.erl b/system/doc/tutorial/complex6.erl new file mode 100644 index 0000000000..a5f51886c8 --- /dev/null +++ b/system/doc/tutorial/complex6.erl @@ -0,0 +1,11 @@ +-module(complex6). +-export([foo/1, bar/1]). +-on_load(init/0). + +init() -> + ok = erlang:load_nif("./complex6_nif", 0). + +foo(_X) -> + exit(nif_library_not_loaded). +bar(_Y) -> + exit(nif_library_not_loaded). diff --git a/system/doc/tutorial/complex6_nif.c b/system/doc/tutorial/complex6_nif.c new file mode 100644 index 0000000000..b656ed43ce --- /dev/null +++ b/system/doc/tutorial/complex6_nif.c @@ -0,0 +1,32 @@ +#include "erl_nif.h" + +extern int foo(int x); +extern int bar(int y); + +static ERL_NIF_TERM foo_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) +{ + int x, ret; + if (!enif_get_int(env, argv[0], &x)) { + return enif_make_badarg(env); + } + ret = foo(x); + return enif_make_int(env, ret); +} + +static ERL_NIF_TERM bar_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) +{ + int y, ret; + if (!enif_get_int(env, argv[0], &y)) { + return enif_make_badarg(env); + } + ret = bar(y); + return enif_make_int(env, ret); +} + +static ErlNifFunc nif_funcs[] = { + {"foo", 1, foo_nif}, + {"bar", 1, bar_nif} +}; + +ERL_NIF_INIT(complex6, nif_funcs, NULL, NULL, NULL, NULL) + diff --git a/system/doc/tutorial/nif.xmlsrc b/system/doc/tutorial/nif.xmlsrc new file mode 100644 index 0000000000..f9197c69dd --- /dev/null +++ b/system/doc/tutorial/nif.xmlsrc @@ -0,0 +1,136 @@ + + + + +
+ + 20002009 + Ericsson AB. 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. + + + + NIFs + + + + + nif.xml +
+

This is an example of how to solve the example problem + by using NIFs. NIFs where introduced in R13B03 as an experimental + feature. It is a simpler and more efficient way of calling C-code + than using port drivers. NIFs are most suitable for synchronous functions like + foo and bar in the example, that does some + relatively short calculations without side effects and return the result.

+
+ NIFs +

A NIF (Native Implemented Function) is a function that is + implemented in C instead of Erlang. NIFs appear as any other functions to + the callers. They belong to a module and are called like any other Erlang + functions. The NIFs of a module are compiled and linked into a dynamic + loadable shared library (SO in Unix, DLL in Windows). The NIF library must + be loaded in runtime by the Erlang code of the module.

+

Since a NIF library is dynamically linked into the emulator + process, this is the fastest way of calling C-code from Erlang (alongside + port drivers). Calling NIFs requires no context switches. But it is also + the least safe, because a crash in a NIF will bring the emulator down + too.

+
+ +
+ Erlang Program +

Even if all functions of a module will be NIFs, you still need an Erlang + module for two reasons. First, the NIF library must be explicitly loaded + by Erlang code in the same module. Second, all NIFs of a module must have + an Erlang implementation as well. Normally these are minimal stub + implementations that throw an exception. But it can also be used as + fallback implementations for functions that do not have native + implemenations on some architectures.

+

NIF libraries are loaded by calling erlang:load_nif/2, with the + name of the shared library as argument. The second argument can be any + term that will be passed on to the library and used for + initialization.

+ + + +

We use the directive on_load to get function init to be + automatically called when the module is loaded. If init + returns anything other than ok, such when the loading of + the NIF library fails in this example, the module will be + unloaded and calls to functions within it will fail.

+

Loading the NIF library will override the stub implementations + and cause calls to foo and bar to be dispatched to + the NIF implementations instead.

+
+
+ NIF library code +

The NIFs of the module are compiled and linked into a + shared library. Each NIF is implemented as a normal C function. The macro + ERL_NIF_INIT together with an array of structures defines the names, + arity and function pointers of all the NIFs in the module. The header + file erl_nif.h must be included. Since the library is a shared + module, not a program, no main function should be present.

+

The function arguments passed to a NIF appears in an array argv, + with argc as the length of the array and thus the arity of the + function. The Nth argument of the function can be accessed as + argv[N-1]. NIFs also takes an environment argument that + serves as an opaque handle that is needed to be passed on to + most API functions. The environment contains information about + the calling Erlang process.

+ + + +

The first argument to ERL_NIF_INIT must be the name of the + Erlang module as a C-identifier. It will be stringified by the + macro. The second argument is the array of ErlNifFunc + structures containing name, arity and function pointer of + each NIF. The other arguments are pointers to callback functions + that can be used to initialize the library. We do not use them + is this simple example so we set them all to NULL.

+

Function arguments and return values are represented as values + of type ERL_NIF_TERM. We use functions like enif_get_int + and enif_make_int to convert between Erlang term and C-type. + If the function argument argv[0] is not an integer then + enif_get_int will return false, in which case we return + by throwing a badarg-exception with enif_make_badarg.

+
+ +
+ Running the Example +

1. Compile the C code.

+
+unix> gcc -o complex6_nif.so -fpic -shared complex.c complex6_nif.c
+windows> cl -LD -MD -Fe complex6_nif.dll complex.c complex6_nif.c
+

2. Start Erlang and compile the Erlang code.

+
+> erl
+Erlang R13B04 (erts-5.7.5) [64-bit] [smp:4:4] [rq:4] [async-threads:0] [kernel-poll:false]
+
+Eshell V5.7.5  (abort with ^G)
+1> c(complex6).
+{ok,complex6}
+

3. Run the example.

+
+3> complex6:foo(3).
+4
+4> complex6:bar(5).
+10
+5> complex6:foo("not an integer").
+** exception error: bad argument
+     in function  complex6:foo/1
+        called as comlpex6:foo("not an integer")
+
+
+
diff --git a/system/doc/tutorial/part.xml b/system/doc/tutorial/part.xml index 1a8a873242..ff73b668c0 100644 --- a/system/doc/tutorial/part.xml +++ b/system/doc/tutorial/part.xml @@ -4,7 +4,7 @@
- 20002009 + 20002010 Ericsson AB. All Rights Reserved. @@ -13,19 +13,19 @@ 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. - + Interoperability Tutorial Gunilla Hugosson 2000-01-18 - R7B + R14A
@@ -34,5 +34,6 @@ +
diff --git a/system/doc/tutorial/xmlfiles.mk b/system/doc/tutorial/xmlfiles.mk index 794ef49774..95562bec60 100644 --- a/system/doc/tutorial/xmlfiles.mk +++ b/system/doc/tutorial/xmlfiles.mk @@ -1,19 +1,19 @@ # # %CopyrightBegin% -# -# Copyright Ericsson AB 2009. All Rights Reserved. -# +# +# Copyright Ericsson AB 2009-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% # TUTORIAL_CHAPTER_FILES = \ @@ -23,7 +23,8 @@ TUTORIAL_CHAPTER_FILES = \ erl_interface.xml \ c_portdriver.xml \ example.xml\ - overview.xml + overview.xml\ + nif.xml # appendix.xml # distribution.xml (to be part of tutorial later) -- cgit v1.2.3