diff options
author | Micael Karlberg <bmk@erlang.org> | 2021-04-23 19:23:40 +0200 |
---|---|---|
committer | Micael Karlberg <bmk@erlang.org> | 2021-04-26 16:07:26 +0200 |
commit | 3a1bbe1e023e58c70c469bf9a7ffc78daa43d4ad (patch) | |
tree | 12aa33549376ca25222be393b17c3074f85fa969 /lib/kernel | |
parent | e54747c59dbb573757875f9c982705ac60d11f4d (diff) | |
download | erlang-3a1bbe1e023e58c70c469bf9a7ffc78daa43d4ad.tar.gz |
[kernel] Add some utility functions (prep for observer).
Add a couple of utility functions, soch as listing monitors
for a socket och which processes has monitored a socket.
Also add utility function to convert a socket to a string (to_list/1)
comparable to erlang:port_to_list/1.
OTP-17155
Diffstat (limited to 'lib/kernel')
-rw-r--r-- | lib/kernel/src/gen_tcp_socket.erl | 15 | ||||
-rw-r--r-- | lib/kernel/src/inet.erl | 13 | ||||
-rw-r--r-- | lib/kernel/src/socket.erl | 47 | ||||
-rw-r--r-- | lib/kernel/test/socket_SUITE.erl | 158 |
4 files changed, 207 insertions, 26 deletions
diff --git a/lib/kernel/src/gen_tcp_socket.erl b/lib/kernel/src/gen_tcp_socket.erl index 743c64cfe5..1d49c1c666 100644 --- a/lib/kernel/src/gen_tcp_socket.erl +++ b/lib/kernel/src/gen_tcp_socket.erl @@ -37,7 +37,7 @@ ]). %% Utility --export([info/1]). +-export([info/1, socket_to_list/1]). -ifdef(undefined). -export([unrecv/2]). @@ -511,8 +511,10 @@ monitor(?module_socket(_Server, ESock) = Socket) -> monitor(Socket) -> erlang:error(badarg, [Socket]). +cancel_monitor(MRef) when is_reference(MRef) -> + socket:cancel_monitor(MRef); cancel_monitor(MRef) -> - socket:cancel_monitor(MRef). + erlang:error(badarg, [MRef]). %% ------------------------------------------------------------------------- @@ -554,6 +556,15 @@ info(?MODULE_socket(Server, _Socket)) -> call(Server, info). +%% ------------------------------------------------------------------------- + +socket_to_list(?module_socket(_Server, Socket)) -> + "#Socket" ++ Id = socket:to_list(Socket), + "#InetSocket" ++ Id; +socket_to_list(Socket) -> + erlang:error(badarg, [Socket]). + + %%% ======================================================================== %%% Socket glue code %%% diff --git a/lib/kernel/src/inet.erl b/lib/kernel/src/inet.erl index 219876bac2..17c278923f 100644 --- a/lib/kernel/src/inet.erl +++ b/lib/kernel/src/inet.erl @@ -31,7 +31,7 @@ getif/1, getif/0, getiflist/0, getiflist/1, ifget/3, ifget/2, ifset/3, ifset/2, getstat/1, getstat/2, - info/1, + info/1, socket_to_list/1, ip/1, stats/0, options/0, pushf/3, popf/1, close/1, gethostname/0, gethostname/1, parse_ipv4_address/1, parse_ipv6_address/1, parse_ipv4strict_address/1, @@ -655,6 +655,17 @@ gethostbyaddr_tm(Address,Timer) -> gethostbyaddr_tm(Address, Timer, inet_db:res_option(lookup)). +-spec socket_to_list(Socket) -> list() when + Socket :: socket(). + +socket_to_list({'$inet', GenSocketMod, _} = Socket) + when is_atom(GenSocketMod) -> + GenSocketMod:to_list(Socket); +socket_to_list(Socket) when is_port(Socket) -> + erlang:port_to_list(Socket). + + + -spec info(Socket) -> Info when Socket :: socket(), Info :: term(). diff --git a/lib/kernel/src/socket.erl b/lib/kernel/src/socket.erl index d63d80bfe8..cc973d81c2 100644 --- a/lib/kernel/src/socket.erl +++ b/lib/kernel/src/socket.erl @@ -31,12 +31,15 @@ %% (registry) Socket monitor functions number_of_monitors/0, number_of_monitors/1, which_monitors/1, + monitored_by/1, debug/1, socket_debug/1, use_registry/1, info/0, info/1, monitor/1, cancel_monitor/1, supports/0, supports/1, supports/2, - is_supported/1, is_supported/2, is_supported/3 + is_supported/1, is_supported/2, is_supported/3, + + to_list/1 ]). -export([ @@ -807,14 +810,50 @@ number_of_monitors(Pid) when is_pid(Pid) -> %% *** which_monitors/1 *** %% %% Interface function to the socket registry -%% Returns a list of all the monitors of the process. +%% Returns a list of all the monitors of the process or socket. %% -spec which_monitors(Pid) -> [reference()] when - Pid :: pid(). + Pid :: pid(); + (Socket) -> [reference()] when + Socket :: socket(). which_monitors(Pid) when is_pid(Pid) -> - ?REGISTRY:which_monitors(Pid). + ?REGISTRY:which_monitors(Pid); +which_monitors(?socket(SockRef) = Socket) when is_reference(SockRef) -> + ?REGISTRY:which_monitors(Socket); +which_monitors(Socket) -> + erlang:error(badarg, [Socket]). + + +%% *** monitor_by/1 *** +%% +%% Interface function to the socket registry +%% Returns a list of all the process'es monitoring the socket. +%% + +-spec monitored_by(Socket) -> [reference()] when + Socket :: socket(). + +monitored_by(?socket(SockRef) = Socket) when is_reference(SockRef) -> + ?REGISTRY:monitored_by(Socket); +monitored_by(Socket) -> + erlang:error(badarg, [Socket]). + + +%% *** to_list/1 *** +%% +%% This is intended to convert a socket() to a printable string. +%% + +-spec to_list(Socket) -> list() when + Socket :: socket(). + +to_list(?socket(SockRef)) when is_reference(SockRef) -> + "#Ref" ++ Id = erlang:ref_to_list(SockRef), + "#Socket" ++ Id; +to_list(Socket) -> + erlang:error(badarg, [Socket]). %% =========================================================================== diff --git a/lib/kernel/test/socket_SUITE.erl b/lib/kernel/test/socket_SUITE.erl index 221e0ea888..efa755fa73 100644 --- a/lib/kernel/test/socket_SUITE.erl +++ b/lib/kernel/test/socket_SUITE.erl @@ -25822,20 +25822,60 @@ mon_simple_open_and_close(InitState) -> 0 = socket:number_of_monitors(self()), ok end}, - #{desc => "monitor socket", + #{desc => "monitor socket - create two", cmd => fun(#{sock := Sock} = State) -> - MRef = socket:monitor(Sock), - ?SEV_IPRINT("Monitor: ~p", [MRef]), - {ok, State#{mon => MRef}} + MRef1 = socket:monitor(Sock), + MRef2 = socket:monitor(Sock), + ?SEV_IPRINT("Monitor(s): " + "~n 1: ~p" + "~n 2: ~p", [MRef1, MRef2]), + {ok, State#{mon1 => MRef1, mon2 => MRef2}} end}, - #{desc => "verify total number of monitors (=1)", + #{desc => "verify total number of monitors (=2)", cmd => fun(_State) -> - 1 = socket:number_of_monitors(), + 2 = socket:number_of_monitors(), ok end}, - #{desc => "verify own number of monitors (=1)", + #{desc => "verify own number of monitors (=2)", cmd => fun(_State) -> - 1 = socket:number_of_monitors(self()), + 2 = socket:number_of_monitors(self()), + ok + end}, + #{desc => "verify which monitors - (self) two", + cmd => fun(#{mon1 := MRef1, + mon2 := MRef2} = _State) -> + Mons = lists:sort([MRef1, MRef2]), + case lists:sort(socket:which_monitors(self())) of + Mons -> + ok; + SMons -> + ?SEV_EPRINT("Unexpected (self) monitors: " + "~n Expected: ~p" + "~n Actual: ~p", + [Mons, SMons]), + {error, unexpected_monitors} + end + end}, + #{desc => "verify which monitors - (sock) two", + cmd => fun(#{sock := Sock, + mon1 := MRef1, + mon2 := MRef2} = _State) -> + Mons = lists:sort([MRef1, MRef2]), + case lists:sort(socket:which_monitors(Sock)) of + Mons -> + ok; + SMons -> + ?SEV_EPRINT("Unexpected (sock) monitors: " + "~n Expected: ~p" + "~n Actual: ~p", + [Mons, SMons]), + {error, unexpected_monitors} + end + end}, + #{desc => "verify monitored by - only us", + cmd => fun(#{sock := Sock} = _State) -> + Self = self(), + [Self] = socket:monitored_by(Sock), ok end}, @@ -25845,17 +25885,37 @@ mon_simple_open_and_close(InitState) -> ?SEV_ANNOUNCE_CONTINUE(Pid, close), ok end}, - #{desc => "await socket down", + #{desc => "await socket down 1", cmd => fun(#{sock := Sock, - mon := MRef} = _State) -> + mon1 := MRef} = _State) -> receive {'DOWN', MRef, socket, Sock, Info} -> ?SEV_IPRINT("received expected down: " "~n MRef: ~p" - "~n Socket: ~p" + "~n Socket: ~s" "~n Info: ~p", - [MRef, Sock, Info]), - ok + [MRef, + socket:to_list(Sock), + Info]), + {ok, maps:remove(mon1, State)} + after 5000 -> + ?SEV_EPRINT("socket down timeout"), + {error, timeout} + end + end}, + #{desc => "await socket down 2", + cmd => fun(#{sock := Sock, + mon2 := MRef} = State) -> + receive + {'DOWN', MRef, socket, Sock, Info} -> + ?SEV_IPRINT("received expected down: " + "~n MRef: ~p" + "~n Socket: ~s" + "~n Info: ~p", + [MRef, + socket:to_list(Sock), + Info]), + {ok, maps:remove(mon2, State)} after 5000 -> ?SEV_EPRINT("socket down timeout"), {error, timeout} @@ -25871,6 +25931,17 @@ mon_simple_open_and_close(InitState) -> 0 = socket:number_of_monitors(self()), ok end}, + #{desc => "verify which monitors - only one", + cmd => fun(#{sock := Sock} = _State) -> + [] = socket:which_monitors(self()), + [] = socket:which_monitors(Sock), + ok + end}, + #{desc => "verify monitored by - none", + cmd => fun(#{sock := Sock} = _State) -> + [] = socket:monitored_by(Sock), + ok + end}, %% Cleanup #{desc => "order (owner) terminate", @@ -26016,6 +26087,19 @@ mon_simple_open_and_exit(InitState) -> 1 = socket:number_of_monitors(self()), ok end}, + #{desc => "verify which monitors - only one", + cmd => fun(#{sock := Sock, + mon := MRef} = _State) -> + [MRef] = socket:which_monitors(self()), + [MRef] = socket:which_monitors(Sock), + ok + end}, + #{desc => "verify monitored by - only us", + cmd => fun(#{sock := Sock} = _State) -> + Self = self(), + [Self] = socket:monitored_by(Sock), + ok + end}, %% The actual test #{desc => "order (owner) terminate", @@ -26059,6 +26143,17 @@ mon_simple_open_and_exit(InitState) -> 0 = socket:number_of_monitors(self()), ok end}, + #{desc => "verify which monitors - only one", + cmd => fun(#{sock := Sock} = _State) -> + [] = socket:which_monitors(self()), + [] = socket:which_monitors(Sock), + ok + end}, + #{desc => "verify monitored by - none", + cmd => fun(#{sock := Sock} = _State) -> + [] = socket:monitored_by(Sock), + ok + end}, %% *** We are done *** ?SEV_FINISH_NORMAL @@ -26519,9 +26614,11 @@ mon_open_and_close_multi_socks(InitState) -> {'DOWN', MRef, socket, Sock, Info} -> ?SEV_IPRINT("received expected down: " "~n MRef: ~p" - "~n Socket: ~p" + "~n Socket: ~s" "~n Info: ~p", - [MRef, Sock, Info]), + [MRef, + socket:to_list(Sock), + Info]), State2 = maps:remove(sock1, State), State3 = maps:remove(mon1, State2), {ok, State3} @@ -26553,9 +26650,11 @@ mon_open_and_close_multi_socks(InitState) -> {'DOWN', MRef, socket, Sock, Info} -> ?SEV_IPRINT("received expected down: " "~n MRef: ~p" - "~n Socket: ~p" + "~n Socket: ~s" "~n Info: ~p", - [MRef, Sock, Info]), + [MRef, + socket:to_list(Sock), + Info]), State2 = maps:remove(sock2, State), State3 = maps:remove(mon2, State2), {ok, State3} @@ -26587,9 +26686,11 @@ mon_open_and_close_multi_socks(InitState) -> {'DOWN', MRef, socket, Sock, Info} -> ?SEV_IPRINT("received expected down: " "~n MRef: ~p" - "~n Socket: ~p" + "~n Socket: ~s" "~n Info: ~p", - [MRef, Sock, Info]), + [MRef, + socket:to_list(Sock), + Info]), State2 = maps:remove(sock3, State), State3 = maps:remove(mon3, State2), {ok, State3} @@ -27792,6 +27893,25 @@ mon_open_and_close_multi_mon(InitState) -> 5 = socket:number_of_monitors(), ok end}, + #{desc => "verify monitored by - none", + cmd => fun(#{sock := Sock, + client1 := Pid1, + client2 := Pid2, + client3 := Pid3, + client4 := Pid4, + client5 := Pid5} = _State) -> + Clients = lists:sort([Pid1, Pid2, Pid3, Pid4, Pid5]), + case lists:sort(socket:monitored_by(Sock)) of + Clients -> + ok; + SClients -> + ?SEV_EPRINT("Unexpected clients: " + "~n Expected: ~p" + "~n Actual: ~p", + [Clients, SClients]), + {error, unexpected_clients} + end + end}, #{desc => "order client 1 to await down", cmd => fun(#{client1 := Pid} = _State) -> |