diff options
-rw-r--r-- | erts/doc/src/erl_nif.xml | 56 | ||||
-rw-r--r-- | erts/emulator/beam/erl_nif.c | 14 | ||||
-rw-r--r-- | erts/emulator/beam/erl_nif_api_funcs.h | 6 | ||||
-rw-r--r-- | erts/emulator/sys/common/erl_check_io.c | 1 | ||||
-rw-r--r-- | erts/emulator/test/nif_SUITE.erl | 36 | ||||
-rw-r--r-- | erts/emulator/test/nif_SUITE_data/nif_SUITE.c | 79 |
6 files changed, 182 insertions, 10 deletions
diff --git a/erts/doc/src/erl_nif.xml b/erts/doc/src/erl_nif.xml index d58ebd3171..cc7452bab5 100644 --- a/erts/doc/src/erl_nif.xml +++ b/erts/doc/src/erl_nif.xml @@ -783,14 +783,16 @@ typedef struct { <p>A process identifier (pid). In contrast to pid terms (instances of <c>ERL_NIF_TERM</c>), <c>ErlNifPid</c>s are self-contained and not bound to any <seealso marker="#ErlNifEnv">environment</seealso>. - <c>ErlNifPid</c> is an opaque type.</p> + <c>ErlNifPid</c> is an opaque type. It can be copied, moved + in memory, forgotten, and so on.</p> </item> <tag><marker id="ErlNifPort"/><c>ErlNifPort</c></tag> <item> <p>A port identifier. In contrast to port ID terms (instances of <c>ERL_NIF_TERM</c>), <c>ErlNifPort</c>s are self-contained and not bound to any <seealso marker="#ErlNifEnv">environment</seealso>. - <c>ErlNifPort</c> is an opaque type.</p> + <c>ErlNifPort</c> is an opaque type. It can be copied, moved + in memory, forgotten, and so on.</p> </item> <tag><marker id="ErlNifResourceType"/><c>ErlNifResourceType</c></tag> <item> @@ -1088,6 +1090,20 @@ typedef struct { </func> <func> + <name since="OTP @OTP-15011@"><ret>int</ret> + <nametext>enif_compare_pids(const ErlNifPid *pid1, const ErlNifPid *pid2) + </nametext></name> + <fsummary>Compare two pids.</fsummary> + <desc> + <p>Compares two <seealso marker="#ErlNifPid"><c>ErlNifPid</c> + </seealso>s according to term order.</p> + <p>Returns <c>0</c> if <c>pid1</c> and <c>pid2</c> are equal, + < <c>0</c> if <c>pid1</c> < <c>pid2</c>, and + > <c>0</c> if <c>pid1</c> > <c>pid2</c>.</p> + </desc> + </func> + + <func> <name since="OTP R13B04"><ret>void</ret> <nametext>enif_cond_broadcast(ErlNifCond *cnd)</nametext></name> <fsummary></fsummary> @@ -1392,6 +1408,9 @@ enif_free_iovec(iovec);]]></code> initializes the pid variable <c>*pid</c> from it and returns <c>true</c>. Otherwise returns <c>false</c>. No check is done to see if the process is alive.</p> + <note><p><c>enif_get_local_pid</c> will return false if argument + <c>term</c> is the atom <seealso marker="#enif_make_pid"> + <c>undefined</c></seealso>.</p></note> </desc> </func> @@ -1871,6 +1890,17 @@ enif_inspect_iovec(env, max_elements, term, &tail, &iovec); </func> <func> + <name since="OTP @OTP-15011@"><ret>int</ret> + <nametext>enif_is_pid_undefined(const ErlNifPid* pid)</nametext></name> + <fsummary>Determine if pid is undefined.</fsummary> + <desc> + <p>Returns <c>true</c> if <c>pid</c> has been set as undefined by + <seealso marker="#enif_set_pid_undefined"><c>enif_set_pid_undefined</c> + </seealso>.</p> + </desc> + </func> + + <func> <name since="OTP R13B04"><ret>int</ret> <nametext>enif_is_port(ErlNifEnv* env, ERL_NIF_TERM term)</nametext> </name> @@ -2259,7 +2289,8 @@ enif_inspect_iovec(env, max_elements, term, &tail, &iovec); </name> <fsummary>Make a pid term.</fsummary> <desc> - <p>Makes a pid term from <c>*pid</c>.</p> + <p>Makes a pid term or the atom <seealso marker="#enif_set_pid_undefined"> + <c>undefined</c></seealso> from <c>*pid</c>.</p> </desc> </func> @@ -2625,7 +2656,9 @@ enif_map_iterator_destroy(env, &iter);</code> <p>Argument <c>caller_env</c> is the environment of the calling process or callback. Must only be NULL if calling from a custom thread.</p> <p>Returns <c>0</c> on success, < 0 if no <c>down</c> callback is - provided, and > 0 if the process is no longer alive.</p> + provided, and > 0 if the process is no longer alive or if + <c>target_pid</c> is <seealso marker="#enif_set_pid_undefined"> + undefined</seealso>.</p> <p>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.</p> @@ -3080,7 +3113,9 @@ enif_map_iterator_destroy(env, &iter);</code> <seealso marker="#enif_select_write"><c>enif_select_write</c></seealso> introduced in erts-11.0 (OTP-22.0).</p> </note> - <p>Argument <c>pid</c> may be <c>NULL</c> to indicate the calling process.</p> + <p>Argument <c>pid</c> may be <c>NULL</c> to indicate the calling + process. It must not be set as <seealso marker="#enif_set_pid_undefined"> + undefined</seealso>.</p> <p>Argument <c>obj</c> is a resource object obtained from <seealso marker="#enif_alloc_resource"><c>enif_alloc_resource</c></seealso>. The purpose of the resource objects is as a container of the event object @@ -3271,6 +3306,17 @@ if (retval & ERL_NIF_SELECT_STOP_CALLED) { </func> <func> + <name since="OTP @OTP-15011@"><ret>void</ret> + <nametext>enif_set_pid_undefined(ErlNifPid* pid)</nametext></name> + <fsummary>Set pid as undefined.</fsummary> + <desc> + <p>Sets an <seealso marker="#ErlNifPid"><c>ErlNifPid</c></seealso> + variable as undefined. See <seealso marker="#enif_is_pid_undefined"> + <c>enif_is_pid_undefined</c></seealso>.</p> + </desc> + </func> + + <func> <name since="OTP R13B04"><ret>unsigned</ret> <nametext>enif_sizeof_resource(void* obj)</nametext></name> <fsummary>Get the byte size of a resource object.</fsummary> diff --git a/erts/emulator/beam/erl_nif.c b/erts/emulator/beam/erl_nif.c index b2bd28fcbb..349d9bf13a 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)) { @@ -3341,6 +3352,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..8ab454c8dd 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) @@ -629,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/sys/common/erl_check_io.c b/erts/emulator/sys/common/erl_check_io.c index a699ece23e..80e8030d74 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..4a0ad9c1d5 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,30 @@ 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), + + 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: @@ -3475,5 +3501,11 @@ 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. +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 af2d062857..0d5d900d31 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,65 @@ 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 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}, @@ -3615,7 +3685,12 @@ 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}, + {"compare_pids_nif", 2, compare_pids_nif} }; ERL_NIF_INIT(nif_SUITE,nif_funcs,load,NULL,upgrade,unload) |