diff options
author | Rickard Green <rickard@erlang.org> | 2020-07-30 14:00:31 +0200 |
---|---|---|
committer | Rickard Green <rickard@erlang.org> | 2020-11-12 18:19:17 +0100 |
commit | 7f4faa03a0fac9e841d16f4e3a47e66a4668b58e (patch) | |
tree | 8ec298b22c9ac2e39ba6d23108d3f8402fef3ca5 | |
parent | 9362aa5e226954ddadcde3bd41c4e0441a4d56c1 (diff) | |
download | erlang-7f4faa03a0fac9e841d16f4e3a47e66a4668b58e.tar.gz |
Use alias in gen behaviours
-rw-r--r-- | lib/stdlib/doc/src/gen_event.xml | 70 | ||||
-rw-r--r-- | lib/stdlib/doc/src/gen_server.xml | 65 | ||||
-rw-r--r-- | lib/stdlib/doc/src/gen_statem.xml | 66 | ||||
-rw-r--r-- | lib/stdlib/src/gen.erl | 81 | ||||
-rw-r--r-- | lib/stdlib/src/gen_event.erl | 13 | ||||
-rw-r--r-- | lib/stdlib/src/gen_fsm.erl | 6 | ||||
-rw-r--r-- | lib/stdlib/src/gen_server.erl | 11 | ||||
-rw-r--r-- | lib/stdlib/src/gen_statem.erl | 30 | ||||
-rw-r--r-- | lib/stdlib/src/stdlib.app.src | 2 | ||||
-rw-r--r-- | lib/stdlib/test/gen_fsm_SUITE.erl | 5 | ||||
-rw-r--r-- | lib/stdlib/test/gen_server_SUITE.erl | 6 | ||||
-rw-r--r-- | lib/stdlib/test/gen_statem_SUITE.erl | 3 | ||||
-rw-r--r-- | lib/wx/test/wx_basic_SUITE.erl | 8 |
13 files changed, 317 insertions, 49 deletions
diff --git a/lib/stdlib/doc/src/gen_event.xml b/lib/stdlib/doc/src/gen_event.xml index 2ddff240d2..74ae2674ee 100644 --- a/lib/stdlib/doc/src/gen_event.xml +++ b/lib/stdlib/doc/src/gen_event.xml @@ -297,7 +297,7 @@ gen_event:stop -----> Module:terminate/2 <func> - <name since="OTP-23">check_response(Msg, RequestId) -> Result</name> + <name since="OTP 23.0">check_response(Msg, RequestId) -> Result</name> <fsummary>Check if a message is a reply from a server.</fsummary> <type> <v>Msg = term()</v> @@ -393,9 +393,59 @@ gen_event:stop -----> Module:terminate/2 </desc> </func> + <func> + <name since="OTP @OTP-16718@">receive_response(RequestId, Timeout) -> Result</name> + <fsummary>Receive for a reply from a server.</fsummary> + <type> + <v>RequestId = request_id()</v> + <v>Reply = term()</v> + <v>Timeout = timeout()</v> + <v>Result = {reply, Reply} | timeout | {error, Error}</v> + <v>Reply = Error = term()</v> + </type> + <desc> + <p> + This function is used to receive for a reply of a request made with + <seemfa marker="#send_request/3"><c>send_request/3</c></seemfa> + to the event manager. This function must be called from the same + process from which <seemfa marker="#send_request/3"><c>send_request/3</c></seemfa> + was made. + </p> + <p> + <c>Timeout</c> is an integer greater then or equal to zero + that specifies how many milliseconds to wait for an reply, or + the atom <c>infinity</c> to wait indefinitely. + If no reply is received within the specified + time, the function returns <c>timeout</c>. Assuming that the + server executes on a node supporting aliases (introduced in + OTP 24) no response will be received after a timeout. Otherwise, + a garbage response might be received at a later time. + </p> + <p> + The return value <c>Reply</c> is defined in the return value + of <c>Module:handle_call/3</c>. + </p> + <p> + If the specified event handler is not + installed, the function returns <c>{error,bad_module}</c>. If + the callback function fails with <c>Reason</c> or returns an + unexpected value <c>Term</c>, this function returns + <c>{error,{'EXIT',Reason}}</c> or <c>{error,Term}</c>, + respectively. If the event manager dies before or during the + request this function returns <c>{error,{Reason, EventMgrRef}}</c>. + </p> + <p> + The difference between + <seemfa marker="#wait_response/2"><c>wait_response()</c></seemfa> + and <c>receive_response()</c> is that <c>receive_response()</c> + abandons the request at timeout so that a potential future + response is ignored, while <c>wait_response()</c> does not. + </p> + </desc> + </func> <func> - <name since="OTP-23">send_request(EventMgrRef, Handler, Request) -> RequestId</name> + <name since="OTP 23.0">send_request(EventMgrRef, Handler, Request) -> RequestId</name> <fsummary>Send a request to a generic event manager.</fsummary> <type> <v>EventMgrRef = Name | {Name,Node} | {global,GlobalName}</v> @@ -413,8 +463,9 @@ gen_event:stop -----> Module:terminate/2 Sends a request to event handler <c>Handler</c> installed in event manager <c>EventMgrRef</c> and returns a handle <c>RequestId</c>. The return value <c>RequestId</c> shall - later be used with <seemfa marker="#wait_response/2"> - <c>wait_response/2</c></seemfa> or <seemfa + later be used with <seemfa marker="#receive_response/2"> + <c>receive_response/2</c></seemfa>, <seemfa marker="#wait_response/2"> + <c>wait_response/2</c></seemfa>, or <seemfa marker="#check_response/2"> <c>check_response/2</c></seemfa> in the same process to fetch the actual result of the request. @@ -668,7 +719,7 @@ gen_event:stop -----> Module:terminate/2 </func> <func> - <name since="OTP-23">wait_response(RequestId, Timeout) -> Result</name> + <name since="OTP 23.0">wait_response(RequestId, Timeout) -> Result</name> <fsummary>Wait for a reply from a server.</fsummary> <type> <v>RequestId = request_id()</v> @@ -681,7 +732,7 @@ gen_event:stop -----> Module:terminate/2 <p> This function is used to wait for a reply of a request made with <seemfa marker="#send_request/3"><c>send_request/3</c></seemfa> - from the event manager. This function must be called from the same + to the event manager. This function must be called from the same process from which <seemfa marker="#send_request/3"><c>send_request/3</c></seemfa> was made. </p> @@ -707,6 +758,13 @@ gen_event:stop -----> Module:terminate/2 respectively. If the event manager dies before or during the request this function returns <c>{error,{Reason, EventMgrRef}}</c>. </p> + <p> + The difference between + <seemfa marker="#receive_response/2"><c>receive_response()</c></seemfa> + and <c>wait_response()</c> is that <c>receive_response()</c> + abandons the request at timeout so that a potential future + response is ignored, while <c>wait_response()</c> does not. + </p> </desc> </func> diff --git a/lib/stdlib/doc/src/gen_server.xml b/lib/stdlib/doc/src/gen_server.xml index 4abb91439e..472d77578a 100644 --- a/lib/stdlib/doc/src/gen_server.xml +++ b/lib/stdlib/doc/src/gen_server.xml @@ -346,6 +346,57 @@ gen_server:abcast -----> Module:handle_cast/2 </func> <func> + <name since="OTP @OTP-16718@">receive_response(RequestId, Timeout) -> Result</name> + <fsummary>Receive for a reply from a server.</fsummary> + <type> + <v>RequestId = term()</v> + <v>Result = {reply, Reply} | timeout | {error, {Reason, ServerRef}}</v> + <v>Reply = term()</v> + <v>Timeout = timeout()</v> + <v>Reason = term()</v> + <v>ServerRef = Name | {Name,Node} | {global,GlobalName}</v> + <v> | {via,Module,ViaName} | pid()</v> + <v> Node = atom()</v> + <v> GlobalName = ViaName = term()</v> + </type> + <desc> + <p> + This function is used to receive a reply of a request made with + <seemfa marker="#send_request/2"><c>send_request/2</c></seemfa> + to a <c>gen_server</c> process. This function must be called + from the same process from which + <seemfa marker="#send_request/2"><c>send_request/2</c></seemfa> + was made. + </p> + <p> + <c>Timeout</c> is an integer greater then or equal to zero + that specifies how many milliseconds to wait for an reply, or + the atom <c>infinity</c> to wait indefinitely. + If no reply is received within the specified + time, the function returns <c>timeout</c>. Assuming that the + server executes on a node supporting aliases (introduced in + OTP 24) no response will be received after a timeout. Otherwise, + a garbage response might be received at a later time. + </p> + <p> + The return value <c>Reply</c> is defined in the return value + of <c>Module:handle_call/3</c>. + </p> + <p> + The function returns an error if the <c>gen_server</c> + dies before or during this request. + </p> + <p> + The difference between + <seemfa marker="#wait_response/2"><c>wait_response()</c></seemfa> + and <c>receive_response()</c> is that <c>receive_response()</c> + abandons the request at timeout so that a potential future + response is ignored, while <c>wait_response()</c> does not. + </p> + </desc> + </func> + + <func> <name since="">reply(Client, Reply) -> ok</name> <fsummary>Send a reply to a client.</fsummary> <type> @@ -368,7 +419,7 @@ gen_server:abcast -----> Module:handle_cast/2 </func> <func> - <name since="OTP-23">send_request(ServerRef, Request) -> RequestId</name> + <name since="OTP 23.0">send_request(ServerRef, Request) -> RequestId</name> <fsummary>Sends a request to a generic server.</fsummary> <type> <v>ServerRef = Name | {Name,Node} | {global,GlobalName}</v> @@ -384,7 +435,8 @@ gen_server:abcast -----> Module:handle_cast/2 Sends a request to the <c>ServerRef</c> of the <c>gen_server</c> process and returns a handle <c>RequestId</c>. The return value <c>RequestId</c> shall later be used with - <seemfa marker="#wait_response/2"> <c>wait_response/2</c></seemfa> or + <seemfa marker="#receive_response/2"> <c>receive_response/2</c></seemfa>, + <seemfa marker="#wait_response/2"> <c>wait_response/2</c></seemfa>, or <seemfa marker="#check_response/2"> <c>check_response/2</c></seemfa> to fetch the actual result of the request. </p> @@ -622,7 +674,7 @@ gen_server:abcast -----> Module:handle_cast/2 </func> <func> - <name since="OTP-23">wait_response(RequestId, Timeout) -> Result</name> + <name since="OTP 23.0">wait_response(RequestId, Timeout) -> Result</name> <fsummary>Wait for a reply from a server.</fsummary> <type> <v>RequestId = term()</v> @@ -661,6 +713,13 @@ gen_server:abcast -----> Module:handle_cast/2 The function returns an error if the <c>gen_server</c> dies before or during this request. </p> + <p> + The difference between + <seemfa marker="#receive_response/2"><c>receive_response()</c></seemfa> + and <c>wait_response()</c> is that <c>receive_response()</c> + abandons the request at timeout so that a potential future + response is ignored, while <c>wait_response()</c> does not. + </p> </desc> </func> </funcs> diff --git a/lib/stdlib/doc/src/gen_statem.xml b/lib/stdlib/doc/src/gen_statem.xml index fa3f20535d..1d608ad64d 100644 --- a/lib/stdlib/doc/src/gen_statem.xml +++ b/lib/stdlib/doc/src/gen_statem.xml @@ -1831,6 +1831,53 @@ handle_event(_, _, State, Data) -> </func> <func> + <name name="receive_response" arity="1" since="OTP @OTP-16718@"/> + <name name="receive_response" arity="2" since="OTP @OTP-16718@"/> + <fsummary>Receive for a reply from a server.</fsummary> + <desc> + <p> + This function is used to receive for a reply of a request made with + <seemfa marker="#send_request/2"><c>send_request/2</c></seemfa> + to the <c>gen_statem</c> process. This function must be called + from the same process from which + <seemfa marker="#send_request/2"><c>send_request/2</c></seemfa> + was made. + </p> + <p> + <c>Timeout</c> is an integer greater then or equal to zero + that specifies how many milliseconds to wait for an reply, or + the atom <c>infinity</c> to wait indefinitely. Defaults to + <c>infinity</c>. + If no reply is received within the specified + time, the function returns <c>timeout</c>. Assuming that the + server executes on a node supporting aliases (introduced in + OTP 24) no response will be received after a timeout. Otherwise, + a garbage response might be received at a later time. + </p> + <p> + The return value <c><anno>Reply</anno></c> is generated when a + <seeerl marker="#state callback"><em>state callback</em></seeerl> + returns with + <c>{reply,From,<anno>Reply</anno>}</c> as one + <seetype marker="#action"><c>action()</c></seetype>, + and that <c><anno>Reply</anno></c> becomes the return value + of this function. + </p> + <p> + The function returns an error if the <c>gen_statem</c> + dies before or during this function call. + </p> + <p> + The difference between + <seemfa marker="#wait_response/2"><c>wait_response()</c></seemfa> + and <c>receive_response()</c> is that <c>receive_response()</c> + abandons the request at timeout so that a potential future + response is ignored, while <c>wait_response()</c> does not. + </p> + </desc> + </func> + + <func> <name name="reply" arity="1" since="OTP 19.0"/> <name name="reply" arity="2" since="OTP 19.0"/> <fsummary>Reply to a caller.</fsummary> @@ -1874,7 +1921,8 @@ handle_event(_, _, State, Data) -> </p> <p> The return value <c><anno>RequestId</anno></c> shall later be used with - <seemfa marker="#wait_response/2"> <c>wait_response/1,2</c></seemfa> or + <seemfa marker="#receive_response/2"> <c>receive_response/1,2</c></seemfa>, + <seemfa marker="#wait_response/2"> <c>wait_response/1,2</c></seemfa>, or <seemfa marker="#check_response/2"> <c>check_response/2</c></seemfa> to fetch the actual result of the request. </p> @@ -1899,7 +1947,8 @@ handle_event(_, _, State, Data) -> <c>{reply,From,Reply}</c> as one <seetype marker="#action"><c>action()</c></seetype>, and that <c>Reply</c> becomes the return value - of <seemfa marker="#wait_response/2"> <c>wait_response/1,2</c></seemfa> or + of <seemfa marker="#receive_response/2"> <c>receive_response/1,2</c></seemfa>, + <seemfa marker="#wait_response/2"> <c>wait_response/1,2</c></seemfa>, or <seemfa marker="#check_response/2"> <c>check_response/2</c></seemfa> function. </p> </desc> @@ -2125,14 +2174,14 @@ handle_event(_, _, State, Data) -> </func> <func> - <name name="wait_response" arity="1" since="OTP-23"/> - <name name="wait_response" arity="2" since="OTP-23"/> + <name name="wait_response" arity="1" since="OTP 23.0"/> + <name name="wait_response" arity="2" since="OTP 23.0"/> <fsummary>Wait for a reply from a server.</fsummary> <desc> <p> This function is used to wait for a reply of a request made with <seemfa marker="#send_request/2"><c>send_request/2</c></seemfa> - from the <c>gen_statem</c> process. This function must be called + to the <c>gen_statem</c> process. This function must be called from the same process from which <seemfa marker="#send_request/2"><c>send_request/2</c></seemfa> was made. @@ -2160,6 +2209,13 @@ handle_event(_, _, State, Data) -> The function returns an error if the <c>gen_statem</c> dies before or during this function call. </p> + <p> + The difference between + <seemfa marker="#receive_response/2"><c>receive_response()</c></seemfa> + and <c>wait_response()</c> is that <c>receive_response()</c> + abandons the request at timeout so that a potential future + response is ignored, while <c>wait_response()</c> does not. + </p> </desc> </func> </funcs> diff --git a/lib/stdlib/src/gen.erl b/lib/stdlib/src/gen.erl index be14665d80..b2f2a0ff4e 100644 --- a/lib/stdlib/src/gen.erl +++ b/lib/stdlib/src/gen.erl @@ -29,7 +29,8 @@ -export([start/5, start/6, debug_options/2, hibernate_after/1, name/1, unregister_name/1, get_proc_name/1, get_parent/0, call/3, call/4, reply/2, - send_request/3, wait_response/2, check_response/2, + send_request/3, wait_response/2, + receive_response/2, check_response/2, stop/1, stop/3]). -export([init_it/6, init_it/7]). @@ -198,17 +199,41 @@ call(Process, Label, Request, Timeout) Fun = fun(Pid) -> do_call(Pid, Label, Request, Timeout) end, do_for_proc(Process, Fun). -do_call(Process, Label, Request, Timeout) when is_atom(Process) =:= false -> +-dialyzer({no_improper_lists, do_call/4}). + +do_call(Process, Label, Request, infinity) + when (is_pid(Process) + andalso (node(Process) == node())) + orelse (element(2, Process) == node() + andalso is_atom(element(1, Process)) + andalso (tuple_size(Process) =:= 2)) -> Mref = erlang:monitor(process, Process), + %% Local without timeout; no need to use alias since we unconditionally + %% will wait for either a reply or a down message which corresponds to + %% the process being terminated (as opposed to 'noconnection')... + Process ! {Label, {self(), Mref}, Request}, + receive + {Mref, Reply} -> + erlang:demonitor(Mref, [flush]), + {ok, Reply}; + {'DOWN', Mref, _, _, Reason} -> + exit(Reason) + end; +do_call(Process, Label, Request, Timeout) when is_atom(Process) =:= false -> + Mref = erlang:monitor(process, Process, [{alias,demonitor}]), + + Tag = [alias | Mref], - %% OTP-21: - %% Auto-connect is asynchronous. But we still use 'noconnect' to make sure - %% we send on the monitored connection, and not trigger a new auto-connect. + %% OTP-24: + %% Using alias to prevent responses after 'noconnection' and timeouts. + %% We however still may call nodes responding via process identifier, so + %% we still use 'noconnect' on send in order to try to send on the + %% monitored connection, and not trigger a new auto-connect. %% - erlang:send(Process, {Label, {self(), Mref}, Request}, [noconnect]), + erlang:send(Process, {Label, {self(), Tag}, Request}, [noconnect]), receive - {Mref, Reply} -> + {[alias | Mref], Reply} -> erlang:demonitor(Mref, [flush]), {ok, Reply}; {'DOWN', Mref, _, _, noconnection} -> @@ -218,7 +243,12 @@ do_call(Process, Label, Request, Timeout) when is_atom(Process) =:= false -> exit(Reason) after Timeout -> erlang:demonitor(Mref, [flush]), - exit(timeout) + receive + {[alias | Mref], Reply} -> + {ok, Reply} + after 0 -> + exit(timeout) + end end. get_node(Process) -> @@ -246,9 +276,11 @@ send_request(Process, Label, Request) -> Mref end. +-dialyzer({no_improper_lists, do_send_request/3}). + do_send_request(Process, Label, Request) -> - Mref = erlang:monitor(process, Process), - erlang:send(Process, {Label, {self(), {'$gen_request_id', Mref}}, Request}, [noconnect]), + Mref = erlang:monitor(process, Process, [{alias, demonitor}]), + erlang:send(Process, {Label, {self(), [alias|Mref]}, Request}, [noconnect]), Mref. %% @@ -257,10 +289,9 @@ do_send_request(Process, Label, Request) -> -spec wait_response(RequestId::request_id(), timeout()) -> {reply, Reply::term()} | 'timeout' | {error, {term(), server_ref()}}. -wait_response(Mref, Timeout) - when is_reference(Mref) -> +wait_response(Mref, Timeout) when is_reference(Mref) -> receive - {{'$gen_request_id', Mref}, Reply} -> + {[alias|Mref], Reply} -> erlang:demonitor(Mref, [flush]), {reply, Reply}; {'DOWN', Mref, _, Object, Reason} -> @@ -269,12 +300,30 @@ wait_response(Mref, Timeout) timeout end. +-spec receive_response(RequestId::request_id(), timeout()) -> + {reply, Reply::term()} | 'timeout' | {error, {term(), server_ref()}}. +receive_response(Mref, Timeout) when is_reference(Mref) -> + receive + {[alias|Mref], Reply} -> + erlang:demonitor(Mref, [flush]), + {reply, Reply}; + {'DOWN', Mref, _, Object, Reason} -> + {error, {Reason, Object}} + after Timeout -> + erlang:demonitor(Mref, [flush]), + receive + {[alias|Mref], Reply} -> + {reply, Reply} + after 0 -> + timeout + end + end. + -spec check_response(RequestId::term(), Key::request_id()) -> {reply, Reply::term()} | 'no_reply' | {error, {term(), server_ref()}}. -check_response(Msg, Mref) - when is_reference(Mref) -> +check_response(Msg, Mref) when is_reference(Mref) -> case Msg of - {{'$gen_request_id', Mref}, Reply} -> + {[alias|Mref], Reply} -> erlang:demonitor(Mref, [flush]), {reply, Reply}; {'DOWN', Mref, _, Object, Reason} -> diff --git a/lib/stdlib/src/gen_event.erl b/lib/stdlib/src/gen_event.erl index 8024221cab..0d069119c9 100644 --- a/lib/stdlib/src/gen_event.erl +++ b/lib/stdlib/src/gen_event.erl @@ -43,7 +43,7 @@ notify/2, sync_notify/2, add_handler/3, add_sup_handler/3, delete_handler/3, swap_handler/3, swap_sup_handler/3, which_handlers/1, call/3, call/4, - send_request/3, wait_response/2, check_response/2, + send_request/3, wait_response/2, receive_response/2, check_response/2, wake_hib/5]). -export([init_it/6, @@ -248,6 +248,14 @@ wait_response(RequestId, Timeout) -> Return -> Return end. +-spec receive_response(RequestId::request_id(), timeout()) -> + {reply, Reply::term()} | 'timeout' | {error, {Reason::term(), emgr_ref()}}. +receive_response(RequestId, Timeout) -> + case gen:receive_response(RequestId, Timeout) of + {reply, {error, _} = Err} -> Err; + Return -> Return + end. + -spec check_response(Msg::term(), RequestId::request_id()) -> {reply, Reply::term()} | 'no_reply' | {error, {Reason::term(), emgr_ref()}}. check_response(Msg, RequestId) -> @@ -396,6 +404,9 @@ terminate_server(Reason, Parent, MSL, ServerName) -> do_unlink(Parent, MSL), exit(Reason). +reply({To, [alias|Alias] = Tag}, Reply) when is_pid(To), is_reference(Alias) -> + Alias ! {Tag, Reply}, + ok; reply({From, Ref}, Msg) -> From ! {Ref, Msg}, ok. diff --git a/lib/stdlib/src/gen_fsm.erl b/lib/stdlib/src/gen_fsm.erl index f4752c37d4..9ff58584eb 100644 --- a/lib/stdlib/src/gen_fsm.erl +++ b/lib/stdlib/src/gen_fsm.erl @@ -564,8 +564,12 @@ from({'$gen_sync_all_state_event', From, _Event}) -> From; from(_) -> undefined. %% Send a reply to the client. +reply({To, [alias|Alias] = Tag}, Reply) when is_pid(To), is_reference(Alias) -> + Alias ! {Tag, Reply}, + ok; reply({To, Tag}, Reply) -> - catch To ! {Tag, Reply}. + catch To ! {Tag, Reply}, + ok. reply(Name, From, Reply, Debug, StateName) -> reply(From, Reply), diff --git a/lib/stdlib/src/gen_server.erl b/lib/stdlib/src/gen_server.erl index e49961a5f0..86196eaf2a 100644 --- a/lib/stdlib/src/gen_server.erl +++ b/lib/stdlib/src/gen_server.erl @@ -97,7 +97,8 @@ start_monitor/3, start_monitor/4, stop/1, stop/3, call/2, call/3, - send_request/2, wait_response/2, check_response/2, + send_request/2, wait_response/2, + receive_response/2, check_response/2, cast/2, reply/2, abcast/2, abcast/3, multi_call/2, multi_call/3, multi_call/4, @@ -260,6 +261,11 @@ send_request(Name, Request) -> wait_response(RequestId, Timeout) -> gen:wait_response(RequestId, Timeout). +-spec receive_response(RequestId::request_id(), timeout()) -> + {reply, Reply::term()} | 'timeout' | {error, {Reason::term(), server_ref()}}. +receive_response(RequestId, Timeout) -> + gen:receive_response(RequestId, Timeout). + -spec check_response(Msg::term(), RequestId::request_id()) -> {reply, Reply::term()} | 'no_reply' | {error, {Reason::term(), server_ref()}}. check_response(Msg, RequestId) -> @@ -290,6 +296,9 @@ cast_msg(Request) -> {'$gen_cast',Request}. %% ----------------------------------------------------------------- %% Send a reply to the client. %% ----------------------------------------------------------------- +reply({To, [alias|Alias] = Tag}, Reply) when is_pid(To), is_reference(Alias) -> + Alias ! {Tag, Reply}, + ok; reply({To, Tag}, Reply) -> catch To ! {Tag, Reply}, ok. diff --git a/lib/stdlib/src/gen_statem.erl b/lib/stdlib/src/gen_statem.erl index adf1a82a08..9b73a919c8 100644 --- a/lib/stdlib/src/gen_statem.erl +++ b/lib/stdlib/src/gen_statem.erl @@ -32,7 +32,8 @@ start_monitor/3,start_monitor/4, stop/1,stop/3, cast/2,call/2,call/3, - send_request/2,wait_response/1,wait_response/2,check_response/2, + send_request/2,wait_response/1,wait_response/2, + receive_response/1,receive_response/2,check_response/2, enter_loop/4,enter_loop/5,enter_loop/6, reply/1,reply/2]). @@ -596,6 +597,16 @@ wait_response(RequestId) -> wait_response(RequestId, Timeout) -> gen:wait_response(RequestId, Timeout). +-spec receive_response(RequestId::request_id()) -> + {reply, Reply::term()} | {error, {term(), server_ref()}}. +receive_response(RequestId) -> + gen:receive_response(RequestId, infinity). + +-spec receive_response(RequestId::request_id(), timeout()) -> + {reply, Reply::term()} | 'timeout' | {error, {term(), server_ref()}}. +receive_response(RequestId, Timeout) -> + gen:receive_response(RequestId, Timeout). + -spec check_response(Msg::term(), RequestId::request_id()) -> {reply, Reply::term()} | 'no_reply' | {error, {term(), server_ref()}}. check_response(Msg, RequestId) -> @@ -610,6 +621,9 @@ reply(Replies) when is_list(Replies) -> %% -compile({inline, [reply/2]}). -spec reply(From :: from(), Reply :: term()) -> ok. +reply({To, [alias|Alias] = Tag}, Reply) when is_pid(To), is_reference(Alias) -> + Alias ! {Tag, Reply}, + ok; reply({To,Tag}, Reply) when is_pid(To) -> Msg = {Tag,Reply}, try To ! Msg of @@ -679,8 +693,22 @@ call_dirty(ServerRef, Request, Timeout, T) -> Stacktrace) end. +call_clean(ServerRef, Request, Timeout, T) + when (is_pid(ServerRef) + andalso (node(ServerRef) == node())) + orelse (element(2, ServerRef) == node() + andalso is_atom(element(1, ServerRef)) + andalso (tuple_size(ServerRef) =:= 2)) -> + %% No need to use a proxy locally since we know alias will be + %% used as of OTP 24 which will prevent garbage responses... + call_dirty(ServerRef, Request, Timeout, T); call_clean(ServerRef, Request, Timeout, T) -> %% Call server through proxy process to dodge any late reply + %% + %% We still need a proxy in the distributed case since we may + %% communicate with a node that does not understand aliases. + %% This can be removed when alias support is mandatory. + %% Probably in OTP 26. Ref = make_ref(), Self = self(), Pid = spawn( diff --git a/lib/stdlib/src/stdlib.app.src b/lib/stdlib/src/stdlib.app.src index b59e3b28c0..60ddb64640 100644 --- a/lib/stdlib/src/stdlib.app.src +++ b/lib/stdlib/src/stdlib.app.src @@ -109,6 +109,6 @@ dets]}, {applications, [kernel]}, {env, []}, - {runtime_dependencies, ["sasl-3.0","kernel-7.0","erts-11.0","crypto-3.3", + {runtime_dependencies, ["sasl-3.0","kernel-7.0","erts-@OTP-16718@","crypto-3.3", "compiler-5.0"]} ]}. diff --git a/lib/stdlib/test/gen_fsm_SUITE.erl b/lib/stdlib/test/gen_fsm_SUITE.erl index 6840184c74..539dbe3edc 100644 --- a/lib/stdlib/test/gen_fsm_SUITE.erl +++ b/lib/stdlib/test/gen_fsm_SUITE.erl @@ -410,11 +410,6 @@ abnormal1(Config) when is_list(Config) -> delayed = gen_fsm:sync_send_event(my_fsm, {delayed_answer,1}, 100), {'EXIT',{timeout,_}} = (catch gen_fsm:sync_send_event(my_fsm, {delayed_answer,10}, 1)), - receive - Msg -> - %% Ignore the delayed answer from the server. - io:format("Delayed message: ~p", [Msg]) - end, [] = get_messages(), ok. diff --git a/lib/stdlib/test/gen_server_SUITE.erl b/lib/stdlib/test/gen_server_SUITE.erl index 8015126b0d..c9ebcef188 100644 --- a/lib/stdlib/test/gen_server_SUITE.erl +++ b/lib/stdlib/test/gen_server_SUITE.erl @@ -536,11 +536,11 @@ send_request(Config) when is_list(Config) -> Promise3 = gen_server:send_request(my_test_name, {call_within, 1000}), no_reply = gen_server:check_response({foo, bar}, Promise3), - receive {{'$gen_request_id',Ref},_} = Msg when is_reference(Ref) -> + receive {[alias|Ref],_} = Msg when is_reference(Ref) -> {reply, ok} = gen_server:check_response(Msg, Promise3) after 1000 -> - %% Format not yet doumented so it might be ok - %% This test is just to make you aware that you have changed it + %% Format changed which is ok. This test is just to make you + %% aware that you have changed it exit(message_format_changed) end, timer:sleep(1500), diff --git a/lib/stdlib/test/gen_statem_SUITE.erl b/lib/stdlib/test/gen_statem_SUITE.erl index 76dee868e9..16763ce0f9 100644 --- a/lib/stdlib/test/gen_statem_SUITE.erl +++ b/lib/stdlib/test/gen_statem_SUITE.erl @@ -582,8 +582,7 @@ abnormal1dirty(Config) -> ok = gen_statem:stop(Name), ?t:sleep(1100), case flush() of - [{Ref,delayed}] when is_reference(Ref) -> - ok + [] -> ok end. %% Check that bad return values makes the stm crash. Note that we must diff --git a/lib/wx/test/wx_basic_SUITE.erl b/lib/wx/test/wx_basic_SUITE.erl index 433b705673..8d77c42e8c 100644 --- a/lib/wx/test/wx_basic_SUITE.erl +++ b/lib/wx/test/wx_basic_SUITE.erl @@ -395,13 +395,13 @@ wx_object(Config) -> ?m(false, wxWindow:getParent(Panel) =:= Frame), ?m(true, wx:equal(wxWindow:getParent(Panel),Frame)), flush(), - ReqId = wx_object:send_request(Frame, fun(_US) -> timer:sleep(10), yes end), + ReqId = wx_object:send_request(Frame, fun(_US) -> timer:sleep(10), yes1 end), timeout = wx_object:wait_response(ReqId, 0), - {reply, {call, yes, {Me,{_,ReqId}}}} = wx_object:wait_response(ReqId, 1000), - ReqId2 = wx_object:send_request(Frame, yes), + {reply, {call, yes1, {Me,_}}} = wx_object:wait_response(ReqId, 1000), + ReqId2 = wx_object:send_request(Frame, yes2), [Msg] = flush(), no_reply = wx_object:check_response(Msg, ReqId), - {reply, {call, yes, {Me,{_,ReqId2}}}} = wx_object:check_response(Msg, ReqId2), + {reply, {call, yes2, {Me,_}}} = wx_object:check_response(Msg, ReqId2), FramePid = wx_object:get_pid(Frame), io:format("wx_object pid ~p~n",[FramePid]), |