From 4d3c48a050e2d28a41b75c3b02b48520659e52e6 Mon Sep 17 00:00:00 2001
From: Rickard Green <rickard@erlang.org>
Date: Mon, 2 May 2016 16:17:42 +0200
Subject: Add dirty_call_while_terminated test case

---
 erts/emulator/test/dirty_nif_SUITE.erl             | 59 +++++++++++++++++++++-
 .../test/dirty_nif_SUITE_data/dirty_nif_SUITE.c    | 42 +++++++++++++++
 2 files changed, 99 insertions(+), 2 deletions(-)

(limited to 'erts')

diff --git a/erts/emulator/test/dirty_nif_SUITE.erl b/erts/emulator/test/dirty_nif_SUITE.erl
index 963b2c5db1..71fbf17a2e 100644
--- a/erts/emulator/test/dirty_nif_SUITE.erl
+++ b/erts/emulator/test/dirty_nif_SUITE.erl
@@ -31,7 +31,7 @@
 	 init_per_testcase/2, end_per_testcase/2,
 	 dirty_nif/1, dirty_nif_send/1,
 	 dirty_nif_exception/1, call_dirty_nif_exception/1,
-	 dirty_scheduler_exit/1]).
+	 dirty_scheduler_exit/1, dirty_call_while_terminated/1]).
 
 -define(nif_stub,nif_stub_error(?LINE)).
 
@@ -41,7 +41,8 @@ all() ->
     [dirty_nif,
      dirty_nif_send,
      dirty_nif_exception,
-     dirty_scheduler_exit].
+     dirty_scheduler_exit,
+     dirty_call_while_terminated].
 
 init_per_suite(Config) ->
     try erlang:system_info(dirty_cpu_schedulers) of
@@ -184,6 +185,59 @@ wait_dse([Pid|Pids]) ->
     end,
     wait_dse(Pids).
 
+dirty_call_while_terminated(Config) when is_list(Config) ->
+    Me = self(),
+    Bin = list_to_binary(lists:duplicate(4711, $r)),
+    {value, {BinAddr, 4711, 1}} = lists:keysearch(4711, 2,
+						  element(2,
+							  process_info(self(),
+								       binary))),
+    {Dirty, DM} = spawn_opt(fun () ->
+				    dirty_call_while_terminated_nif(Me),
+				    blipp:blupp(Bin)
+			    end,
+			    [monitor,link]),
+    receive {dirty_alive, Pid} -> ok end,
+    {value, {BinAddr, 4711, 2}} = lists:keysearch(4711, 2,
+						  element(2,
+							  process_info(self(),
+								       binary))),
+    Reason = die_dirty_process,
+    OT = process_flag(trap_exit, true),
+    exit(Dirty, Reason),
+    receive
+	{'DOWN', DM, process, Dirty, R0} ->
+	    R0 = Reason
+    end,
+    receive
+	{'EXIT', Dirty, R1} ->
+	    R1 = Reason
+    end,
+    undefined = process_info(Dirty),
+    undefined = process_info(Dirty, status),
+    false = erlang:is_process_alive(Dirty),
+    false = lists:member(Dirty, processes()),
+    %% Binary still refered by Dirty process not yet cleaned up
+    %% since the dirty nif has not yet returned...
+    {value, {BinAddr, 4711, 2}} = lists:keysearch(4711, 2,
+						  element(2,
+							  process_info(self(),
+								       binary))),
+    receive after 2000 -> ok end,
+    receive
+	Msg ->
+	    ct:fail({unexpected_message, Msg})
+    after
+	0 ->
+	    ok
+    end,
+    {value, {BinAddr, 4711, 1}} = lists:keysearch(4711, 2,
+						  element(2,
+							  process_info(self(),
+								       binary))),
+    process_flag(trap_exit, OT),
+    ok.
+
 %%
 %% Internal...
 %%
@@ -234,6 +288,7 @@ call_dirty_nif(_,_,_) -> ?nif_stub.
 send_from_dirty_nif(_) -> ?nif_stub.
 call_dirty_nif_exception(_) -> ?nif_stub.
 call_dirty_nif_zero_args() -> ?nif_stub.
+dirty_call_while_terminated_nif(_) -> ?nif_stub.
 dirty_sleeper() -> ?nif_stub.
 
 nif_stub_error(Line) ->
diff --git a/erts/emulator/test/dirty_nif_SUITE_data/dirty_nif_SUITE.c b/erts/emulator/test/dirty_nif_SUITE_data/dirty_nif_SUITE.c
index 72ceb300c9..8de60d1020 100644
--- a/erts/emulator/test/dirty_nif_SUITE_data/dirty_nif_SUITE.c
+++ b/erts/emulator/test/dirty_nif_SUITE_data/dirty_nif_SUITE.c
@@ -156,6 +156,47 @@ dirty_sleeper(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
     return enif_make_atom(env, "ok");
 }
 
+static ERL_NIF_TERM dirty_call_while_terminated_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{
+    ErlNifPid self;
+    ERL_NIF_TERM result, self_term;
+    ErlNifPid to;
+    ErlNifEnv* menv;
+    int res;
+
+    if (!enif_get_local_pid(env, argv[0], &to))
+	return enif_make_badarg(env);
+
+    if (!enif_self(env, &self))
+	return enif_make_badarg(env);
+
+    self_term = enif_make_pid(env, &self);
+
+    result = enif_make_tuple2(env, enif_make_atom(env, "dirty_alive"), self_term);
+    menv = enif_alloc_env();
+    res = enif_send(env, &to, menv, result);
+    enif_free_env(menv);
+    if (!res)
+	return enif_make_badarg(env);
+
+    /* Wait until we have been killed */
+    while (enif_is_process_alive(env, &self))
+	;
+
+    result = enif_make_tuple2(env, enif_make_atom(env, "dirty_dead"), self_term);
+    menv = enif_alloc_env();
+    res = enif_send(env, &to, menv, result);
+    enif_free_env(menv);
+
+#ifdef __WIN32__
+    Sleep(1000);
+#else
+    sleep(1);
+#endif
+
+    return enif_make_atom(env, "ok");
+}
+
 static ErlNifFunc nif_funcs[] =
 {
     {"lib_loaded", 0, lib_loaded},
@@ -164,6 +205,7 @@ static ErlNifFunc nif_funcs[] =
     {"call_dirty_nif_exception", 1, call_dirty_nif_exception, ERL_NIF_DIRTY_JOB_IO_BOUND},
     {"call_dirty_nif_zero_args", 0, call_dirty_nif_zero_args, ERL_NIF_DIRTY_JOB_CPU_BOUND},
     {"dirty_sleeper", 0, dirty_sleeper, ERL_NIF_DIRTY_JOB_IO_BOUND},
+    {"dirty_call_while_terminated_nif", 1, dirty_call_while_terminated_nif, ERL_NIF_DIRTY_JOB_CPU_BOUND}
 };
 
 ERL_NIF_INIT(dirty_nif_SUITE,nif_funcs,load,NULL,NULL,NULL)
-- 
cgit v1.2.3