Skip to content

Commit

Permalink
kernel: bypass unicode translation in group for latin1 putc_requests
Browse files Browse the repository at this point in the history
user_drv knows whether the request should be converted to unicode.
  • Loading branch information
frazze-jobb committed Nov 1, 2024
1 parent 14e885a commit 9ca7cba
Show file tree
Hide file tree
Showing 4 changed files with 44 additions and 6 deletions.
4 changes: 1 addition & 3 deletions lib/kernel/src/group.erl
Original file line number Diff line number Diff line change
Expand Up @@ -609,9 +609,7 @@ putc_request({put_chars,unicode,M,F,As}, Drv, From) ->
end
end;
putc_request({put_chars,latin1,Binary}, Drv, From) when is_binary(Binary) ->
send_drv(Drv, {put_chars_sync, unicode,
unicode:characters_to_binary(Binary,latin1),
From}),
send_drv(Drv, {put_chars_sync, latin1, Binary, From}),
noreply;
putc_request({put_chars,latin1,Chars}, Drv, From) ->
case catch unicode:characters_to_binary(Chars,latin1) of
Expand Down
13 changes: 13 additions & 0 deletions lib/kernel/src/user_drv.erl
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,9 @@
%% Same as put_chars/3, but sends Reply to From when the characters are
%% guaranteed to have been written to the terminal
{put_chars_sync, unicode, binary(), {From :: pid(), Reply :: term()}} |
%% When we receive latin1 binary output requests, and encoding is in latin1,
%% then we will output the binary without conversion to unicode.
{put_chars_sync, latin1, binary(), {From :: pid(), Reply :: term()}} |
%% Put text in expansion area
{put_expand, unicode, binary(), integer()} |
{move_expand, -32768..32767} |
Expand Down Expand Up @@ -867,6 +870,16 @@ io_request(delete_line, TTY) ->
write(prim_tty:handle_request(TTY, delete_line));
io_request({put_chars, unicode, Chars}, TTY) ->
write(prim_tty:handle_request(TTY, {putc, unicode:characters_to_binary(Chars)}));
io_request({put_chars_sync, latin1, Bin, Reply}, TTY) when is_binary(Bin) ->
Unicode = prim_tty:unicode(TTY),
{Output, NewTTY} = if Unicode =:= false ->
prim_tty:handle_request(TTY, {putc_raw, Bin});
true ->
prim_tty:handle_request(TTY,
{putc, unicode:characters_to_binary(Bin, latin1)})
end,
{ok, MonitorRef} = prim_tty:write(NewTTY, Output, self()),
{Reply, MonitorRef, NewTTY};
io_request({put_chars_sync, unicode, Chars, Reply}, TTY) ->
{Output, NewTTY} = prim_tty:handle_request(TTY, {putc, unicode:characters_to_binary(Chars)}),
{ok, MonitorRef} = prim_tty:write(NewTTY, Output, self()),
Expand Down
26 changes: 23 additions & 3 deletions lib/stdlib/test/escript_SUITE.erl
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,8 @@
overflow/1,
verify_sections/4,
unicode/1,
bad_io_server/1
bad_io_server/1,
bypass_unicode_conversion/1
]).

-include_lib("common_test/include/ct.hrl").
Expand All @@ -54,9 +55,10 @@ all() ->
emulator_flags_no_shebang, two_lines,
module_script, beam_script, archive_script, epp,
create_and_extract, foldl, overflow,
archive_script_file_access, unicode, bad_io_server].
archive_script_file_access, unicode, bad_io_server,
bypass_unicode_conversion].

groups() ->
groups() ->
[].

init_per_suite(Config) ->
Expand Down Expand Up @@ -978,6 +980,24 @@ bad_io_server(Config) when is_list(Config) ->
"called as '\\x{400}' / 0\nExitCode:127">>]),
ok.

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

bypass_unicode_conversion(Config) when is_list(Config) ->
Data = proplists:get_value(data_dir, Config),
Dir = filename:absname(Data), %Get rid of trailing slash.
Cmd = fun(Enc) -> "bypass_unicode_conversion "++atom_to_list(Enc)++" 1> /dev/null" end,
{TimeLatin1, _} = timer:tc(
fun() -> run(Config, Dir, Cmd(latin1), [<<"ExitCode:0">>]) end),
{TimeUnicode, _} = timer:tc(
fun() -> run(Config, Dir, Cmd(unicode), [<<"ExitCode:0">>]) end),
%% Check that Time(latin1) is about the same as Time(unicode) with a maximum 10% difference
%% Without the bypass, the time difference would be about 5x.
io:format("Time(latin1) = ~p ~~= Time(unicode) = ~p~n", [TimeLatin1, TimeUnicode]),
true = TimeLatin1 =< TimeUnicode * 1.1,
ok.

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

run(Config, Dir, Cmd, Expected) ->
run_with_opts(Config, Dir, "", Cmd, Expected).

Expand Down
7 changes: 7 additions & 0 deletions lib/stdlib/test/escript_SUITE_data/bypass_unicode_conversion
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
#!/usr/bin/env escript

main([Enc]) ->
Data = {tuple, {list, lists:seq(1,1000000)}},
io:setopts(erlang:group_leader(), [binary, {encoding, list_to_atom(Enc)}]),
file:write(erlang:group_leader(), term_to_binary(Data)),
ok.

0 comments on commit 9ca7cba

Please sign in to comment.