Sign Up
Log In
Log In
or
Sign Up
Places
All Projects
Status Monitor
Collapse sidebar
home:Ledest:erlang:26
erlang
2463-Fix-handling-of-timeout-0-for-stream-socke...
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
File 2463-Fix-handling-of-timeout-0-for-stream-sockets.patch of Package erlang
From 437dbdb88c08fbaf06128c85d8acc31276554a78 Mon Sep 17 00:00:00 2001 From: Raimo Niskanen <raimo@erlang.org> Date: Fri, 2 Feb 2024 14:39:37 +0100 Subject: [PATCH 13/14] Fix handling of timeout 0 for stream sockets --- erts/emulator/nifs/unix/unix_socket_syncio.c | 68 ++++++++++------ lib/kernel/src/socket.erl | 85 +++++++++++--------- 2 files changed, 91 insertions(+), 62 deletions(-) diff --git a/erts/emulator/nifs/unix/unix_socket_syncio.c b/erts/emulator/nifs/unix/unix_socket_syncio.c index 82c3723211..2683e1d0d7 100644 --- a/erts/emulator/nifs/unix/unix_socket_syncio.c +++ b/erts/emulator/nifs/unix/unix_socket_syncio.c @@ -391,7 +391,8 @@ static ERL_NIF_TERM recv_check_partial_done(ErlNifEnv* env, ESockDescriptor* descP, ssize_t read, ErlNifBinary* bufP, - ERL_NIF_TERM sockRef); + ERL_NIF_TERM sockRef, + ERL_NIF_TERM returnTag); static ERL_NIF_TERM recv_check_partial_part(ErlNifEnv* env, ESockDescriptor* descP, ssize_t read, @@ -7041,7 +7042,7 @@ ERL_NIF_TERM recv_check_fail(ErlNifEnv* env, "\r\n", sockRef, descP->sock, recvRef) ); if (COMPARE(recvRef, esock_atom_zero) == 0) - res = esock_atom_ok; + res = esock_atom_timeout; else res = recv_check_retry(env, descP, sockRef, recvRef); @@ -7179,40 +7180,57 @@ ERL_NIF_TERM recv_check_partial(ErlNifEnv* env, descP->rNumCnt = 0; - if ((toRead == 0) || - (descP->type != SOCK_STREAM) || - (COMPARE(recvRef, esock_atom_zero) == 0)) { + /* Buffer not filled */ + + if ((descP->type == SOCK_STREAM) && (toRead > 0)) { - /* +++ We got it all, but since we +++ - * +++ did not fill the buffer, we +++ - * +++ must deliver part of the binary. +++ + /* A stream socket with specified read size + * - more data is needed */ - SSDBG( descP, - ("UNIX-ESSIO", - "recv_check_partial(%T) {%d} -> [%ld] split buffer" - "\r\n recvRef: %T" - "\r\n", sockRef, descP->sock, (long) toRead, - recvRef) ); + if (COMPARE(recvRef, esock_atom_zero) == 0) { + + /* Polling read - deliver as {timeout,Data} */ + + SSDBG( descP, + ("UNIX-ESSIO", + "recv_check_partial(%T) {%d} -> [%ld] split buffer time-out" + "\r\n recvRef: %T" + "\r\n", sockRef, descP->sock, (long) toRead, + recvRef) ); + + res = recv_check_partial_done(env, descP, read, bufP, sockRef, + esock_atom_timeout); + } else { - res = recv_check_partial_done(env, descP, read, bufP, sockRef); + /* Incomplete data + * - return a select result to initiate a retry + */ + SSDBG( descP, + ("UNIX-ESSIO", + "recv_check_partial(%T) {%d} -> [%ld]" + " only part of message - expect more" + "\r\n recvRef: %T" + "\r\n", sockRef, descP->sock, (long) toRead, + recvRef) ); + + res = recv_check_partial_part(env, descP, read, + bufP, sockRef, recvRef); + } } else { - /* A stream socket with specified read size - * and not a polling read, we got a partial read - * - return a select result to initiate a retry - */ + + /* No more data is needed - deliver as {ok,Data} */ SSDBG( descP, ("UNIX-ESSIO", - "recv_check_partial(%T) {%d} -> [%ld]" - " only part of message - expect more" + "recv_check_partial(%T) {%d} -> [%ld] split buffer" "\r\n recvRef: %T" "\r\n", sockRef, descP->sock, (long) toRead, recvRef) ); - res = recv_check_partial_part(env, descP, read, - bufP, sockRef, recvRef); + res = recv_check_partial_done(env, descP, read, bufP, sockRef, + esock_atom_ok); } return res; @@ -7229,7 +7247,8 @@ ERL_NIF_TERM recv_check_partial_done(ErlNifEnv* env, ESockDescriptor* descP, ssize_t read, ErlNifBinary* bufP, - ERL_NIF_TERM sockRef) + ERL_NIF_TERM sockRef, + ERL_NIF_TERM returnTag) { ERL_NIF_TERM data; @@ -7256,6 +7275,7 @@ ERL_NIF_TERM recv_check_partial_done(ErlNifEnv* env, ("UNIX-ESSIO", "recv_check_partial_done(%T) {%d} -> [%ld] done\r\n", sockRef, descP->sock, (long) read) ); + return MKT2(env, returnTag, data); return esock_make_ok2(env, data); } diff --git a/lib/kernel/src/socket.erl b/lib/kernel/src/socket.erl index 94a393038f..65cb01f48b 100644 --- a/lib/kernel/src/socket.erl +++ b/lib/kernel/src/socket.erl @@ -3486,15 +3486,16 @@ recv_zero(SockRef, Length, Flags, Buf) -> case prim_socket:recv(SockRef, Length, Flags, zero) of {more, Bin} -> % Type == stream, Length == 0, default buffer filled recv_zero(SockRef, Length, Flags, [Bin | Buf]); - %% - %% If Buf =/= [] we have gotten {more,_} before - %% so it is a stream socket and Length =:= 0 - %% - ok when Buf =:= [] -> + timeout when Buf =:= [] -> {error, timeout}; - ok -> + timeout -> + %% We have gotten some {more,_} before so it is + %% a stream socket and Length =:= 0 {ok, condense_buffer(Buf)}; - {ok, Bin} -> + {timeout, Bin} -> + %% Stream socket with Length > 0 and not all data + {error, {timeout, condense_buffer([Bin | Buf])}}; + {ok, Bin} -> % All requested data {ok, condense_buffer([Bin | Buf])}; {error, _} = Error when Buf =:= [] -> Error; @@ -3526,12 +3527,35 @@ recv_nowait(SockRef, Length, Flags, Handle) -> %% result) when the data arrives. *No* further action %% is required. {completion, ?COMPLETION_INFO(recv, Handle)}; - {ok, _} = OK -> + {ok, _} = OK -> % All requested data OK; {error, _} = Error -> Error end. +%% prim_socket:recv(_, AskedFor, _, zero|Handle) +%% +%% if got 0, type == STREAM -> {error, closed} +%% if got full buffer -> +%% if asked for 0, type == STREAM -> +%% if rNum =< rNumCnt -> {ok, Bin} +%% else rNumCnt < rNum -> {more, Bin} +%% end +%% else asked for N; type != STREAM -> {ok, Bin} +%% end +%% else got less than buffer -> +%% if asked for N, type == STREAM -> +%% if Timeout zero -> -> {timeout, Bin} +%% else nowait Handle -> -> {select, Bin} +%% else type != STREAM; asked for 0 -> -> {ok, Bin} +%% end +%% else got no data and would block -> +%% if Timeout zero -> -> timeout +%% else nowait Handle -> select +%% end +%% else read error -> {error, _} +%% end + %% We will only recurse with Length == 0 if Length is 0, %% so Length == 0 means to return all available data also when recursing @@ -3539,6 +3563,7 @@ recv_deadline(SockRef, Length, Flags, Deadline, Buf) -> Handle = make_ref(), case prim_socket:recv(SockRef, Length, Flags, Handle) of {more, Bin} -> % Type = stream, Length = 0, default buffer filled + 0 = Length, recv_zero(SockRef, Length, Flags, [Bin]); %% {select, Bin} -> @@ -3589,7 +3614,7 @@ recv_deadline(SockRef, Length, Flags, Deadline, Buf) -> select -> % Length is 0 (request any amount of data), Buf not empty %% %% We first got some data and are then asked to wait, - %% but we only want the first that comes + %% but what we already got will do just fine; %% - cancel and return what we have _ = cancel(SockRef, recv, Handle), {ok, condense_buffer(Buf)}; @@ -3628,29 +3653,13 @@ recv_deadline(SockRef, Length, Flags, Deadline, Buf) -> recv_error(Buf, timeout) end; %% - %% We got some data, but not all - {ok, Bin} -> - if - byte_size(Bin) < Length -> - Timeout = timeout(Deadline), - if - 0 < Timeout -> - %% Recv more - recv_deadline( - SockRef, Length - byte_size(Bin), Flags, - Deadline, [Bin | Buf]); - true -> - recv_error([Bin | Buf], timeout) - end; - true -> - {ok, condense_buffer([Bin | Buf])} - end; + {ok, Bin} -> % All requested data + {ok, condense_buffer([Bin | Buf])}; %% {error, Reason} -> recv_error(Buf, Reason) end. - recv_error([], Reason) -> {error, Reason}; recv_error(Buf, Reason) when is_list(Buf) -> @@ -3875,7 +3884,7 @@ recvfrom(?socket(SockRef), BufSz, Flags, Timeout) recvfrom_nowait(SockRef, BufSz, Handle, Flags); zero -> case prim_socket:recvfrom(SockRef, BufSz, Flags, zero) of - ok -> + timeout -> {error, timeout}; Result -> recvfrom_result(Result) @@ -4174,8 +4183,8 @@ recvmsg(?socket(SockRef), BufSz, CtrlSz, Flags, Timeout) recvmsg_nowait(SockRef, BufSz, CtrlSz, Flags, Handle); zero -> case prim_socket:recvmsg(SockRef, BufSz, CtrlSz, Flags, zero) of - ok -> - {error, timeout}; + timeout = Tag -> + {error, Tag}; Result -> recvmsg_result(Result) end; @@ -4187,10 +4196,10 @@ recvmsg(Socket, BufSz, CtrlSz, Flags, Timeout) -> recvmsg_nowait(SockRef, BufSz, CtrlSz, Flags, Handle) -> case prim_socket:recvmsg(SockRef, BufSz, CtrlSz, Flags, Handle) of - select -> - {select, ?SELECT_INFO(recvmsg, Handle)}; - completion -> - {completion, ?COMPLETION_INFO(recvmsg, Handle)}; + select = Tag -> + {Tag, ?SELECT_INFO(recvmsg, Handle)}; + completion = Tag -> + {Tag, ?COMPLETION_INFO(recvmsg, Handle)}; Result -> recvmsg_result(Result) end. @@ -4198,12 +4207,12 @@ recvmsg_nowait(SockRef, BufSz, CtrlSz, Flags, Handle) -> recvmsg_deadline(SockRef, BufSz, CtrlSz, Flags, Deadline) -> Handle = make_ref(), case prim_socket:recvmsg(SockRef, BufSz, CtrlSz, Flags, Handle) of - select -> + select = Tag -> %% There is nothing just now, but we will be notified when there %% is something to read (a select message). Timeout = timeout(Deadline), receive - ?socket_msg(?socket(SockRef), select, Handle) -> + ?socket_msg(?socket(SockRef), Tag, Handle) -> recvmsg_deadline( SockRef, BufSz, CtrlSz, Flags, Deadline); ?socket_msg(_Socket, abort, {Handle, Reason}) -> @@ -4213,12 +4222,12 @@ recvmsg_deadline(SockRef, BufSz, CtrlSz, Flags, Deadline) -> {error, timeout} end; - completion -> + completion = Tag -> %% There is nothing just now, but we will be notified when there %% is something to read (a completion message). Timeout = timeout(Deadline), receive - ?socket_msg(?socket(SockRef), completion, + ?socket_msg(?socket(SockRef), Tag, {Handle, CompletionStatus}) -> recvmsg_result(CompletionStatus); ?socket_msg(_Socket, abort, {Handle, Reason}) -> -- 2.35.3
Locations
Projects
Search
Status Monitor
Help
OpenBuildService.org
Documentation
API Documentation
Code of Conduct
Contact
Support
@OBShq
Terms
openSUSE Build Service is sponsored by
The Open Build Service is an
openSUSE project
.
Sign Up
Log In
Places
Places
All Projects
Status Monitor