Skip to content

Commit 4be9a7e

Browse files
author
Erlang/OTP
committed
Merge branch 'jcpetruzza/fix_suspend_internal_error/OTP-19799' into maint-27
* jcpetruzza/fix_suspend_internal_error/OTP-19799: Testcase Fix unsafe access to process struct from dirty sched Fix suspend_process() issue on processes in dirty schedulers
2 parents 70305a4 + 410680d commit 4be9a7e

File tree

2 files changed

+99
-4
lines changed

2 files changed

+99
-4
lines changed

erts/emulator/beam/erl_proc_sig_queue.c

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5046,6 +5046,7 @@ sync_suspend_reply(Process *c_p, ErtsMessage *mp, erts_aint32_t state)
50465046
*/
50475047
Process *rp;
50485048
ErtsSyncSuspendRequest *ssusp;
5049+
int is_managed;
50495050

50505051
ssusp = (ErtsSyncSuspendRequest *) (char *) (&mp->hfrag.mem[0]
50515052
+ mp->hfrag.used_size);
@@ -5065,7 +5066,10 @@ sync_suspend_reply(Process *c_p, ErtsMessage *mp, erts_aint32_t state)
50655066
mp->data.attached = ERTS_MSG_COMBINED_HFRAG;
50665067
mp->next = NULL;
50675068

5068-
rp = erts_proc_lookup(ssusp->requester);
5069+
is_managed = erts_thr_progress_is_managed_thread();
5070+
rp = (is_managed
5071+
? erts_proc_lookup(ssusp->requester)
5072+
: erts_proc_lookup_inc_refc(ssusp->requester));
50695073
if (!rp)
50705074
erts_cleanup_messages(mp);
50715075
else {
@@ -5084,6 +5088,8 @@ sync_suspend_reply(Process *c_p, ErtsMessage *mp, erts_aint32_t state)
50845088
}
50855089
ERL_MESSAGE_TOKEN(mp) = am_undefined;
50865090
erts_queue_proc_message(c_p, rp, 0, mp, ssusp->message);
5091+
if (!is_managed)
5092+
erts_proc_dec_refc(rp);
50875093
}
50885094
}
50895095

@@ -5229,6 +5235,8 @@ erts_proc_sig_handle_pending_suspend(Process *c_p)
52295235
msp = next_msp;
52305236
}
52315237

5238+
state = erts_atomic32_read_nob(&c_p->state);
5239+
52325240
sync = psusp->sync;
52335241

52345242
while (sync) {

erts/emulator/test/dirty_bif_SUITE.erl

Lines changed: 90 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,8 @@
3939
dirty_process_register/1,
4040
dirty_process_trace/1,
4141
code_purge/1,
42-
otp_15688/1]).
42+
otp_15688/1,
43+
suspend_process/1]).
4344

4445
suite() -> [{ct_hooks,[ts_install_cth]}].
4546

@@ -66,7 +67,8 @@ all() ->
6667
dirty_process_register,
6768
dirty_process_trace,
6869
code_purge,
69-
otp_15688].
70+
otp_15688,
71+
suspend_process].
7072

7173
init_per_suite(Config) ->
7274
case erlang:system_info(dirty_cpu_schedulers) of
@@ -539,7 +541,92 @@ otp_15688(Config) when is_list(Config) ->
539541
exit(See, kill),
540542
ct:fail({suspendee_stuck, PI})
541543
end.
542-
544+
545+
suspend_process(Config) when is_list(Config) ->
546+
Go = make_ref(),
547+
AS = make_ref(),
548+
Tester = self(),
549+
P = spawn_link(fun () ->
550+
receive {Go, 1} -> ok end,
551+
Tester ! {Go, 2},
552+
erts_debug:dirty_io(wait, 500),
553+
receive {Go, 3}-> ok end,
554+
Tester ! {Go, 4},
555+
erts_debug:dirty_io(wait, 500),
556+
receive {Go, 5} -> ok end,
557+
Tester ! {Go, 6},
558+
erts_debug:dirty_cpu(wait, 500),
559+
receive {Go, 7} -> ok end,
560+
Tester ! {Go, 8},
561+
erts_debug:dirty_cpu(wait, 500)
562+
end),
563+
564+
%% Sync DIO
565+
{status, Status1} = erlang:process_info(P, status),
566+
false = Status1 == suspended,
567+
568+
P ! {Go, 1},
569+
receive {Go, 2} -> ok end,
570+
erlang:yield(),
571+
true = erlang:suspend_process(P),
572+
573+
{status, Status2} = erlang:process_info(P, status),
574+
true = Status2 == suspended,
575+
576+
true = erlang:resume_process(P),
577+
578+
%% Async DIO
579+
{status, Status3} = erlang:process_info(P, status),
580+
false = Status3 == suspended,
581+
582+
P ! {Go, 3},
583+
receive {Go, 4} -> ok end,
584+
erlang:yield(),
585+
586+
true = erlang:suspend_process(P, [{asynchronous, AS}]),
587+
receive {AS, What1} -> suspended = What1 end,
588+
589+
{status, Status4} = erlang:process_info(P, status),
590+
true = Status4 == suspended,
591+
592+
true = erlang:resume_process(P),
593+
594+
%% Sync DCPU
595+
{status, Status5} = erlang:process_info(P, status),
596+
false = Status5 == suspended,
597+
598+
P ! {Go, 5},
599+
receive {Go, 6} -> ok end,
600+
erlang:yield(),
601+
602+
true = erlang:suspend_process(P),
603+
604+
{status, Status6} = erlang:process_info(P, status),
605+
true = Status6 == suspended,
606+
607+
true = erlang:resume_process(P),
608+
609+
%% Async DCPU
610+
{status, Status7} = erlang:process_info(P, status),
611+
false = Status7 == suspended,
612+
613+
P ! {Go, 7},
614+
receive {Go, 8} -> ok end,
615+
erlang:yield(),
616+
617+
true = erlang:suspend_process(P, [{asynchronous, AS}]),
618+
receive {AS, What2} -> suspended = What2 end,
619+
620+
{status, Status8} = erlang:process_info(P, status),
621+
true = Status8 == suspended,
622+
623+
true = erlang:resume_process(P),
624+
625+
unlink(P),
626+
exit(P, kill),
627+
false = is_process_alive(P),
628+
629+
ok.
543630

544631
%%
545632
%% Internal...

0 commit comments

Comments
 (0)