diff options
author | John Högberg <[email protected]> | 2019-05-07 11:39:34 +0200 |
---|---|---|
committer | John Högberg <[email protected]> | 2019-05-07 14:22:36 +0200 |
commit | 4df8cf1f67a12d2c730e85ab4de64b6fd7557050 (patch) | |
tree | b737b8be2a5c913f2a4766b34a7c23ab7ae3a986 | |
parent | 0e10a805bde0f1ce8ba9282660aaa2fd1e01fc81 (diff) | |
download | otp-4df8cf1f67a12d2c730e85ab4de64b6fd7557050.tar.gz otp-4df8cf1f67a12d2c730e85ab4de64b6fd7557050.tar.bz2 otp-4df8cf1f67a12d2c730e85ab4de64b6fd7557050.zip |
kernel: Force synchronous port_commands in user/user_drv
Banging data to a local port was always synchronous prior to
Erlang/OTP R16, and these modules relied on that behavior to report
that data had successfully been enqueued on the stdout port. This
would cause data to be silently dropped if the command didn't run
synchronously and the emulator halted before the port received the
data.
This was fairly rare in practice, but could be seen from time to
time on Windows with escripts that ended with a call to
io:format/2, such as the one used by the
escript_SUITE:create_and_extract test.
This is a minimal band-aid to make things reliable again. A more
complete fix would add explicit synchronization with the port.
-rw-r--r-- | lib/kernel/src/user.erl | 3 | ||||
-rw-r--r-- | lib/kernel/src/user_drv.erl | 37 |
2 files changed, 18 insertions, 22 deletions
diff --git a/lib/kernel/src/user.erl b/lib/kernel/src/user.erl index 0c9e1ea303..5a3487a9ba 100644 --- a/lib/kernel/src/user.erl +++ b/lib/kernel/src/user.erl @@ -296,7 +296,8 @@ io_requests([], Stat, _) -> %% port. put_port(List, Port) -> - send_port(Port, {command, List}). + true = port_command(Port, List), + ok. %% send_port(Port, Command) diff --git a/lib/kernel/src/user_drv.erl b/lib/kernel/src/user_drv.erl index 69ff8e7971..644aa752b6 100644 --- a/lib/kernel/src/user_drv.erl +++ b/lib/kernel/src/user_drv.erl @@ -543,19 +543,14 @@ set_unicode_state(Iport, Bool) -> %% io_request(Request, InPort, OutPort) %% io_requests(Requests, InPort, OutPort) %% Note: InPort is unused. - -io_request(Request, Iport, Oport) -> - try io_command(Request) of - {command,_} = Command -> - Oport ! {self(),Command}, - ok; - {Command,Reply} -> - Oport ! {self(),Command}, - Reply - catch - {requests,Rs} -> - io_requests(Rs, Iport, Oport); - _ -> +io_request({requests,Rs}, Iport, Oport) -> + io_requests(Rs, Iport, Oport); +io_request(Request, _Iport, Oport) -> + case io_command(Request) of + {Data, Reply} -> + true = port_command(Oport, Data), + Reply; + unhandled -> ok end. @@ -575,19 +570,19 @@ put_int16(N, Tail) -> %% to the console before the vm stops when calling erlang:halt(integer()). -dialyzer({no_improper_lists, io_command/1}). io_command({put_chars_sync, unicode,Cs,Reply}) -> - {{command,[?OP_PUTC_SYNC|unicode:characters_to_binary(Cs,utf8)]},Reply}; + {[?OP_PUTC_SYNC|unicode:characters_to_binary(Cs,utf8)], Reply}; io_command({put_chars, unicode,Cs}) -> - {command,[?OP_PUTC|unicode:characters_to_binary(Cs,utf8)]}; + {[?OP_PUTC|unicode:characters_to_binary(Cs,utf8)], ok}; io_command({move_rel,N}) -> - {command,[?OP_MOVE|put_int16(N, [])]}; + {[?OP_MOVE|put_int16(N, [])], ok}; io_command({insert_chars,unicode,Cs}) -> - {command,[?OP_INSC|unicode:characters_to_binary(Cs,utf8)]}; + {[?OP_INSC|unicode:characters_to_binary(Cs,utf8)], ok}; io_command({delete_chars,N}) -> - {command,[?OP_DELC|put_int16(N, [])]}; + {[?OP_DELC|put_int16(N, [])], ok}; io_command(beep) -> - {command,[?OP_BEEP]}; -io_command(Else) -> - throw(Else). + {[?OP_BEEP], ok}; +io_command(_) -> + unhandled. %% gr_new() %% gr_get_num(Group, Index) |