From f584be53357613c61987e280806483d49f04e36b Mon Sep 17 00:00:00 2001 From: Sverker Eriksson Date: Wed, 17 Feb 2010 15:20:29 +0000 Subject: [PATCH] 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/doc/src/erl_nif.xml | 78 ++++++++++++++++++++++++++++------------ 1 file changed, 56 insertions(+), 22 deletions(-) diff --git a/erts/doc/src/erl_nif.xml b/erts/doc/src/erl_nif.xml index d25c63be3d56..2e55f13ed509 100644 --- a/erts/doc/src/erl_nif.xml +++ b/erts/doc/src/erl_nif.xml @@ -115,7 +115,7 @@ ok

A loaded NIF library is tied to the Erlang module code version that loaded it. If the module is upgraded with a new version, the - new code will have to load its own NIF library (or maybe choose not + new Erlang code will have to load its own NIF library (or maybe choose not to). The new code version can however choose to load the exact same NIF library as the old code if it wants to. Sharing the same dynamic library will mean that static data defined by the library @@ -146,7 +146,8 @@ ok to query terms, like enif_is_atom, enif_is_identical and enif_compare.

Binaries -

Terms of type binary are accessed through the struct type ErlNifBinary +

Terms of type binary are accessed with the help of the struct type + ErlNifBinary that contains a pointer (data) to the raw binary data and the length (size) of the data in bytes. Both data and size are read-only and should only be written using calls to API functions. @@ -155,17 +156,20 @@ ok

The raw data pointed to by data is only mutable after a call to enif_alloc_binary. All other functions that operates on a binary will leave the data as read-only. - An allocated binary must in the end either be freed with - enif_release_binary - or transferred to an Erlang term with enif_make_binary. - But it does not have do happen in the same NIF call.

-

Binaries must be a number of whole bytes. Bitstrings with an arbitrary + A mutable binary allocated with enif_alloc_binary must in the end + either be freed with enif_release_binary + or made read-only by transferring it to an Erlang term with + enif_make_binary. + But it does not have do happen in the same NIF call. Read-only binaries + does not have to be released.

+

Binaries are sequences of whole bytes. Bitstrings with an arbitrary bit length have no support yet.

Resource objects -

Resource objects are a way to return pointers to native data - structures from a NIF in a safe way. A resource object is just a block - of memory allocated with enif_alloc_resource(). +

The use of resource objects is a way to return pointers to + native data structures from a NIF in a safe way. A resource object is + just a block of memory allocated with + enif_alloc_resource(). A handle ("safe pointer") to this memory block can then be returned to Erlang by the use of enif_make_resource(). The term returned by enif_make_resource @@ -178,20 +182,46 @@ ok released with enif_release_resource() (not necessarily in that order).

All resource objects are created as instances of some resource type. - This makes resources from different modules or applications to be distinguishable. + This makes resources from different modules to be distinguishable. A resource type is created by calling enif_open_resource_type() when a library is loaded. Objects of that resource type can then later be allocated and enif_get_resource verifies that the resource is of the expected type. - A resource type can have a destructor function that is automatically - called when resources of that type are released (by either the garbage - collector or enif_release_resource). Resource types also support - upgrade in runtime by allowing a loaded NIF library to takeover an already - existing resource type and thereby "inherit" all existing objects of that type. - The destructor of the new library will thereafter be called for the inherited - objects and the library with the old destructor function can be safely - unloaded. Resource types are uniquely identified by a supplied name string. + A resource type can have a user supplied destructor function that is + automatically called when resources of that type are released (by either + the garbage collector or enif_release_resource). Resource types + are uniquely identified by a supplied name string.

+

Resource types support upgrade in runtime by allowing a loaded NIF + library to takeover an already existing resource type and thereby + "inherit" all existing objects of that type. The destructor of the new + library will thereafter be called for the inherited objects and the + library with the old destructor function can be safely unloaded. Existing + resource objects, of a module that is upgraded, must either be deleted + or taken over by the new NIF library. The unloading of a library will be + postponed as long as it exists resource objects with a destructor + function in the library.

+

Here is a template example of how to create and return a resource object.

+

+ + ERL_NIF_TERM term; + MyStruct* ptr = enif_alloc_resource(env, my_resource_type, sizeof(MyStruct)); + + /* initialize struct ... */ + + term = enif_make_resource(env, ptr); + + if (keep_a_reference_of_our_own) { + /* store 'ptr' in static variable, private data or other resource object */ + } + else { + enif_release_resource(env, obj); + /* resource now only owned by "Erlang" */ + } + return term; +} + + Threads and concurrency

A NIF is thread-safe without any explicit synchronization as @@ -232,7 +262,9 @@ ok and there is no previously loaded library for this module.

*priv_data can be set to point to some private data that the library needs in able to keep a state between NIF - calls. enif_priv_data() will return this pointer.

+ calls. enif_priv_data() will return this pointer. + *priv_data will be initialized to NULL when load is + called.

load_info is the second argument to erlang:load_nif/2.

The library will fail to load if load returns @@ -258,7 +290,8 @@ ok

Works the same as load. The only difference is that *old_priv_data already contains the value set by the last call to load or reload for the old module - code. It is allowed to write to both *priv_data and *old_priv_data.

+ code. *priv_data will be initialized to NULL when upgrade + is called. It is allowed to write to both *priv_data and *old_priv_data.

The library will fail to load if upgrade returns anything other than 0 or if upgrade is NULL.

@@ -266,7 +299,8 @@ ok void (*unload)(ErlNifEnv* env, void* priv_data)

unload is called when the module code that the NIF library belongs to is purged as old. New code - of the same module may or may not exist.

+ of the same module may or may not exist. Note that unload is not + called for a replaced library as a consequence of reload.