aboutsummaryrefslogtreecommitdiffstats
path: root/erts/emulator
diff options
context:
space:
mode:
authorRickard Green <[email protected]>2019-03-20 17:43:24 +0100
committerRickard Green <[email protected]>2019-03-20 18:27:09 +0100
commit938cd607f31559d5497b620b0c5ed8b92972bb27 (patch)
tree8ebdd94f2c68bcacc4431f4b642f02b24951072d /erts/emulator
parenta4f71b669ad9ece1a4afa671601c7c72dc89f042 (diff)
downloadotp-938cd607f31559d5497b620b0c5ed8b92972bb27.tar.gz
otp-938cd607f31559d5497b620b0c5ed8b92972bb27.tar.bz2
otp-938cd607f31559d5497b620b0c5ed8b92972bb27.zip
Fix reception of resume signal on process executing dirty
If a suspend/resume signal pair was sent to a process while it was executing dirty the resume counter on the process got into an inconsistent state. This in turn could cause the process to enter a suspended state indefinitely.
Diffstat (limited to 'erts/emulator')
-rw-r--r--erts/emulator/beam/erl_proc_sig_queue.c10
-rw-r--r--erts/emulator/test/dirty_bif_SUITE.erl54
2 files changed, 60 insertions, 4 deletions
diff --git a/erts/emulator/beam/erl_proc_sig_queue.c b/erts/emulator/beam/erl_proc_sig_queue.c
index 18418a76e1..c95b7057fd 100644
--- a/erts/emulator/beam/erl_proc_sig_queue.c
+++ b/erts/emulator/beam/erl_proc_sig_queue.c
@@ -3247,9 +3247,15 @@ erts_proc_sig_handle_incoming(Process *c_p, erts_aint32_t *statep,
erts_nif_demonitored((ErtsResource *) tmon->other.ptr);
cnt++;
break;
- case ERTS_MON_TYPE_SUSPEND:
- erts_resume(c_p, ERTS_PROC_LOCK_MAIN);
+ case ERTS_MON_TYPE_SUSPEND: {
+ ErtsMonitorSuspend *msp;
+ erts_aint_t mstate;
+ msp = (ErtsMonitorSuspend *) erts_monitor_to_data(tmon);
+ mstate = erts_atomic_read_acqb(&msp->state);
+ if (mstate & ERTS_MSUSPEND_STATE_FLG_ACTIVE)
+ erts_resume(c_p, ERTS_PROC_LOCK_MAIN);
break;
+ }
default:
break;
}
diff --git a/erts/emulator/test/dirty_bif_SUITE.erl b/erts/emulator/test/dirty_bif_SUITE.erl
index 46eb0cba58..4f5ad0295a 100644
--- a/erts/emulator/test/dirty_bif_SUITE.erl
+++ b/erts/emulator/test/dirty_bif_SUITE.erl
@@ -38,7 +38,8 @@
dirty_process_info/1,
dirty_process_register/1,
dirty_process_trace/1,
- code_purge/1]).
+ code_purge/1,
+ otp_15688/1]).
suite() -> [{ct_hooks,[ts_install_cth]}].
@@ -64,7 +65,8 @@ all() ->
dirty_process_info,
dirty_process_register,
dirty_process_trace,
- code_purge].
+ code_purge,
+ otp_15688].
init_per_suite(Config) ->
case erlang:system_info(dirty_cpu_schedulers) of
@@ -498,10 +500,58 @@ code_purge(Config) when is_list(Config) ->
true = Time =< 1000,
ok.
+otp_15688(Config) when is_list(Config) ->
+ ImBack = make_ref(),
+ {See, SeeMon} = spawn_monitor(fun () ->
+ erts_debug:dirty_io(wait, 2000),
+ exit(ImBack)
+ end),
+ wait_until(fun () ->
+ [{current_function, {erts_debug, dirty_io, 2}},
+ {status, running}]
+ == process_info(See,
+ [current_function, status])
+ end),
+ {Ser1, Ser1Mon} = spawn_monitor(fun () ->
+ erlang:suspend_process(See,
+ [asynchronous])
+ end),
+ erlang:suspend_process(See, [asynchronous]),
+ receive {'DOWN', Ser1Mon, process, Ser1, normal} -> ok end,
+
+ %% Verify that we sent the suspend request while it was executing dirty...
+ [{current_function, {erts_debug, dirty_io, 2}},
+ {status, running}] = process_info(See, [current_function, status]),
+
+ wait_until(fun () ->
+ {status, suspended} == process_info(See, status)
+ end),
+ erlang:resume_process(See),
+
+ receive
+ {'DOWN', SeeMon, process, See, Reason} ->
+ ImBack = Reason
+ after 4000 ->
+ %% Resume bug seems to have hit us...
+ PI = process_info(See),
+ exit(See, kill),
+ ct:fail({suspendee_stuck, PI})
+ end.
+
+
%%
%% Internal...
%%
+wait_until(Fun) ->
+ case Fun() of
+ true ->
+ ok;
+ _ ->
+ receive after 100 -> ok end,
+ wait_until(Fun)
+ end.
+
access_dirty_process(Config, Start, Test, Finish) ->
{ok, Node} = start_node(Config, ""),
[ok] = mcall(Node,