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(-) (limited to 'erts') 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.

ErlNifPort

A port identifier. In contrast to port ID terms (instances of ERL_NIF_TERM), ErlNifPorts are self-contained and not bound to any environment. - ErlNifPort is an opaque type.

+ ErlNifPort is an opaque type. It can be copied, moved + in memory, forgotten, and so on.

ErlNifResourceType @@ -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(-) (limited to 'erts') 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(-) (limited to 'erts') 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