summaryrefslogtreecommitdiff
path: root/lib/kernel
diff options
context:
space:
mode:
authorMicael Karlberg <bmk@erlang.org>2021-04-23 19:23:40 +0200
committerMicael Karlberg <bmk@erlang.org>2021-04-26 16:07:26 +0200
commit3a1bbe1e023e58c70c469bf9a7ffc78daa43d4ad (patch)
tree12aa33549376ca25222be393b17c3074f85fa969 /lib/kernel
parente54747c59dbb573757875f9c982705ac60d11f4d (diff)
downloaderlang-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.erl15
-rw-r--r--lib/kernel/src/inet.erl13
-rw-r--r--lib/kernel/src/socket.erl47
-rw-r--r--lib/kernel/test/socket_SUITE.erl158
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) ->