From 9197f6ea9af095eebbbf42e4ceca5ef762467276 Mon Sep 17 00:00:00 2001
From: Sverker Eriksson
Date: Wed, 20 Feb 2019 16:04:58 +0100
Subject: erts: Add enif_set_pid_undefined & enif_is_pid_undefined
---
erts/doc/src/erl_nif.xml | 42 +++++++++++++++--
erts/emulator/beam/erl_nif.c | 14 ++++++
erts/emulator/beam/erl_nif_api_funcs.h | 5 +-
erts/emulator/sys/common/erl_check_io.c | 1 +
erts/emulator/test/nif_SUITE.erl | 28 ++++++++++-
erts/emulator/test/nif_SUITE_data/nif_SUITE.c | 68 ++++++++++++++++++++++++++-
6 files changed, 148 insertions(+), 10 deletions(-)
diff --git a/erts/doc/src/erl_nif.xml b/erts/doc/src/erl_nif.xml
index d58ebd3171..ac873d0c8c 100644
--- a/erts/doc/src/erl_nif.xml
+++ b/erts/doc/src/erl_nif.xml
@@ -783,14 +783,16 @@ typedef struct {
A process identifier (pid). In contrast to pid terms (instances of
ERL_NIF_TERM), ErlNifPids are self-contained and not
bound to any environment.
- ErlNifPid is an opaque type.
+ ErlNifPid is an opaque type. It can be copied, moved
+ in memory, forgotten, and so on.
-
@@ -1392,6 +1394,9 @@ enif_free_iovec(iovec);]]>
initializes the pid variable *pid from it and returns
true. Otherwise returns false. No check is done to see
if the process is alive.
+
enif_get_local_pid will return false if argument
+ term is the atom
+ undefined.
@@ -1870,6 +1875,17 @@ enif_inspect_iovec(env, max_elements, term, &tail, &iovec);
+
+ int
+ enif_is_pid_undefined(const ErlNifPid* pid)
+ Determine if pid is undefined.
+
+ Returns true if pid has been set as undefined by
+ enif_set_pid_undefined
+ .
+
+
+
int
enif_is_port(ErlNifEnv* env, ERL_NIF_TERM term)
@@ -2259,7 +2275,8 @@ enif_inspect_iovec(env, max_elements, term, &tail, &iovec);
Make a pid term.
- Makes a pid term from *pid.
+ Makes a pid term or the atom
+ undefined from *pid.
@@ -2625,7 +2642,9 @@ enif_map_iterator_destroy(env, &iter);
Argument caller_env is the environment of the calling process
or callback. Must only be NULL if calling from a custom thread.
Returns 0 on success, < 0 if no down callback is
- provided, and > 0 if the process is no longer alive.
+ provided, and > 0 if the process is no longer alive or if
+ target_pid is
+ undefined.
This function is only thread-safe when the emulator with SMP support
is used. It can only be used in a non-SMP emulator from a NIF-calling
thread.
@@ -3080,7 +3099,9 @@ enif_map_iterator_destroy(env, &iter);
enif_select_write
introduced in erts-11.0 (OTP-22.0).
- Argument pid may be NULL to indicate the calling process.
+ Argument pid may be NULL to indicate the calling
+ process. It must not be set as
+ undefined.
Argument obj is a resource object obtained from
enif_alloc_resource.
The purpose of the resource objects is as a container of the event object
@@ -3270,6 +3291,17 @@ if (retval & ERL_NIF_SELECT_STOP_CALLED) {
+
+ void
+ enif_set_pid_undefined(ErlNifPid* pid)
+ Set pid as undefined.
+
+ Sets an ErlNifPid
+ variable as undefined. See
+ enif_is_pid_undefined.
+
+
+
unsigned
enif_sizeof_resource(void* obj)
diff --git a/erts/emulator/beam/erl_nif.c b/erts/emulator/beam/erl_nif.c
index 82645d4091..0efef37802 100644
--- a/erts/emulator/beam/erl_nif.c
+++ b/erts/emulator/beam/erl_nif.c
@@ -1083,6 +1083,17 @@ int enif_get_local_pid(ErlNifEnv* env, ERL_NIF_TERM term, ErlNifPid* pid)
return 0;
}
+void enif_set_pid_undefined(ErlNifPid* pid)
+{
+ pid->pid = am_undefined;
+}
+
+int enif_is_pid_undefined(const ErlNifPid* pid)
+{
+ ASSERT(pid->pid == am_undefined || is_internal_pid(pid->pid));
+ return pid->pid == am_undefined;
+}
+
int enif_get_local_port(ErlNifEnv* env, ERL_NIF_TERM term, ErlNifPort* port)
{
if (is_internal_port(term)) {
@@ -3336,6 +3347,9 @@ int enif_monitor_process(ErlNifEnv* env, void* obj, const ErlNifPid* target_pid,
}
ASSERT(rsrc->type->down);
+ if (target_pid->pid == am_undefined)
+ return 1;
+
ref = erts_make_ref_in_buffer(tmp);
mdp = erts_monitor_create(ERTS_MON_TYPE_RESOURCE, ref,
diff --git a/erts/emulator/beam/erl_nif_api_funcs.h b/erts/emulator/beam/erl_nif_api_funcs.h
index 4ea6a2f7b0..a87f3154a9 100644
--- a/erts/emulator/beam/erl_nif_api_funcs.h
+++ b/erts/emulator/beam/erl_nif_api_funcs.h
@@ -212,7 +212,8 @@ ERL_NIF_API_FUNC_DECL(int,enif_make_map_from_arrays,(ErlNifEnv *env, ERL_NIF_TER
ERL_NIF_API_FUNC_DECL(int,enif_select_x,(ErlNifEnv* env, ErlNifEvent e, enum ErlNifSelectFlags flags, void* obj, const ErlNifPid* pid, ERL_NIF_TERM msg, ErlNifEnv* msg_env));
ERL_NIF_API_FUNC_DECL(ERL_NIF_TERM,enif_make_monitor_term,(ErlNifEnv* env, const ErlNifMonitor*));
-
+ERL_NIF_API_FUNC_DECL(void,enif_set_pid_undefined,(ErlNifPid* pid));
+ERL_NIF_API_FUNC_DECL(int,enif_is_pid_undefined,(const ErlNifPid* pid));
/*
** ADD NEW ENTRIES HERE (before this comment) !!!
@@ -398,6 +399,8 @@ ERL_NIF_API_FUNC_DECL(ERL_NIF_TERM,enif_make_monitor_term,(ErlNifEnv* env, const
# define enif_make_map_from_arrays ERL_NIF_API_FUNC_MACRO(enif_make_map_from_arrays)
# define enif_select_x ERL_NIF_API_FUNC_MACRO(enif_select_x)
# define enif_make_monitor_term ERL_NIF_API_FUNC_MACRO(enif_make_monitor_term)
+# define enif_set_pid_undefined ERL_NIF_API_FUNC_MACRO(enif_set_pid_undefined)
+# define enif_is_pid_undefined ERL_NIF_API_FUNC_MACRO(enif_is_pid_undefined)
/*
** ADD NEW ENTRIES HERE (before this comment)
diff --git a/erts/emulator/sys/common/erl_check_io.c b/erts/emulator/sys/common/erl_check_io.c
index e367087455..68b780b6a0 100644
--- a/erts/emulator/sys/common/erl_check_io.c
+++ b/erts/emulator/sys/common/erl_check_io.c
@@ -1181,6 +1181,7 @@ enif_select_x(ErlNifEnv* env,
if (on) {
const Eterm recipient = pid ? pid->pid : env->proc->common.id;
+ ASSERT(is_internal_pid(recipient));
if (!state->driver.nif)
state->driver.nif = alloc_nif_select_data();
if (state->type == ERTS_EV_TYPE_NONE) {
diff --git a/erts/emulator/test/nif_SUITE.erl b/erts/emulator/test/nif_SUITE.erl
index 168df76301..c2d368bb72 100644
--- a/erts/emulator/test/nif_SUITE.erl
+++ b/erts/emulator/test/nif_SUITE.erl
@@ -64,7 +64,8 @@
nif_phash2/1,
nif_whereis/1, nif_whereis_parallel/1,
nif_whereis_threaded/1, nif_whereis_proxy/1,
- nif_ioq/1
+ nif_ioq/1,
+ pid/1
]).
-export([many_args_100/100]).
@@ -103,7 +104,8 @@ all() ->
nif_internal_hash_salted,
nif_phash2,
nif_whereis, nif_whereis_parallel, nif_whereis_threaded,
- nif_ioq].
+ nif_ioq,
+ pid].
groups() ->
[{G, [], api_repeaters()} || G <- api_groups()]
@@ -3367,6 +3369,23 @@ make_unaligned_binary(Bin0) ->
<<0:3,Bin:Size/binary,31:5>> = id(<<0:3,Bin0/binary,31:5>>),
Bin.
+pid(Config) ->
+ ensure_lib_loaded(Config),
+ Self = self(),
+ {true, ErlNifPid} = get_local_pid_nif(Self),
+ false = is_pid_undefined_nif(ErlNifPid),
+ Self = make_pid_nif(ErlNifPid),
+
+ UndefPid = set_pid_undefined_nif(),
+ true = is_pid_undefined_nif(UndefPid),
+ undefined = make_pid_nif(UndefPid),
+ 0 = send_term(UndefPid, message),
+
+ {false, _} = get_local_pid_nif(undefined),
+ ok.
+
+
+
id(I) -> I.
%% The NIFs:
@@ -3475,5 +3494,10 @@ convert_time_unit(_,_,_) -> ?nif_stub.
now_time() -> ?nif_stub.
cpu_time() -> ?nif_stub.
+get_local_pid_nif(_) -> ?nif_stub.
+make_pid_nif(_) -> ?nif_stub.
+set_pid_undefined_nif() -> ?nif_stub.
+is_pid_undefined_nif(_) -> ?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 af2d062857..4dbd22fa8c 100644
--- a/erts/emulator/test/nif_SUITE_data/nif_SUITE.c
+++ b/erts/emulator/test/nif_SUITE_data/nif_SUITE.c
@@ -1882,12 +1882,23 @@ static ERL_NIF_TERM copy_blob(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[
return enif_make_copy(env, mti.p->blob);
}
+static int get_pidbin(ErlNifEnv* env, ERL_NIF_TERM pidbin, ErlNifPid* pid)
+{
+ ErlNifBinary bin;
+
+ if (!enif_inspect_binary(env, pidbin, &bin) || bin.size != sizeof(ErlNifPid))
+ return 0;
+
+ memcpy(pid, bin.data, bin.size);
+ return 1;
+}
+
static ERL_NIF_TERM send_term(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{
ErlNifEnv* menv;
ErlNifPid pid;
int ret;
- if (!enif_get_local_pid(env, argv[0], &pid)) {
+ if (!enif_get_local_pid(env, argv[0], &pid) && !get_pidbin(env, argv[0], &pid)) {
return enif_make_badarg(env);
}
menv = enif_alloc_env();
@@ -3513,6 +3524,55 @@ static ERL_NIF_TERM ioq(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
return enif_make_badarg(env);
}
+static ERL_NIF_TERM make_bool(ErlNifEnv* env, int bool)
+{
+ return bool ? atom_true : atom_false;
+}
+
+static ERL_NIF_TERM get_local_pid_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{
+ ErlNifPid pid;
+ ERL_NIF_TERM pid_bin;
+ int ret = enif_get_local_pid(env, argv[0], &pid);
+
+ memcpy(enif_make_new_binary(env, sizeof(ErlNifPid), &pid_bin),
+ &pid, sizeof(ErlNifPid));
+
+ return enif_make_tuple2(env, make_bool(env, ret), pid_bin);
+}
+
+static ERL_NIF_TERM make_pid_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{
+ ErlNifPid pid;
+
+ if (!get_pidbin(env, argv[0], &pid))
+ return enif_make_badarg(env);
+
+ return enif_make_pid(env, &pid);
+}
+
+static ERL_NIF_TERM set_pid_undefined_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{
+ ErlNifPid pid;
+ ERL_NIF_TERM pid_bin;
+
+ enif_set_pid_undefined(&pid);
+ memcpy(enif_make_new_binary(env, sizeof(ErlNifPid), &pid_bin),
+ &pid, sizeof(ErlNifPid));
+
+ return pid_bin;
+}
+
+static ERL_NIF_TERM is_pid_undefined_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{
+ ErlNifPid pid;
+
+ if (!get_pidbin(env, argv[0], &pid))
+ return enif_make_badarg(env);
+
+ return make_bool(env, enif_is_pid_undefined(&pid));
+}
+
static ErlNifFunc nif_funcs[] =
{
{"lib_version", 0, lib_version},
@@ -3615,7 +3675,11 @@ static ErlNifFunc nif_funcs[] =
{"ioq_nif", 1, ioq},
{"ioq_nif", 2, ioq},
{"ioq_nif", 3, ioq},
- {"ioq_nif", 4, ioq}
+ {"ioq_nif", 4, ioq},
+ {"get_local_pid_nif", 1, get_local_pid_nif},
+ {"make_pid_nif", 1, make_pid_nif},
+ {"set_pid_undefined_nif", 0, set_pid_undefined_nif},
+ {"is_pid_undefined_nif", 1, is_pid_undefined_nif}
};
ERL_NIF_INIT(nif_SUITE,nif_funcs,load,NULL,upgrade,unload)
--
cgit v1.2.3
From 1937c8e3f7860ff3dfbeb6d25dd434fcd3102ba8 Mon Sep 17 00:00:00 2001
From: Sverker Eriksson
Date: Wed, 20 Feb 2019 16:06:03 +0100
Subject: erts: Add enif_compare_pids
as a macro wrappper around enif_compare
---
erts/doc/src/erl_nif.xml | 13 +++++++++++++
erts/emulator/beam/erl_nif_api_funcs.h | 1 +
erts/emulator/test/nif_SUITE.erl | 10 +++++++++-
erts/emulator/test/nif_SUITE_data/nif_SUITE.c | 13 ++++++++++++-
4 files changed, 35 insertions(+), 2 deletions(-)
diff --git a/erts/doc/src/erl_nif.xml b/erts/doc/src/erl_nif.xml
index ac873d0c8c..919f9f3245 100644
--- a/erts/doc/src/erl_nif.xml
+++ b/erts/doc/src/erl_nif.xml
@@ -1089,6 +1089,19 @@ typedef struct {
+
+ int
+ enif_compare_pids(const ErlNifPid *pid1, const ErlNifPid *pid2)
+ Compare two pids.
+
+ Compares two ErlNifPid
+ s according to term order.
+ Returns 0 if pid1 and pid2 are equal,
+ < 0 if pid1 < pid2, and
+ > 0 if pid1 > pid2.
+
+
+
void
enif_cond_broadcast(ErlNifCond *cnd)
diff --git a/erts/emulator/beam/erl_nif_api_funcs.h b/erts/emulator/beam/erl_nif_api_funcs.h
index a87f3154a9..8ab454c8dd 100644
--- a/erts/emulator/beam/erl_nif_api_funcs.h
+++ b/erts/emulator/beam/erl_nif_api_funcs.h
@@ -632,6 +632,7 @@ static ERL_NIF_INLINE ERL_NIF_TERM enif_make_list9(ErlNifEnv* env,
#ifndef enif_make_pid
# define enif_make_pid(ENV, PID) ((void)(ENV),(const ERL_NIF_TERM)((PID)->pid))
+# define enif_compare_pids(A, B) (enif_compare((A)->pid,(B)->pid))
# define enif_select_read(ENV, E, OBJ, PID, MSG, MSG_ENV) \
enif_select_x(ENV, E, ERL_NIF_SELECT_READ | ERL_NIF_SELECT_CUSTOM_MSG, \
OBJ, PID, MSG, MSG_ENV)
diff --git a/erts/emulator/test/nif_SUITE.erl b/erts/emulator/test/nif_SUITE.erl
index c2d368bb72..4a0ad9c1d5 100644
--- a/erts/emulator/test/nif_SUITE.erl
+++ b/erts/emulator/test/nif_SUITE.erl
@@ -3381,11 +3381,18 @@ pid(Config) ->
undefined = make_pid_nif(UndefPid),
0 = send_term(UndefPid, message),
+ Other = spawn(fun() -> ok end),
+ {true,OtherNifPid} = get_local_pid_nif(Other),
+ Cmp = compare_pids_nif(ErlNifPid, OtherNifPid),
+ true = if Cmp < 0 -> Self < Other;
+ Cmp > 0 -> Self > Other
+ end,
+ 0 = compare_pids_nif(ErlNifPid, ErlNifPid),
+
{false, _} = get_local_pid_nif(undefined),
ok.
-
id(I) -> I.
%% The NIFs:
@@ -3498,6 +3505,7 @@ get_local_pid_nif(_) -> ?nif_stub.
make_pid_nif(_) -> ?nif_stub.
set_pid_undefined_nif() -> ?nif_stub.
is_pid_undefined_nif(_) -> ?nif_stub.
+compare_pids_nif(_, _) -> ?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 4dbd22fa8c..0d5d900d31 100644
--- a/erts/emulator/test/nif_SUITE_data/nif_SUITE.c
+++ b/erts/emulator/test/nif_SUITE_data/nif_SUITE.c
@@ -3573,6 +3573,16 @@ static ERL_NIF_TERM is_pid_undefined_nif(ErlNifEnv* env, int argc, const ERL_NIF
return make_bool(env, enif_is_pid_undefined(&pid));
}
+static ERL_NIF_TERM compare_pids_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{
+ ErlNifPid a, b;
+
+ if (!get_pidbin(env, argv[0], &a) || !get_pidbin(env, argv[1], &b))
+ return enif_make_badarg(env);
+
+ return enif_make_int(env, enif_compare_pids(&a, &b));
+}
+
static ErlNifFunc nif_funcs[] =
{
{"lib_version", 0, lib_version},
@@ -3679,7 +3689,8 @@ static ErlNifFunc nif_funcs[] =
{"get_local_pid_nif", 1, get_local_pid_nif},
{"make_pid_nif", 1, make_pid_nif},
{"set_pid_undefined_nif", 0, set_pid_undefined_nif},
- {"is_pid_undefined_nif", 1, is_pid_undefined_nif}
+ {"is_pid_undefined_nif", 1, is_pid_undefined_nif},
+ {"compare_pids_nif", 2, compare_pids_nif}
};
ERL_NIF_INIT(nif_SUITE,nif_funcs,load,NULL,upgrade,unload)
--
cgit v1.2.3
From edcec4c9166bfdfbd3131ee1472abcade8ccac15 Mon Sep 17 00:00:00 2001
From: Sverker Eriksson
Date: Thu, 21 Feb 2019 14:51:34 +0100
Subject: fixup! erts: Add enif_compare_pids
fix broken html link
---
erts/doc/src/erl_nif.xml | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/erts/doc/src/erl_nif.xml b/erts/doc/src/erl_nif.xml
index 919f9f3245..cc7452bab5 100644
--- a/erts/doc/src/erl_nif.xml
+++ b/erts/doc/src/erl_nif.xml
@@ -1090,8 +1090,9 @@ typedef struct {
- int
- enif_compare_pids(const ErlNifPid *pid1, const ErlNifPid *pid2)
+ int
+ enif_compare_pids(const ErlNifPid *pid1, const ErlNifPid *pid2)
+
Compare two pids.
Compares two ErlNifPid
--
cgit v1.2.3