aboutsummaryrefslogtreecommitdiffstats
path: root/lib/kernel
diff options
context:
space:
mode:
Diffstat (limited to 'lib/kernel')
-rw-r--r--lib/kernel/include/dist.hrl26
-rw-r--r--lib/kernel/src/dist_util.erl199
-rw-r--r--lib/kernel/src/net_kernel.erl8
-rw-r--r--lib/kernel/src/rpc.erl5
-rw-r--r--lib/kernel/test/pdict_SUITE.erl32
5 files changed, 123 insertions, 147 deletions
diff --git a/lib/kernel/include/dist.hrl b/lib/kernel/include/dist.hrl
index db4a5eaebc..b7c35712a6 100644
--- a/lib/kernel/include/dist.hrl
+++ b/lib/kernel/include/dist.hrl
@@ -42,31 +42,5 @@
-define(DFLAG_BIG_CREATION, 16#40000).
-define(DFLAG_SEND_SENDER, 16#80000).
-%% DFLAGs that require strict ordering or:ed together...
--define(DFLAGS_STRICT_ORDER_DELIVERY,
- ?DFLAG_DIST_HDR_ATOM_CACHE).
-
-
%% Also update dflag2str() in ../src/dist_util.erl
%% when adding flags...
-
--define(DFLAGS_ALL,
- (?DFLAG_PUBLISHED
- bor ?DFLAG_ATOM_CACHE
- bor ?DFLAG_EXTENDED_REFERENCES
- bor ?DFLAG_DIST_MONITOR
- bor ?DFLAG_FUN_TAGS
- bor ?DFLAG_DIST_MONITOR_NAME
- bor ?DFLAG_HIDDEN_ATOM_CACHE
- bor ?DFLAG_NEW_FUN_TAGS
- bor ?DFLAG_EXTENDED_PIDS_PORTS
- bor ?DFLAG_EXPORT_PTR_TAG
- bor ?DFLAG_BIT_BINARIES
- bor ?DFLAG_NEW_FLOATS
- bor ?DFLAG_UNICODE_IO
- bor ?DFLAG_DIST_HDR_ATOM_CACHE
- bor ?DFLAG_SMALL_ATOM_TAGS
- bor ?DFLAG_UTF8_ATOMS
- bor ?DFLAG_MAP_TAG
- bor ?DFLAG_BIG_CREATION
- bor ?DFLAG_SEND_SENDER)).
diff --git a/lib/kernel/src/dist_util.erl b/lib/kernel/src/dist_util.erl
index 5ea0ca991f..f7a84c14b4 100644
--- a/lib/kernel/src/dist_util.erl
+++ b/lib/kernel/src/dist_util.erl
@@ -27,6 +27,7 @@
%%-compile(export_all).
-export([handshake_we_started/1, handshake_other_started/1,
+ strict_order_flags/0,
start_timer/1, setup_timer/2,
reset_timer/1, cancel_timer/1,
shutdown/3, shutdown/4]).
@@ -116,22 +117,8 @@ dflag2str(_) ->
"UNKNOWN".
-remove_flag(Flag, Flags) ->
- case Flags band Flag of
- 0 ->
- Flags;
- _ ->
- Flags - Flag
- end.
-
-adjust_flags(ThisFlags, OtherFlags, RejectFlags) ->
- case (?DFLAG_PUBLISHED band ThisFlags) band OtherFlags of
- 0 ->
- {remove_flag(?DFLAG_PUBLISHED, ThisFlags),
- remove_flag(?DFLAG_PUBLISHED, OtherFlags)};
- _ ->
- {ThisFlags, OtherFlags band (bnot RejectFlags)}
- end.
+adjust_flags(ThisFlags, OtherFlags) ->
+ ThisFlags band OtherFlags.
publish_flag(hidden, _) ->
0;
@@ -143,50 +130,35 @@ publish_flag(_, OtherNode) ->
0
end.
--define(DFLAGS_REMOVABLE,
- (?DFLAG_DIST_HDR_ATOM_CACHE
- bor ?DFLAG_HIDDEN_ATOM_CACHE
- bor ?DFLAG_ATOM_CACHE)).
-
--define(DFLAGS_ADDABLE,
- (?DFLAGS_ALL
- band (bnot (?DFLAG_PUBLISHED
- bor ?DFLAG_HIDDEN_ATOM_CACHE
- bor ?DFLAG_ATOM_CACHE)))).
-
--define(DFLAGS_THIS_DEFAULT,
- (?DFLAG_EXPORT_PTR_TAG
- bor ?DFLAG_EXTENDED_PIDS_PORTS
- bor ?DFLAG_EXTENDED_REFERENCES
- bor ?DFLAG_DIST_MONITOR
- bor ?DFLAG_FUN_TAGS
- bor ?DFLAG_DIST_MONITOR_NAME
- bor ?DFLAG_NEW_FUN_TAGS
- bor ?DFLAG_BIT_BINARIES
- bor ?DFLAG_NEW_FLOATS
- bor ?DFLAG_UNICODE_IO
- bor ?DFLAG_DIST_HDR_ATOM_CACHE
- bor ?DFLAG_SMALL_ATOM_TAGS
- bor ?DFLAG_UTF8_ATOMS
- bor ?DFLAG_MAP_TAG
- bor ?DFLAG_BIG_CREATION
- bor ?DFLAG_SEND_SENDER)).
-
-make_this_flags(RequestType, AddFlags, RemoveFlags, OtherNode) ->
- case RemoveFlags band (bnot ?DFLAGS_REMOVABLE) of
+
+%% Sync with dist.c
+-record(erts_dflags, {
+ default, % flags erts prefers
+ mandatory, % flags erts needs
+ addable, % flags local dist implementation is allowed to add
+ rejectable, % flags local dist implementation is allowed to reject
+ strict_order % flags for features needing strict order delivery
+}).
+
+-spec strict_order_flags() -> integer().
+strict_order_flags() ->
+ EDF = erts_internal:get_dflags(),
+ EDF#erts_dflags.strict_order.
+
+make_this_flags(RequestType, AddFlags, RejectFlags, OtherNode,
+ #erts_dflags{}=EDF) ->
+ case RejectFlags band (bnot EDF#erts_dflags.rejectable) of
0 -> ok;
Rerror -> exit({"Rejecting non rejectable flags", Rerror})
end,
- case AddFlags band (bnot ?DFLAGS_ADDABLE) of
+ case AddFlags band (bnot EDF#erts_dflags.addable) of
0 -> ok;
Aerror -> exit({"Adding non addable flags", Aerror})
end,
- Flgs0 = ?DFLAGS_THIS_DEFAULT,
+ Flgs0 = EDF#erts_dflags.default,
Flgs1 = Flgs0 bor publish_flag(RequestType, OtherNode),
Flgs2 = Flgs1 bor AddFlags,
- Flgs3 = Flgs2 band (bnot (?DFLAG_HIDDEN_ATOM_CACHE
- bor ?DFLAG_ATOM_CACHE)),
- Flgs3 band (bnot RemoveFlags).
+ Flgs2 band (bnot RejectFlags).
handshake_other_started(#hs_data{request_type=ReqType,
add_flags=AddFlgs0,
@@ -196,19 +168,18 @@ handshake_other_started(#hs_data{request_type=ReqType,
RejFlgs = convert_flags(RejFlgs0),
ReqFlgs = convert_flags(ReqFlgs0),
{PreOtherFlags,Node,Version} = recv_name(HSData0),
- PreThisFlags = make_this_flags(ReqType, AddFlgs, RejFlgs, Node),
- {ThisFlags, OtherFlags} = adjust_flags(PreThisFlags,
- PreOtherFlags,
- RejFlgs),
- HSData = HSData0#hs_data{this_flags=ThisFlags,
- other_flags=OtherFlags,
+ EDF = erts_internal:get_dflags(),
+ PreThisFlags = make_this_flags(ReqType, AddFlgs, RejFlgs, Node, EDF),
+ ChosenFlags = adjust_flags(PreThisFlags, PreOtherFlags),
+ HSData = HSData0#hs_data{this_flags=ChosenFlags,
+ other_flags=ChosenFlags,
other_version=Version,
other_node=Node,
other_started=true,
add_flags=AddFlgs,
reject_flags=RejFlgs,
require_flags=ReqFlgs},
- check_dflags(HSData),
+ check_dflags(HSData, EDF),
is_allowed(HSData),
?debug({"MD5 connection from ~p (V~p)~n",
[Node, HSData#hs_data.other_version]}),
@@ -247,14 +218,11 @@ is_allowed(#hs_data{other_node = Node,
check_dflags(#hs_data{other_node = Node,
other_flags = OtherFlags,
other_started = OtherStarted,
- require_flags = RequiredFlags} = HSData) ->
- Mandatory = ((?DFLAG_EXTENDED_REFERENCES
- bor ?DFLAG_EXTENDED_PIDS_PORTS
- bor ?DFLAG_UTF8_ATOMS
- bor ?DFLAG_NEW_FUN_TAGS)
- bor RequiredFlags),
- Missing = check_mandatory(0, ?DFLAGS_ALL, Mandatory,
- OtherFlags, []),
+ require_flags = RequiredFlags} = HSData,
+ #erts_dflags{}=EDF) ->
+
+ Mandatory = (EDF#erts_dflags.mandatory bor RequiredFlags),
+ Missing = check_mandatory(Mandatory, OtherFlags, []),
case Missing of
[] ->
ok;
@@ -274,21 +242,20 @@ check_dflags(#hs_data{other_node = Node,
?shutdown2(Node, {check_dflags_failed, Missing})
end.
-check_mandatory(_Bit, 0, _Mandatory, _OtherFlags, Missing) ->
+check_mandatory(0, _OtherFlags, Missing) ->
Missing;
-check_mandatory(Bit, Left, Mandatory, OtherFlags, Missing) ->
- DFlag = (1 bsl Bit),
- NewLeft = Left band (bnot DFlag),
- NewMissing = case {DFlag band Mandatory,
- DFlag band OtherFlags} of
- {DFlag, 0} ->
+check_mandatory(Mandatory, OtherFlags, Missing) ->
+ Left = Mandatory band (Mandatory - 1), % clear lowest set bit
+ DFlag = Mandatory bxor Left, % only lowest set bit
+ NewMissing = case DFlag band OtherFlags of
+ 0 ->
%% Mandatory and missing...
[dflag2str(DFlag) | Missing];
_ ->
- %% Not mandatory or present...
+ %% Mandatory and present...
Missing
end,
- check_mandatory(Bit+1, NewLeft, Mandatory, OtherFlags, NewMissing).
+ check_mandatory(Left, OtherFlags, NewMissing).
%% No nodedown will be sent if we fail before this process has
@@ -410,7 +377,8 @@ handshake_we_started(#hs_data{request_type=ReqType,
AddFlgs = convert_flags(AddFlgs0),
RejFlgs = convert_flags(RejFlgs0),
ReqFlgs = convert_flags(ReqFlgs0),
- PreThisFlags = make_this_flags(ReqType, AddFlgs, RejFlgs, Node),
+ EDF = erts_internal:get_dflags(),
+ PreThisFlags = make_this_flags(ReqType, AddFlgs, RejFlgs, Node, EDF),
HSData = PreHSData#hs_data{this_flags = PreThisFlags,
add_flags = AddFlgs,
reject_flags = RejFlgs,
@@ -418,13 +386,11 @@ handshake_we_started(#hs_data{request_type=ReqType,
send_name(HSData),
recv_status(HSData),
{PreOtherFlags,ChallengeA} = recv_challenge(HSData),
- {ThisFlags,OtherFlags} = adjust_flags(PreThisFlags,
- PreOtherFlags,
- RejFlgs),
- NewHSData = HSData#hs_data{this_flags = ThisFlags,
- other_flags = OtherFlags,
+ ChosenFlags = adjust_flags(PreThisFlags, PreOtherFlags),
+ NewHSData = HSData#hs_data{this_flags = ChosenFlags,
+ other_flags = ChosenFlags,
other_started = false},
- check_dflags(NewHSData),
+ check_dflags(NewHSData, EDF),
MyChallenge = gen_challenge(),
{MyCookie,HisCookie} = get_cookies(Node),
send_challenge_reply(NewHSData,MyChallenge,
@@ -588,7 +554,7 @@ con_loop({Kernel, Node, Socket, Type, DHandle, MFTick, MFGetstat,
{Kernel, aux_tick} ->
case getstat(DHandle, Socket, MFGetstat) of
{ok, _, _, PendWrite} ->
- send_tick(Socket, PendWrite, MFTick);
+ send_aux_tick(Type, Socket, PendWrite, MFTick);
_ ->
ignore_it
end,
@@ -841,49 +807,56 @@ send_status(#hs_data{socket = Socket, other_node = Node,
%% The detection time interval is thus, by default, 45s < DT < 75s
-%% A HIDDEN node is always (if not a pending write) ticked if
-%% we haven't read anything as a hidden node only ticks when it receives
-%% a TICK !!
+%% A HIDDEN node is always ticked if we haven't read anything
+%% as a (primitive) hidden node only ticks when it receives a TICK !!
send_tick(DHandle, Socket, Tick, Type, MFTick, MFGetstat) ->
#tick{tick = T0,
read = Read,
write = Write,
- ticked = Ticked} = Tick,
+ ticked = Ticked0} = Tick,
T = T0 + 1,
T1 = T rem 4,
case getstat(DHandle, Socket, MFGetstat) of
- {ok, Read, _, _} when Ticked =:= T ->
+ {ok, Read, _, _} when Ticked0 =:= T ->
{error, not_responding};
- {ok, Read, W, Pend} when Type =:= hidden ->
- send_tick(Socket, Pend, MFTick),
- {ok, Tick#tick{write = W + 1,
- tick = T1}};
- {ok, Read, Write, Pend} ->
- send_tick(Socket, Pend, MFTick),
- {ok, Tick#tick{write = Write + 1,
- tick = T1}};
- {ok, R, Write, Pend} ->
- send_tick(Socket, Pend, MFTick),
- {ok, Tick#tick{write = Write + 1,
- read = R,
- tick = T1,
- ticked = T}};
- {ok, Read, W, _} ->
- {ok, Tick#tick{write = W,
- tick = T1}};
- {ok, R, W, _} ->
- {ok, Tick#tick{write = W,
- read = R,
- tick = T1,
- ticked = T}};
+
+ {ok, R, W1, Pend} ->
+ RDiff = R - Read,
+ W2 = case need_to_tick(Type, RDiff, W1-Write, Pend) of
+ true ->
+ MFTick(Socket),
+ W1 + 1;
+ false ->
+ W1
+ end,
+
+ Ticked1 = case RDiff of
+ 0 -> Ticked0;
+ _ -> T
+ end,
+
+ {ok, Tick#tick{write = W2,
+ tick = T1,
+ read = R,
+ ticked = Ticked1}};
+
Error ->
Error
end.
-send_tick(_, Pend, _) when Pend /= false, Pend /= 0 ->
+need_to_tick(_, _, 0, 0) -> % nothing written and empty send queue
+ true;
+need_to_tick(_, _, 0, false) -> % nothing written and empty send queue
+ true;
+need_to_tick(hidden, 0, _, _) -> % nothing read from hidden
+ true;
+need_to_tick(_, _, _, _) ->
+ false.
+
+send_aux_tick(normal, _, Pend, _) when Pend /= false, Pend /= 0 ->
ok; %% Dont send tick if pending write.
-send_tick(Socket, _Pend, MFTick) ->
+send_aux_tick(_Type, Socket, _Pend, MFTick) ->
MFTick(Socket).
%% ------------------------------------------------------------
diff --git a/lib/kernel/src/net_kernel.erl b/lib/kernel/src/net_kernel.erl
index cdb10a7b12..f38989d103 100644
--- a/lib/kernel/src/net_kernel.erl
+++ b/lib/kernel/src/net_kernel.erl
@@ -1777,16 +1777,16 @@ async_reply({reply, Msg, State}, From) ->
async_gen_server_reply(From, Msg) ->
{Pid, Tag} = From,
M = {Tag, Msg},
- case catch erlang:send(Pid, M, [nosuspend, noconnect]) of
+ try erlang:send(Pid, M, [nosuspend, noconnect]) of
ok ->
ok;
nosuspend ->
_ = spawn(fun() -> catch erlang:send(Pid, M, [noconnect]) end),
ok;
noconnect ->
- ok; % The gen module takes care of this case.
- {'EXIT', _} ->
- ok
+ ok % The gen module takes care of this case.
+ catch
+ _:_ -> ok
end.
call_owner(Owner, Msg) ->
diff --git a/lib/kernel/src/rpc.erl b/lib/kernel/src/rpc.erl
index b04aa9030b..d197de942f 100644
--- a/lib/kernel/src/rpc.erl
+++ b/lib/kernel/src/rpc.erl
@@ -418,10 +418,7 @@ abcast(Name, Mess) ->
abcast([Node|Tail], Name, Mess) ->
Dest = {Name,Node},
- case catch erlang:send(Dest, Mess, [noconnect]) of
- noconnect -> spawn(erlang, send, [Dest,Mess]), ok;
- _ -> ok
- end,
+ try erlang:send(Dest, Mess) catch error:_ -> ok end,
abcast(Tail, Name, Mess);
abcast([], _,_) -> abcast.
diff --git a/lib/kernel/test/pdict_SUITE.erl b/lib/kernel/test/pdict_SUITE.erl
index d105952df9..a891451c82 100644
--- a/lib/kernel/test/pdict_SUITE.erl
+++ b/lib/kernel/test/pdict_SUITE.erl
@@ -33,6 +33,7 @@
init_per_group/2,end_per_group/2,
mixed/1,
literals/1,
+ destructive/1,
simple/1, complicated/1, heavy/1, simple_all_keys/1, info/1]).
-export([init_per_testcase/2, end_per_testcase/2]).
-export([other_process/2]).
@@ -52,6 +53,7 @@ suite() ->
all() ->
[simple, complicated, heavy, simple_all_keys, info,
literals,
+ destructive,
mixed].
groups() ->
@@ -367,6 +369,36 @@ match_keys(All) ->
ok.
+%% Test destructive put optimization of immed values
+%% does not affect get/0 or process_info.
+destructive(_Config) ->
+ Keys = lists:seq(1,100),
+ [put(Key, 17) || Key <- Keys],
+ Get1 = get(),
+ {dictionary,PI1} = process_info(self(), dictionary),
+
+ [begin
+ {Key, 17} = lists:keyfind(Key, 1, Get1),
+ {Key, 17} = lists:keyfind(Key, 1, PI1)
+ end
+ || Key <- Keys],
+
+ [17 = put(Key, 42) || Key <- Keys], % Mutate
+
+ Get2 = get(),
+ {dictionary,PI2} = process_info(self(), dictionary),
+
+ [begin
+ {Key, 17} = lists:keyfind(Key, 1, Get1),
+ {Key, 17} = lists:keyfind(Key, 1, PI1),
+ {Key, 42} = lists:keyfind(Key, 1, Get2),
+ {Key, 42} = lists:keyfind(Key, 1, PI2)
+
+ end
+ || Key <- Keys],
+
+ ok.
+
%% Do random mixed put/erase to test grow/shrink
%% Written for a temporary bug in gc during shrink
mixed(_Config) ->