aboutsummaryrefslogtreecommitdiffstats
path: root/erts/emulator
diff options
context:
space:
mode:
Diffstat (limited to 'erts/emulator')
-rw-r--r--erts/emulator/beam/atom.names1
-rw-r--r--erts/emulator/beam/beam_load.c43
-rw-r--r--erts/emulator/beam/erl_init.c2
-rw-r--r--erts/emulator/beam/erl_map.c4
-rw-r--r--erts/emulator/beam/erl_nif.c80
-rw-r--r--erts/emulator/beam/erl_nif.h12
-rw-r--r--erts/emulator/beam/erl_nif_api_funcs.h19
-rw-r--r--erts/emulator/test/module_info_SUITE.erl18
-rw-r--r--erts/emulator/test/nif_SUITE.erl6
-rw-r--r--erts/emulator/test/nif_SUITE_data/nif_SUITE.c47
10 files changed, 204 insertions, 28 deletions
diff --git a/erts/emulator/beam/atom.names b/erts/emulator/beam/atom.names
index 7963386e1d..cceca66850 100644
--- a/erts/emulator/beam/atom.names
+++ b/erts/emulator/beam/atom.names
@@ -673,3 +673,4 @@ atom xor
atom x86
atom yes
atom yield
+atom nifs
diff --git a/erts/emulator/beam/beam_load.c b/erts/emulator/beam/beam_load.c
index 0184c567f1..af620d7432 100644
--- a/erts/emulator/beam/beam_load.c
+++ b/erts/emulator/beam/beam_load.c
@@ -554,6 +554,7 @@ static Eterm get_module_info(Process* p, ErtsCodeIndex code_ix,
static Eterm exported_from_module(Process* p, ErtsCodeIndex code_ix,
Eterm mod);
static Eterm functions_in_module(Process* p, BeamCodeHeader*);
+static Eterm nifs_in_module(Process* p, Eterm module);
static Eterm attributes_for_module(Process* p, BeamCodeHeader*);
static Eterm compilation_info_for_module(Process* p, BeamCodeHeader*);
static Eterm md5_of_module(Process* p, BeamCodeHeader*);
@@ -5954,6 +5955,8 @@ get_module_info(Process* p, ErtsCodeIndex code_ix, BeamCodeHeader* code_hdr,
return exported_from_module(p, code_ix, module);
} else if (what == am_functions) {
return functions_in_module(p, code_hdr);
+ } else if (what == am_nifs) {
+ return nifs_in_module(p, module);
} else if (what == am_attributes) {
return attributes_for_module(p, code_hdr);
} else if (what == am_compile) {
@@ -6007,6 +6010,46 @@ functions_in_module(Process* p, /* Process whose heap to use. */
}
/*
+ * Builds a list of all NIFs in the given module:
+ * [{Name, Arity},...]
+ */
+Eterm
+nifs_in_module(Process* p, Eterm module)
+{
+ Eterm nif_list, *hp;
+ Module *mod;
+
+ mod = erts_get_module(module, erts_active_code_ix());
+ nif_list = NIL;
+
+ if (mod->curr.nif != NULL) {
+ int func_count, func_ix;
+ ErlNifFunc *funcs;
+
+ func_count = erts_nif_get_funcs(mod->curr.nif, &funcs);
+ hp = HAlloc(p, func_count * 5);
+
+ for (func_ix = func_count - 1; func_ix >= 0; func_ix--) {
+ Eterm name, arity, pair;
+ ErlNifFunc *func;
+
+ func = &funcs[func_ix];
+
+ name = am_atom_put(func->name, sys_strlen(func->name));
+ arity = make_small(func->arity);
+
+ pair = TUPLE2(hp, name, arity);
+ hp += 3;
+
+ nif_list = CONS(hp, pair, nif_list);
+ hp += 2;
+ }
+ }
+
+ return nif_list;
+}
+
+/*
* Returns 'true' if mod has any native compiled functions, otherwise 'false'
*/
diff --git a/erts/emulator/beam/erl_init.c b/erts/emulator/beam/erl_init.c
index 83ed2e4cd6..1e20d48a73 100644
--- a/erts/emulator/beam/erl_init.c
+++ b/erts/emulator/beam/erl_init.c
@@ -62,7 +62,7 @@
# include <sys/resource.h>
#endif
-#define ERTS_DEFAULT_NO_ASYNC_THREADS 10
+#define ERTS_DEFAULT_NO_ASYNC_THREADS 1
#define ERTS_DEFAULT_SCHED_STACK_SIZE 128
#define ERTS_DEFAULT_DCPU_SCHED_STACK_SIZE 40
diff --git a/erts/emulator/beam/erl_map.c b/erts/emulator/beam/erl_map.c
index 8047a9567f..4ec6960997 100644
--- a/erts/emulator/beam/erl_map.c
+++ b/erts/emulator/beam/erl_map.c
@@ -490,7 +490,9 @@ Eterm erts_map_from_ks_and_vs(ErtsHeapFactory *factory, Eterm *ks0, Eterm *vs0,
sys_memcpy(ks, ks0, n * sizeof(Eterm));
sys_memcpy(vs, vs0, n * sizeof(Eterm));
- erts_validate_and_sort_flatmap(mp);
+ if (!erts_validate_and_sort_flatmap(mp)) {
+ return THE_NON_VALUE;
+ }
return make_flatmap(mp);
} else {
diff --git a/erts/emulator/beam/erl_nif.c b/erts/emulator/beam/erl_nif.c
index cd4fd7b635..f883b3f1e3 100644
--- a/erts/emulator/beam/erl_nif.c
+++ b/erts/emulator/beam/erl_nif.c
@@ -1966,6 +1966,12 @@ ErlNifTid enif_thread_self(void) { return erl_drv_thread_self(); }
int enif_equal_tids(ErlNifTid tid1, ErlNifTid tid2) { return erl_drv_equal_tids(tid1,tid2); }
void enif_thread_exit(void *resp) { erl_drv_thread_exit(resp); }
int enif_thread_join(ErlNifTid tid, void **respp) { return erl_drv_thread_join(tid,respp); }
+
+char* enif_mutex_name(ErlNifMutex *mtx) {return erl_drv_mutex_name(mtx); }
+char* enif_cond_name(ErlNifCond *cnd) { return erl_drv_cond_name(cnd); }
+char* enif_rwlock_name(ErlNifRWLock* rwlck) { return erl_drv_rwlock_name(rwlck); }
+char* enif_thread_name(ErlNifTid tid) { return erl_drv_thread_name(tid); }
+
int enif_getenv(const char *key, char *value, size_t *value_size) { return erl_drv_getenv(key, value, value_size); }
ErlNifTime enif_monotonic_time(ErlNifTimeUnit time_unit)
@@ -1988,16 +1994,21 @@ enif_convert_time_unit(ErlNifTime val,
(int) to);
}
-int enif_fprintf(void* filep, const char* format, ...)
+int enif_fprintf(FILE* filep, const char* format, ...)
{
int ret;
va_list arglist;
va_start(arglist, format);
- ret = erts_vfprintf((FILE*)filep, format, arglist);
+ ret = erts_vfprintf(filep, format, arglist);
va_end(arglist);
return ret;
}
+int enif_vfprintf(FILE* filep, const char *format, va_list ap)
+{
+ return erts_vfprintf(filep, format, ap);
+}
+
int enif_snprintf(char *buffer, size_t size, const char* format, ...)
{
int ret;
@@ -2008,6 +2019,12 @@ int enif_snprintf(char *buffer, size_t size, const char* format, ...)
return ret;
}
+int enif_vsnprintf(char* buffer, size_t size, const char *format, va_list ap)
+{
+ return erts_vsnprintf(buffer, size, format, ap);
+}
+
+
/***********************************************************
** Memory managed (GC'ed) "resource" objects **
***********************************************************/
@@ -2917,6 +2934,44 @@ ERL_NIF_TERM enif_make_new_map(ErlNifEnv* env)
return make_flatmap(mp);
}
+int enif_make_map_from_arrays(ErlNifEnv *env,
+ ERL_NIF_TERM keys[],
+ ERL_NIF_TERM values[],
+ size_t cnt,
+ ERL_NIF_TERM *map_out)
+{
+ ErtsHeapFactory factory;
+ int succeeded;
+
+#ifdef ERTS_NIF_ASSERT_IN_ENV
+ size_t index = 0;
+
+ while (index < cnt) {
+ ASSERT_IN_ENV(env, keys[index], index, "key");
+ ASSERT_IN_ENV(env, values[index], index, "value");
+ index++;
+ }
+#endif
+
+ flush_env(env);
+
+ erts_factory_proc_prealloc_init(&factory, env->proc,
+ cnt * 2 + MAP_HEADER_FLATMAP_SZ + 1);
+
+ (*map_out) = erts_map_from_ks_and_vs(&factory, keys, values, cnt);
+ succeeded = (*map_out) != THE_NON_VALUE;
+
+ if (!succeeded) {
+ erts_factory_undo(&factory);
+ }
+
+ erts_factory_close(&factory);
+
+ cache_env(env);
+
+ return succeeded;
+}
+
int enif_make_map_put(ErlNifEnv* env,
Eterm map_in,
Eterm key,
@@ -3843,6 +3898,11 @@ static struct erl_module_nif* create_lib(const ErlNifEntry* src)
} else {
dst->sizeof_ErlNifResourceTypeInit = 0;
}
+ if (AT_LEAST_VERSION(src, 2, 14)) {
+ dst->min_erts = src->min_erts;
+ } else {
+ dst->min_erts = "erts-?";
+ }
return lib;
};
@@ -3955,14 +4015,20 @@ BIF_RETTYPE load_nif_2(BIF_ALIST_2)
(entry = erts_sys_ddll_call_nif_init(init_func)) == NULL)) {
ret = load_nif_error(BIF_P, bad_lib, "Library init-call unsuccessful");
}
+ else if (entry->major > ERL_NIF_MAJOR_VERSION
+ || (entry->major == ERL_NIF_MAJOR_VERSION
+ && entry->minor > ERL_NIF_MINOR_VERSION)) {
+ char* fmt = "That '%T' NIF library needs %s or newer. Either try to"
+ " recompile the NIF lib or use a newer erts runtime.";
+ ret = load_nif_error(BIF_P, bad_lib, fmt, mod_atom, entry->min_erts);
+ }
else if (entry->major < ERL_NIF_MIN_REQUIRED_MAJOR_VERSION_ON_LOAD
- || (ERL_NIF_MAJOR_VERSION < entry->major
- || (ERL_NIF_MAJOR_VERSION == entry->major
- && ERL_NIF_MINOR_VERSION < entry->minor))
|| (entry->major==2 && entry->minor == 5)) { /* experimental maps */
- ret = load_nif_error(BIF_P, bad_lib, "Library version (%d.%d) not compatible (with %d.%d).",
- entry->major, entry->minor, ERL_NIF_MAJOR_VERSION, ERL_NIF_MINOR_VERSION);
+ char* fmt = "That old NIF library (%d.%d) is not compatible with this "
+ "erts runtime (%d.%d). Try recompile the NIF lib.";
+ ret = load_nif_error(BIF_P, bad_lib, fmt, entry->major, entry->minor,
+ ERL_NIF_MAJOR_VERSION, ERL_NIF_MINOR_VERSION);
}
else if (AT_LEAST_VERSION(entry, 2, 1)
&& sys_strcmp(entry->vm_variant, ERL_NIF_VM_VARIANT) != 0) {
diff --git a/erts/emulator/beam/erl_nif.h b/erts/emulator/beam/erl_nif.h
index a99b4db705..1906da732b 100644
--- a/erts/emulator/beam/erl_nif.h
+++ b/erts/emulator/beam/erl_nif.h
@@ -52,10 +52,12 @@
** 2.11: 19.0 enif_snprintf
** 2.12: 20.0 add enif_select, enif_open_resource_type_x
** 2.13: 20.1 add enif_ioq
-** 2.14: 21.0 add enif_ioq_peek_head
+** 2.14: 21.0 add enif_ioq_peek_head, enif_(mutex|cond|rwlock|thread)_name
+** enif_vfprintf, enif_vsnprintf, enif_make_map_from_arrays
*/
#define ERL_NIF_MAJOR_VERSION 2
#define ERL_NIF_MINOR_VERSION 14
+#define ERL_NIF_MIN_ERTS_VERSION "erts-10.0 (OTP-21)"
/*
* The emulator will refuse to load a nif-lib with a major version
@@ -70,6 +72,8 @@
#define ERL_NIF_MIN_REQUIRED_MAJOR_VERSION_ON_LOAD 2
#include <stdlib.h>
+#include <stdio.h>
+#include <stdarg.h>
#ifdef __cplusplus
extern "C" {
@@ -128,6 +132,9 @@ typedef struct enif_entry_t
/* Added in 2.12 */
size_t sizeof_ErlNifResourceTypeInit;
+
+ /* Added in 2.14 */
+ const char* min_erts;
}ErlNifEntry;
@@ -350,7 +357,8 @@ ERL_NIF_INIT_DECL(NAME) \
LOAD, RELOAD, UPGRADE, UNLOAD, \
ERL_NIF_VM_VARIANT, \
1, \
- sizeof(ErlNifResourceTypeInit) \
+ sizeof(ErlNifResourceTypeInit), \
+ ERL_NIF_MIN_ERTS_VERSION \
}; \
ERL_NIF_INIT_BODY; \
return &entry; \
diff --git a/erts/emulator/beam/erl_nif_api_funcs.h b/erts/emulator/beam/erl_nif_api_funcs.h
index 3750fd9b68..61f8fcf6ed 100644
--- a/erts/emulator/beam/erl_nif_api_funcs.h
+++ b/erts/emulator/beam/erl_nif_api_funcs.h
@@ -92,7 +92,7 @@ ERL_NIF_API_FUNC_DECL(int,enif_thread_join,(ErlNifTid, void **respp));
ERL_NIF_API_FUNC_DECL(void*,enif_realloc,(void* ptr, size_t size));
ERL_NIF_API_FUNC_DECL(void,enif_system_info,(ErlNifSysInfo *sip, size_t si_size));
-ERL_NIF_API_FUNC_DECL(int,enif_fprintf,(void/* FILE* */ *filep, const char *format, ...));
+ERL_NIF_API_FUNC_DECL(int,enif_fprintf,(FILE* filep, const char *format, ...));
ERL_NIF_API_FUNC_DECL(int,enif_inspect_iolist_as_binary,(ErlNifEnv*, ERL_NIF_TERM term, ErlNifBinary* bin));
ERL_NIF_API_FUNC_DECL(ERL_NIF_TERM,enif_make_sub_binary,(ErlNifEnv*, ERL_NIF_TERM bin_term, size_t pos, size_t size));
ERL_NIF_API_FUNC_DECL(int,enif_get_string,(ErlNifEnv*, ERL_NIF_TERM list, char* buf, unsigned len, ErlNifCharEncoding));
@@ -200,6 +200,16 @@ ERL_NIF_API_FUNC_DECL(void,enif_free_iovec,(ErlNifIOVec *iov));
ERL_NIF_API_FUNC_DECL(int,enif_ioq_peek_head,(ErlNifEnv *env, ErlNifIOQueue *q, size_t *size, ERL_NIF_TERM *head));
+ERL_NIF_API_FUNC_DECL(char*,enif_mutex_name,(ErlNifMutex*));
+ERL_NIF_API_FUNC_DECL(char*,enif_cond_name,(ErlNifCond*));
+ERL_NIF_API_FUNC_DECL(char*,enif_rwlock_name,(ErlNifRWLock*));
+ERL_NIF_API_FUNC_DECL(char*,enif_thread_name,(ErlNifTid));
+
+ERL_NIF_API_FUNC_DECL(int,enif_vfprintf,(FILE*, const char *fmt, va_list));
+ERL_NIF_API_FUNC_DECL(int,enif_vsnprintf,(char*, size_t, const char *fmt, va_list));
+
+ERL_NIF_API_FUNC_DECL(int,enif_make_map_from_arrays,(ErlNifEnv *env, ERL_NIF_TERM keys[], ERL_NIF_TERM values[], size_t cnt, ERL_NIF_TERM *map_out));
+
/*
** ADD NEW ENTRIES HERE (before this comment) !!!
*/
@@ -375,6 +385,13 @@ ERL_NIF_API_FUNC_DECL(int,enif_ioq_peek_head,(ErlNifEnv *env, ErlNifIOQueue *q,
# define enif_inspect_iovec ERL_NIF_API_FUNC_MACRO(enif_inspect_iovec)
# define enif_free_iovec ERL_NIF_API_FUNC_MACRO(enif_free_iovec)
# define enif_ioq_peek_head ERL_NIF_API_FUNC_MACRO(enif_ioq_peek_head)
+# define enif_mutex_name ERL_NIF_API_FUNC_MACRO(enif_mutex_name)
+# define enif_cond_name ERL_NIF_API_FUNC_MACRO(enif_cond_name)
+# define enif_rwlock_name ERL_NIF_API_FUNC_MACRO(enif_rwlock_name)
+# define enif_thread_name ERL_NIF_API_FUNC_MACRO(enif_thread_name)
+# define enif_vfprintf ERL_NIF_API_FUNC_MACRO(enif_vfprintf)
+# define enif_vsnprintf ERL_NIF_API_FUNC_MACRO(enif_vsnprintf)
+# define enif_make_map_from_arrays ERL_NIF_API_FUNC_MACRO(enif_make_map_from_arrays)
/*
** ADD NEW ENTRIES HERE (before this comment)
diff --git a/erts/emulator/test/module_info_SUITE.erl b/erts/emulator/test/module_info_SUITE.erl
index ba9b564fdc..46a3bba732 100644
--- a/erts/emulator/test/module_info_SUITE.erl
+++ b/erts/emulator/test/module_info_SUITE.erl
@@ -23,7 +23,7 @@
-include_lib("common_test/include/ct.hrl").
-export([all/0, suite/0,
- exports/1,functions/1,deleted/1,native/1,info/1]).
+ exports/1,functions/1,deleted/1,native/1,info/1,nifs/1]).
%%-compile(native).
@@ -38,7 +38,7 @@ all() ->
modules().
modules() ->
- [exports, functions, deleted, native, info].
+ [exports, functions, deleted, native, info, nifs].
%% Should return all functions exported from this module. (local)
all_exported() ->
@@ -62,12 +62,24 @@ exports(Config) when is_list(Config) ->
All = lists:sort(?MODULE:module_info(exports)),
ok.
-%% Test that the list of exported functions from this module is correct.
+%% Test that the list of local and exported functions from this module is
+%% correct.
functions(Config) when is_list(Config) ->
All = all_functions(),
All = lists:sort(?MODULE:module_info(functions)),
ok.
+nifs(Config) when is_list(Config) ->
+ [] = ?MODULE:module_info(nifs),
+
+ %% erl_tracer is guaranteed to be present and contain these NIFs
+ TraceNIFs = erl_tracer:module_info(nifs),
+ true = lists:member({enabled, 3}, TraceNIFs),
+ true = lists:member({trace, 5}, TraceNIFs),
+ 2 = length(TraceNIFs),
+
+ ok.
+
%% Test that deleted modules cause badarg
deleted(Config) when is_list(Config) ->
Data = proplists:get_value(data_dir, Config),
diff --git a/erts/emulator/test/nif_SUITE.erl b/erts/emulator/test/nif_SUITE.erl
index b6e15ababb..a9eb4b2768 100644
--- a/erts/emulator/test/nif_SUITE.erl
+++ b/erts/emulator/test/nif_SUITE.erl
@@ -1170,6 +1170,12 @@ maps(Config) when is_list(Config) ->
{1, M2} = make_map_remove_nif(M2, "key3"),
{0, undefined} = make_map_remove_nif(self(), key),
+ M1 = maps_from_list_nif(maps:to_list(M1)),
+ M2 = maps_from_list_nif(maps:to_list(M2)),
+ M3 = maps_from_list_nif(maps:to_list(M3)),
+
+ has_duplicate_keys = maps_from_list_nif([{1,1},{1,1}]),
+
verify_tmpmem(TmpMem),
ok.
diff --git a/erts/emulator/test/nif_SUITE_data/nif_SUITE.c b/erts/emulator/test/nif_SUITE_data/nif_SUITE.c
index fa9ae1015c..e8d9302505 100644
--- a/erts/emulator/test/nif_SUITE_data/nif_SUITE.c
+++ b/erts/emulator/test/nif_SUITE_data/nif_SUITE.c
@@ -2140,24 +2140,45 @@ static ERL_NIF_TERM make_map_remove_nif(ErlNifEnv* env, int argc, const ERL_NIF_
/* maps */
static ERL_NIF_TERM maps_from_list_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{
- ERL_NIF_TERM cell = argv[0];
- ERL_NIF_TERM map = enif_make_new_map(env);
- ERL_NIF_TERM tuple;
- const ERL_NIF_TERM *pair;
- int arity = -1;
+ ERL_NIF_TERM *keys, *values;
+ ERL_NIF_TERM result, cell;
+ unsigned count;
- if (argc != 1 && !enif_is_list(env, cell)) return enif_make_badarg(env);
+ if (argc != 1 || !enif_get_list_length(env, argv[0], &count)) {
+ return enif_make_badarg(env);
+ }
- /* assume sorted keys */
+ keys = enif_alloc(sizeof(ERL_NIF_TERM) * count * 2);
+ values = keys + count;
- while (!enif_is_empty_list(env,cell)) {
- if (!enif_get_list_cell(env, cell, &tuple, &cell)) return enif_make_badarg(env);
- if (enif_get_tuple(env,tuple,&arity,&pair)) {
- enif_make_map_put(env, map, pair[0], pair[1], &map);
- }
+ cell = argv[0];
+ count = 0;
+
+ while (!enif_is_empty_list(env, cell)) {
+ const ERL_NIF_TERM *pair;
+ ERL_NIF_TERM tuple;
+ int arity;
+
+ if (!enif_get_list_cell(env, cell, &tuple, &cell)
+ || !enif_get_tuple(env, tuple, &arity, &pair)
+ || arity != 2) {
+ enif_free(keys);
+ return enif_make_badarg(env);
+ }
+
+ keys[count] = pair[0];
+ values[count] = pair[1];
+
+ count++;
}
- return map;
+ if (!enif_make_map_from_arrays(env, keys, values, count, &result)) {
+ result = enif_make_atom(env, "has_duplicate_keys");
+ }
+
+ enif_free(keys);
+
+ return result;
}
static ERL_NIF_TERM sorted_list_from_maps_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) {