From 6b414fbc67d2c7f703fe677f2acda1a6fa67d8ed Mon Sep 17 00:00:00 2001
From: Sverker Eriksson <sverker@erlang.org>
Date: Tue, 19 Mar 2019 20:01:45 +0100
Subject: erts: Add test of enif_whereis* from resource destructor

---
 erts/emulator/test/nif_SUITE.erl              | 27 ++++++++++++++-------
 erts/emulator/test/nif_SUITE_data/nif_SUITE.c | 34 ++++++++++++++++++---------
 2 files changed, 41 insertions(+), 20 deletions(-)

(limited to 'erts')

diff --git a/erts/emulator/test/nif_SUITE.erl b/erts/emulator/test/nif_SUITE.erl
index 6ca0990a8a..d8c2cb0e43 100644
--- a/erts/emulator/test/nif_SUITE.erl
+++ b/erts/emulator/test/nif_SUITE.erl
@@ -3065,22 +3065,31 @@ nif_whereis_threaded(Config) when is_list(Config) ->
     RegName = nif_whereis_test_threaded,
     undefined = erlang:whereis(RegName),
 
-    Ref = make_ref(),
-    {Pid, Mon} = spawn_monitor(?MODULE, nif_whereis_proxy, [Ref]),
-    true = register(RegName, Pid),
+    Self = self(),
+    true = register(RegName, Self),
 
-    {ok, ProcThr} = whereis_thd_lookup(pid, RegName),
-    {ok, Pid} = whereis_thd_result(ProcThr),
+    {ok, ProcThr} = whereis_thd_lookup(pid, RegName, "dtor to proc"),
+    {ok, Self} = whereis_thd_result(ProcThr),
 
-    Pid ! {Ref, quit},
-    ok = receive {'DOWN', Mon, process, Pid, normal} -> ok end,
+    nif_whereis_threaded_2(RegName).
+
+nif_whereis_threaded_2(RegName) ->
+    erlang:garbage_collect(),
+    "dtor to proc" = receive_any(1000),
+    true = unregister(RegName),
 
     Port = open_port({spawn, echo_drv}, [eof]),
     true = register(RegName, Port),
 
-    {ok, PortThr} = whereis_thd_lookup(port, RegName),
+    {ok, PortThr} = whereis_thd_lookup(port, RegName, "dtor to port"),
     {ok, Port} = whereis_thd_result(PortThr),
 
+    nif_whereis_threaded_3(Port).
+
+nif_whereis_threaded_3(Port) ->
+    erlang:garbage_collect(),
+    {Port, {data, "dtor to port"}} = receive_any(1000),
+
     port_close(Port),
     ok.
 
@@ -3426,7 +3435,7 @@ ioq_nif(_,_,_,_) -> ?nif_stub.
 %% whereis
 whereis_send(_Type,_Name,_Msg) -> ?nif_stub.
 whereis_term(_Type,_Name) -> ?nif_stub.
-whereis_thd_lookup(_Type,_Name) -> ?nif_stub.
+whereis_thd_lookup(_Type,_Name, _Msg) -> ?nif_stub.
 whereis_thd_result(_Thd) -> ?nif_stub.
 
 %% maps
diff --git a/erts/emulator/test/nif_SUITE_data/nif_SUITE.c b/erts/emulator/test/nif_SUITE_data/nif_SUITE.c
index 9ae5966e80..463aa3b246 100644
--- a/erts/emulator/test/nif_SUITE_data/nif_SUITE.c
+++ b/erts/emulator/test/nif_SUITE_data/nif_SUITE.c
@@ -1217,6 +1217,7 @@ typedef struct {
     ErlNifTid tid;
     int type;
     int rc;
+    ERL_NIF_TERM dtor_msg;
 } whereis_thread_resource_t;
 
 static whereis_thread_resource_t* whereis_thread_resource_create(void)
@@ -1229,9 +1230,21 @@ static whereis_thread_resource_t* whereis_thread_resource_create(void)
     return rp;
 }
 
+static int whereis_lookup_internal(ErlNifEnv*, int type, ERL_NIF_TERM name,
+                                   whereis_term_data_t* out);
+static int whereis_send_internal(ErlNifEnv*, int type, whereis_term_data_t* to,
+                                 ERL_NIF_TERM msg);
+
+
 static void whereis_thread_resource_dtor(ErlNifEnv* env, void* obj)
 {
     whereis_thread_resource_t* rp = (whereis_thread_resource_t*) obj;
+    whereis_term_data_t to;
+
+    if (whereis_lookup_internal(env, rp->type, rp->name, &to)
+        == WHEREIS_SUCCESS) {
+        whereis_send_internal(env, rp->type, &to, rp->dtor_msg);
+    }
     enif_free_env(rp->env);
 }
 
@@ -1323,7 +1336,6 @@ static ERL_NIF_TERM
 whereis_term(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
 {
     whereis_term_data_t res;
-    ERL_NIF_TERM ret;
     int type, rc;
 
     assert(argc == 2);
@@ -1357,12 +1369,13 @@ whereis_send(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
     return whereis_result_term(env, rc);
 }
 
-/* whereis_thd_lookup(Type, Name) -> {ok, Resource} | {error, SysErrno} */
+/* whereis_thd_lookup(Type, Name, DtorMsg) -> {ok, Resource} | {error, SysErrno} */
 static ERL_NIF_TERM
 whereis_thd_lookup(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
 {
     whereis_thread_resource_t* rp;
     int type, rc;
+    ERL_NIF_TERM ret;
 
     assert(argc == 3);
     if (!enif_is_atom(env, argv[1]))
@@ -1374,17 +1387,17 @@ whereis_thd_lookup(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
     rp = whereis_thread_resource_create();
     rp->type = type;
     rp->name = enif_make_copy(rp->env, argv[1]);
+    rp->dtor_msg = enif_make_copy(rp->env, argv[2]);
 
     rc = enif_thread_create(
         "nif_SUITE:whereis_thd", & rp->tid, whereis_lookup_thread, rp, NULL);
 
-    if (rc == 0) {
-        return enif_make_tuple2(env, atom_ok, enif_make_resource(env, rp));
-    }
-    else {
-        enif_release_resource(rp);
-        return enif_make_tuple2(env, atom_error, enif_make_int(env, rc));
-    }
+    if (rc == 0)
+        ret = enif_make_tuple2(env, atom_ok, enif_make_resource(env, rp));
+    else
+        ret = enif_make_tuple2(env, atom_error, enif_make_int(env, rc));
+    enif_release_resource(rp);
+    return ret;
 }
 
 /* whereis_thd_result(Resource) -> {ok, pid() | port()} | {error, ErrNum} */
@@ -1409,7 +1422,6 @@ whereis_thd_result(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
     else
         ret = whereis_result_term(env, rp->rc);
     
-    enif_release_resource(rp);
     return ret;
 }
 
@@ -3564,7 +3576,7 @@ static ErlNifFunc nif_funcs[] =
     {"monitor_frenzy_nif", 4, monitor_frenzy_nif},
     {"whereis_send", 3, whereis_send},
     {"whereis_term", 2, whereis_term},
-    {"whereis_thd_lookup", 2, whereis_thd_lookup},
+    {"whereis_thd_lookup", 3, whereis_thd_lookup},
     {"whereis_thd_result", 1, whereis_thd_result},
     {"ioq_nif", 1, ioq},
     {"ioq_nif", 2, ioq},
-- 
cgit v1.2.3