diff options
author | Dan Gudmundsson <dgud@erlang.org> | 2017-09-21 13:43:52 +0200 |
---|---|---|
committer | Dan Gudmundsson <dgud@erlang.org> | 2019-12-04 17:00:36 +0100 |
commit | 9a4f7576f8b85e87686705d0b6cf8e778a5cb7a8 (patch) | |
tree | fadc95542fd4e8b0bacac13289dd2e466bb67910 /lib/wx/test | |
parent | c4c3b9168d77e6e3f74628c2481753f66a4456bd (diff) | |
download | erlang-9a4f7576f8b85e87686705d0b6cf8e778a5cb7a8.tar.gz |
stdlib: Add 'send_request' and 'wait_response' to generic behaviors
Simplify and encourage users to do more async work. The usage pattern
is already available in the 'rpc' module and similar usages are
available in other languages and standards.
Currently async calls can be implemented via cast or regular messages,
but the user needs to implement it in both client and server.
In the implementation in this commit the server does not need to know
that the client are making async calls.
`wait_response(Promise)` returns `{reply, Reply} | {error, Reason}`.
`wait_response(Promise, Timeout)` returns `{reply, Reply}` | {error,
Reason} or `timeout` if there is a client-side timeout.
The reason for the `reply` tuple is that `Reply` may be positive or
negative answer. That is, `{reply, {ok, Value}}` and `{reply, {error,
Reason}}` looks better than `{ok, {error, Reason}}` or `{ok, {ok,
Value}}`. We also need to encapsulate the return value to
differentiate between client timeouts and the server response that may
be the atom `timeout`.
We don't want do `exit(timeout)` since in that case is is not possible
to do non-blocking wait_response without catching the call to `wait_response(Promise, 0)`.
`check_response(Message, ReqId)` returns `{reply, Reply}` if the
`Message` is a reply from the server associated with the handle
`ReqId`. Otherwise it returns `no_reply`.
`check_response/2` is introduced to be able to handle concurrent
async_calls in a receive loop or in a handle_info callback in another
gen_server.
```
Promise = gen:send_request(..),
.
.
.
dispatch(State) ->
receive
Msg ->
case gen:check_response(Msg, Promise) of
{reply, Reply} ->
{Reply, State};
no_reply ->
State0 = handle_msg(Msg, State0),
dispatch(State0)
end
end.
```
Both wait_response and check_response leaves the monitor until a proper response
is received or the moniter fires. To be able to poll for response.
The functions in rpc are named async_call and yield but
OTB decided to use the names 'send_request', 'wait_response' and
'check_response' here instead.
Returns error tuples in case of server (or network) errors in
'check_response' and 'wait_response'.
For some cases, for example named process not existing, the
'send_request' part in 'gen:call' exited, this is now catched and a
'DOWN' message is faked so that all error handling can be done when
handling the response.
This enables to extend the functionality with
check_response_m(Msg, MapWithRequestIds)
Diffstat (limited to 'lib/wx/test')
-rw-r--r-- | lib/wx/test/wx_basic_SUITE.erl | 11 |
1 files changed, 10 insertions, 1 deletions
diff --git a/lib/wx/test/wx_basic_SUITE.erl b/lib/wx/test/wx_basic_SUITE.erl index ad03a378de..16b531be6c 100644 --- a/lib/wx/test/wx_basic_SUITE.erl +++ b/lib/wx/test/wx_basic_SUITE.erl @@ -394,10 +394,19 @@ wx_object(Config) -> {call, {Frame,Panel}, _} = wx_object:call(Frame, fun(US) -> US end), ?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), + 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), + [Msg] = flush(), + no_reply = wx_object:check_response(Msg, ReqId), + {reply, {call, yes, {Me,ReqId2}}} = wx_object:check_response(Msg, ReqId2), + FramePid = wx_object:get_pid(Frame), io:format("wx_object pid ~p~n",[FramePid]), FramePid ! foo3, - ?m([{info, foo3}|_], flush()), + ?m([{info, foo3}], flush()), ?m(ok, wx_object:cast(Frame, fun(_) -> hehe end)), ?m([{cast, hehe}|_], flush()), |