From f7c1ea4ff481a8dd7bd8c79ae540342fd8213434 Mon Sep 17 00:00:00 2001
From: Sverker Eriksson
Date: Wed, 9 Dec 2009 11:04:51 +0000
Subject: OTP-8304 Incompatible changes in the experimental NIF feature.
Changed the NIF function prototypes in order to allow more than 3
function arguments. Also an incompatible change in the return value
of erlang:load_nif/2. Added support for references, floats and term
comparison in NIFs. Read more in the documentation of erl_nif and
erlang:load_nif/2.
---
erts/doc/src/erl_nif.xml | 196 +++++++++++++--------
erts/doc/src/erlang.xml | 13 +-
erts/emulator/beam/beam_emu.c | 95 ++++------
erts/emulator/beam/break.c | 2 +
erts/emulator/beam/erl_nif.c | 148 ++++++++++++++--
erts/emulator/beam/erl_nif.h | 16 +-
erts/emulator/beam/erl_nif_api_funcs.h | 24 +++
erts/emulator/beam/global.h | 3 +-
erts/emulator/test/nif_SUITE.erl | 49 +++++-
erts/emulator/test/nif_SUITE_data/nif_SUITE.c | 174 +++++++++++++++++-
erts/emulator/test/nif_SUITE_data/nif_mod.c | 6 +-
.../emulator/test/trace_nif_SUITE_data/trace_nif.c | 6 +-
12 files changed, 552 insertions(+), 180 deletions(-)
(limited to 'erts')
diff --git a/erts/doc/src/erl_nif.xml b/erts/doc/src/erl_nif.xml
index c636d65ef3..2033ba8a66 100644
--- a/erts/doc/src/erl_nif.xml
+++ b/erts/doc/src/erl_nif.xml
@@ -34,12 +34,14 @@
erl_nif
API functions for an Erlang NIF library
- The NIF concept is introduced in R13B03 as an
+ The NIF concept was introduced in R13B03 as an
EXPERIMENTAL feature. The interfaces may be changed in any way
- in coming releases. The API introduced in this release is very
- sparse and contains only the most basic functions to read and
- write Erlang terms.
-
+ in coming releases. The API is still sparse and contains only
+ the most basic functions to read and write Erlang terms.
+
R13B04: The function prototypes of the NIFs
+ have changed to expect argc and argv
+ arguments. The arity of a NIF is by that no longer limited to
+ 3.
A NIF library contains native implementation of some functions
of an erlang module. The native implemented functions (NIFs) are
@@ -56,7 +58,7 @@
/* niftest.c */
#include "erl_nif.h"
-static ERL_NIF_TERM hello(ErlNifEnv* env)
+static ERL_NIF_TERM hello(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{
return enif_make_string(env, "Hello world!");
}
@@ -100,8 +102,9 @@ ok
A better solution for a real module is to take advantage of
- the new attribute on_load to automatically load the NIF
- library when the module is loaded.
+ the new directive on_load to automatically
+ load the NIF library when the module is loaded.
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
@@ -190,7 +193,7 @@ ok
DATA TYPES
- ErlDrvEnv
+ ErlNifEnv
-
ErlNifEnv contains information about the context in
which a NIF call is made. This pointer should not be
@@ -205,31 +208,28 @@ ok
typedef struct {
- const char* name;
- unsigned arity;
- ERL_NIF_TERM (*fptr)(ErlNifEnv* env, ...);
+ const char* name;
+ unsigned arity;
+ ERL_NIF_TERM (*fptr)(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
} ErlNifFunc;
Describes a NIF by its name, arity and implementation.
fptr is a pointer to the function that implements the
- NIF. The number of arguments must match the arity. A NIF of
- arity 2 will thus look like:
-
-
-ERL_NIF_TERM my_nif(ErlNifEnv* env, ERL_NIF_TERM arg1, ERL_NIF_TERM arg2)
-{
- /* ... */
-}
-
- The maximum allowed arity for a NIF is 3 in current implementation.
+ NIF. The argument argv of a NIF will contain the
+ function arguments passed to the NIF and argc is the
+ length of the array, i.e. the function arity. argv[N-1]
+ will thus denote the Nth argument to the NIF. Note that the
+ argc argument allows for the same C function to
+ implement several Erlang functions with different arity (but
+ same name probably).
ErlNifBinary
-
typedef struct {
- unsigned size;
- unsigned char* data;
+ unsigned size;
+ unsigned char* data;
} ErlNifBinary;
ErlNifBinary contains transient information about an
@@ -249,37 +249,36 @@ typedef struct {
- void*enif_get_data(ErlNifEnv* env)
- Get the private data of a NIF library
- Returns the pointer to the private data that was set by load, reload or upgrade.
-
void*enif_alloc(ErlNifEnv* env, size_t size)
Allocate dynamic memory.
- Allocate memory of size bytes.
-
- voidenif_free(ErlNifEnv* env, void* ptr)
- Free dynamic memory
- Free memory allocated by enif_alloc.
-
- intenif_is_binary(ErlNifEnv* env, ERL_NIF_TERM term)
- Determine if a term is a binary
- Return true if term is a binary
-
- intenif_inspect_binary(ErlNifEnv* env, ERL_NIF_TERM bin_term, ErlNifBinary* bin)
- Inspect the content of a binary
- Initialize the structure pointed to by bin with
- transient information about the binary term
- bin_term. Return false if bin_term is not a binary.
+ Allocate memory of size bytes. Return NULL if allocation failed.
intenif_alloc_binary(ErlNifEnv* env, unsigned size, ErlNifBinary* bin)
Create a new binary.
Allocate a new binary of size of size
bytes. Initialize the structure pointed to by bin to
- refer to the allocated binary.
+ refer to the allocated binary. Return false if allocation failed.
- voidenif_release_binary(ErlNifEnv* env, ErlNifBinary* bin)
- Release a binary.
- Release a binary obtained from enif_alloc_binary or enif_inspect_binary.
+ intenif_compare(ErlNifEnv* env, ERL_NIF_TERM lhs, ERL_NIF_TERM rhs)
+ Compare two terms
+ Return an integer less than, equal to, or greater than
+ zero if lhs is found, respectively, to be less than,
+ equal, or greater than rhs. Corresponds to the Erlang
+ operators ==, /=, =<, <,
+ >= and > (but not =:= or =/=).
+
+ voidenif_free(ErlNifEnv* env, void* ptr)
+ Free dynamic memory
+ Free memory allocated by enif_alloc.
+
+ void*enif_get_data(ErlNifEnv* env)
+ Get the private data of a NIF library
+ Return the pointer to the private data that was set by load, reload or upgrade.
+
+ intenif_get_double(ErlNifEnv* env, ERL_NIF_TERM term, double* dp)
+ Read a floating-point number term.
+ Set *dp to the floating point value of
+ term or return false if term is not a float.
intenif_get_int(ErlNifEnv* env, ERL_NIF_TERM term, int* ip)
Read an integer term.
@@ -287,45 +286,80 @@ typedef struct {
term or return false if term is not an integer or is
outside the bounds of type int
- intenif_get_ulong(ErlNifEnv* env, ERL_NIF_TERM term, unsigned long* ip)
- Read an unsigned long integer
- Set *ip to the unsigned long integer value of
- term or return false if term is not an unsigned
- integer or is outside the bounds of type unsigned long
-
intenif_get_list_cell(ErlNifEnv* env, ERL_NIF_TERM list, ERL_NIF_TERM* head, ERL_NIF_TERM* tail)
Get head and tail from a list
Set *head and *tail from
list or return false if list is not a non-empty
list.
- ERL_NIF_TERMenif_make_binary(ErlNifEnv* env, ErlNifBinary* bin)
- Make a binary term.
- Make a binary term from bin. Will also release
- the binary.
+ intenif_get_tuple(ErlNifEnv* env, ERL_NIF_TERM term, int* arity, const ERL_NIF_TERM** array)
+ Inspect the elements of a tuple.
+ If term is a tuple, set *array to point
+ to an array containing the elements of the tuple and set
+ *arity to the number of elements. Note that the array
+ is read-only an (*array)[N-1] will be the Nth element of
+ the tuple. *array is undefined if the arity of the tuple
+ is zero.
Return false if term is not a
+ tuple.
- ERL_NIF_TERMenif_make_badarg(ErlNifEnv* env)
- Make a badarg exception.
- Make a badarg exception to be returned from a NIF.
+ intenif_get_ulong(ErlNifEnv* env, ERL_NIF_TERM term, unsigned long* ip)
+ Read an unsigned integer term.
+ Set *ip to the unsigned long integer value of
+ term or return false if term is not an unsigned integer or is
+ outside the bounds of type unsigned long
- ERL_NIF_TERMenif_make_int(ErlNifEnv* env, int i)
- Create an integer term
- Create an integer term.
+ intenif_inspect_binary(ErlNifEnv* env, ERL_NIF_TERM bin_term, ErlNifBinary* bin)
+ Inspect the content of a binary
+ Initialize the structure pointed to by bin with
+ transient information about the binary term
+ bin_term. Return false if bin_term is not a binary.
- ERL_NIF_TERMenif_make_ulong(ErlNifEnv* env, unsigned long i)
- Create an integer term from an unsigned long int
- Create an integer term from an unsigned long int.
+ intenif_is_atom(ErlNifEnv* env, ERL_NIF_TERM term)
+ Determine if a term is an atom
+ Return true if term is an atom.
+
+ intenif_is_binary(ErlNifEnv* env, ERL_NIF_TERM term)
+ Determine if a term is a binary
+ Return true if term is a binary
+
+ intenif_is_identical(ErlNifEnv* env, ERL_NIF_TERM lhs, ERL_NIF_TERM rhs)
+ Erlang operator =:=
+ Return true if and only if the two terms are
+ identical. Corresponds to the Erlang operators =:= and
+ =/=.
+
+ intenif_is_ref(ErlNifEnv* env, ERL_NIF_TERM term)
+ Determine if a term is a reference
+ Return true if term is a reference.
ERL_NIF_TERMenif_make_atom(ErlNifEnv* env, const char* name)
Create an atom term
Create an atom term from the C-string name. Atom
terms may be saved and used between NIF calls.
- ERL_NIF_TERMenif_make_tuple(ErlNifEnv* env, unsigned cnt, ...)
- Create a tuple term.
- Create a tuple term of arity cnt. Expects
- cnt number of arguments (after cnt) of type ERL_NIF_TERM as the
- elements of the tuple.
+ ERL_NIF_TERMenif_make_badarg(ErlNifEnv* env)
+ Make a badarg exception.
+ Make a badarg exception to be returned from a NIF.
+
+ ERL_NIF_TERMenif_make_binary(ErlNifEnv* env, ErlNifBinary* bin)
+ Make a binary term.
+ Make a binary term from bin. Will also release
+ the binary.
+
+ ERL_NIF_TERMenif_make_double(ErlNifEnv* env, double d)
+ Create an floating-point term
+ Create an floating-point term from a double.
+
+ intenif_make_existing_atom(ErlNifEnv* env, const char* name, ERL_NIF_TERM* atom)
+ Create an existing atom term
+ Try to create the term of an already existing atom from
+ the C-string name. If the atom already exist store the
+ term in *atom and return true, otherwise return
+ false.
+
+ ERL_NIF_TERMenif_make_int(ErlNifEnv* env, int i)
+ Create an integer term
+ Create an integer term.
ERL_NIF_TERMenif_make_list(ErlNifEnv* env, unsigned cnt, ...)
Create a list term.
@@ -337,11 +371,29 @@ typedef struct {
Create a list cell.
Create a list cell [head | tail].
+ ERL_NIF_TERMenif_make_ref(ErlNifEnv* env)
+ Create a reference.
+ Create a reference like erlang:make_ref/0.
+
ERL_NIF_TERMenif_make_string(ErlNifEnv* env, const char* string)
Create a string.
- Creates a list containing the characters of the
+ Create a list containing the characters of the
C-string string.
+ ERL_NIF_TERMenif_make_tuple(ErlNifEnv* env, unsigned cnt, ...)
+ Create a tuple term.
+ Create a tuple term of arity cnt. Expects
+ cnt number of arguments (after cnt) of type ERL_NIF_TERM as the
+ elements of the tuple.
+
+ ERL_NIF_TERMenif_make_ulong(ErlNifEnv* env, unsigned long i)
+ Create an integer term from an unsigned long int
+ Create an integer term from an unsigned long int.
+
+ voidenif_release_binary(ErlNifEnv* env, ErlNifBinary* bin)
+ Release a binary.
+ Release a binary obtained from enif_alloc_binary or enif_inspect_binary.
+
SEE ALSO
diff --git a/erts/doc/src/erlang.xml b/erts/doc/src/erlang.xml
index 3f54d0a6f9..871fc0fd63 100644
--- a/erts/doc/src/erlang.xml
+++ b/erts/doc/src/erlang.xml
@@ -1929,7 +1929,7 @@ os_prompt%
- erlang:load_nif(Path, LoadInfo) -> ok | {error, Reason, Text}
+ erlang:load_nif(Path, LoadInfo) -> ok | {error, {Reason, Text}}
Load NIF library
Path = string()
@@ -1940,9 +1940,10 @@ os_prompt%
- This BIF is currently introduced as an experimental
- feature. The interface may be changed in any way in future
- releases.
+ This BIF is still an experimental feature. The interface
+ may be changed in any way in future releases.
In
+ R13B03 the return value on failure was
+ {error,Reason,Text}.
Loads and links a dynamic library containing native
implemented functions (NIFs) for a module. Path is a
@@ -1957,10 +1958,10 @@ os_prompt%
The call to load_nif/2 must be made
directly from the Erlang code of the module that the
NIF library belongs to.
- It returns either ok, or {error,Reason,Text}
+
It returns either ok, or {error,{Reason,Text}}
if loading fails. Reason is one of the atoms below,
while Text is a human readable string that may give
- some more information about the failure:
+ some more information about the failure.
load_failed
-
diff --git a/erts/emulator/beam/beam_emu.c b/erts/emulator/beam/beam_emu.c
index dcaa43b51c..4ebb8853be 100644
--- a/erts/emulator/beam/beam_emu.c
+++ b/erts/emulator/beam/beam_emu.c
@@ -974,10 +974,6 @@ static int hibernate(Process* c_p, Eterm module, Eterm function,
static Eterm* call_fun(Process* p, int arity, Eterm* reg, Eterm args);
static Eterm* apply_fun(Process* p, Eterm fun, Eterm args, Eterm* reg);
static Eterm new_fun(Process* p, Eterm* reg, ErlFunEntry* fe, int num_free);
-static BIF_RETTYPE nif_dispatcher_0(Process* p, Uint* I);
-static BIF_RETTYPE nif_dispatcher_1(Process* p, Eterm arg1, Uint* I);
-static BIF_RETTYPE nif_dispatcher_2(Process* p, Eterm arg1, Eterm arg2, Uint* I);
-static BIF_RETTYPE nif_dispatcher_3(Process* p, Eterm arg1, Eterm arg2, Eterm arg3, Uint* I);
#if defined(_OSE_) || defined(VXWORKS)
static int init_done;
@@ -2949,11 +2945,38 @@ void process_main(void)
OpCase(call_nif):
{
- static void* const dispatchers[4] = {
- nif_dispatcher_0, nif_dispatcher_1, nif_dispatcher_2, nif_dispatcher_3
- };
- BifFunction vbf = dispatchers[I[-1]];
- goto apply_bif_or_nif;
+ /*
+ * call_nif is always first instruction in function:
+ *
+ * I[-3]: Module
+ * I[-2]: Function
+ * I[-1]: Arity
+ * I[0]: &&call_nif
+ * I[1]: Function pointer to NIF function
+ * I[2]: priv_data pointer
+ */
+ BifFunction vbf;
+
+ c_p->current = I-3; /* current and vbf set to please handle_error */
+ SWAPOUT;
+ c_p->fcalls = FCALLS - 1;
+ PROCESS_MAIN_CHK_LOCKS(c_p);
+ tmp_arg2 = I[-1];
+ ERTS_SMP_UNREQ_PROC_MAIN_LOCK(c_p);
+
+ ASSERT(!ERTS_PROC_IS_EXITING(c_p));
+ {
+ typedef Eterm NifF(struct enif_environment_t*, int argc, Eterm argv[]);
+ NifF* fp = vbf = (NifF*) I[1];
+ struct enif_environment_t env;
+ erts_pre_nif(&env, c_p, (void*)I[2]);
+ reg[0] = r(0);
+ tmp_arg1 = (*fp)(&env, tmp_arg2, reg);
+ erts_post_nif(&env);
+ }
+ ASSERT(!ERTS_PROC_IS_EXITING(c_p) || is_non_value(tmp_arg1));
+ PROCESS_MAIN_CHK_LOCKS(c_p);
+ goto apply_bif_or_nif_epilogue;
OpCase(apply_bif):
/*
@@ -2966,17 +2989,15 @@ void process_main(void)
* code[3]: &&apply_bif
* code[4]: Function pointer to BIF function
*/
- vbf = (BifFunction) Arg(0);
- apply_bif_or_nif:
c_p->current = I-3; /* In case we apply process_info/1,2 or load_nif/1 */
c_p->i = I; /* In case we apply check_process_code/2. */
c_p->arity = 0; /* To allow garbage collection on ourselves
* (check_process_code/2).
*/
-
SWAPOUT;
c_p->fcalls = FCALLS - 1;
+ vbf = (BifFunction) Arg(0);
PROCESS_MAIN_CHK_LOCKS(c_p);
tmp_arg2 = I[-1];
ASSERT(tmp_arg2 <= 3);
@@ -3019,6 +3040,7 @@ void process_main(void)
break;
}
}
+apply_bif_or_nif_epilogue:
ERTS_SMP_REQ_PROC_MAIN_LOCK(c_p);
ERTS_HOLE_CHECK(c_p);
if (c_p->mbuf) {
@@ -5245,6 +5267,7 @@ save_stacktrace(Process* c_p, Eterm* pc, Eterm* reg, BifFunction bf,
* The Bif does not really exist (no BIF entry). It is a
* TRAP and traps are called through apply_bif, which also
* sets c_p->current (luckily).
+ * OR it is a NIF called by call_nif where current is also set.
*/
ASSERT(c_p->current);
s->current = c_p->current;
@@ -6148,51 +6171,3 @@ erts_current_reductions(Process *current, Process *p)
}
}
-static BIF_RETTYPE nif_dispatcher_0(Process* p, Uint* I)
-{
- typedef Eterm NifF(struct enif_environment_t*);
- NifF* fp = (NifF*) I[1];
- struct enif_environment_t env;
- Eterm ret;
- erts_pre_nif(&env, p, (void*)I[2]);
- ret = (*fp)(&env);
- erts_post_nif(&env);
- return ret;
-}
-
-static BIF_RETTYPE nif_dispatcher_1(Process* p, Eterm arg1, Uint* I)
-{
- typedef Eterm NifF(struct enif_environment_t*, Eterm);
- NifF* fp = (NifF*) I[1];
- struct enif_environment_t env;
- Eterm ret;
- erts_pre_nif(&env, p, (void*)I[2]);
- ret = (*fp)(&env, arg1);
- erts_post_nif(&env);
- return ret;
-}
-
-static BIF_RETTYPE nif_dispatcher_2(Process* p, Eterm arg1, Eterm arg2, Uint* I)
-{
- typedef Eterm NifF(struct enif_environment_t*, Eterm, Eterm);
- NifF* fp = (NifF*) I[1];
- struct enif_environment_t env;
- Eterm ret;
- erts_pre_nif(&env, p, (void*)I[2]);
- ret = (*fp)(&env, arg1, arg2);
- erts_post_nif(&env);
- return ret;
-}
-
-static BIF_RETTYPE nif_dispatcher_3(Process* p, Eterm arg1, Eterm arg2, Eterm arg3, Uint* I)
-{
- typedef Eterm NifF(struct enif_environment_t*, Eterm, Eterm, Eterm);
- NifF* fp = (NifF*) I[1];
- struct enif_environment_t env;
- Eterm ret;
- erts_pre_nif(&env, p, (void*)I[2]);
- ret = (*fp)(&env, arg1, arg2, arg3);
- erts_post_nif(&env);
- return ret;
-}
-
diff --git a/erts/emulator/beam/break.c b/erts/emulator/beam/break.c
index 5ea47e16f5..cc69977b79 100644
--- a/erts/emulator/beam/break.c
+++ b/erts/emulator/beam/break.c
@@ -703,6 +703,8 @@ erl_crash_dump_v(char *file, int line, char* fmt, va_list args)
erts_fdprintf(fd, "System version: ");
erts_print_system_version(fd, NULL, NULL);
erts_fdprintf(fd, "%s\n", "Compiled: " ERLANG_COMPILE_DATE);
+ erts_fdprintf(fd, "Taints: ");
+ erts_print_nif_taints(fd, NULL);
erts_fdprintf(fd, "Atoms: %d\n", atom_table_size());
info(fd, NULL); /* General system info */
if (process_tab != NULL) /* XXX true at init */
diff --git a/erts/emulator/beam/erl_nif.c b/erts/emulator/beam/erl_nif.c
index fa4454a3f3..b09f92d342 100644
--- a/erts/emulator/beam/erl_nif.c
+++ b/erts/emulator/beam/erl_nif.c
@@ -35,13 +35,6 @@
#include
-/*
-static ERTS_INLINE Eterm* alloc_heap(ErlNifEnv* env, unsigned need)
-{
- return HAlloc(env->proc, need);
-}
-*/
-
#define MIN_HEAP_FRAG_SZ 200
static Eterm* alloc_heap_heavy(ErlNifEnv* env, unsigned need);
@@ -116,12 +109,21 @@ void enif_free(ErlNifEnv* env, void* ptr)
erts_free(ERTS_ALC_T_NIF, ptr);
}
+int enif_is_atom(ErlNifEnv* env, ERL_NIF_TERM term)
+{
+ return is_atom(term);
+}
int enif_is_binary(ErlNifEnv* env, ERL_NIF_TERM term)
{
return is_binary(term) && (binary_bitsize(term) % 8 == 0);
}
-
+
+int enif_is_ref(ErlNifEnv* env, ERL_NIF_TERM term)
+{
+ return is_ref(term);
+}
+
int enif_inspect_binary(ErlNifEnv* env, Eterm bin_term, ErlNifBinary* bin)
{
@@ -157,6 +159,25 @@ int enif_alloc_binary(ErlNifEnv* env, unsigned size, ErlNifBinary* bin)
return 1;
}
+int enif_realloc_binary(ErlNifEnv* env, ErlNifBinary* bin, unsigned size)
+{
+ Binary* oldbin;
+ Binary* newbin;
+ ASSERT(bin->ref_bin != NULL);
+
+ oldbin = (Binary*) bin->ref_bin;
+ newbin = (Binary *) erts_bin_realloc_fnf(oldbin, size);
+ if (!newbin) {
+ return 0;
+ }
+ newbin->orig_size = size;
+ bin->ref_bin = newbin;
+ bin->data = (unsigned char*) newbin->orig_bytes;
+ bin->size = size;
+ return 1;
+}
+
+
void enif_release_binary(ErlNifEnv* env, ErlNifBinary* bin)
{
if (bin->ref_bin == NULL) {
@@ -177,6 +198,28 @@ void enif_release_binary(ErlNifEnv* env, ErlNifBinary* bin)
#endif
}
+int enif_is_identical(ErlNifEnv* env, Eterm lhs, Eterm rhs)
+{
+ return EQ(lhs,rhs);
+}
+
+int enif_compare(ErlNifEnv* env, Eterm lhs, Eterm rhs)
+{
+ return cmp(lhs,rhs);
+}
+
+int enif_get_tuple(ErlNifEnv* env, Eterm tpl, int* arity, Eterm** array)
+{
+ Eterm* ptr;
+ if (is_not_tuple(tpl)) {
+ return 0;
+ }
+ ptr = tuple_val(tpl);
+ *arity = arityval(*ptr);
+ *array = ptr+1;
+ return 1;
+}
+
Eterm enif_make_binary(ErlNifEnv* env, ErlNifBinary* bin)
{
if (bin->ref_bin == NULL) {
@@ -203,7 +246,7 @@ Eterm enif_make_binary(ErlNifEnv* env, ErlNifBinary* bin)
}
}
-ERL_NIF_TERM enif_make_badarg(ErlNifEnv* env)
+Eterm enif_make_badarg(ErlNifEnv* env)
{
BIF_ERROR(env->proc, BADARG);
}
@@ -212,7 +255,7 @@ ERL_NIF_TERM enif_make_badarg(ErlNifEnv* env)
int enif_get_int(ErlNifEnv* env, Eterm term, int* ip)
{
#if SIZEOF_INT == SIZEOF_VOID_P
- return term_to_Sint(term, ip);
+ return term_to_Sint(term, (Sint*)ip);
#elif SIZEOF_LONG == SIZEOF_VOID_P
Sint i;
if (!term_to_Sint(term, &i) || i < INT_MIN || i > INT_MAX) {
@@ -234,6 +277,17 @@ int enif_get_ulong(ErlNifEnv* env, Eterm term, unsigned long* ip)
#endif
}
+int enif_get_double(ErlNifEnv* env, Eterm term, double* dp)
+{
+ FloatDef f;
+ if (is_not_float(term)) {
+ return 0;
+ }
+ GET_DOUBLE(term, f);
+ *dp = f.fd;
+ return 1;
+}
+
int enif_get_list_cell(ErlNifEnv* env, Eterm term, Eterm* head, Eterm* tail)
{
Eterm* val;
@@ -267,12 +321,24 @@ ERL_NIF_TERM enif_make_ulong(ErlNifEnv* env, unsigned long i)
}
+ERL_NIF_TERM enif_make_double(ErlNifEnv* env, double d)
+{
+ Eterm* hp = alloc_heap(env,FLOAT_SIZE_OBJECT);
+ FloatDef f;
+ f.fd = d;
+ PUT_DOUBLE(f, hp);
+ return make_float(hp);
+}
ERL_NIF_TERM enif_make_atom(ErlNifEnv* env, const char* name)
{
return am_atom_put(name, sys_strlen(name));
}
+int enif_make_existing_atom(ErlNifEnv* env, const char* name, ERL_NIF_TERM* atom)
+{
+ return erts_atom_get(name, sys_strlen(name), atom);
+}
ERL_NIF_TERM enif_make_tuple(ErlNifEnv* env, unsigned cnt, ...)
{
@@ -320,13 +386,43 @@ ERL_NIF_TERM enif_make_list(ErlNifEnv* env, unsigned cnt, ...)
ERL_NIF_TERM enif_make_string(ErlNifEnv* env, const char* string)
{
- Sint n = strlen(string);
+ Sint n = sys_strlen(string);
Eterm* hp = alloc_heap(env,n*2);
return erts_bld_string_n(&hp,NULL,string,n);
}
+ERL_NIF_TERM enif_make_ref(ErlNifEnv* env)
+{
+ Eterm* hp = alloc_heap(env, REF_THING_SIZE);
+ return erts_make_ref_in_buffer(hp);
+}
+
+#if 0 /* To be continued... */
+typedef struct enif_handle_type_t
+{
+ struct enif_handle_type_t* next;
+ struct enif_handle_type_t* prev;
+ const char* name;
+ void (*dtor)(void* obj);
+ erts_smp_atomic_t ref_cnt; /* num of handles of this type */
+}ErlNifHandleType;
+
+ErlNifHandleType*
+enif_create_handle_type(ErlNifEnv* env, const char* type_name,
+ void (*dtor)(void *))
+{
+
+}
+
+ERL_NIF_TERM enif_make_handle(ErlNifEnv* env, ErlNifHandleType* htype, void* obj)
+{
+}
+int enif_get_handle(ErlNifEnv* env, ERL_NIF_TERM term, void** objp)
+{
+}
+#endif
/***************************************************************************
** load_nif/2 **
@@ -361,7 +457,7 @@ static void refresh_cached_nif_data(Eterm* mod_code,
ErlNifFunc* func = &mod_nif->entry->funcs[i];
Uint* code_ptr;
- erts_atom_get(func->name, strlen(func->name), &f_atom);
+ erts_atom_get(func->name, sys_strlen(func->name), &f_atom);
code_ptr = *get_func_pp(mod_code, f_atom, func->arity);
code_ptr[5+2] = (Uint) mod_nif->data;
}
@@ -411,6 +507,18 @@ Eterm erts_nif_taints(Process* p)
return list;
}
+void erts_print_nif_taints(int to, void* to_arg)
+{
+ struct tainted_module_t* t;
+ const char* delim = "";
+ for (t=first_tainted_module ; t!=NULL; t=t->next) {
+ const Atom* atom = atom_tab(atom_val(t->module_atom));
+ erts_print(to,to_arg,"%s%.*s", delim, atom->len, atom->name);
+ delim = ",";
+ }
+ erts_print(to,to_arg,"\n");
+}
+
static Eterm load_nif_error(Process* p, const char* atom, const char* format, ...)
{
@@ -428,7 +536,8 @@ static Eterm load_nif_error(Process* p, const char* atom, const char* format, ..
for (;;) {
Eterm txt = erts_bld_string_n(hpp, &sz, dsbufp->str, dsbufp->str_len);
- ret = erts_bld_tuple(hpp, szp, 3, am_error, mkatom(atom), txt);
+ ret = erts_bld_tuple(hpp, szp, 2, am_error,
+ erts_bld_tuple(hpp, szp, 2, mkatom(atom), txt));
if (hpp != NULL) {
break;
}
@@ -489,8 +598,13 @@ BIF_RETTYPE load_nif_2(BIF_ALIST_2)
"module '%T' not allowed", mod_atom);
}
else if ((err=erts_sys_ddll_open2(lib_name, &handle, &errdesc)) != ERL_DE_NO_ERROR) {
- ret = load_nif_error(BIF_P, "load_failed", "Failed to load NIF library"
- " %s: '%s'", lib_name, errdesc.str);
+ const char slogan[] = "Failed to load NIF library";
+ if (strstr(errdesc.str, lib_name) != NULL) {
+ ret = load_nif_error(BIF_P, "load_failed", "%s: '%s'", slogan, errdesc.str);
+ }
+ else {
+ ret = load_nif_error(BIF_P, "load_failed", "%s %s: '%s'", slogan, lib_name, errdesc.str);
+ }
}
else if (erts_sys_ddll_load_nif_init(handle, &init_func, &errdesc) != ERL_DE_NO_ERROR) {
ret = load_nif_error(BIF_P, bad_lib, "Failed to find library init"
@@ -521,7 +635,7 @@ BIF_RETTYPE load_nif_2(BIF_ALIST_2)
ret = load_nif_error(BIF_P,bad_lib,"Function arity too high for NIF %s/%u",
f->name, f->arity);
}
- else if (!erts_atom_get(f->name, strlen(f->name), &f_atom)
+ else if (!erts_atom_get(f->name, sys_strlen(f->name), &f_atom)
|| (code_pp = get_func_pp(mod->code, f_atom, f->arity))==NULL) {
ret = load_nif_error(BIF_P,bad_lib,"Function not found %T:%s/%u",
mod_atom, f->name, f->arity);
@@ -612,7 +726,7 @@ BIF_RETTYPE load_nif_2(BIF_ALIST_2)
for (i=0; i < entry->num_of_funcs; i++)
{
Uint* code_ptr;
- erts_atom_get(entry->funcs[i].name, strlen(entry->funcs[i].name), &f_atom);
+ erts_atom_get(entry->funcs[i].name, sys_strlen(entry->funcs[i].name), &f_atom);
code_ptr = *get_func_pp(mod->code, f_atom, entry->funcs[i].arity);
if (code_ptr[1] == 0) {
diff --git a/erts/emulator/beam/erl_nif.h b/erts/emulator/beam/erl_nif.h
index 8650b7ce47..e5e6d65c0e 100644
--- a/erts/emulator/beam/erl_nif.h
+++ b/erts/emulator/beam/erl_nif.h
@@ -20,23 +20,27 @@
/* Include file for writers of Native Implemented Functions.
*/
-#define ERL_NIF_MAJOR_VERSION 0
-#define ERL_NIF_MINOR_VERSION 1
+/* Version history:
+** 0.1: R13B03
+** 1.0: R13B04
+*/
+#define ERL_NIF_MAJOR_VERSION 1
+#define ERL_NIF_MINOR_VERSION 0
#include
typedef unsigned long ERL_NIF_TERM;
+struct enif_environment_t;
+typedef struct enif_environment_t ErlNifEnv;
+
typedef struct
{
const char* name;
unsigned arity;
- void* fptr; //ERL_NIF_TERM (*fptr)(void*, ...);
+ ERL_NIF_TERM (*fptr)(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
}ErlNifFunc;
-struct enif_environment_t;
-typedef struct enif_environment_t ErlNifEnv;
-
typedef struct enif_entry_t
{
int major;
diff --git a/erts/emulator/beam/erl_nif_api_funcs.h b/erts/emulator/beam/erl_nif_api_funcs.h
index 400c1822cc..7556806ce4 100644
--- a/erts/emulator/beam/erl_nif_api_funcs.h
+++ b/erts/emulator/beam/erl_nif_api_funcs.h
@@ -25,44 +25,68 @@
ERL_NIF_API_FUNC_DECL(void*,enif_get_data,(ErlNifEnv*));
ERL_NIF_API_FUNC_DECL(void*,enif_alloc,(ErlNifEnv*, size_t size));
ERL_NIF_API_FUNC_DECL(void,enif_free,(ErlNifEnv*, void* ptr));
+ERL_NIF_API_FUNC_DECL(int,enif_is_atom,(ErlNifEnv*, ERL_NIF_TERM term));
ERL_NIF_API_FUNC_DECL(int,enif_is_binary,(ErlNifEnv*, ERL_NIF_TERM term));
+ERL_NIF_API_FUNC_DECL(int,enif_is_ref,(ErlNifEnv*, ERL_NIF_TERM term));
ERL_NIF_API_FUNC_DECL(int,enif_inspect_binary,(ErlNifEnv*, ERL_NIF_TERM bin_term, ErlNifBinary* bin));
ERL_NIF_API_FUNC_DECL(int,enif_alloc_binary,(ErlNifEnv*, unsigned size, ErlNifBinary* bin));
+ERL_NIF_API_FUNC_DECL(int,enif_realloc_binary,(ErlNifEnv*, ErlNifBinary* bin, unsigned size));
ERL_NIF_API_FUNC_DECL(void,enif_release_binary,(ErlNifEnv*, ErlNifBinary* bin));
ERL_NIF_API_FUNC_DECL(int,enif_get_int,(ErlNifEnv*, ERL_NIF_TERM term, int* ip));
ERL_NIF_API_FUNC_DECL(int,enif_get_ulong,(ErlNifEnv*, ERL_NIF_TERM term, unsigned long* ip));
+ERL_NIF_API_FUNC_DECL(int,enif_get_double,(ErlNifEnv*, ERL_NIF_TERM term, double* dp));
ERL_NIF_API_FUNC_DECL(int,enif_get_list_cell,(ErlNifEnv* env, ERL_NIF_TERM term, ERL_NIF_TERM* head, ERL_NIF_TERM* tail));
+ERL_NIF_API_FUNC_DECL(int,enif_get_tuple,(ErlNifEnv* env, ERL_NIF_TERM tpl, int* arity, ERL_NIF_TERM** array));
+ERL_NIF_API_FUNC_DECL(int,enif_is_identical,(ErlNifEnv* env, ERL_NIF_TERM lhs, ERL_NIF_TERM rhs));
+ERL_NIF_API_FUNC_DECL(int,enif_compare,(ErlNifEnv* env, ERL_NIF_TERM lhs, ERL_NIF_TERM rhs));
ERL_NIF_API_FUNC_DECL(ERL_NIF_TERM,enif_make_binary,(ErlNifEnv* env, ErlNifBinary* bin));
ERL_NIF_API_FUNC_DECL(ERL_NIF_TERM,enif_make_badarg,(ErlNifEnv* env));
ERL_NIF_API_FUNC_DECL(ERL_NIF_TERM,enif_make_int,(ErlNifEnv* env, int i));
ERL_NIF_API_FUNC_DECL(ERL_NIF_TERM,enif_make_ulong,(ErlNifEnv* env, unsigned long i));
+ERL_NIF_API_FUNC_DECL(ERL_NIF_TERM,enif_make_double,(ErlNifEnv* env, double d));
ERL_NIF_API_FUNC_DECL(ERL_NIF_TERM,enif_make_atom,(ErlNifEnv* env, const char* name));
+ERL_NIF_API_FUNC_DECL(int,enif_make_existing_atom,(ErlNifEnv* env, const char* name, ERL_NIF_TERM* atom));
ERL_NIF_API_FUNC_DECL(ERL_NIF_TERM,enif_make_tuple,(ErlNifEnv* env, unsigned cnt, ...));
ERL_NIF_API_FUNC_DECL(ERL_NIF_TERM,enif_make_list,(ErlNifEnv* env, unsigned cnt, ...));
ERL_NIF_API_FUNC_DECL(ERL_NIF_TERM,enif_make_list_cell,(ErlNifEnv* env, ERL_NIF_TERM car, ERL_NIF_TERM cdr));
ERL_NIF_API_FUNC_DECL(ERL_NIF_TERM,enif_make_string,(ErlNifEnv* env, const char* string));
+ERL_NIF_API_FUNC_DECL(ERL_NIF_TERM,enif_make_ref,(ErlNifEnv* env));
+/*
+** Add last to keep compatibility on Windows!!!
+*/
#endif
#ifdef ERL_NIF_API_FUNC_MACRO
# define enif_get_data ERL_NIF_API_FUNC_MACRO(enif_get_data)
# define enif_alloc ERL_NIF_API_FUNC_MACRO(enif_alloc)
# define enif_free ERL_NIF_API_FUNC_MACRO(enif_free)
+# define enif_is_atom ERL_NIF_API_FUNC_MACRO(enif_is_atom)
# define enif_is_binary ERL_NIF_API_FUNC_MACRO(enif_is_binary)
+# define enif_is_ref ERL_NIF_API_FUNC_MACRO(enif_is_ref)
# define enif_inspect_binary ERL_NIF_API_FUNC_MACRO(enif_inspect_binary)
# define enif_alloc_binary ERL_NIF_API_FUNC_MACRO(enif_alloc_binary)
+# define enif_realloc_binary ERL_NIF_API_FUNC_MACRO(enif_realloc_binary)
# define enif_release_binary ERL_NIF_API_FUNC_MACRO(enif_release_binary)
# define enif_get_int ERL_NIF_API_FUNC_MACRO(enif_get_int)
# define enif_get_ulong ERL_NIF_API_FUNC_MACRO(enif_get_ulong)
+# define enif_get_double ERL_NIF_API_FUNC_MACRO(enif_get_double)
+# define enif_get_tuple ERL_NIF_API_FUNC_MACRO(enif_get_tuple)
# define enif_get_list_cell ERL_NIF_API_FUNC_MACRO(enif_get_list_cell)
+# define enif_is_identical ERL_NIF_API_FUNC_MACRO(enif_is_identical)
+# define enif_compare ERL_NIF_API_FUNC_MACRO(enif_compare)
# define enif_make_binary ERL_NIF_API_FUNC_MACRO(enif_make_binary)
# define enif_make_badarg ERL_NIF_API_FUNC_MACRO(enif_make_badarg)
# define enif_make_int ERL_NIF_API_FUNC_MACRO(enif_make_int)
# define enif_make_ulong ERL_NIF_API_FUNC_MACRO(enif_make_ulong)
+# define enif_make_double ERL_NIF_API_FUNC_MACRO(enif_make_double)
# define enif_make_atom ERL_NIF_API_FUNC_MACRO(enif_make_atom)
+# define enif_make_existing_atom ERL_NIF_API_FUNC_MACRO(enif_make_existing_atom)
# define enif_make_tuple ERL_NIF_API_FUNC_MACRO(enif_make_tuple)
# define enif_make_list ERL_NIF_API_FUNC_MACRO(enif_make_list)
# define enif_make_list_cell ERL_NIF_API_FUNC_MACRO(enif_make_list_cell)
# define enif_make_string ERL_NIF_API_FUNC_MACRO(enif_make_string)
+# define enif_make_ref ERL_NIF_API_FUNC_MACRO(enif_make_ref)
+
#endif
diff --git a/erts/emulator/beam/global.h b/erts/emulator/beam/global.h
index 1b64e23174..62a788cbff 100644
--- a/erts/emulator/beam/global.h
+++ b/erts/emulator/beam/global.h
@@ -86,7 +86,8 @@ struct enif_environment_t /* ErlNifEnv */
};
extern void erts_pre_nif(struct enif_environment_t*, Process*, void* nif_data);
extern void erts_post_nif(struct enif_environment_t* env);
-extern Eterm erts_nif_taints(Process* p);
+extern Eterm erts_nif_taints(Process* p);
+extern void erts_print_nif_taints(int to, void* to_arg);
/*
* Port Specific Data.
diff --git a/erts/emulator/test/nif_SUITE.erl b/erts/emulator/test/nif_SUITE.erl
index 213ff6637a..3d1607475e 100644
--- a/erts/emulator/test/nif_SUITE.erl
+++ b/erts/emulator/test/nif_SUITE.erl
@@ -24,12 +24,12 @@
-include("test_server.hrl").
-export([all/1, fin_per_testcase/2, basic/1, reload/1, upgrade/1, heap_frag/1,
- neg/1]).
+ types/1, neg/1]).
-define(nif_stub,nif_stub_error(?LINE)).
all(suite) ->
- [basic, reload, upgrade, heap_frag, neg].
+ [basic, reload, upgrade, heap_frag, types, neg].
fin_per_testcase(_Func, _Config) ->
P1 = code:purge(nif_mod),
@@ -184,19 +184,56 @@ heap_frag_do(N, Max) ->
L = list_seq(N),
heap_frag_do(((N*5) div 4) + 1, Max).
+types(doc) -> ["Type tests"];
+types(suite) -> [];
+types(Config) when is_list(Config) ->
+ ensure_lib_loaded(Config),
+ ?line ok = type_test(),
+ lists:foreach(fun(Tpl) ->
+ Lst = erlang:tuple_to_list(Tpl),
+ Lst = tuple_2_list(Tpl)
+ end,
+ [{},{ok},{{}},{[],{}},{1,2,3,4,5}]),
+ Stuff = [[],{},0,0.0,(1 bsl 100),(fun()-> ok end),make_ref(),self()],
+ [eq_cmp(A,clone(B)) || A<-Stuff, B<-Stuff],
+ ok.
+
+clone(X) ->
+ binary_to_term(term_to_binary(X)).
+
+eq_cmp(A,B) ->
+ eq_cmp_do(A,B),
+ eq_cmp_do([A,B],[A,B]),
+ eq_cmp_do({A,B},{A,B}).
+
+eq_cmp_do(A,B) ->
+ %%?t:format("compare ~p and ~p\n",[A,B]),
+ Eq = (A =:= B),
+ ?line Eq = is_identical(A,B),
+ ?line Cmp = if
+ A < B -> -1;
+ A == B -> 0;
+ A > B -> 1
+ end,
+ ?line Cmp = case compare(A,B) of
+ C when is_integer(C), C < 0 -> -1;
+ 0 -> 0;
+ C when is_integer(C) -> 1
+ end,
+ ok.
neg(doc) -> ["Negative testing of load_nif"];
neg(suite) -> [];
neg(Config) when is_list(Config) ->
?line {'EXIT',{badarg,_}} = (catch erlang:load_nif(badarg, 0)),
- ?line {error,load_failed,_} = erlang:load_nif("pink_unicorn", 0),
+ ?line {error,{load_failed,_}} = erlang:load_nif("pink_unicorn", 0),
?line Data = ?config(data_dir, Config),
?line File = filename:join(Data, "nif_mod"),
?line {ok,nif_mod,Bin} = compile:file(File, [binary,return_errors]),
?line {module,nif_mod} = erlang:load_module(nif_mod,Bin),
- ?line {error,bad_lib,_} = nif_mod:load_nif_lib(Config, no_init),
+ ?line {error,{bad_lib,_}} = nif_mod:load_nif_lib(Config, no_init),
?line ok.
@@ -230,6 +267,10 @@ call_history() -> ?nif_stub.
hold_nif_mod_priv_data(_Ptr) -> ?nif_stub.
nif_mod_call_history() -> ?nif_stub.
list_seq(_To) -> ?nif_stub.
+type_test() -> ?nif_stub.
+tuple_2_list(_) -> ?nif_stub.
+is_identical(_,_) -> ?nif_stub.
+compare(_,_) -> ?nif_stub.
nif_stub_error(Line) ->
exit({nif_not_loaded,module,?MODULE,line,Line}).
diff --git a/erts/emulator/test/nif_SUITE_data/nif_SUITE.c b/erts/emulator/test/nif_SUITE_data/nif_SUITE.c
index 852495e234..0d5ed6e28f 100644
--- a/erts/emulator/test/nif_SUITE_data/nif_SUITE.c
+++ b/erts/emulator/test/nif_SUITE_data/nif_SUITE.c
@@ -1,6 +1,9 @@
#include "erl_nif.h"
+
+#include
#include
#include
+#include
#include "nif_mod.h"
@@ -65,7 +68,7 @@ static void unload(ErlNifEnv* env, void* priv_data)
}
}
-static ERL_NIF_TERM lib_version(ErlNifEnv* env)
+static ERL_NIF_TERM lib_version(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{
ADD_CALL("lib_version");
return enif_make_int(env, NIF_SUITE_LIB_VER);
@@ -89,19 +92,19 @@ static ERL_NIF_TERM make_call_history(ErlNifEnv* env, CallInfo** headp)
return list;
}
-static ERL_NIF_TERM call_history(ErlNifEnv* env)
+static ERL_NIF_TERM call_history(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{
PrivData* data = (PrivData*) enif_get_data(env);
return make_call_history(env,&data->call_history);
}
-static ERL_NIF_TERM hold_nif_mod_priv_data(ErlNifEnv* env, ERL_NIF_TERM a1)
+static ERL_NIF_TERM hold_nif_mod_priv_data(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{
PrivData* data = (PrivData*) enif_get_data(env);
unsigned long ptr_as_ulong;
- if (!enif_get_ulong(env,a1,&ptr_as_ulong)) {
+ if (!enif_get_ulong(env,argv[0],&ptr_as_ulong)) {
return enif_make_badarg(env);
}
if (data->nif_mod != NULL && --(data->nif_mod->ref_cnt) == 0) {
@@ -111,7 +114,7 @@ static ERL_NIF_TERM hold_nif_mod_priv_data(ErlNifEnv* env, ERL_NIF_TERM a1)
return enif_make_int(env,++(data->nif_mod->ref_cnt));
}
-static ERL_NIF_TERM nif_mod_call_history(ErlNifEnv* env)
+static ERL_NIF_TERM nif_mod_call_history(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{
PrivData* data = (PrivData*) enif_get_data(env);
@@ -121,11 +124,11 @@ static ERL_NIF_TERM nif_mod_call_history(ErlNifEnv* env)
return make_call_history(env,&data->nif_mod->call_history);
}
-static ERL_NIF_TERM list_seq(ErlNifEnv* env, ERL_NIF_TERM a1)
+static ERL_NIF_TERM list_seq(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{
ERL_NIF_TERM list;
int n;
- if (!enif_get_int(env, a1, &n)) {
+ if (!enif_get_int(env, argv[0], &n)) {
return enif_make_badarg(env);
}
list = enif_make_list(env, 0); /* NIL */
@@ -136,13 +139,168 @@ static ERL_NIF_TERM list_seq(ErlNifEnv* env, ERL_NIF_TERM a1)
return list;
}
+static int test_int(ErlNifEnv* env, int i1)
+{
+ int i2 = 0;
+ ERL_NIF_TERM int_term = enif_make_int(env, i1);
+ if (!enif_get_int(env,int_term, &i2) || i1 != i2) {
+ fprintf(stderr, "test_int(%d) ...FAILED i2=%d\r\n", i1, i2);
+ return 0;
+ }
+ return 1;
+}
+
+static int test_ulong(ErlNifEnv* env, unsigned long i1)
+{
+ unsigned long i2 = 0;
+ ERL_NIF_TERM int_term = enif_make_ulong(env, i1);
+ if (!enif_get_ulong(env,int_term, &i2) || i1 != i2) {
+ fprintf(stderr, "SVERK: test_ulong(%lu) ...FAILED i2=%lu\r\n", i1, i2);
+ return 0;
+ }
+ return 1;
+}
+
+static int test_double(ErlNifEnv* env, double d1)
+{
+ double d2 = 0;
+ ERL_NIF_TERM term = enif_make_double(env, d1);
+ if (!enif_get_double(env,term, &d2) || d1 != d2) {
+ fprintf(stderr, "SVERK: test_double(%e) ...FAILED i2=%e\r\n", d1, d2);
+ return 0;
+ }
+ return 1;
+}
+
+#define TAG_BITS 4
+#define SMALL_BITS (sizeof(void*)*8 - TAG_BITS)
+#define MAX_SMALL ((1L << (SMALL_BITS-1))-1)
+#define MIN_SMALL (-(1L << (SMALL_BITS-1)))
+
+static ERL_NIF_TERM type_test(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{
+ int i;
+ unsigned long u;
+ double d;
+ ERL_NIF_TERM atom, ref1, ref2;
+
+ i = INT_MIN;
+ do {
+ if (!test_int(env,i)) {
+ goto error;
+ }
+ i += ~i / 3 + 1;
+ } while (i < 0);
+ i = INT_MAX;
+ do {
+ if (!test_int(env,i)) {
+ goto error;
+ }
+ i -= i / 3 + 1;
+ } while (i >= 0);
+
+ u = ULONG_MAX;
+ for (;;) {
+ if (!test_ulong(env,u)) {
+
+ }
+ if (u == 0) break;
+ u -= u / 3 + 1;
+ }
+
+ if (MAX_SMALL < INT_MAX) { /* 32-bit */
+ for (i=-10 ; i <= 10; i++) {
+ if (!test_int(env,MAX_SMALL+i)) {
+ goto error;
+ }
+ }
+ for (i=-10 ; i <= 10; i++) {
+ if (!test_int(env,MIN_SMALL+i)) {
+ goto error;
+ }
+ }
+ }
+ assert((MAX_SMALL < INT_MAX) == (MIN_SMALL > INT_MIN));
+
+ for (u=0 ; u < 10; u++) {
+ if (!test_ulong(env,MAX_SMALL+u) || !test_ulong(env,MAX_SMALL-u)) {
+ goto error;
+ }
+ }
+
+ for (d=3.141592e-100 ; d < 1e100 ; d *= 9.97) {
+ if (!test_double(env,d) || !test_double(env,-d)) {
+ goto error;
+ }
+ }
+
+ if (!enif_make_existing_atom(env,"nif_SUITE", &atom)
+ || !enif_is_identical(env,atom,enif_make_atom(env,"nif_SUITE"))) {
+ fprintf(stderr, "SVERK: nif_SUITE not an atom?\r\n");
+ goto error;
+ }
+ for (i=2; i; i--) {
+ if (enif_make_existing_atom(env,"nif_SUITE_pink_unicorn", &atom)) {
+ fprintf(stderr, "SVERK: pink unicorn exist?\r\n");
+ goto error;
+ }
+ }
+ ref1 = enif_make_ref(env);
+ ref2 = enif_make_ref(env);
+ if (!enif_is_ref(env,ref1) || !enif_is_ref(env,ref2)
+ || enif_is_identical(env,ref1,ref2) || enif_compare(env,ref1,ref2)==0) {
+ fprintf(stderr, "SVERK: strange refs?\r\n");
+ }
+ return enif_make_atom(env,"ok");
+
+error:
+ return enif_make_atom(env,"error");
+}
+
+static ERL_NIF_TERM tuple_2_list(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{
+ int arity = -1;
+ ERL_NIF_TERM* ptr;
+ ERL_NIF_TERM list = enif_make_list(env,0);
+
+ if (argc!=1 || !enif_get_tuple(env,argv[0],&arity,&ptr)) {
+ return enif_make_badarg(env);
+ }
+ while (--arity >= 0) {
+ list = enif_make_list_cell(env,ptr[arity],list);
+ }
+ return list;
+}
+
+static ERL_NIF_TERM is_identical(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{
+ if (argc != 2) {
+ return enif_make_badarg(env);
+ }
+ return enif_make_atom(env, (enif_is_identical(env,argv[0],argv[1]) ?
+ "true" : "false"));
+}
+
+static ERL_NIF_TERM compare(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{
+ if (argc != 2) {
+ return enif_make_badarg(env);
+ }
+ return enif_make_int(env, enif_compare(env,argv[0],argv[1]));
+}
+
+
static ErlNifFunc nif_funcs[] =
{
{"lib_version", 0, lib_version},
{"call_history", 0, call_history},
{"hold_nif_mod_priv_data", 1, hold_nif_mod_priv_data},
{"nif_mod_call_history", 0, nif_mod_call_history},
- {"list_seq", 1, list_seq}
+ {"list_seq", 1, list_seq},
+ {"type_test", 0, type_test},
+ {"tuple_2_list", 1, tuple_2_list},
+ {"is_identical",2,is_identical},
+ {"compare",2,compare}
};
ERL_NIF_INIT(nif_SUITE,nif_funcs,load,reload,upgrade,unload)
diff --git a/erts/emulator/test/nif_SUITE_data/nif_mod.c b/erts/emulator/test/nif_SUITE_data/nif_mod.c
index 18f676335a..2f2267cf78 100644
--- a/erts/emulator/test/nif_SUITE_data/nif_mod.c
+++ b/erts/emulator/test/nif_SUITE_data/nif_mod.c
@@ -58,13 +58,13 @@ static void unload(ErlNifEnv* env, void* priv_data)
}
}
-static ERL_NIF_TERM lib_version(ErlNifEnv* env)
+static ERL_NIF_TERM lib_version(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{
ADD_CALL("lib_version");
return enif_make_int(env, NIF_LIB_VER);
}
-static ERL_NIF_TERM call_history(ErlNifEnv* env)
+static ERL_NIF_TERM call_history(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{
NifModPrivData* data = (NifModPrivData*) enif_get_data(env);
ERL_NIF_TERM list = enif_make_list(env, 0); /* NIL */
@@ -81,7 +81,7 @@ static ERL_NIF_TERM call_history(ErlNifEnv* env)
return list;
}
-static ERL_NIF_TERM get_priv_data_ptr(ErlNifEnv* env)
+static ERL_NIF_TERM get_priv_data_ptr(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{
ADD_CALL("get_priv_data_ptr");
return enif_make_ulong(env, (unsigned long)enif_get_data(env));
diff --git a/erts/emulator/test/trace_nif_SUITE_data/trace_nif.c b/erts/emulator/test/trace_nif_SUITE_data/trace_nif.c
index 732f1010ae..26f2420b8b 100644
--- a/erts/emulator/test/trace_nif_SUITE_data/trace_nif.c
+++ b/erts/emulator/test/trace_nif_SUITE_data/trace_nif.c
@@ -20,18 +20,18 @@ static void unload(ErlNifEnv* env, void* priv_data)
{
}
-static ERL_NIF_TERM nif_0(ErlNifEnv* env)
+static ERL_NIF_TERM nif_0(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{
return enif_make_tuple(env,2,
enif_make_atom(env,"ok"),
enif_make_list(env,0));
}
-static ERL_NIF_TERM nif_1(ErlNifEnv* env, ERL_NIF_TERM a1)
+static ERL_NIF_TERM nif_1(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{
return enif_make_tuple(env,2,
enif_make_atom(env,"ok"),
- enif_make_list(env,1,a1));
+ enif_make_list(env,1,argv[0]));
}
--
cgit v1.2.3