aboutsummaryrefslogtreecommitdiffstats
path: root/lib/kernel
diff options
context:
space:
mode:
authorLukas Larsson <[email protected]>2017-02-22 15:39:35 +0100
committerLukas Larsson <[email protected]>2017-02-22 15:39:35 +0100
commit833de830b9805666f3a6a3752d5339aa0a577a3e (patch)
treec60e0af4fc37cb9d009a2c96b0ec3c8aaf5b5422 /lib/kernel
parentae5ab58d64d18365a9b94a780760fd9c50119900 (diff)
parentbf9f79e81530b37d5ac4abe1494f270986d92cb4 (diff)
downloadotp-833de830b9805666f3a6a3752d5339aa0a577a3e.tar.gz
otp-833de830b9805666f3a6a3752d5339aa0a577a3e.tar.bz2
otp-833de830b9805666f3a6a3752d5339aa0a577a3e.zip
Merge branch 'lukas/kernel/fix_os_cmd_close_race/OTP-14232' into maint
* lukas/kernel/fix_os_cmd_close_race/OTP-14232: kernel: Fix hanging os:cmd race condition
Diffstat (limited to 'lib/kernel')
-rw-r--r--lib/kernel/src/os.erl24
1 files changed, 15 insertions, 9 deletions
diff --git a/lib/kernel/src/os.erl b/lib/kernel/src/os.erl
index f8519d3a5e..03d4324992 100644
--- a/lib/kernel/src/os.erl
+++ b/lib/kernel/src/os.erl
@@ -289,12 +289,11 @@ get_data(Port, MonRef, Eot, Sofar) ->
more ->
get_data(Port, MonRef, Eot, [Sofar,Bytes]);
Last ->
- Port ! {self(), close},
- flush_until_closed(Port),
- flush_exit(Port),
+ catch port_close(Port),
+ flush_until_down(Port, MonRef),
iolist_to_binary([Sofar, Last])
end;
- {'DOWN', MonRef, _, _ , _} ->
+ {'DOWN', MonRef, _, _, _} ->
flush_exit(Port),
iolist_to_binary(Sofar)
end.
@@ -308,18 +307,25 @@ eot(Bs, Eot) ->
binary:part(Bs,{0, Pos})
end.
-flush_until_closed(Port) ->
+%% When port_close returns we know that all the
+%% messages sent have been sent and that the
+%% DOWN message is after them all.
+flush_until_down(Port, MonRef) ->
receive
{Port, {data, _Bytes}} ->
- flush_until_closed(Port);
- {Port, closed} ->
- true
+ flush_until_down(Port, MonRef);
+ {'DOWN', MonRef, _, _, _} ->
+ flush_exit(Port)
end.
+%% The exit signal is always delivered before
+%% the down signal, so we can be sure that if there
+%% was an exit message sent, it will be in the
+%% mailbox now.
flush_exit(Port) ->
receive
{'EXIT', Port, _} ->
ok
- after 1 -> % force context switch
+ after 0 ->
ok
end.