From 250a556b1e3eb8486ec294f94d3b918c9ac91542 Mon Sep 17 00:00:00 2001 From: Lukas Larsson Date: Fri, 2 Dec 2011 17:13:49 +0100 Subject: Make solaris use sendfilev sendfilev is a richer API which allows us to do non blocking TCP on solaris. The normal sendfile API seems to have some issue with non blocking sockets and the return value of sendfile. --- lib/kernel/test/sendfile_SUITE.erl | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) (limited to 'lib') diff --git a/lib/kernel/test/sendfile_SUITE.erl b/lib/kernel/test/sendfile_SUITE.erl index 04af16a6b9..1b5119c684 100644 --- a/lib/kernel/test/sendfile_SUITE.erl +++ b/lib/kernel/test/sendfile_SUITE.erl @@ -99,7 +99,7 @@ t_sendfile_big(Config) when is_list(Config) -> Size end, - ok = sendfile_send("localhost", Send, 0). + ok = sendfile_send({127,0,0,1}, Send, 0). t_sendfile_partial(Config) -> Filename = proplists:get_value(small_file, Config), @@ -185,14 +185,14 @@ t_sendfile_sendduring(Config) -> {ok, #file_info{size = Size}} = file:read_file_info(Filename), spawn_link(fun() -> - timer:sleep(10), + timer:sleep(50), ok = gen_tcp:send(Sock, <<2>>) end), {ok, Size} = file:sendfile(Filename, Sock), Size+1 end, - ok = sendfile_send("localhost", Send, 0). + ok = sendfile_send({127,0,0,1}, Send, 0). t_sendfile_recvduring(Config) -> Filename = proplists:get_value(big_file, Config), @@ -201,7 +201,7 @@ t_sendfile_recvduring(Config) -> {ok, #file_info{size = Size}} = file:read_file_info(Filename), spawn_link(fun() -> - timer:sleep(10), + timer:sleep(50), ok = gen_tcp:send(Sock, <<1>>), {ok,<<1>>} = gen_tcp:recv(Sock, 1) end), @@ -210,11 +210,11 @@ t_sendfile_recvduring(Config) -> Size+1 end, - ok = sendfile_send("localhost", Send, 0). + ok = sendfile_send({127,0,0,1}, Send, 0). %% TODO: consolidate tests and reduce code sendfile_send(Send) -> - sendfile_send("localhost",Send). + sendfile_send({127,0,0,1},Send). sendfile_send(Host, Send) -> sendfile_send(Host, Send, []). sendfile_send(Host, Send, Orig) -> @@ -245,7 +245,6 @@ sendfile_server(ClientPid, Orig) -> gen_tcp:send(Sock, <<1>>). -define(SENDFILE_TIMEOUT, 10000). -%% f(),{ok, S} = gen_tcp:connect("localhost",7890,[binary]),file:sendfile("/ldisk/lukas/otp/sendfiletest.dat",S). sendfile_do_recv(Sock, Bs) -> receive {tcp, Sock, B} -> -- cgit v1.2.3 From ec885e883c99825e7d737752b1b0aebbbafbd670 Mon Sep 17 00:00:00 2001 From: Lukas Larsson Date: Mon, 5 Dec 2011 18:45:44 +0100 Subject: Clarify some code comments Thanks Tuncer Ayaz --- lib/kernel/test/sendfile_SUITE.erl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/kernel/test/sendfile_SUITE.erl b/lib/kernel/test/sendfile_SUITE.erl index 1b5119c684..4a6cd604e0 100644 --- a/lib/kernel/test/sendfile_SUITE.erl +++ b/lib/kernel/test/sendfile_SUITE.erl @@ -212,7 +212,7 @@ t_sendfile_recvduring(Config) -> ok = sendfile_send({127,0,0,1}, Send, 0). -%% TODO: consolidate tests and reduce code +%% Generic sendfile server code sendfile_send(Send) -> sendfile_send({127,0,0,1},Send). sendfile_send(Host, Send) -> -- cgit v1.2.3 From 1137c0a08b25ab5e38286260f0b7c51ba015afbb Mon Sep 17 00:00:00 2001 From: Lukas Larsson Date: Wed, 7 Dec 2011 14:46:26 +0100 Subject: Return {error,closed} from sendfile if closed If the socket is closed by the remote end, sendfile now returns {error,closed}. --- lib/kernel/src/file.erl | 6 ++++-- lib/kernel/test/sendfile_SUITE.erl | 41 ++++++++++++++++++++++++++++++++++++-- 2 files changed, 43 insertions(+), 4 deletions(-) (limited to 'lib') diff --git a/lib/kernel/src/file.erl b/lib/kernel/src/file.erl index 0b0f91d86a..a3c0e7da26 100644 --- a/lib/kernel/src/file.erl +++ b/lib/kernel/src/file.erl @@ -1124,7 +1124,8 @@ change_time(Name, Atime, Mtime) -define(MAX_CHUNK_SIZE, (1 bsl 20)*20). %% 20 MB, has to fit in primary memory -spec sendfile(RawFile, Socket, Offset, Bytes, Opts) -> - {'ok', non_neg_integer()} | {'error', inet:posix() | badarg | not_owner} when + {'ok', non_neg_integer()} | {'error', inet:posix() | + closed | badarg | not_owner} when RawFile :: file:fd(), Socket :: inet:socket(), Offset :: non_neg_integer(), @@ -1149,7 +1150,8 @@ sendfile(File, Sock, Offset, Bytes, Opts) -> %% sendfile/2 -spec sendfile(Filename, Socket) -> - {'ok', non_neg_integer()} | {'error', inet:posix() | badarg | not_owner} + {'ok', non_neg_integer()} | {'error', inet:posix() | + closed | badarg | not_owner} when Filename :: file:name(), Socket :: inet:socket(). sendfile(Filename, Sock) -> diff --git a/lib/kernel/test/sendfile_SUITE.erl b/lib/kernel/test/sendfile_SUITE.erl index 4a6cd604e0..483290b91a 100644 --- a/lib/kernel/test/sendfile_SUITE.erl +++ b/lib/kernel/test/sendfile_SUITE.erl @@ -33,6 +33,7 @@ all() -> ,t_sendfile_recvafter ,t_sendfile_sendduring ,t_sendfile_recvduring + ,t_sendfile_closeduring ]. init_per_suite(Config) -> @@ -212,19 +213,52 @@ t_sendfile_recvduring(Config) -> ok = sendfile_send({127,0,0,1}, Send, 0). +t_sendfile_closeduring(Config) -> + Filename = proplists:get_value(big_file, Config), + + Send = fun(Sock,SFServPid) -> + spawn_link(fun() -> + timer:sleep(50), + SFServPid ! stop + end), + case erlang:system_info(thread_pool_size) of + 0 -> + {error, closed} = file:sendfile(Filename, Sock); + _Else -> + %% This can return how much has been sent or + %% {error,closed} depending on OS. + %% How much is sent impossible to know as + %% the socket was closed mid sendfile + case file:sendfile(Filename, Sock) of + {error, closed} -> + ok; + {ok, Size} when is_integer(Size) -> + ok + end + end, + -1 + end, + + ok = sendfile_send({127,0,0,1}, Send, 0). + %% Generic sendfile server code sendfile_send(Send) -> sendfile_send({127,0,0,1},Send). sendfile_send(Host, Send) -> sendfile_send(Host, Send, []). sendfile_send(Host, Send, Orig) -> - spawn_link(?MODULE, sendfile_server, [self(), Orig]), + SFServer = spawn_link(?MODULE, sendfile_server, [self(), Orig]), receive {server, Port} -> {ok, Sock} = gen_tcp:connect(Host, Port, [binary,{packet,0}, {active,false}]), - Data = Send(Sock), + Data = case proplists:get_value(arity,erlang:fun_info(Send)) of + 1 -> + Send(Sock); + 2 -> + Send(Sock, SFServer) + end, ok = gen_tcp:close(Sock), receive {ok, Bin} -> @@ -247,6 +281,9 @@ sendfile_server(ClientPid, Orig) -> -define(SENDFILE_TIMEOUT, 10000). sendfile_do_recv(Sock, Bs) -> receive + stop when Bs /= 0,is_integer(Bs) -> + gen_tcp:close(Sock), + {ok, -1}; {tcp, Sock, B} -> case binary:match(B,<<1>>) of nomatch when is_list(Bs) -> -- cgit v1.2.3 From 4181dc36580a0ec7476aeed389948976a89c755d Mon Sep 17 00:00:00 2001 From: Lukas Larsson Date: Wed, 7 Dec 2011 14:47:40 +0100 Subject: Fix cleanup when sendfile process crashes When sendfile crashes during a send there should be no error_logger printouts about stolen fds. --- lib/kernel/test/sendfile_SUITE.erl | 41 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) (limited to 'lib') diff --git a/lib/kernel/test/sendfile_SUITE.erl b/lib/kernel/test/sendfile_SUITE.erl index 483290b91a..6d0848ee05 100644 --- a/lib/kernel/test/sendfile_SUITE.erl +++ b/lib/kernel/test/sendfile_SUITE.erl @@ -34,6 +34,7 @@ all() -> ,t_sendfile_sendduring ,t_sendfile_recvduring ,t_sendfile_closeduring + ,t_sendfile_crashduring ]. init_per_suite(Config) -> @@ -241,6 +242,35 @@ t_sendfile_closeduring(Config) -> ok = sendfile_send({127,0,0,1}, Send, 0). +t_sendfile_crashduring(Config) -> + Filename = proplists:get_value(big_file, Config), + + error_logger:add_report_handler(?MODULE,[self()]), + + Send = fun(Sock) -> + spawn_link(fun() -> + timer:sleep(50), + exit(die) + end), + {error, closed} = file:sendfile(Filename, Sock), + -1 + end, + process_flag(trap_exit,true), + spawn_link(fun() -> + ok = sendfile_send({127,0,0,1}, Send, 0) + end), + receive + {stolen,Reason} -> + process_flag(trap_exit,false), + ct:fail(Reason) + after 200 -> + receive + {'EXIT',_,Reason} -> + process_flag(trap_exit,false), + die = Reason + end + end. + %% Generic sendfile server code sendfile_send(Send) -> sendfile_send({127,0,0,1},Send). @@ -312,3 +342,14 @@ sendfile_file_info(File) -> {ok, #file_info{size = Size}} = file:read_file_info(File), {ok, Data} = file:read_file(File), {Size, Data}. + + +%% Error handler + +init([Proc]) -> {ok,Proc}. + +handle_event({error,noproc,{emulator,Format,Args}}, Proc) -> + Proc ! {stolen,lists:flatten(io_lib:format(Format,Args))}, + {ok,Proc}; +handle_event(_, Proc) -> + {ok,Proc}. -- cgit v1.2.3