aboutsummaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/kernel/src/Makefile1
-rw-r--r--lib/kernel/src/kernel.app.src2
-rw-r--r--lib/kernel/src/kernel.erl11
-rw-r--r--lib/kernel/src/kernel_refc.erl139
-rw-r--r--lib/kernel/test/kernel_SUITE.erl69
-rw-r--r--lib/runtime_tools/src/observer_backend.erl6
-rw-r--r--lib/sasl/test/release_handler_SUITE.erl38
-rw-r--r--lib/tools/emacs/erlang.el2
8 files changed, 246 insertions, 22 deletions
diff --git a/lib/kernel/src/Makefile b/lib/kernel/src/Makefile
index 4a713b2a99..0bc9f121a0 100644
--- a/lib/kernel/src/Makefile
+++ b/lib/kernel/src/Makefile
@@ -106,6 +106,7 @@ MODULES = \
inet_sctp \
kernel \
kernel_config \
+ kernel_refc \
local_udp \
local_tcp \
net \
diff --git a/lib/kernel/src/kernel.app.src b/lib/kernel/src/kernel.app.src
index e4852a6e75..82a3571da9 100644
--- a/lib/kernel/src/kernel.app.src
+++ b/lib/kernel/src/kernel.app.src
@@ -57,6 +57,7 @@
inet_tcp_dist,
kernel,
kernel_config,
+ kernel_refc,
local_tcp,
local_udp,
net,
@@ -114,6 +115,7 @@
heart,
init,
kernel_config,
+ kernel_refc,
kernel_sup,
net_kernel,
net_sup,
diff --git a/lib/kernel/src/kernel.erl b/lib/kernel/src/kernel.erl
index cba57088ec..0382764b39 100644
--- a/lib/kernel/src/kernel.erl
+++ b/lib/kernel/src/kernel.erl
@@ -111,6 +111,13 @@ init([]) ->
type => worker,
modules => [kernel_config]},
+ RefC = #{id => kernel_refc,
+ start => {kernel_refc, start_link, []},
+ restart => permanent,
+ shutdown => 2000,
+ type => worker,
+ modules => [kernel_refc]},
+
Code = #{id => code_server,
start => {code, start_link, []},
restart => permanent,
@@ -148,7 +155,7 @@ init([]) ->
case init:get_argument(mode) of
{ok, [["minimal"]]} ->
- {ok, {SupFlags, [Code, File, StdError, User, Config, SafeSup]}};
+ {ok, {SupFlags, [Code, File, StdError, User, Config, RefC, SafeSup]}};
_ ->
Rpc = #{id => rex,
start => {rpc, start_link, []},
@@ -199,7 +206,7 @@ init([]) ->
{ok, {SupFlags,
[Code, Rpc, Global, InetDb | DistAC] ++
[NetSup, GlGroup, File, SigSrv,
- StdError, User, Config, SafeSup] ++ Timer}}
+ StdError, User, Config, RefC, SafeSup] ++ Timer}}
end;
init(safe) ->
SupFlags = #{strategy => one_for_one,
diff --git a/lib/kernel/src/kernel_refc.erl b/lib/kernel/src/kernel_refc.erl
new file mode 100644
index 0000000000..05076dc885
--- /dev/null
+++ b/lib/kernel/src/kernel_refc.erl
@@ -0,0 +1,139 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2017. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%%
+-module(kernel_refc).
+
+-behaviour(gen_server).
+
+%% External exports
+-export([start_link/0, scheduler_wall_time/1]).
+%% Internal exports
+-export([init/1, handle_info/2, terminate/2]).
+-export([handle_call/3, handle_cast/2, code_change/3]).
+
+%%%-----------------------------------------------------------------
+%%% This module implements a process that handles reference counters for
+%%% various erts or other kernel resources which needs reference counting.
+%%%
+%%% Should not be documented nor used directly by user applications.
+%%%-----------------------------------------------------------------
+start_link() ->
+ gen_server:start_link({local,kernel_refc}, kernel_refc, [], []).
+
+-spec scheduler_wall_time(boolean()) -> boolean().
+scheduler_wall_time(Bool) ->
+ gen_server:call(kernel_refc, {scheduler_wall_time, self(), Bool}, infinity).
+
+%%-----------------------------------------------------------------
+%% Callback functions from gen_server
+%%-----------------------------------------------------------------
+
+-spec init([]) -> {'ok', map()} | {'stop', term()}.
+
+init([]) ->
+ resource(scheduler_wall_time, false),
+ {ok, #{scheduler_wall_time=>#{}}}.
+
+-spec handle_call(term(), term(), State) -> {'reply', term(), State}.
+handle_call({What, Who, false}, _From, State) ->
+ {Reply, Cnt} = do_stop(What, maps:get(What, State), Who),
+ {reply, Reply, State#{What:=Cnt}};
+handle_call({What, Who, true}, _From, State) ->
+ {Reply, Cnt} = do_start(What, maps:get(What, State), Who),
+ {reply, Reply, State#{What:=Cnt}};
+handle_call(_, _From, State) ->
+ {reply, badarg, State}.
+
+-spec handle_cast(term(), State) -> {'noreply', State}.
+handle_cast(_, State) ->
+ {noreply, State}.
+
+-spec handle_info(term(), State) -> {'noreply', State}.
+handle_info({'DOWN', _Ref, process, Pid, _}, State) ->
+ Cleanup = fun(Resource, Cnts) ->
+ cleanup(Resource, Cnts, Pid)
+ end,
+ {noreply, maps:map(Cleanup, State)};
+handle_info(_, State) ->
+ {noreply, State}.
+
+-spec terminate(term(), term()) -> 'ok'.
+terminate(_Reason, _State) ->
+ ok.
+
+-spec code_change(term(), State, term()) -> {'ok', State}.
+code_change(_OldVsn, State, _Extra) ->
+ {ok, State}.
+
+%%-----------------------------------------------------------------
+%% Internal functions
+%%-----------------------------------------------------------------
+
+do_start(Resource, Cnt, Pid) ->
+ case maps:get(Pid, Cnt, undefined) of
+ undefined ->
+ Ref = erlang:monitor(process, Pid),
+ case any(Cnt) of
+ true ->
+ {true, Cnt#{Pid=>{1, Ref}}};
+ false ->
+ resource(Resource, true),
+ {false, Cnt#{Pid=>{1, Ref}}}
+ end;
+ {N, Ref} ->
+ {true, Cnt#{Pid=>{N+1, Ref}}}
+ end.
+
+do_stop(Resource, Cnt0, Pid) ->
+ case maps:get(Pid, Cnt0, undefined) of
+ undefined ->
+ {any(Cnt0), Cnt0};
+ {1, Ref} ->
+ erlang:demonitor(Ref, [flush]),
+ Cnt = maps:remove(Pid, Cnt0),
+ case any(Cnt) of
+ true ->
+ {true, Cnt};
+ false ->
+ resource(Resource, false),
+ {true, Cnt}
+ end;
+ {N, Ref} ->
+ {true, Cnt0#{Pid=>{N-1, Ref}}}
+ end.
+
+cleanup(Resource, Cnt0, Pid) ->
+ case maps:is_key(Pid, Cnt0) of
+ true ->
+ Cnt = maps:remove(Pid, Cnt0),
+ case any(Cnt) of
+ true ->
+ Cnt;
+ false ->
+ resource(Resource, false),
+ Cnt
+ end;
+ false ->
+ Cnt0
+ end.
+
+any(Cnt) -> maps:size(Cnt) > 0.
+
+resource(scheduler_wall_time, Enable) ->
+ _ = erts_internal:scheduler_wall_time(Enable).
diff --git a/lib/kernel/test/kernel_SUITE.erl b/lib/kernel/test/kernel_SUITE.erl
index da56359294..7898988dbe 100644
--- a/lib/kernel/test/kernel_SUITE.erl
+++ b/lib/kernel/test/kernel_SUITE.erl
@@ -30,14 +30,14 @@
-export([init_per_testcase/2, end_per_testcase/2]).
%% Test cases must be exported.
--export([app_test/1, appup_test/1]).
+-export([app_test/1, appup_test/1, refc/1]).
suite() ->
[{ct_hooks,[ts_install_cth]},
{timetrap,{minutes,2}}].
all() ->
- [app_test, appup_test].
+ [app_test, appup_test, refc].
groups() ->
[].
@@ -163,3 +163,68 @@ check_appup([Vsn|Vsns],Instrs,Expected) ->
end;
check_appup([],_,_) ->
ok.
+
+%%% Check that refc module handles the counters as expected
+refc(_Config) ->
+ Enable = fun(Enable) -> erlang:system_flag(scheduler_wall_time, Enable) end,
+ IsOn = fun() -> undefined /= erlang:statistics(scheduler_wall_time) end,
+ Tester = self(),
+ Loop = fun Loop() ->
+ receive
+ die -> normal;
+ {apply, Bool} ->
+ Res = Enable(Bool),
+ Tester ! {self(), Res},
+ Loop()
+ end
+ end,
+
+ %% Counter should be 0
+ false = Enable(false),
+
+ false = Enable(true),
+ true = Enable(true),
+ true = Enable(false),
+ true = Enable(false),
+
+ %% Counter should be 0
+ false = IsOn(),
+
+ P1 = spawn_link(Loop),
+ P1 ! {apply, true},
+ receive {P1, R1} -> false = R1 end,
+
+ %% P1 has turned it on counter should be one
+ true = IsOn(),
+ true = Enable(true),
+ true = Enable(false),
+ true = IsOn(),
+
+ P1 ! {apply, false},
+ receive {P1, R2} -> true = R2 end,
+ false = IsOn(),
+
+ P1 ! {apply, true},
+ receive {P1, R3} -> false = R3 end,
+ true = IsOn(),
+ true = Enable(false),
+
+
+ P1 ! die,
+ timer:sleep(100),
+ false = IsOn(),
+ false = Enable(false),
+
+ P2 = spawn_link(Loop),
+ P2 ! {apply, true},
+ receive {P2, R4} -> false = R4 end,
+ true = IsOn(),
+ P2 ! {apply, true},
+ receive {P2, R5} -> true = R5 end,
+ true = IsOn(),
+
+ P2 ! die,
+ timer:sleep(100),
+ false = IsOn(),
+
+ ok.
diff --git a/lib/runtime_tools/src/observer_backend.erl b/lib/runtime_tools/src/observer_backend.erl
index 1b075a507d..a1edde8516 100644
--- a/lib/runtime_tools/src/observer_backend.erl
+++ b/lib/runtime_tools/src/observer_backend.erl
@@ -293,7 +293,7 @@ fetch_stats_loop(Parent, Time) ->
erlang:system_flag(scheduler_wall_time, true),
receive
_Msg ->
- %% erlang:system_flag(scheduler_wall_time, false)
+ erlang:system_flag(scheduler_wall_time, false),
ok
after Time ->
_M = Parent ! {stats, 1,
@@ -340,7 +340,6 @@ etop_collect(Collector) ->
case SchedulerWallTime of
undefined ->
- erlang:system_flag(scheduler_wall_time,true),
spawn(fun() -> flag_holder_proc(Collector) end),
ok;
_ ->
@@ -348,10 +347,11 @@ etop_collect(Collector) ->
end.
flag_holder_proc(Collector) ->
+ erlang:system_flag(scheduler_wall_time,true),
Ref = erlang:monitor(process,Collector),
receive
{'DOWN',Ref,_,_,_} ->
- %% erlang:system_flag(scheduler_wall_time,false)
+ erlang:system_flag(scheduler_wall_time,false),
ok
end.
diff --git a/lib/sasl/test/release_handler_SUITE.erl b/lib/sasl/test/release_handler_SUITE.erl
index 4935782cf2..824820c214 100644
--- a/lib/sasl/test/release_handler_SUITE.erl
+++ b/lib/sasl/test/release_handler_SUITE.erl
@@ -22,7 +22,8 @@
-include_lib("common_test/include/ct.hrl").
-include("test_lib.hrl").
--compile(export_all).
+-compile([export_all, nowarn_export_all]).
+-export([scheduler_wall_time/0, garbage_collect/0]). %% rpc'ed
% Default timetrap timeout (set in init_per_testcase).
%-define(default_timeout, ?t:minutes(40)).
@@ -1085,8 +1086,9 @@ otp_9395_update_many_mods(Conf) when is_list(Conf) ->
Rel2Dir = filename:dirname(Rel2),
%% Start a slave node
+ PA = filename:dirname(code:which(?MODULE)),
{ok, Node} = t_start_node(otp_9395_update_many_mods, Rel1,
- filename:join(Rel1Dir,"sys.config")),
+ filename:join(Rel1Dir,"sys.config"), "-pa " ++ PA),
%% Start a lot of processes on the new node, all with refs to each
%% module that will be updated
@@ -1109,8 +1111,8 @@ otp_9395_update_many_mods(Conf) when is_list(Conf) ->
[RelVsn2, filename:join(Rel2Dir, "sys.config")]),
%% First, install release directly and check how much time it takes
- rpc:call(Node,erlang,garbage_collect,[]),
- rpc:call(Node,erlang,system_flag,[scheduler_wall_time,true]),
+ rpc:call(Node,?MODULE,garbage_collect,[]),
+ SWTFlag0 = spawn_link(Node, ?MODULE, scheduler_wall_time, []),
{TInst0,{ok, _, []}} =
timer:tc(rpc,call,[Node, release_handler, install_release, [RelVsn2]]),
SWT0 = rpc:call(Node,erlang,statistics,[scheduler_wall_time]),
@@ -1135,9 +1137,9 @@ otp_9395_update_many_mods(Conf) when is_list(Conf) ->
%% Finally install release after check and purge, and check that
%% this install was faster than the first.
- rpc:call(Node,erlang,system_flag,[scheduler_wall_time,false]),
- rpc:call(Node,erlang,garbage_collect,[]),
- rpc:call(Node,erlang,system_flag,[scheduler_wall_time,true]),
+ SWTFlag0 ! die,
+ rpc:call(Node,?MODULE,garbage_collect,[]),
+ _SWTFlag1 = spawn_link(Node, ?MODULE, scheduler_wall_time, []),
{TInst2,{ok, _RelVsn1, []}} =
timer:tc(rpc,call,[Node, release_handler, install_release, [RelVsn2]]),
SWT2 = rpc:call(Node,erlang,statistics,[scheduler_wall_time]),
@@ -1161,6 +1163,15 @@ otp_9395_update_many_mods(Conf) when is_list(Conf) ->
ok.
+scheduler_wall_time() ->
+ erlang:system_flag(scheduler_wall_time,true),
+ receive _Msg -> normal end.
+
+garbage_collect() ->
+ Pids = processes(),
+ [erlang:garbage_collect(Pid) || Pid <- Pids].
+
+
otp_9395_update_many_mods(cleanup,_Conf) ->
stop_node(node_name(otp_9395_update_many_mods)).
@@ -1190,8 +1201,9 @@ otp_9395_rm_many_mods(Conf) when is_list(Conf) ->
Rel2Dir = filename:dirname(Rel2),
%% Start a slave node
+ PA = filename:dirname(code:which(?MODULE)),
{ok, Node} = t_start_node(otp_9395_rm_many_mods, Rel1,
- filename:join(Rel1Dir,"sys.config")),
+ filename:join(Rel1Dir,"sys.config"), "-pa " ++ PA),
%% Start a lot of processes on the new node, all with refs to each
%% module that will be updated
@@ -1214,8 +1226,8 @@ otp_9395_rm_many_mods(Conf) when is_list(Conf) ->
[RelVsn2, filename:join(Rel2Dir, "sys.config")]),
%% First, install release directly and check how much time it takes
- rpc:call(Node,erlang,garbage_collect,[]),
- rpc:call(Node,erlang,system_flag,[scheduler_wall_time,true]),
+ rpc:call(Node,?MODULE,garbage_collect,[]),
+ SWTFlag0 = spawn_link(Node, ?MODULE, scheduler_wall_time, []),
{TInst0,{ok, _, []}} =
timer:tc(rpc,call,[Node, release_handler, install_release, [RelVsn2]]),
SWT0 = rpc:call(Node,erlang,statistics,[scheduler_wall_time]),
@@ -1240,9 +1252,9 @@ otp_9395_rm_many_mods(Conf) when is_list(Conf) ->
%% Finally install release after check and purge, and check that
%% this install was faster than the first.
- rpc:call(Node,erlang,system_flag,[scheduler_wall_time,false]),
- rpc:call(Node,erlang,garbage_collect,[]),
- rpc:call(Node,erlang,system_flag,[scheduler_wall_time,true]),
+ SWTFlag0 ! die,
+ rpc:call(Node,?MODULE,garbage_collect,[]),
+ _SWTFlag1 = spawn_link(Node, ?MODULE, scheduler_wall_time, []),
{TInst2,{ok, _RelVsn1, []}} =
timer:tc(rpc,call,[Node, release_handler, install_release, [RelVsn2]]),
SWT2 = rpc:call(Node,erlang,statistics,[scheduler_wall_time]),
diff --git a/lib/tools/emacs/erlang.el b/lib/tools/emacs/erlang.el
index d9efadf64a..6b93d63182 100644
--- a/lib/tools/emacs/erlang.el
+++ b/lib/tools/emacs/erlang.el
@@ -885,7 +885,6 @@ resulting regexp is surrounded by \\_< and \\_>."
"append"
"append_element"
"await_proc_exit"
- "await_sched_wall_time_modifications"
"bump_reductions"
"call_on_load_function"
"cancel_timer"
@@ -923,7 +922,6 @@ resulting regexp is surrounded by \\_< and \\_>."
"function_exported"
"garbage_collect_message_area"
"gather_gc_info_result"
- "gather_sched_wall_time_result"
"get_cookie"
"get_module_info"
"get_stacktrace"