diff options
author | Lukas Larsson <[email protected]> | 2017-02-22 15:39:35 +0100 |
---|---|---|
committer | Lukas Larsson <[email protected]> | 2017-02-22 15:39:35 +0100 |
commit | 833de830b9805666f3a6a3752d5339aa0a577a3e (patch) | |
tree | c60e0af4fc37cb9d009a2c96b0ec3c8aaf5b5422 /lib/kernel/src/os.erl | |
parent | ae5ab58d64d18365a9b94a780760fd9c50119900 (diff) | |
parent | bf9f79e81530b37d5ac4abe1494f270986d92cb4 (diff) | |
download | otp-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/src/os.erl')
-rw-r--r-- | lib/kernel/src/os.erl | 24 |
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. |