aboutsummaryrefslogtreecommitdiffstats
path: root/erts/preloaded
diff options
context:
space:
mode:
Diffstat (limited to 'erts/preloaded')
-rw-r--r--erts/preloaded/ebin/erl_prim_loader.beambin55752 -> 55808 bytes
-rw-r--r--erts/preloaded/ebin/erl_tracer.beambin2200 -> 2204 bytes
-rw-r--r--erts/preloaded/ebin/erlang.beambin104816 -> 105140 bytes
-rw-r--r--erts/preloaded/ebin/erts_code_purger.beambin8696 -> 12088 bytes
-rw-r--r--erts/preloaded/ebin/erts_dirty_process_code_checker.beambin0 -> 2144 bytes
-rw-r--r--erts/preloaded/ebin/erts_internal.beambin10536 -> 11156 bytes
-rw-r--r--erts/preloaded/ebin/erts_literal_area_collector.beambin0 -> 3304 bytes
-rw-r--r--erts/preloaded/ebin/init.beambin50048 -> 50064 bytes
-rw-r--r--erts/preloaded/ebin/otp_ring0.beambin1444 -> 1448 bytes
-rw-r--r--erts/preloaded/ebin/prim_eval.beambin1312 -> 1448 bytes
-rw-r--r--erts/preloaded/ebin/prim_file.beambin44764 -> 44768 bytes
-rw-r--r--erts/preloaded/ebin/prim_inet.beambin76236 -> 76496 bytes
-rw-r--r--erts/preloaded/ebin/prim_zip.beambin23152 -> 23156 bytes
-rw-r--r--erts/preloaded/ebin/zlib.beambin14136 -> 14140 bytes
-rw-r--r--erts/preloaded/src/Makefile4
-rw-r--r--erts/preloaded/src/erl_prim_loader.erl23
-rw-r--r--erts/preloaded/src/erlang.erl34
-rw-r--r--erts/preloaded/src/erts.app.src2
-rw-r--r--erts/preloaded/src/erts_code_purger.erl170
-rw-r--r--erts/preloaded/src/erts_dirty_process_code_checker.erl82
-rw-r--r--erts/preloaded/src/erts_internal.erl55
-rw-r--r--erts/preloaded/src/erts_literal_area_collector.erl113
-rw-r--r--erts/preloaded/src/init.erl13
-rw-r--r--erts/preloaded/src/prim_eval.S43
-rw-r--r--erts/preloaded/src/prim_inet.erl21
25 files changed, 487 insertions, 73 deletions
diff --git a/erts/preloaded/ebin/erl_prim_loader.beam b/erts/preloaded/ebin/erl_prim_loader.beam
index 796cbd74c5..6af1633726 100644
--- a/erts/preloaded/ebin/erl_prim_loader.beam
+++ b/erts/preloaded/ebin/erl_prim_loader.beam
Binary files differ
diff --git a/erts/preloaded/ebin/erl_tracer.beam b/erts/preloaded/ebin/erl_tracer.beam
index 4406a82a36..d0ed09dc91 100644
--- a/erts/preloaded/ebin/erl_tracer.beam
+++ b/erts/preloaded/ebin/erl_tracer.beam
Binary files differ
diff --git a/erts/preloaded/ebin/erlang.beam b/erts/preloaded/ebin/erlang.beam
index b62da04bfd..7a2d9e5a81 100644
--- a/erts/preloaded/ebin/erlang.beam
+++ b/erts/preloaded/ebin/erlang.beam
Binary files differ
diff --git a/erts/preloaded/ebin/erts_code_purger.beam b/erts/preloaded/ebin/erts_code_purger.beam
index a0da864824..ab63e4745f 100644
--- a/erts/preloaded/ebin/erts_code_purger.beam
+++ b/erts/preloaded/ebin/erts_code_purger.beam
Binary files differ
diff --git a/erts/preloaded/ebin/erts_dirty_process_code_checker.beam b/erts/preloaded/ebin/erts_dirty_process_code_checker.beam
new file mode 100644
index 0000000000..9c99d80581
--- /dev/null
+++ b/erts/preloaded/ebin/erts_dirty_process_code_checker.beam
Binary files differ
diff --git a/erts/preloaded/ebin/erts_internal.beam b/erts/preloaded/ebin/erts_internal.beam
index d897c8e92f..c84acc12a1 100644
--- a/erts/preloaded/ebin/erts_internal.beam
+++ b/erts/preloaded/ebin/erts_internal.beam
Binary files differ
diff --git a/erts/preloaded/ebin/erts_literal_area_collector.beam b/erts/preloaded/ebin/erts_literal_area_collector.beam
new file mode 100644
index 0000000000..2c1ec7473a
--- /dev/null
+++ b/erts/preloaded/ebin/erts_literal_area_collector.beam
Binary files differ
diff --git a/erts/preloaded/ebin/init.beam b/erts/preloaded/ebin/init.beam
index b856bff4fe..5c0c6605af 100644
--- a/erts/preloaded/ebin/init.beam
+++ b/erts/preloaded/ebin/init.beam
Binary files differ
diff --git a/erts/preloaded/ebin/otp_ring0.beam b/erts/preloaded/ebin/otp_ring0.beam
index b601c048b3..2eb09599be 100644
--- a/erts/preloaded/ebin/otp_ring0.beam
+++ b/erts/preloaded/ebin/otp_ring0.beam
Binary files differ
diff --git a/erts/preloaded/ebin/prim_eval.beam b/erts/preloaded/ebin/prim_eval.beam
index 77909b01f0..7d3e32b452 100644
--- a/erts/preloaded/ebin/prim_eval.beam
+++ b/erts/preloaded/ebin/prim_eval.beam
Binary files differ
diff --git a/erts/preloaded/ebin/prim_file.beam b/erts/preloaded/ebin/prim_file.beam
index 5bbbaf14d5..b8b8402a07 100644
--- a/erts/preloaded/ebin/prim_file.beam
+++ b/erts/preloaded/ebin/prim_file.beam
Binary files differ
diff --git a/erts/preloaded/ebin/prim_inet.beam b/erts/preloaded/ebin/prim_inet.beam
index fba03d52bd..3fddd2f357 100644
--- a/erts/preloaded/ebin/prim_inet.beam
+++ b/erts/preloaded/ebin/prim_inet.beam
Binary files differ
diff --git a/erts/preloaded/ebin/prim_zip.beam b/erts/preloaded/ebin/prim_zip.beam
index 6afeb454d6..102a29396e 100644
--- a/erts/preloaded/ebin/prim_zip.beam
+++ b/erts/preloaded/ebin/prim_zip.beam
Binary files differ
diff --git a/erts/preloaded/ebin/zlib.beam b/erts/preloaded/ebin/zlib.beam
index 4c48742344..8955885373 100644
--- a/erts/preloaded/ebin/zlib.beam
+++ b/erts/preloaded/ebin/zlib.beam
Binary files differ
diff --git a/erts/preloaded/src/Makefile b/erts/preloaded/src/Makefile
index 4a447d3a09..2ab9edaf5e 100644
--- a/erts/preloaded/src/Makefile
+++ b/erts/preloaded/src/Makefile
@@ -44,7 +44,9 @@ PRE_LOADED_ERL_MODULES = \
erts_code_purger \
erlang \
erts_internal \
- erl_tracer
+ erl_tracer \
+ erts_literal_area_collector \
+ erts_dirty_process_code_checker
PRE_LOADED_BEAM_MODULES = \
prim_eval
diff --git a/erts/preloaded/src/erl_prim_loader.erl b/erts/preloaded/src/erl_prim_loader.erl
index b3ec73a60e..1d09aeded9 100644
--- a/erts/preloaded/src/erl_prim_loader.erl
+++ b/erts/preloaded/src/erl_prim_loader.erl
@@ -555,17 +555,18 @@ efile_gm_get(Paths, Mod, ParentRef, Process) ->
efile_gm_get_1([P|Ps], File0, Mod, {Parent,Ref}=PR, Process) ->
File = join(P, File0),
- Res = try prim_file:read_file(File) of
- {ok,Bin} ->
- gm_process(Mod, File, Bin, Process);
- Error ->
- _ = check_file_result(get_modules, File, Error),
- efile_gm_get_1(Ps, File0, Mod, PR, Process)
- catch
- _:Reason ->
- {error,{crash,Reason}}
- end,
- Parent ! {Ref,Mod,Res};
+ try prim_file:read_file(File) of
+ {ok,Bin} ->
+ Res = gm_process(Mod, File, Bin, Process),
+ Parent ! {Ref,Mod,Res};
+ Error ->
+ _ = check_file_result(get_modules, File, Error),
+ efile_gm_get_1(Ps, File0, Mod, PR, Process)
+ catch
+ _:Reason ->
+ Res = {error,{crash,Reason}},
+ Parent ! {Ref,Mod,Res}
+ end;
efile_gm_get_1([], _, Mod, {Parent,Ref}, _Process) ->
Parent ! {Ref,Mod,{error,enoent}}.
diff --git a/erts/preloaded/src/erlang.erl b/erts/preloaded/src/erlang.erl
index edf79b8f75..8771089b65 100644
--- a/erts/preloaded/src/erlang.erl
+++ b/erts/preloaded/src/erlang.erl
@@ -59,6 +59,7 @@
-export_type([timestamp/0]).
-export_type([time_unit/0]).
+-export_type([deprecated_time_unit/0]).
-type ext_binary() :: binary().
-type timestamp() :: {MegaSecs :: non_neg_integer(),
@@ -67,12 +68,20 @@
-type time_unit() ::
pos_integer()
- | 'seconds'
+ | 'second'
+ | 'millisecond'
+ | 'microsecond'
+ | 'nanosecond'
+ | 'native'
+ | 'perf_counter'
+ | deprecated_time_unit().
+
+%% Deprecated symbolic units...
+-type deprecated_time_unit() ::
+ 'seconds'
| 'milli_seconds'
| 'micro_seconds'
- | 'nano_seconds'
- | 'native'
- | 'perf_counter'.
+ | 'nano_seconds'.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% Native code BIF stubs and their types
@@ -1365,19 +1374,33 @@ convert_time_unit(Time, FromUnit, ToUnit) ->
FU = case FromUnit of
native -> erts_internal:time_unit();
perf_counter -> erts_internal:perf_counter_unit();
+ nanosecond -> 1000*1000*1000;
+ microsecond -> 1000*1000;
+ millisecond -> 1000;
+ second -> 1;
+
+ %% Deprecated symbolic units...
nano_seconds -> 1000*1000*1000;
micro_seconds -> 1000*1000;
milli_seconds -> 1000;
seconds -> 1;
+
_ when FromUnit > 0 -> FromUnit
end,
TU = case ToUnit of
native -> erts_internal:time_unit();
perf_counter -> erts_internal:perf_counter_unit();
+ nanosecond -> 1000*1000*1000;
+ microsecond -> 1000*1000;
+ millisecond -> 1000;
+ second -> 1;
+
+ %% Deprecated symbolic units...
nano_seconds -> 1000*1000*1000;
micro_seconds -> 1000*1000;
milli_seconds -> 1000;
seconds -> 1;
+
_ when ToUnit > 0 -> ToUnit
end,
case Time < 0 of
@@ -2385,10 +2408,11 @@ term_to_binary(_Term, _Options) ->
tl(_List) ->
erlang:nif_error(undefined).
+-type match_variable() :: atom(). % Approximation of '$1' | '$2' | ...
-type trace_pattern_mfa() ::
{atom(),atom(),arity() | '_'} | on_load.
-type trace_match_spec() ::
- [{[term()] | '_' ,[term()],[term()]}].
+ [{[term()] | '_' | match_variable() ,[term()],[term()]}].
-spec erlang:trace_pattern(MFA, MatchSpec) -> non_neg_integer() when
MFA :: trace_pattern_mfa() | send | 'receive',
diff --git a/erts/preloaded/src/erts.app.src b/erts/preloaded/src/erts.app.src
index e18da28905..7ab06164b4 100644
--- a/erts/preloaded/src/erts.app.src
+++ b/erts/preloaded/src/erts.app.src
@@ -37,7 +37,7 @@
{registered, []},
{applications, []},
{env, []},
- {runtime_dependencies, ["stdlib-3.0", "kernel-5.0", "sasl-3.0"]}
+ {runtime_dependencies, ["stdlib-3.0", "kernel-5.0", "sasl-3.0.1"]}
]}.
%% vim: ft=erlang
diff --git a/erts/preloaded/src/erts_code_purger.erl b/erts/preloaded/src/erts_code_purger.erl
index d1e64342e0..28d71fd07e 100644
--- a/erts/preloaded/src/erts_code_purger.erl
+++ b/erts/preloaded/src/erts_code_purger.erl
@@ -22,7 +22,8 @@
%% Purpose : Implement system process erts_code_purger
%% to handle code module purging.
--export([start/0, purge/1, soft_purge/1]).
+-export([start/0, purge/1, soft_purge/1, pending_purge_lambda/3,
+ finish_after_on_load/2]).
-spec start() -> term().
start() ->
@@ -40,10 +41,48 @@ loop() ->
Res = do_soft_purge(Mod),
From ! {reply, soft_purge, Res, Ref};
+ {finish_after_on_load,{Mod,Keep},From,Ref}
+ when is_atom(Mod), is_pid(From) ->
+ Res = do_finish_after_on_load(Mod, Keep),
+ From ! {reply, finish_after_on_load, Res, Ref};
+
+ {test_purge, Mod, From, Type, Ref} when is_atom(Mod), is_pid(From) ->
+ do_test_purge(Mod, From, Type, Ref);
+
_Other -> ignore
end,
loop().
+%%
+%% Processes that tries to call a fun that belongs to
+%% a module that currently is being purged will end
+%% up here (pending_purge_lambda) in a suspended state.
+%% When the purge operation completes or aborts (soft
+%% purge that failed) these processes will be resumed.
+%%
+pending_purge_lambda(_Module, Fun, Args) ->
+ %%
+ %% When the process is resumed, the following
+ %% scenarios exist:
+ %% * The code that the fun refers to is still
+ %% there due to a failed soft purge. The
+ %% call to the fun will succeed via apply/2.
+ %% * The code was purged, and a current version
+ %% of the module is loaded which does not
+ %% contain this fun. The call will result
+ %% in an exception being raised.
+ %% * The code was purged, and no current
+ %% version of the module is loaded. An attempt
+ %% to load the module (via the error_handler)
+ %% will be made. This may or may not succeed.
+ %% If the module is loaded, it may or may
+ %% not contain the fun. The call will
+ %% succeed if the error_handler was able
+ %% to load the module and loaded module
+ %% contains this fun; otherwise, an exception
+ %% will be raised.
+ %%
+ apply(Fun, Args).
%% purge(Module)
%% Kill all processes running code from *old* Module, and then purge the
@@ -60,16 +99,14 @@ purge(Mod) when is_atom(Mod) ->
Result
end.
-
do_purge(Mod) ->
- case erts_internal:copy_literals(Mod, true) of
- false ->
- {false, false};
- true ->
- DidKill = check_proc_code(erlang:processes(), Mod, true),
- true = erts_internal:copy_literals(Mod, false),
- WasPurged = erts_internal:purge_module(Mod),
- {WasPurged, DidKill}
+ case erts_internal:purge_module(Mod, prepare) of
+ false ->
+ {false, false};
+ true ->
+ DidKill = check_proc_code(erlang:processes(), Mod, true),
+ true = erts_internal:purge_module(Mod, complete),
+ {true, DidKill}
end.
%% soft_purge(Module)
@@ -85,23 +122,48 @@ soft_purge(Mod) ->
Result
end.
-
do_soft_purge(Mod) ->
- case erts_internal:copy_literals(Mod, true) of
+ case erts_internal:purge_module(Mod, prepare) of
false ->
true;
true ->
- DoPurge = check_proc_code(erlang:processes(), Mod, false),
- true = erts_internal:copy_literals(Mod, false),
- case DoPurge of
+ Res = check_proc_code(erlang:processes(), Mod, false),
+ erts_internal:purge_module(Mod,
+ case Res of
+ false -> abort;
+ true -> complete
+ end)
+ end.
+
+%% finish_after_on_load(Module, Keep)
+%% Finish after running on_load function. If Keep is false,
+%% purge the code for the on_load function.
+
+finish_after_on_load(Mod, Keep) ->
+ Ref = make_ref(),
+ erts_code_purger ! {finish_after_on_load, {Mod,Keep}, self(), Ref},
+ receive
+ {reply, finish_after_on_load, Result, Ref} ->
+ Result
+ end.
+
+do_finish_after_on_load(Mod, Keep) ->
+ erlang:finish_after_on_load(Mod, Keep),
+ case Keep of
+ true ->
+ ok;
+ false ->
+ case erts_internal:purge_module(Mod, prepare_on_load) of
false ->
- false;
+ true;
true ->
- erts_internal:purge_module(Mod),
- true
+ _ = check_proc_code(erlang:processes(), Mod, true),
+ true = erts_internal:purge_module(Mod, complete)
end
end.
+
+
%%
%% check_proc_code(Pids, Mod, Hard) - Send asynchronous
%% requests to all processes to perform a check_process_code
@@ -283,8 +345,7 @@ cpc_sched_kill(Pid,
cpc_request(#cpc_static{tag = Tag, module = Mod}, Pid, AllowGc) ->
erts_internal:check_process_code(Pid, Mod, [{async, {Tag, Pid, AllowGc}},
- {allow_gc, AllowGc},
- {copy_literals, true}]).
+ {allow_gc, AllowGc}]).
cpc_request_gc(CpcS, [Pid|Pids]) ->
cpc_request(CpcS, Pid, true),
@@ -297,3 +358,72 @@ cpc_init(CpcS, [Pid|Pids], NoReqs) ->
cpc_init(CpcS, Pids, NoReqs+1).
% end of check_proc_code() implementation.
+
+%%
+%% FOR TESTING ONLY
+%%
+%% do_test_purge() is for testing only. The purge is done
+%% as usual, but the tester can control when to enter the
+%% specific phases.
+%%
+do_test_purge(Mod, From, Type, Ref) when Type == true; Type == false ->
+ Mon = erlang:monitor(process, From),
+ Res = case Type of
+ true -> do_test_hard_purge(Mod, From, Ref, Mon);
+ false -> do_test_soft_purge(Mod, From, Ref, Mon)
+ end,
+ From ! {test_purge, Res, Ref},
+ erlang:demonitor(Mon, [flush]),
+ ok;
+do_test_purge(_, _, _, _) ->
+ ok.
+
+do_test_soft_purge(Mod, From, Ref, Mon) ->
+ PrepRes = erts_internal:purge_module(Mod, prepare),
+ TestRes = test_progress(started, From, Mon, Ref, ok),
+ case PrepRes of
+ false ->
+ _ = test_progress(continued, From, Mon, Ref, TestRes),
+ true;
+ true ->
+ Res = check_proc_code(erlang:processes(), Mod, false),
+ _ = test_progress(continued, From, Mon, Ref, TestRes),
+ erts_internal:purge_module(Mod,
+ case Res of
+ false -> abort;
+ true -> complete
+ end)
+ end.
+
+do_test_hard_purge(Mod, From, Ref, Mon) ->
+ PrepRes = erts_internal:purge_module(Mod, prepare),
+ TestRes = test_progress(started, From, Mon, Ref, ok),
+ case PrepRes of
+ false ->
+ _ = test_progress(continued, From, Mon, Ref, TestRes),
+ {false, false};
+ true ->
+ DidKill = check_proc_code(erlang:processes(), Mod, true),
+ _ = test_progress(continued, From, Mon, Ref, TestRes),
+ true = erts_internal:purge_module(Mod, complete),
+ {true, DidKill}
+ end.
+
+test_progress(_State, _From, _Mon, _Ref, died) ->
+ %% Test process died; continue so we wont
+ %% leave the system in an inconsistent
+ %% state...
+ died;
+test_progress(started, From, Mon, Ref, ok) ->
+ From ! {started, Ref},
+ receive
+ {'DOWN', Mon, process, From, _} -> died;
+ {continue, Ref} -> ok
+ end;
+test_progress(continued, From, Mon, Ref, ok) ->
+ From ! {continued, Ref},
+ receive
+ {'DOWN', Mon, process, From, _} -> died;
+ {complete, Ref} -> ok
+ end.
+
diff --git a/erts/preloaded/src/erts_dirty_process_code_checker.erl b/erts/preloaded/src/erts_dirty_process_code_checker.erl
new file mode 100644
index 0000000000..911642082c
--- /dev/null
+++ b/erts/preloaded/src/erts_dirty_process_code_checker.erl
@@ -0,0 +1,82 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2016. 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(erts_dirty_process_code_checker).
+
+-export([start/0]).
+
+%%
+%% The erts_dirty_process_code_checker is started at
+%% VM boot by the VM. It is a spawned as a system
+%% process, i.e, the whole VM will terminate if
+%% this process terminates.
+%%
+start() ->
+ process_flag(trap_exit, true),
+ msg_loop().
+
+msg_loop() ->
+ _ = receive
+ Request ->
+ handle_request(Request)
+ end,
+ msg_loop().
+
+check_process(Requester, Target, ReqId, Module) ->
+ Result = erts_internal:check_dirty_process_code(Target, Module),
+ Requester ! {check_process_code, ReqId, Result}.
+
+handle_request({Requester,
+ Target,
+ Prio,
+ {check_process_code,
+ ReqId,
+ Module,
+ _Flags} = Op}) ->
+ %%
+ %% Target may have stopped executing dirty since the
+ %% initial request was made. Check its current state
+ %% and try to send the request if possible; otherwise,
+ %% check the dirty executing process and send the result...
+ %%
+ try
+ case erts_internal:is_process_executing_dirty(Target) of
+ true ->
+ check_process(Requester, Target, ReqId, Module);
+ false ->
+ case erts_internal:request_system_task(Requester,
+ Target,
+ Prio,
+ Op) of
+ ok ->
+ ok;
+ dirty_execution ->
+ check_process(Requester, Target, ReqId, Module)
+ end
+ end
+ catch
+ _ : _ ->
+ ok %% Ignore all failures; someone passed us garbage...
+ end;
+handle_request(_Garbage) ->
+ ignore.
+
+
+
diff --git a/erts/preloaded/src/erts_internal.erl b/erts/preloaded/src/erts_internal.erl
index 2459ea2a2c..f4518c4008 100644
--- a/erts/preloaded/src/erts_internal.erl
+++ b/erts/preloaded/src/erts_internal.erl
@@ -38,11 +38,13 @@
-export([system_check/1,
gather_system_check_result/1]).
--export([request_system_task/3]).
+-export([request_system_task/3, request_system_task/4]).
-export([check_process_code/3]).
--export([copy_literals/2]).
--export([purge_module/1]).
+-export([check_dirty_process_code/2]).
+-export([is_process_executing_dirty/1]).
+-export([release_literal_area_switch/0]).
+-export([purge_module/2]).
-export([flush_monitor_messages/3]).
@@ -204,14 +206,25 @@ port_info(_Result, _Item) ->
-spec request_system_task(Pid, Prio, Request) -> 'ok' when
Prio :: 'max' | 'high' | 'normal' | 'low',
Request :: {'garbage_collect', term()}
- | {'check_process_code', term(), module(), non_neg_integer()},
+ | {'check_process_code', term(), module(), non_neg_integer()}
+ | {'copy_literals', term(), boolean()},
Pid :: pid().
request_system_task(_Pid, _Prio, _Request) ->
erlang:nif_error(undefined).
+-spec request_system_task(RequesterPid, TargetPid, Prio, Request) -> 'ok' | 'dirty_execution' when
+ Prio :: 'max' | 'high' | 'normal' | 'low',
+ Request :: {'garbage_collect', term()}
+ | {'check_process_code', term(), module(), non_neg_integer()}
+ | {'copy_literals', term(), boolean()},
+ RequesterPid :: pid(),
+ TargetPid :: pid().
+
+request_system_task(_RequesterPid, _TargetPid, _Prio, _Request) ->
+ erlang:nif_error(undefined).
+
-define(ERTS_CPC_ALLOW_GC, (1 bsl 0)).
--define(ERTS_CPC_COPY_LITERALS, (1 bsl 1)).
-spec check_process_code(Module, Flags) -> boolean() when
Module :: module(),
@@ -223,7 +236,7 @@ check_process_code(_Module, _Flags) ->
Pid :: pid(),
Module :: module(),
RequestId :: term(),
- Option :: {async, RequestId} | {allow_gc, boolean()} | {copy_literals, boolean()},
+ Option :: {async, RequestId} | {allow_gc, boolean()},
OptionList :: [Option],
CheckResult :: boolean() | aborted.
check_process_code(Pid, Module, OptionList) ->
@@ -265,8 +278,6 @@ get_cpc_opts([{async, _ReqId} = AsyncTuple | Options], _OldAsync, Flags) ->
get_cpc_opts(Options, AsyncTuple, Flags);
get_cpc_opts([{allow_gc, AllowGC} | Options], Async, Flags) ->
get_cpc_opts(Options, Async, cpc_flags(Flags, ?ERTS_CPC_ALLOW_GC, AllowGC));
-get_cpc_opts([{copy_literals, CopyLit} | Options], Async, Flags) ->
- get_cpc_opts(Options, Async, cpc_flags(Flags, ?ERTS_CPC_COPY_LITERALS, CopyLit));
get_cpc_opts([], Async, Flags) ->
{Async, Flags}.
@@ -275,15 +286,26 @@ cpc_flags(OldFlags, Bit, true) ->
cpc_flags(OldFlags, Bit, false) ->
OldFlags band (bnot Bit).
--spec copy_literals(Module,Bool) -> 'true' | 'false' | 'aborted' when
- Module :: module(),
- Bool :: boolean().
-copy_literals(_Mod, _Bool) ->
+-spec check_dirty_process_code(Pid,Module) -> 'true' | 'false' when
+ Pid :: pid(),
+ Module :: module().
+check_dirty_process_code(_Pid,_Module) ->
erlang:nif_error(undefined).
--spec purge_module(Module) -> boolean() when
- Module :: module().
-purge_module(_Module) ->
+-spec is_process_executing_dirty(Pid) -> 'true' | 'false' when
+ Pid :: pid().
+is_process_executing_dirty(_Pid) ->
+ erlang:nif_error(undefined).
+
+-spec release_literal_area_switch() -> 'true' | 'false'.
+
+release_literal_area_switch() ->
+ erlang:nif_error(undefined).
+
+-spec purge_module(Module, Op) -> boolean() when
+ Module :: module(),
+ Op :: 'prepare' | 'prepare_on_load' | 'abort' | 'complete'.
+purge_module(_Module, _Op) ->
erlang:nif_error(undefined).
-spec system_check(Type) -> 'ok' when
@@ -416,10 +438,11 @@ microstate_accounting(Ref, Threads) ->
trace(_PidSpec, _How, _FlagList) ->
erlang:nif_error(undefined).
+-type match_variable() :: atom(). % Approximation of '$1' | '$2' | ...
-type trace_pattern_mfa() ::
{atom(),atom(),arity() | '_'} | on_load.
-type trace_match_spec() ::
- [{[term()] | '_' ,[term()],[term()]}].
+ [{[term()] | '_' | match_variable() ,[term()],[term()]}].
-spec trace_pattern(MFA, MatchSpec, FlagList) -> non_neg_integer() when
MFA :: trace_pattern_mfa(),
diff --git a/erts/preloaded/src/erts_literal_area_collector.erl b/erts/preloaded/src/erts_literal_area_collector.erl
new file mode 100644
index 0000000000..3befad8dfb
--- /dev/null
+++ b/erts/preloaded/src/erts_literal_area_collector.erl
@@ -0,0 +1,113 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2016. 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(erts_literal_area_collector).
+
+-export([start/0]).
+
+%% Currently we only allow two outstanding literal
+%% copying jobs that garbage collect in order to
+%% copy the literals. Maybe we could allow more
+%% than two outstanding processes, but for now we
+%% play it safe...
+-define(MAX_GC_OUTSTND, 2).
+
+%%
+%% The erts_literal_area_collector is started at
+%% VM boot by the VM. It is a spawned as a system
+%% process, i.e, the whole VM will terminate if
+%% this process terminates.
+%%
+start() ->
+ process_flag(trap_exit, true),
+ msg_loop(undefined, 0, 0, []).
+
+%%
+%% The VM will send us a 'copy_literals' message
+%% when it has a new literal area that needs to
+%% be handled is added. We will also be informed
+%% about more areas when we call
+%% erts_internal:release_literal_area_switch().
+%%
+msg_loop(Area, Outstnd, GcOutstnd, NeedGC) ->
+ receive
+
+ %% A new area to handle has arrived...
+ copy_literals when Outstnd == 0 ->
+ switch_area();
+
+ %% Process (_Pid) has completed the request...
+ {copy_literals, {Area, _GcAllowed, _Pid}, ok} when Outstnd == 1 ->
+ switch_area(); %% Last process completed...
+ {copy_literals, {Area, false, _Pid}, ok} ->
+ msg_loop(Area, Outstnd-1, GcOutstnd, NeedGC);
+ {copy_literals, {Area, true, _Pid}, ok} when NeedGC == [] ->
+ msg_loop(Area, Outstnd-1, GcOutstnd-1, []);
+ {copy_literals, {Area, true, _Pid}, ok} ->
+ send_copy_req(hd(NeedGC), Area, true),
+ msg_loop(Area, Outstnd-1, GcOutstnd, tl(NeedGC));
+
+ %% Process (Pid) failed to complete the request
+ %% since it needs to garbage collect in order to
+ %% complete the request...
+ {copy_literals, {Area, false, Pid}, need_gc} when GcOutstnd < ?MAX_GC_OUTSTND ->
+ send_copy_req(Pid, Area, true),
+ msg_loop(Area, Outstnd, GcOutstnd+1, NeedGC);
+ {copy_literals, {Area, false, Pid}, need_gc} ->
+ msg_loop(Area, Outstnd, GcOutstnd, [Pid|NeedGC]);
+
+ %% Not handled message regarding the area that we
+ %% currently are working with. Crash the VM so
+ %% we notice this bug...
+ {copy_literals, {Area, _, _}, _} = Msg when erlang:is_reference(Area) ->
+ exit({not_handled_message, Msg});
+
+ %% Unexpected garbage message. Get rid of it...
+ _Ignore ->
+ msg_loop(Area, Outstnd, GcOutstnd, NeedGC)
+
+ end.
+
+switch_area() ->
+ Res = erts_internal:release_literal_area_switch(),
+ erlang:garbage_collect(), %% Almost no live data now...
+ case Res of
+ false ->
+ %% No more areas to handle...
+ msg_loop(undefined, 0, 0, []);
+ true ->
+ %% Send requests to all processes to copy
+ %% all live data they have referring to the
+ %% literal area that is to be released...
+ Area = make_ref(),
+ Outstnd = send_copy_reqs(erlang:processes(), Area, false),
+ msg_loop(Area, Outstnd, 0, [])
+ end.
+
+send_copy_reqs(Ps, Area, GC) ->
+ send_copy_reqs(Ps, Area, GC, 0).
+
+send_copy_reqs([], _Area, _GC, N) ->
+ N;
+send_copy_reqs([P|Ps], Area, GC, N) ->
+ send_copy_req(P, Area, GC),
+ send_copy_reqs(Ps, Area, GC, N+1).
+
+send_copy_req(P, Area, GC) ->
+ erts_internal:request_system_task(P, normal, {copy_literals, {Area, GC, P}, GC}).
diff --git a/erts/preloaded/src/init.erl b/erts/preloaded/src/init.erl
index 45468b3b9c..551ca4ea40 100644
--- a/erts/preloaded/src/init.erl
+++ b/erts/preloaded/src/init.erl
@@ -205,7 +205,7 @@ boot(BootArgs) ->
{Start0,Flags,Args} = parse_boot_args(BootArgs),
%% We don't get to profile parsing of BootArgs
- case get_flag(profile_boot, Flags, false) of
+ case b2a(get_flag(profile_boot, Flags, false)) of
false -> ok;
true -> debug_profile_start()
end,
@@ -423,9 +423,6 @@ loop(State) ->
Loaded = State#state.loaded, %% boot_loop but is handled here
From ! {init,Loaded}, %% anyway.
loop(State);
- {From, {ensure_loaded, _}} ->
- From ! {init, not_allowed},
- loop(State);
Msg ->
loop(handle_msg(Msg,State))
end.
@@ -465,6 +462,8 @@ do_handle_msg(Msg,State) ->
From ! {init,ok},
{new_state,State#state{subscribed = [Pid|Subscribed]}}
end;
+ {From, {ensure_loaded, _}} ->
+ From ! {init, not_allowed};
X ->
case whereis(user) of
undefined ->
@@ -670,9 +669,9 @@ unload(_) ->
do_unload(sub([heart|erlang:pre_loaded()],erlang:loaded())).
do_unload([M|Mods]) ->
- catch erts_internal:purge_module(M),
+ catch erlang:purge_module(M),
catch erlang:delete_module(M),
- catch erts_internal:purge_module(M),
+ catch erlang:purge_module(M),
do_unload(Mods);
do_unload([]) ->
purge_all_hipe_refs(),
@@ -783,7 +782,7 @@ do_boot(Init,Flags,Start) ->
(catch erlang:system_info({purify, "Node: " ++ atom_to_list(node())})),
start_em(Start),
- case get_flag(profile_boot,Flags,false) of
+ case b2a(get_flag(profile_boot,Flags,false)) of
false -> ok;
true ->
debug_profile_format_mfas(debug_profile_mfas()),
diff --git a/erts/preloaded/src/prim_eval.S b/erts/preloaded/src/prim_eval.S
index e7f09a870c..e4b1560517 100644
--- a/erts/preloaded/src/prim_eval.S
+++ b/erts/preloaded/src/prim_eval.S
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2013-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2013-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.
@@ -26,7 +26,7 @@
{attributes, []}.
-{labels, 10}.
+{labels, 14}.
{function, 'receive', 2, 2}.
@@ -36,6 +36,9 @@
{allocate,2,2}.
{move,{x,1},{y,0}}.
{move,{x,0},{y,1}}.
+ %% Call arg_reg_alloc() in order to ensure
+ %% that def_arg_reg[0] isn't clobbered
+ {call,0,{f,7}}.
{label,3}.
{loop_rec,{f,5},{x,0}}.
{move,{y,1},{x,1}}.
@@ -53,19 +56,43 @@
{deallocate,2}.
return.
-
-{function, module_info, 0, 8}.
+{function, arg_reg_alloc, 0, 7}.
{label,6}.
- {func_info,{atom,prim_eval},{atom,module_info},0}.
+ {func_info,{atom,prim_eval},{atom,arg_reg_alloc},0}.
{label,7}.
+ {allocate,0,0}.
+ {move,{integer,134217727},{x,0}}.
+ {call_ext,1,{extfunc,erlang,bump_reductions,1}}.
+ {move,{atom,true},{x,3}}.
+ {move,{atom,true},{x,4}}.
+ {move,{atom,true},{x,2}}.
+ {move,{atom,true},{x,5}}.
+ {move,{atom,true},{x,1}}.
+ {move,{atom,true},{x,6}}.
+ {move,{atom,true},{x,0}}.
+ {call_last,7,{f,9},0}.
+
+
+{function, arg_reg_alloc, 7, 9}.
+ {label,8}.
+ {func_info,{atom,prim_eval},{atom,arg_reg_alloc},7}.
+ {label,9}.
+ {move,{atom,ok},{x,0}}.
+ return.
+
+
+{function, module_info, 0, 11}.
+ {label,10}.
+ {func_info,{atom,prim_eval},{atom,module_info},0}.
+ {label,11}.
{move,{atom,prim_eval},{x,0}}.
{call_ext_only,1,{extfunc,erlang,get_module_info,1}}.
-{function, module_info, 1, 10}.
- {label,8}.
+{function, module_info, 1, 13}.
+ {label,12}.
{func_info,{atom,prim_eval},{atom,module_info},1}.
- {label,9}.
+ {label,13}.
{move,{x,0},{x,1}}.
{move,{atom,prim_eval},{x,0}}.
{call_ext_only,2,{extfunc,erlang,get_module_info,2}}.
diff --git a/erts/preloaded/src/prim_inet.erl b/erts/preloaded/src/prim_inet.erl
index 560810d222..61f727e8a4 100644
--- a/erts/preloaded/src/prim_inet.erl
+++ b/erts/preloaded/src/prim_inet.erl
@@ -347,7 +347,17 @@ accept_opts(L, S) ->
case getopts(L, [active, nodelay, keepalive, delay_send, priority, tos]) of
{ok, Opts} ->
case setopts(S, Opts) of
- ok -> {ok, S};
+ ok ->
+ case getopts(L, [tclass]) of
+ {ok, []} ->
+ {ok, S};
+ {ok, TClassOpts} ->
+ case setopts(S, TClassOpts) of
+ ok ->
+ {ok, S};
+ Error -> close(S), Error
+ end
+ end;
Error -> close(S), Error
end;
Error ->
@@ -1196,6 +1206,7 @@ enc_opt(sndbuf) -> ?INET_OPT_SNDBUF;
enc_opt(recbuf) -> ?INET_OPT_RCVBUF;
enc_opt(priority) -> ?INET_OPT_PRIORITY;
enc_opt(tos) -> ?INET_OPT_TOS;
+enc_opt(tclass) -> ?INET_OPT_TCLASS;
enc_opt(nodelay) -> ?TCP_OPT_NODELAY;
enc_opt(multicast_if) -> ?UDP_OPT_MULTICAST_IF;
enc_opt(multicast_ttl) -> ?UDP_OPT_MULTICAST_TTL;
@@ -1255,6 +1266,7 @@ dec_opt(?INET_OPT_SNDBUF) -> sndbuf;
dec_opt(?INET_OPT_RCVBUF) -> recbuf;
dec_opt(?INET_OPT_PRIORITY) -> priority;
dec_opt(?INET_OPT_TOS) -> tos;
+dec_opt(?INET_OPT_TCLASS) -> tclass;
dec_opt(?TCP_OPT_NODELAY) -> nodelay;
dec_opt(?UDP_OPT_MULTICAST_IF) -> multicast_if;
dec_opt(?UDP_OPT_MULTICAST_TTL) -> multicast_ttl;
@@ -1329,6 +1341,7 @@ type_opt_1(sndbuf) -> int;
type_opt_1(recbuf) -> int;
type_opt_1(priority) -> int;
type_opt_1(tos) -> int;
+type_opt_1(tclass) -> int;
type_opt_1(nodelay) -> bool;
type_opt_1(ipv6_v6only) -> bool;
%% multicast
@@ -2401,13 +2414,13 @@ get_addrs([F|Addrs]) ->
{Addr,Rest} = get_addr(F, Addrs),
[Addr|get_addrs(Rest)].
-get_addr(?INET_AF_LOCAL, [0]) ->
- {{local,<<>>},[]};
get_addr(?INET_AF_LOCAL, [N|Addr]) ->
{A,Rest} = lists:split(N, Addr),
{{local,iolist_to_binary(A)},Rest};
+get_addr(?INET_AF_UNSPEC, Rest) ->
+ {{unspec,<<>>},Rest};
get_addr(?INET_AF_UNDEFINED, Rest) ->
- {{undefined,0},Rest};
+ {{undefined,<<>>},Rest};
get_addr(Family, [P1,P0|Addr]) ->
{IP,Rest} = get_ip(Family, Addr),
{{IP,?u16(P1, P0)},Rest}.