diff options
Diffstat (limited to 'lib/kernel')
26 files changed, 529 insertions, 339 deletions
diff --git a/lib/kernel/doc/src/code.xml b/lib/kernel/doc/src/code.xml index 4db377bcde..3143cdc825 100644 --- a/lib/kernel/doc/src/code.xml +++ b/lib/kernel/doc/src/code.xml @@ -382,9 +382,14 @@ zip:create("mnesia-4.4.7.ez", <name name="add_pathsa" arity="1"/> <fsummary>Add directories to the beginning of the code path.</fsummary> <desc> - <p>Adds the directories in <c><anno>Dirs</anno></c> to the beginning of - the code path. If a <c><anno>Dir</anno></c> exists, it is removed - from the old position in the code path.</p> + <p>Traverses <c><anno>Dirs</anno></c> and adds + each <c><anno>Dir</anno></c> to the beginning of the code + path. This means that the order of <c><anno>Dirs</anno></c> + is reversed in the resulting code path. For example, if you + add <c>[Dir1,Dir2]</c>, the resulting path will + be <c>[Dir2,Dir1|OldCodePath]</c>.</p> + <p>If a <c><anno>Dir</anno></c> already exists in the code + path, it is removed from the old position.</p> <p>Always returns <c>ok</c>, regardless of the validity of each individual <c><anno>Dir</anno></c>.</p> </desc> diff --git a/lib/kernel/doc/src/file.xml b/lib/kernel/doc/src/file.xml index 09497482cf..b674b3ca93 100644 --- a/lib/kernel/doc/src/file.xml +++ b/lib/kernel/doc/src/file.xml @@ -1477,8 +1477,8 @@ f.txt: {person, "kalle", 25}. <tag><c>16#400</c></tag> <item><p>set group id on execution</p></item> </taglist> - <p>On Unix platforms, the following bits - can also be set:</p> + <p>On Unix platforms, other bits than those listed above + may be set.</p> </item> <tag><c>links = integer() >= 0</c></tag> <item> @@ -2042,8 +2042,8 @@ f.txt: {person, "kalle", 25}. <tag><c>16#400</c></tag> <item><p>Set group id on execution</p></item> </taglist> - <p>On Unix platforms, the following bits - can also be set.</p> + <p>On Unix platforms, other bits than those listed above + may be set.</p> </item> <tag><c>uid = integer() >= 0</c></tag> <item> diff --git a/lib/kernel/doc/src/inet.xml b/lib/kernel/doc/src/inet.xml index 3f4e3684f4..d907cef7d3 100644 --- a/lib/kernel/doc/src/inet.xml +++ b/lib/kernel/doc/src/inet.xml @@ -1092,6 +1092,15 @@ setcap cap_sys_admin,cap_sys_ptrace,cap_dac_read_search+epi beam.smp</code> The option is ignored on platforms where it is not implemented. Use with caution.</p> </item> + <tag><c>{tclass, Integer}</c></tag> + <item> + <p> + Sets <c>IPV6_TCLASS IP</c> level options on platforms + where this is implemented. The behavior and allowed range + varies between different systems. + The option is ignored on platforms where it is not + implemented. Use with caution.</p> + </item> </taglist> <p>In addition to these options, <em>raw</em> option specifications can be used. The raw options are diff --git a/lib/kernel/doc/src/notes.xml b/lib/kernel/doc/src/notes.xml index 9e9be3f661..5bcc0b7c09 100644 --- a/lib/kernel/doc/src/notes.xml +++ b/lib/kernel/doc/src/notes.xml @@ -31,6 +31,74 @@ </header> <p>This document describes the changes made to the Kernel application.</p> +<section><title>Kernel 5.1</title> + + <section><title>Fixed Bugs and Malfunctions</title> + <list> + <item> + <p> + Fix a memory leak when calling + seq_trace:get_system_tracer().</p> + <p> + Own Id: OTP-13742</p> + </item> + <item> + <p> + Fix for the problem that when adding the ebin directory + of an application to the code path, the + <c>code:priv_dir/1</c> function returns an incorrect path + to the priv directory of the same application.</p> + <p> + Own Id: OTP-13758 Aux Id: ERL-195 </p> + </item> + <item> + <p> + Fix code_server crash when adding code paths of two + levels.</p> + <p> + Own Id: OTP-13765 Aux Id: ERL-194 </p> + </item> + <item> + <p> + Respect -proto_dist switch while connection to EPMD</p> + <p> + Own Id: OTP-13770 Aux Id: PR-1129 </p> + </item> + <item> + <p> + Fixed a bug where init:stop could deadlock if a process + with infinite shutdown timeout (e.g. a supervisor) + attempted to load code while terminating.</p> + <p> + Own Id: OTP-13802</p> + </item> + <item> + <p> + Close stdin of commands run in os:cmd. This is a + backwards compatiblity fix that restores the behaviour of + pre 19.0 os:cmd.</p> + <p> + Own Id: OTP-13867 Aux Id: seq13178 </p> + </item> + </list> + </section> + + + <section><title>Improvements and New Features</title> + <list> + <item> + <p> + Add <c>net_kernel:setopts/2</c> and + <c>net_kernel:getopts/2</c> to control options for + distribution sockets in runtime.</p> + <p> + Own Id: OTP-13564</p> + </item> + </list> + </section> + +</section> + <section><title>Kernel 5.0.2</title> <section><title>Fixed Bugs and Malfunctions</title> diff --git a/lib/kernel/doc/src/seq_trace.xml b/lib/kernel/doc/src/seq_trace.xml index 5ac199b6a7..ba7259219d 100644 --- a/lib/kernel/doc/src/seq_trace.xml +++ b/lib/kernel/doc/src/seq_trace.xml @@ -129,7 +129,7 @@ seq_trace:set_token(OldToken), % activate the trace token again <seealso marker="erts:time_correction#Erlang_Monotonic_Time">Erlang monotonic time</seealso> and a monotonically increasing integer. The time-stamp has the same format and value - as produced by <c>{erlang:monotonic_time(nano_seconds), + as produced by <c>{erlang:monotonic_time(nanosecond), erlang:unique_integer([monotonic])}</c>.</p> </item> <tag><c>set_token(monotonic_timestamp, <anno>Bool</anno>)</c></tag> @@ -141,7 +141,7 @@ seq_trace:set_token(OldToken), % activate the trace token again <seealso marker="erts:time_correction#Erlang_Monotonic_Time">Erlang monotonic time</seealso>. The time-stamp has the same format and value as produced by - <c>erlang:monotonic_time(nano_seconds)</c>.</p> + <c>erlang:monotonic_time(nanosecond)</c>.</p> </item> </taglist> <p>If multiple timestamp flags are passed, <c>timestamp</c> has diff --git a/lib/kernel/src/code.erl b/lib/kernel/src/code.erl index 8d0a2fbf66..622b27080c 100644 --- a/lib/kernel/src/code.erl +++ b/lib/kernel/src/code.erl @@ -116,8 +116,8 @@ get_chunk(_, _) -> is_module_native(_) -> erlang:nif_error(undef). --spec make_stub_module(Module, Beam, Info) -> Module when - Module :: module(), +-spec make_stub_module(LoaderState, Beam, Info) -> module() when + LoaderState :: binary(), Beam :: binary(), Info :: {list(), list(), binary()}. diff --git a/lib/kernel/src/code_server.erl b/lib/kernel/src/code_server.erl index 835b7eb588..418b0c50e1 100644 --- a/lib/kernel/src/code_server.erl +++ b/lib/kernel/src/code_server.erl @@ -1130,19 +1130,18 @@ try_load_module_2(File, Mod, Bin, From, Architecture, #state{moddb=Db}=St) -> case catch hipe_unified_loader:load_native_code(Mod, Bin, Architecture) of {module,Mod} = Module -> - ets:insert(Db, [{{native,Mod},true},{Mod,File}]), + ets:insert(Db, {Mod,File}), {reply,Module,St}; no_native -> try_load_module_3(File, Mod, Bin, From, Architecture, St); Error -> error_msg("Native loading of ~ts failed: ~p\n", [File,Error]), - {reply,ok,St} + {reply,{error,Error},St} end. -try_load_module_3(File, Mod, Bin, From, Architecture, St0) -> +try_load_module_3(File, Mod, Bin, From, _Architecture, St0) -> Action = fun({module,_}=Module, #state{moddb=Db}=S) -> ets:insert(Db, {Mod,File}), - post_beam_load([Mod], Architecture, S), {reply,Module,S}; ({error,on_load_failure}=Error, S) -> {reply,Error,S}; @@ -1153,24 +1152,14 @@ try_load_module_3(File, Mod, Bin, From, Architecture, St0) -> Res = erlang:load_module(Mod, Bin), handle_on_load(Res, Action, Mod, From, St0). -hipe_result_to_status(Result, #state{moddb=Db}) -> +hipe_result_to_status(Result, #state{}) -> case Result of - {module,Mod} -> - ets:insert(Db, [{{native,Mod},true}]), + {module,_} -> Result; _ -> {error,Result} end. -post_beam_load(_, undefined, _) -> - %% HiPE is disabled. - ok; -post_beam_load(Mods0, _Architecture, #state{moddb=Db}) -> - %% post_beam_load/2 can potentially be very expensive because it - %% blocks multi-scheduling. Therefore, we only want to call - %% it with modules that are known to have native code loaded. - Mods = [M || M <- Mods0, ets:member(Db, {native,M})], - hipe_unified_loader:post_beam_load(Mods). int_list([H|T]) when is_integer(H) -> int_list(T); int_list([_|_]) -> false; @@ -1313,15 +1302,12 @@ abort_if_sticky(L, Db) -> [_|_] -> {error,Sticky} end. -do_finish_loading(Prepared, #state{moddb=Db}=St) -> +do_finish_loading(Prepared, #state{moddb=Db}) -> MagicBins = [B || {_,{B,_}} <- Prepared], case erlang:finish_loading(MagicBins) of ok -> MFs = [{M,F} || {M,{_,F}} <- Prepared], true = ets:insert(Db, MFs), - Ms = [M || {M,_} <- MFs], - Architecture = erlang:system_info(hipe_architecture), - post_beam_load(Ms, Architecture, St), ok; {Reason,Ms} -> {error,[{M,Reason} || M <- Ms]} diff --git a/lib/kernel/src/file.erl b/lib/kernel/src/file.erl index 58b601e456..1971df9038 100644 --- a/lib/kernel/src/file.erl +++ b/lib/kernel/src/file.erl @@ -397,25 +397,36 @@ write_file(Name, Bin) -> Modes :: [mode()], Reason :: posix() | badarg | terminated | system_limit. -write_file(Name, Bin, ModeList) when is_list(ModeList) -> - case make_binary(Bin) of - B when is_binary(B) -> - case open(Name, [binary, write | - lists:delete(binary, - lists:delete(write, ModeList))]) of - {ok, Handle} -> - case write(Handle, B) of - ok -> - close(Handle); - E1 -> - _ = close(Handle), - E1 - end; - E2 -> - E2 - end; - E3 -> - E3 +write_file(Name, IOData, ModeList) when is_list(ModeList) -> + case lists:member(raw, ModeList) of + true -> + %% For backwards compatibility of error messages + try iolist_size(IOData) of + _Size -> do_write_file(Name, IOData, ModeList) + catch + error:Error -> {error, Error} + end; + false -> + case make_binary(IOData) of + Bin when is_binary(Bin) -> + do_write_file(Name, Bin, ModeList); + Error -> + Error + end + end. + +do_write_file(Name, IOData, ModeList) -> + case open(Name, [binary, write | ModeList]) of + {ok, Handle} -> + case write(Handle, IOData) of + ok -> + close(Handle); + E1 -> + _ = close(Handle), + E1 + end; + E2 -> + E2 end. %% Obsolete, undocumented, local node only, don't use!. diff --git a/lib/kernel/src/hipe_unified_loader.erl b/lib/kernel/src/hipe_unified_loader.erl index 087cceb5d8..04ec1479cb 100644 --- a/lib/kernel/src/hipe_unified_loader.erl +++ b/lib/kernel/src/hipe_unified_loader.erl @@ -41,10 +41,11 @@ % I think the real solution would be to let BIF erlang:load_module/2 redirect all % hipe calls to the module and thereby remove post_beam_load. +% SVERK: Can we remove -compile(no_native) now when post_beam_load is gone? + -export([chunk_name/1, %% Only the code and code_server modules may call the entries below! load_native_code/3, - post_beam_load/1, load_module/4, load/3]). @@ -101,15 +102,13 @@ word_size(Architecture) -> load_native_code(_Mod, _Bin, undefined) -> no_native; load_native_code(Mod, Bin, Architecture) when is_atom(Mod), is_binary(Bin) -> - %% patch_to_emu(Mod), case code:get_chunk(Bin, chunk_name(Architecture)) of undefined -> no_native; NativeCode when is_binary(NativeCode) -> erlang:system_flag(multi_scheduling, block_normal), try - OldReferencesToPatch = patch_to_emu_step1(Mod), - case load_module(Mod, NativeCode, Bin, OldReferencesToPatch, - Architecture) of + put(hipe_patch_closures, false), + case load_common(Mod, NativeCode, Bin, Architecture) of bad_crc -> no_native; Result -> Result end @@ -120,22 +119,6 @@ load_native_code(Mod, Bin, Architecture) when is_atom(Mod), is_binary(Bin) -> %%======================================================================== --spec post_beam_load([module()]) -> 'ok'. - -post_beam_load([])-> - ok; -post_beam_load([_|_]=Mods) -> - erlang:system_flag(multi_scheduling, block_normal), - try - _ = [patch_to_emu(Mod) || Mod <- Mods], - ok - after - erlang:system_flag(multi_scheduling, unblock_normal) - end, - ok. - -%%======================================================================== - version_check(Version, Mod) when is_atom(Mod) -> Ver = ?VERSION_STRING(), case Version < Ver of @@ -153,19 +136,12 @@ version_check(Version, Mod) when is_atom(Mod) -> load_module(Mod, Bin, Beam, Architecture) -> erlang:system_flag(multi_scheduling, block_normal), try - load_module_nosmp(Mod, Bin, Beam, Architecture) + put(hipe_patch_closures, false), + load_common(Mod, Bin, Beam, Architecture) after erlang:system_flag(multi_scheduling, unblock_normal) end. -load_module_nosmp(Mod, Bin, Beam, Architecture) -> - load_module(Mod, Bin, Beam, [], Architecture). - -load_module(Mod, Bin, Beam, OldReferencesToPatch, Architecture) -> - ?debug_msg("************ Loading Module ~w ************\n",[Mod]), - %% Loading a whole module, let the BEAM loader patch closures. - put(hipe_patch_closures, false), - load_common(Mod, Bin, Beam, OldReferencesToPatch, Architecture). %%======================================================================== @@ -175,20 +151,17 @@ load_module(Mod, Bin, Beam, OldReferencesToPatch, Architecture) -> load(Mod, Bin, Architecture) -> erlang:system_flag(multi_scheduling, block_normal), try - load_nosmp(Mod, Bin, Architecture) + ?debug_msg("********* Loading funs in module ~w *********\n",[Mod]), + %% Loading just some functions in a module; patch closures separately. + put(hipe_patch_closures, true), + load_common(Mod, Bin, [], Architecture) after erlang:system_flag(multi_scheduling, unblock_normal) end. -load_nosmp(Mod, Bin, Architecture) -> - ?debug_msg("********* Loading funs in module ~w *********\n",[Mod]), - %% Loading just some functions in a module; patch closures separately. - put(hipe_patch_closures, true), - load_common(Mod, Bin, [], [], Architecture). - %%------------------------------------------------------------------------ -load_common(Mod, Bin, Beam, OldReferencesToPatch, Architecture) -> +load_common(Mod, Bin, Beam, Architecture) -> %% Unpack the binary. [{Version, CheckSum}, ConstAlign, ConstSize, ConstMap, LabelMap, ExportMap, @@ -215,29 +188,31 @@ load_common(Mod, Bin, Beam, OldReferencesToPatch, Architecture) -> put(closures_to_patch, []), WordSize = word_size(Architecture), WriteWord = write_word_fun(WordSize), + LoaderState = hipe_bifs:alloc_loader_state(Mod), + put(hipe_loader_state, LoaderState), %% Create data segment {ConstAddr,ConstMap2} = - create_data_segment(ConstAlign, ConstSize, ConstMap, WriteWord), + create_data_segment(ConstAlign, ConstSize, ConstMap, WriteWord, + LoaderState), %% Find callees for which we may need trampolines. CalleeMFAs = find_callee_mfas(Refs, Architecture), %% Write the code to memory. {CodeAddress,Trampolines} = - enter_code(CodeSize, CodeBinary, CalleeMFAs, Mod, Beam), + enter_code(CodeSize, CodeBinary, CalleeMFAs, LoaderState), %% Construct CalleeMFA-to-trampoline mapping. TrampolineMap = mk_trampoline_map(CalleeMFAs, Trampolines, Architecture), %% Patch references to code labels in data seg. ok = patch_consts(LabelMap, ConstAddr, CodeAddress, WriteWord), + %% Find out which functions are being loaded (and where). - %% Note: Addresses are sorted descending. - {MFAs,Addresses} = exports(ExportMap, CodeAddress), - %% Remove references to old versions of the module. - ReferencesToPatch = get_refs_from(MFAs, []), - %% io:format("References to patch: ~w~n", [ReferencesToPatch]), - ok = remove_refs_from(MFAs), + %% Note: FunDefs are sorted descending address order. + FunDefs = exports(ExportMap, CodeAddress), + %% Patch all dynamic references in the code. %% Function calls, Atoms, Constants, System calls - ok = patch(Refs, CodeAddress, ConstMap2, Addresses, TrampolineMap), + + ok = patch(Refs, CodeAddress, ConstMap2, FunDefs, TrampolineMap), %% Tell the system where the loaded funs are. %% (patches the BEAM code to redirect to native.) @@ -250,25 +225,22 @@ load_common(Mod, Bin, Beam, OldReferencesToPatch, Architecture) -> lists:foreach(fun({FE, DestAddress}) -> hipe_bifs:set_native_address_in_fe(FE, DestAddress) end, erase(closures_to_patch)), - export_funs(Addresses), + ok = hipe_bifs:commit_patch_load(LoaderState), + set_beam_call_traps(FunDefs), ok; BeamBinary when is_binary(BeamBinary) -> %% Find all closures in the code. [] = erase(closures_to_patch), %Clean up, assertion. ClosurePatches = find_closure_patches(Refs), AddressesOfClosuresToPatch = - calculate_addresses(ClosurePatches, CodeAddress, Addresses), - export_funs(Addresses), - export_funs(Mod, MD5, BeamBinary, - Addresses, AddressesOfClosuresToPatch) + calculate_addresses(ClosurePatches, CodeAddress, FunDefs), + export_funs(FunDefs), + make_beam_stub(Mod, LoaderState, MD5, BeamBinary, FunDefs, + AddressesOfClosuresToPatch) end, - %% Redirect references to the old module to the new module's BEAM stub. - patch_to_emu_step2(OldReferencesToPatch), - %% Patch referring functions to call the new function - %% The call to export_funs/1 above updated the native addresses - %% for the targets, so passing 'Addresses' is not needed. - redirect(ReferencesToPatch), + %% Final clean up. + _ = erase(hipe_loader_state), _ = erase(hipe_patch_closures), _ = erase(hipe_assert_code_area), ?debug_msg("****************Loader Finished****************\n", []), @@ -371,31 +343,31 @@ trampoline_map_lookup(Primop, Map) -> is_exported :: boolean()}). exports(ExportMap, BaseAddress) -> - exports(ExportMap, BaseAddress, [], []). + exports(ExportMap, BaseAddress, []). -exports([Offset,M,F,A,IsClosure,IsExported|Rest], BaseAddress, MFAs, Addresses) -> +exports([Offset,M,F,A,IsClosure,IsExported|Rest], BaseAddress, FunDefs) -> case IsExported andalso erlang:is_builtin(M, F, A) of true -> - exports(Rest, BaseAddress, MFAs, Addresses); + exports(Rest, BaseAddress, FunDefs); _false -> MFA = {M,F,A}, Address = BaseAddress + Offset, FunDef = #fundef{address=Address, mfa=MFA, is_closure=IsClosure, is_exported=IsExported}, - exports(Rest, BaseAddress, [MFA|MFAs], [FunDef|Addresses]) + exports(Rest, BaseAddress, [FunDef|FunDefs]) end; -exports([], _, MFAs, Addresses) -> - {MFAs, Addresses}. +exports([], _, FunDefs) -> + FunDefs. mod({M,_F,_A}) -> M. %%------------------------------------------------------------------------ -calculate_addresses(PatchOffsets, Base, Addresses) -> +calculate_addresses(PatchOffsets, Base, FunDefs) -> RemoteOrLocal = local, % closure code refs are local [{Data, offsets_to_addresses(Offsets, Base), - get_native_address(DestMFA, Addresses, RemoteOrLocal)} || + get_native_address(DestMFA, FunDefs, RemoteOrLocal)} || {{DestMFA,_,_}=Data,Offsets} <- PatchOffsets]. offsets_to_addresses(Os, Base) -> @@ -424,9 +396,9 @@ find_closure_refs([], Refs) -> %%------------------------------------------------------------------------ -export_funs([FunDef | Addresses]) -> +set_beam_call_traps([FunDef | FunDefs]) -> #fundef{address=Address, mfa=MFA, is_closure=IsClosure, - is_exported=IsExported} = FunDef, + is_exported=_IsExported} = FunDef, ?IF_DEBUG({M,F,A} = MFA, no_debug), ?IF_DEBUG( case IsClosure of @@ -437,21 +409,38 @@ export_funs([FunDef | Addresses]) -> ?debug_msg("LINKING: ~w:~w/~w to closure (0x~.16b)\n", [M,F,A, Address]) end, no_debug), - hipe_bifs:set_funinfo_native_address(MFA, Address, IsExported), hipe_bifs:set_native_address(MFA, Address, IsClosure), - export_funs(Addresses); + set_beam_call_traps(FunDefs); +set_beam_call_traps([]) -> + ok. + +export_funs([FunDef | FunDefs]) -> + #fundef{address=Address, mfa=MFA, is_closure=_IsClosure, + is_exported=IsExported} = FunDef, + ?IF_DEBUG({M,F,A} = MFA, no_debug), + ?IF_DEBUG( + case _IsClosure of + false -> + ?debug_msg("LINKING: ~w:~w/~w to (0x~.16b)\n", + [M,F,A, Address]); + true -> + ?debug_msg("LINKING: ~w:~w/~w to closure (0x~.16b)\n", + [M,F,A, Address]) + end, no_debug), + hipe_bifs:set_funinfo_native_address(MFA, Address, IsExported), + export_funs(FunDefs); export_funs([]) -> ok. -export_funs(Mod, MD5, Beam, Addresses, ClosuresToPatch) -> - Fs = [{F,A,Address} || #fundef{address=Address, mfa={_M,F,A}} <- Addresses], - Mod = code:make_stub_module(Mod, Beam, {Fs,ClosuresToPatch,MD5}), +make_beam_stub(Mod, LoaderState, MD5, Beam, FunDefs, ClosuresToPatch) -> + Fs = [{F,A,Address} || #fundef{address=Address, mfa={_M,F,A}} <- FunDefs], + Mod = code:make_stub_module(LoaderState, Beam, {Fs,ClosuresToPatch,MD5}), ok. %%======================================================================== %% Patching %% @spec patch(refs(), BaseAddress::integer(), ConstAndZone::term(), -%% Addresses::term(), TrampolineMap::term()) -> 'ok'. +%% FunDefs::term(), TrampolineMap::term()) -> 'ok'. %% @type refs()=[{RefType::integer(), Reflist::reflist()} | refs()] %% %% @type reflist()= [{Data::term(), Offsets::offests()}|reflist()] @@ -463,39 +452,39 @@ export_funs(Mod, MD5, Beam, Addresses, ClosuresToPatch) -> %% (we use this to look up the address of a referred function only once). %% -patch([{Type,SortedRefs}|Rest], CodeAddress, ConstMap2, Addresses, TrampolineMap) -> +patch([{Type,SortedRefs}|Rest], CodeAddress, ConstMap2, FunDefs, TrampolineMap) -> ?debug_msg("Patching ~w at [~w+offset] with ~w\n", [Type,CodeAddress,SortedRefs]), case ?EXT2PATCH_TYPE(Type) of call_local -> - patch_call(SortedRefs, CodeAddress, Addresses, 'local', TrampolineMap); + patch_call(SortedRefs, CodeAddress, FunDefs, 'local', TrampolineMap); call_remote -> - patch_call(SortedRefs, CodeAddress, Addresses, 'remote', TrampolineMap); + patch_call(SortedRefs, CodeAddress, FunDefs, 'remote', TrampolineMap); Other -> - patch_all(Other, SortedRefs, CodeAddress, {ConstMap2,CodeAddress}, Addresses) + patch_all(Other, SortedRefs, CodeAddress, {ConstMap2,CodeAddress}, FunDefs) end, - patch(Rest, CodeAddress, ConstMap2, Addresses, TrampolineMap); + patch(Rest, CodeAddress, ConstMap2, FunDefs, TrampolineMap); patch([], _, _, _, _) -> ok. %%---------------------------------------------------------------- %% Handle a 'call_local' or 'call_remote' patch. %% -patch_call([{DestMFA,Offsets}|SortedRefs], BaseAddress, Addresses, RemoteOrLocal, TrampolineMap) -> +patch_call([{DestMFA,Offsets}|SortedRefs], BaseAddress, FunDefs, RemoteOrLocal, TrampolineMap) -> case bif_address(DestMFA) of false -> - %% Previous code used mfa_to_address(DestMFA, Addresses) + %% Previous code used mfa_to_address(DestMFA, FunDefs) %% here for local calls. That is wrong because even local - %% destinations may not be present in Addresses: they may + %% destinations may not be present in FunDefs: they may %% not have been compiled yet, or they may be BEAM-only %% functions (e.g. module_info). - DestAddress = get_native_address(DestMFA, Addresses, RemoteOrLocal), + DestAddress = get_native_address(DestMFA, FunDefs, RemoteOrLocal), Trampoline = trampoline_map_get(DestMFA, TrampolineMap), - patch_mfa_call_list(Offsets, BaseAddress, DestMFA, DestAddress, Addresses, RemoteOrLocal, Trampoline); + patch_mfa_call_list(Offsets, BaseAddress, DestMFA, DestAddress, FunDefs, RemoteOrLocal, Trampoline); BifAddress when is_integer(BifAddress) -> Trampoline = trampoline_map_lookup(DestMFA, TrampolineMap), patch_bif_call_list(Offsets, BaseAddress, BifAddress, Trampoline) end, - patch_call(SortedRefs, BaseAddress, Addresses, RemoteOrLocal, TrampolineMap); + patch_call(SortedRefs, BaseAddress, FunDefs, RemoteOrLocal, TrampolineMap); patch_call([], _, _, _, _) -> ok. @@ -506,49 +495,48 @@ patch_bif_call_list([Offset|Offsets], BaseAddress, BifAddress, Trampoline) -> patch_bif_call_list(Offsets, BaseAddress, BifAddress, Trampoline); patch_bif_call_list([], _, _, _) -> ok. -patch_mfa_call_list([Offset|Offsets], BaseAddress, DestMFA, DestAddress, Addresses, RemoteOrLocal, Trampoline) -> +patch_mfa_call_list([Offset|Offsets], BaseAddress, DestMFA, DestAddress, FunDefs, RemoteOrLocal, Trampoline) -> CallAddress = BaseAddress+Offset, - add_ref(DestMFA, CallAddress, Addresses, 'call', Trampoline, RemoteOrLocal), + add_ref(DestMFA, CallAddress, FunDefs, 'call', Trampoline, RemoteOrLocal), ?ASSERT(assert_local_patch(CallAddress)), patch_call_insn(CallAddress, DestAddress, Trampoline), - patch_mfa_call_list(Offsets, BaseAddress, DestMFA, DestAddress, Addresses, RemoteOrLocal, Trampoline); + patch_mfa_call_list(Offsets, BaseAddress, DestMFA, DestAddress, FunDefs, RemoteOrLocal, Trampoline); patch_mfa_call_list([], _, _, _, _, _, _) -> ok. patch_call_insn(CallAddress, DestAddress, Trampoline) -> - %% This assertion is false when we're called from redirect/2. - %% ?ASSERT(assert_local_patch(CallAddress)), + ?ASSERT(assert_local_patch(CallAddress)), hipe_bifs:patch_call(CallAddress, DestAddress, Trampoline). %% ____________________________________________________________________ %% -patch_all(Type, [{Dest,Offsets}|Rest], BaseAddress, ConstAndZone, Addresses)-> - patch_all_offsets(Type, Dest, Offsets, BaseAddress, ConstAndZone, Addresses), - patch_all(Type, Rest, BaseAddress, ConstAndZone, Addresses); +patch_all(Type, [{Dest,Offsets}|Rest], BaseAddress, ConstAndZone, FunDefs)-> + patch_all_offsets(Type, Dest, Offsets, BaseAddress, ConstAndZone, FunDefs), + patch_all(Type, Rest, BaseAddress, ConstAndZone, FunDefs); patch_all(_, [], _, _, _) -> ok. patch_all_offsets(Type, Data, [Offset|Offsets], BaseAddress, - ConstAndZone, Addresses) -> + ConstAndZone, FunDefs) -> ?debug_msg("Patching ~w at [~w+~w] with ~w\n", [Type,BaseAddress,Offset, Data]), Address = BaseAddress + Offset, - patch_offset(Type, Data, Address, ConstAndZone, Addresses), + patch_offset(Type, Data, Address, ConstAndZone, FunDefs), ?debug_msg("Patching done\n",[]), - patch_all_offsets(Type, Data, Offsets, BaseAddress, ConstAndZone, Addresses); + patch_all_offsets(Type, Data, Offsets, BaseAddress, ConstAndZone, FunDefs); patch_all_offsets(_, _, [], _, _, _) -> ok. %%---------------------------------------------------------------- %% Handle any patch type except 'call_local' or 'call_remote'. %% -patch_offset(Type, Data, Address, ConstAndZone, Addresses) -> +patch_offset(Type, Data, Address, ConstAndZone, FunDefs) -> case Type of load_address -> - patch_load_address(Data, Address, ConstAndZone, Addresses); + patch_load_address(Data, Address, ConstAndZone, FunDefs); load_atom -> Atom = Data, patch_atom(Address, Atom); sdesc -> - patch_sdesc(Data, Address, ConstAndZone, Addresses); + patch_sdesc(Data, Address, ConstAndZone, FunDefs); x86_abs_pcrel -> patch_instr(Address, Data, x86_abs_pcrel) %% _ -> @@ -561,37 +549,38 @@ patch_atom(Address, Atom) -> patch_instr(Address, hipe_bifs:atom_to_word(Atom), atom). patch_sdesc(?STACK_DESC(SymExnRA, FSize, Arity, Live), - Address, {_ConstMap2,CodeAddress}, _Addresses) -> + Address, {_ConstMap2,CodeAddress}, FunDefs) -> ExnRA = case SymExnRA of [] -> 0; % No catch LabelOffset -> CodeAddress + LabelOffset end, ?ASSERT(assert_local_patch(Address)), - DBG_MFA = ?IF_DEBUG(address_to_mfa_lth(Address, _Addresses), {undefined,undefined,0}), - hipe_bifs:enter_sdesc({Address, ExnRA, FSize, Arity, Live, DBG_MFA}). + MFA = address_to_mfa_lth(Address, FunDefs), + hipe_bifs:enter_sdesc({Address, ExnRA, FSize, Arity, Live, MFA}, + get(hipe_loader_state)). %%---------------------------------------------------------------- %% Handle a 'load_address'-type patch. %% -patch_load_address(Data, Address, ConstAndZone, Addresses) -> +patch_load_address(Data, Address, ConstAndZone, FunDefs) -> case Data of {local_function,DestMFA} -> - patch_load_mfa(Address, DestMFA, Addresses, 'local'); + patch_load_mfa(Address, DestMFA, FunDefs, 'local'); {remote_function,DestMFA} -> - patch_load_mfa(Address, DestMFA, Addresses, 'remote'); + patch_load_mfa(Address, DestMFA, FunDefs, 'remote'); {constant,Name} -> {ConstMap2,_CodeAddress} = ConstAndZone, ConstAddress = find_const(Name, ConstMap2), patch_instr(Address, ConstAddress, constant); {closure,{DestMFA,Uniq,Index}} -> - patch_closure(DestMFA, Uniq, Index, Address, Addresses); + patch_closure(DestMFA, Uniq, Index, Address, FunDefs); {c_const,CConst} -> patch_instr(Address, bif_address(CConst), c_const) end. -patch_closure(DestMFA, Uniq, Index, Address, Addresses) -> +patch_closure(DestMFA, Uniq, Index, Address, FunDefs) -> case get(hipe_patch_closures) of false -> []; % This is taken care of when registering the module. @@ -602,7 +591,7 @@ patch_closure(DestMFA, Uniq, Index, Address, Addresses) -> %% address into the fun entry to ensure that the native code cannot %% be called until it has been completely fixed up. RemoteOrLocal = local, % closure code refs are local - DestAddress = get_native_address(DestMFA, Addresses, RemoteOrLocal), + DestAddress = get_native_address(DestMFA, FunDefs, RemoteOrLocal), BEAMAddress = hipe_bifs:fun_to_address(DestMFA), FE = hipe_bifs:get_fe(mod(DestMFA), {Uniq, Index, BEAMAddress}), put(closures_to_patch, [{FE,DestAddress}|get(closures_to_patch)]), @@ -616,17 +605,17 @@ patch_closure(DestMFA, Uniq, Index, Address, Addresses) -> %% Patch an instruction loading the address of an MFA. %% RemoteOrLocal ::= 'remote' | 'local' %% -patch_load_mfa(CodeAddress, DestMFA, Addresses, RemoteOrLocal) -> +patch_load_mfa(CodeAddress, DestMFA, FunDefs, RemoteOrLocal) -> + ?ASSERT(assert_local_patch(CodeAddress)), DestAddress = case bif_address(DestMFA) of false -> - NativeAddress = get_native_address(DestMFA, Addresses, RemoteOrLocal), - add_ref(DestMFA, CodeAddress, Addresses, 'load_mfa', [], RemoteOrLocal), + NativeAddress = get_native_address(DestMFA, FunDefs, RemoteOrLocal), + add_ref(DestMFA, CodeAddress, FunDefs, 'load_mfa', [], RemoteOrLocal), NativeAddress; BifAddress when is_integer(BifAddress) -> BifAddress end, - ?ASSERT(assert_local_patch(CodeAddress)), patch_instr(CodeAddress, DestAddress, 'load_mfa'). %%---------------------------------------------------------------- @@ -702,9 +691,9 @@ bif_address(Name) when is_atom(Name) -> %% memory, and produces a ConstMap2 mapping each constant's ConstNo to %% its runtime address, tagged if the constant is a term. %% -create_data_segment(DataAlign, DataSize, DataList, WriteWord) -> +create_data_segment(DataAlign, DataSize, DataList, WriteWord, LoaderState) -> %%io:format("create_data_segment: \nDataAlign: ~p\nDataSize: ~p\nDataList: ~p\n",[DataAlign,DataSize,DataList]), - DataAddress = hipe_bifs:alloc_data(DataAlign, DataSize), + DataAddress = hipe_bifs:alloc_data(DataAlign, DataSize, LoaderState), enter_data(DataList, [], DataAddress, DataSize, WriteWord). enter_data(List, ConstMap2, DataAddress, DataSize, WriteWord) -> @@ -772,7 +761,7 @@ find_const(ConstNo, []) -> %%---------------------------------------------------------------- %% Record that the code at address 'Address' has a reference %% of type 'RefType' ('call' or 'load_mfa') to 'CalleeMFA'. -%% 'Addresses' must be an address-descending list from exports/2. +%% 'FunDefs' must be an address-descending list from exports/2. %% %% If 'RefType' is 'call', then 'Trampoline' may be the address %% of a stub branching to 'CalleeMFA', where the stub is reachable @@ -781,34 +770,29 @@ find_const(ConstNo, []) -> %% RemoteOrLocal ::= 'remote' | 'local'. %% -%% -%% -record(ref, {caller_mfa, address, ref_type, trampoline, remote_or_local}). -%% +add_ref(CalleeMFA, Address, FunDefs, RefType, Trampoline, RemoteOrLocal) -> + CallerMFA = address_to_mfa_lth(Address, FunDefs), + case RemoteOrLocal of + local -> + %% assert that the callee and caller are from the same module + {M,_,_} = CalleeMFA, + {M,_,_} = CallerMFA, + ok; + remote -> + hipe_bifs:add_ref(CalleeMFA, {CallerMFA,Address,RefType,Trampoline, + get(hipe_loader_state)}) + end. -add_ref(CalleeMFA, Address, Addresses, RefType, Trampoline, RemoteOrLocal) -> - CallerMFA = address_to_mfa_lth(Address, Addresses), - %% just a sanity assertion below - true = case RemoteOrLocal of - local -> - {M1,_,_} = CalleeMFA, - {M2,_,_} = CallerMFA, - M1 =:= M2; - remote -> - true - end, - %% io:format("Adding ref ~w\n",[{CallerMFA, CalleeMFA, Address, RefType}]), - hipe_bifs:add_ref(CalleeMFA, {CallerMFA,Address,RefType,Trampoline,RemoteOrLocal}). - -% For FunDefs sorted from low to high addresses +%% For FunDefs sorted from low to high addresses address_to_mfa_lth(Address, FunDefs) -> - case address_to_mfa_lth(Address, FunDefs, false) of - false -> - ?error_msg("Local adddress not found ~w\n",[Address]), - exit({?MODULE, local_address_not_found}); - MFA -> - MFA - end. - + case address_to_mfa_lth(Address, FunDefs, false) of + false -> + ?error_msg("Local adddress not found ~w\n",[Address]), + exit({?MODULE, local_address_not_found}); + MFA -> + MFA + end. + address_to_mfa_lth(Address, [#fundef{address=Adr, mfa=MFA}|Rest], Prev) -> if Address < Adr -> Prev; @@ -818,107 +802,33 @@ address_to_mfa_lth(Address, [#fundef{address=Adr, mfa=MFA}|Rest], Prev) -> address_to_mfa_lth(_Address, [], Prev) -> Prev. -% For FunDefs sorted from high to low addresses +%% For FunDefs sorted from high to low addresses %% address_to_mfa_htl(Address, [#fundef{address=Adr, mfa=MFA}|_Rest]) when Address >= Adr -> MFA; %% address_to_mfa_htl(Address, [_ | Rest]) -> address_to_mfa_htl(Address, Rest); %% address_to_mfa_htl(Address, []) -> %% ?error_msg("Local adddress not found ~w\n",[Address]), %% exit({?MODULE, local_address_not_found}). -%%---------------------------------------------------------------- -%% Change callers of the given module to instead trap to BEAM. -%% load_native_code/3 calls this just before loading native code. -%% -patch_to_emu(Mod) -> - patch_to_emu_step2(patch_to_emu_step1(Mod)). - -%% Step 1 must occur before the loading of native code updates -%% references information or creates a new BEAM stub module. -patch_to_emu_step1(Mod) -> - case is_loaded(Mod) of - true -> - %% Get exported functions - MFAs = [{Mod,Fun,Arity} || {Fun,Arity} <- Mod:module_info(exports)], - %% get_refs_from/2 only finds references from compiled static - %% call sites to the module, but some native address entries - %% were added as the result of dynamic apply calls. We must - %% purge them too, but we have no explicit record of them. - %% Therefore invalidate all native addresses for the module. - hipe_bifs:invalidate_funinfo_native_addresses(MFAs), - %% Find all call sites that call these MFAs. As a side-effect, - %% create native stubs for any MFAs that are referred. - ReferencesToPatch = get_refs_from(MFAs, []), - ok = remove_refs_from(MFAs), - ReferencesToPatch; - false -> - %% The first time we load the module, no redirection needs to be done. - [] - end. - -%% Step 2 must occur after the new BEAM stub module is created. -patch_to_emu_step2(ReferencesToPatch) -> - redirect(ReferencesToPatch). - --spec is_loaded(Module::atom()) -> boolean(). -%% @doc Checks whether a module is loaded or not. -is_loaded(M) when is_atom(M) -> - try hipe_bifs:fun_to_address({M,module_info,0}) of - I when is_integer(I) -> true - catch _:_ -> false - end. - -%%-------------------------------------------------------------------- -%% Given a list of MFAs, tag them with their referred_from references. -%% The resulting {MFA,Refs} list is later passed to redirect/1, once -%% the MFAs have been bound to (possibly new) native-code addresses. -%% -get_refs_from(MFAs, []) -> - mark_referred_from(MFAs), - MFAs. - -mark_referred_from(MFAs) -> - lists:foreach(fun(MFA) -> hipe_bifs:mark_referred_from(MFA) end, MFAs). - -%%-------------------------------------------------------------------- -%% Given a list of MFAs with referred_from references, update their -%% callers to refer to their new native-code addresses. -%% -%% The {MFA,Refs} list must come from get_refs_from/2. -%% -redirect(MFAs) -> - lists:foreach(fun(MFA) -> hipe_bifs:redirect_referred_from(MFA) end, MFAs). - -%%-------------------------------------------------------------------- -%% Given a list of MFAs, remove all referred_from references having -%% any of them as CallerMFA. -%% -%% This is the only place using refers_to. Whenever a reference is -%% added from CallerMFA to CalleeMFA, CallerMFA is added to CalleeMFA's -%% referred_from list, and CalleeMFA is added to CallerMFA's refers_to -%% list. The refers_to list is used here to find the CalleeMFAs whose -%% referred_from lists should be updated. -%% -remove_refs_from(MFAs) -> - lists:foreach(fun(MFA) -> hipe_bifs:remove_refs_from(MFA) end, MFAs). %%-------------------------------------------------------------------- %% To find the native code of an MFA we need to look in 3 places: -%% 1. If it is compiled now look in the Addresses data structure. +%% 1. If it is compiled now look in the FunDefs data structure. %% 2. Then look in native_addresses from module info. %% 3. Then (the function might have been singled compiled) look in %% hipe_funinfo %% If all else fails create a native stub for the MFA -get_native_address(MFA, Addresses, RemoteOrLocal) -> - case mfa_to_address(MFA, Addresses, RemoteOrLocal) of +get_native_address(MFA, FunDefs, RemoteOrLocal) -> + case mfa_to_address(MFA, FunDefs, RemoteOrLocal) of Adr when is_integer(Adr) -> Adr; false -> - IsRemote = case RemoteOrLocal of - remote -> true; - local -> false - end, - hipe_bifs:find_na_or_make_stub(MFA, IsRemote) + remote -> + hipe_bifs:find_na_or_make_stub(MFA); + local -> + ?error_msg("Local function ~p not found\n",[MFA]), + exit({function_not_found,MFA}) + end end. mfa_to_address(MFA, [#fundef{address=Adr, mfa=MFA, @@ -958,12 +868,10 @@ assert_local_patch(Address) when is_integer(Address) -> %% ____________________________________________________________________ %% -%% Beam: nil() | binary() (used as a flag) - -enter_code(CodeSize, CodeBinary, CalleeMFAs, Mod, Beam) -> +enter_code(CodeSize, CodeBinary, CalleeMFAs, LoaderState) -> true = byte_size(CodeBinary) =:= CodeSize, - hipe_bifs:update_code_size(Mod, Beam, CodeSize), - {CodeAddress,Trampolines} = hipe_bifs:enter_code(CodeBinary, CalleeMFAs), + {CodeAddress,Trampolines} = hipe_bifs:enter_code(CodeBinary, CalleeMFAs, + LoaderState), ?init_assert_patch(CodeAddress, byte_size(CodeBinary)), {CodeAddress,Trampolines}. diff --git a/lib/kernel/src/inet.erl b/lib/kernel/src/inet.erl index 75dd800c6b..f5c13ecdd7 100644 --- a/lib/kernel/src/inet.erl +++ b/lib/kernel/src/inet.erl @@ -677,7 +677,7 @@ parse_strict_address(Addr) -> %% Return a list of available options options() -> [ - tos, priority, reuseaddr, keepalive, dontroute, linger, + tos, tclass, priority, reuseaddr, keepalive, dontroute, linger, broadcast, sndbuf, recbuf, nodelay, ipv6_v6only, buffer, header, active, packet, deliver, mode, multicast_if, multicast_ttl, multicast_loop, @@ -698,7 +698,7 @@ stats() -> %% Available options for tcp:connect %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% connect_options() -> - [tos, priority, reuseaddr, keepalive, linger, sndbuf, recbuf, nodelay, + [tos, tclass, priority, reuseaddr, keepalive, linger, sndbuf, recbuf, nodelay, header, active, packet, packet_size, buffer, mode, deliver, line_delimiter, exit_on_close, high_watermark, low_watermark, high_msgq_watermark, low_msgq_watermark, send_timeout, send_timeout_close, delay_send, raw, @@ -766,7 +766,7 @@ con_add(Name, Val, #connect_opts{} = R, Opts, AllOpts) -> %% Available options for tcp:listen %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% listen_options() -> - [tos, priority, reuseaddr, keepalive, linger, sndbuf, recbuf, nodelay, + [tos, tclass, priority, reuseaddr, keepalive, linger, sndbuf, recbuf, nodelay, header, active, packet, buffer, mode, deliver, backlog, ipv6_v6only, exit_on_close, high_watermark, low_watermark, high_msgq_watermark, low_msgq_watermark, send_timeout, send_timeout_close, delay_send, @@ -846,7 +846,7 @@ tcp_module_1(Opts, Address) -> %% Available options for udp:open %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% udp_options() -> - [tos, priority, reuseaddr, sndbuf, recbuf, header, active, buffer, mode, + [tos, tclass, priority, reuseaddr, sndbuf, recbuf, header, active, buffer, mode, deliver, ipv6_v6only, broadcast, dontroute, multicast_if, multicast_ttl, multicast_loop, add_membership, drop_membership, read_packets,raw, @@ -917,7 +917,7 @@ udp_module(Opts) -> % (*) passing of open FDs ("fdopen") is not supported. sctp_options() -> [ % The following are generic inet options supported for SCTP sockets: - mode, active, buffer, tos, priority, dontroute, reuseaddr, linger, sndbuf, + mode, active, buffer, tos, tclass, priority, dontroute, reuseaddr, linger, sndbuf, recbuf, ipv6_v6only, high_msgq_watermark, low_msgq_watermark, % Other options are SCTP-specific (though they may be similar to their diff --git a/lib/kernel/src/inet_db.erl b/lib/kernel/src/inet_db.erl index 465cec1b45..6cbb6ac2da 100644 --- a/lib/kernel/src/inet_db.erl +++ b/lib/kernel/src/inet_db.erl @@ -1379,7 +1379,8 @@ cache_rr(_Db, Cache, RR) -> ets:insert(Cache, RR). times() -> - erlang:convert_time_unit(erlang:monotonic_time() - erlang:system_info(start_time),native,seconds). + erlang:convert_time_unit(erlang:monotonic_time() - erlang:system_info(start_time), + native, second). %% lookup and remove old entries diff --git a/lib/kernel/src/inet_int.hrl b/lib/kernel/src/inet_int.hrl index c8a8962e78..4e8f59a3b9 100644 --- a/lib/kernel/src/inet_int.hrl +++ b/lib/kernel/src/inet_int.hrl @@ -153,6 +153,7 @@ -define(INET_LOPT_NETNS, 38). -define(INET_LOPT_TCP_SHOW_ECONNRESET, 39). -define(INET_LOPT_LINE_DELIM, 40). +-define(INET_OPT_TCLASS, 41). % Specific SCTP options: separate range: -define(SCTP_OPT_RTOINFO, 100). -define(SCTP_OPT_ASSOCINFO, 101). diff --git a/lib/kernel/src/kernel.app.src b/lib/kernel/src/kernel.app.src index 56d1699656..4d08a55c7c 100644 --- a/lib/kernel/src/kernel.app.src +++ b/lib/kernel/src/kernel.app.src @@ -118,6 +118,6 @@ {applications, []}, {env, [{error_logger, tty}]}, {mod, {kernel, []}}, - {runtime_dependencies, ["erts-8.0", "stdlib-3.0", "sasl-3.0"]} + {runtime_dependencies, ["erts-9.0", "stdlib-3.0", "sasl-3.0"]} ] }. diff --git a/lib/kernel/src/kernel.appup.src b/lib/kernel/src/kernel.appup.src index d16e200cb3..82cf73cbda 100644 --- a/lib/kernel/src/kernel.appup.src +++ b/lib/kernel/src/kernel.appup.src @@ -18,9 +18,9 @@ %% %CopyrightEnd% {"%VSN%", %% Up from - max one major revision back - [{<<"5\\.0(\\.[0-9]+)*">>,[restart_new_emulator]}, % OTP-19.* + [{<<"5\\.[0-1](\\.[0-9]+)*">>,[restart_new_emulator]}, % OTP-19.* {<<"4\\.[0-2](\\.[0-9]+)*">>,[restart_new_emulator]}], % OTP-18.* %% Down to - max one major revision back - [{<<"5\\.0(\\.[0-9]+)*">>,[restart_new_emulator]}, % OTP-19.* + [{<<"5\\.[0-1](\\.[0-9]+)*">>,[restart_new_emulator]}, % OTP-19.* {<<"4\\.[0-2](\\.[0-9]+)*">>,[restart_new_emulator]}] % OTP-18.* }. diff --git a/lib/kernel/test/code_SUITE.erl b/lib/kernel/test/code_SUITE.erl index c5167efa56..29b3f7caaf 100644 --- a/lib/kernel/test/code_SUITE.erl +++ b/lib/kernel/test/code_SUITE.erl @@ -483,23 +483,35 @@ load_binary(Config) when is_list(Config) -> code:delete(code_b_test), ok. + upgrade(Config) -> DataDir = proplists:get_value(data_dir, Config), - %%T = [beam, hipe], - T = [beam], - - [upgrade_do(DataDir, Client, U1, U2, O1, O2) - || Client<-T, U1<-T, U2<-T, O1<-T, O2<-T], - + case erlang:system_info(hipe_architecture) of + undefined -> + upgrade_do(DataDir, beam, [beam]); + + _ -> + T = [beam, hipe], + [upgrade_do(DataDir, Client, T) || Client <- T], + + case hipe:llvm_support_available() of + false -> ok; + true -> + T2 = [beam, hipe_llvm], + [upgrade_do(DataDir, Client, T2) || Client <- T2] + end + end, ok. -upgrade_do(DataDir, Client, U1, U2, O1, O2) -> +upgrade_do(DataDir, Client, T) -> compile_load(upgrade_client, DataDir, undefined, Client), - upgrade_client:run(DataDir, U1, U2, O1, O2), + [upgrade_client:run(DataDir, U1, U2, O1, O2) + || U1<-T, U2<-T, O1<-T, O2<-T], ok. compile_load(Mod, Dir, Ver, CodeType) -> + %%erlang:display({"{{{{{{{{{{{{{{{{Loading",Mod,Ver,CodeType}), Version = case Ver of undefined -> io:format("Compiling '~p' as ~p\n", [Mod, CodeType]), @@ -511,14 +523,21 @@ compile_load(Mod, Dir, Ver, CodeType) -> end, Target = case CodeType of beam -> []; - hipe -> [native] + hipe -> [native]; + hipe_llvm -> [native,{hipe,[to_llvm]}] end, CompOpts = [binary, report] ++ Target ++ Version, Src = filename:join(Dir, atom_to_list(Mod) ++ ".erl"), + T1 = erlang:now(), {ok,Mod,Code} = compile:file(Src, CompOpts), + T2 = erlang:now(), ObjFile = filename:basename(Src,".erl") ++ ".beam", {module,Mod} = code:load_binary(Mod, ObjFile, Code), + T3 = erlang:now(), + io:format("Compile time ~p ms, Load time ~p ms\n", + [timer:now_diff(T2,T1) div 1000, timer:now_diff(T3,T2) div 1000]), + %%erlang:display({"}}}}}}}}}}}}}}}Loaded",Mod,Ver,CodeType}), ok. dir_req(Config) when is_list(Config) -> @@ -810,8 +829,6 @@ check_funs({'$M_EXPR','$F_EXPR',_}, {code_server,start_link,1}]) -> 0; check_funs({'$M_EXPR','$F_EXPR',_}, [{erlang,spawn_link,1},{code_server,start_link,1}]) -> 0; -check_funs({'$M_EXPR',module_info,1}, - [{hipe_unified_loader,patch_to_emu_step1,1} | _]) -> 0; check_funs({'$M_EXPR','$F_EXPR',2}, [{hipe_unified_loader,write_words,3} | _]) -> 0; check_funs({'$M_EXPR','$F_EXPR',2}, @@ -823,11 +840,7 @@ check_funs({'$M_EXPR','$F_EXPR',2}, {hipe_unified_loader,sort_and_write,5} | _]) -> 0; check_funs({'$M_EXPR','$F_EXPR',1}, [{lists,foreach,2}, - {hipe_unified_loader,patch_consts,3} | _]) -> 0; -check_funs({'$M_EXPR','$F_EXPR',1}, - [{lists,foreach,2}, - {hipe_unified_loader,mark_referred_from,1}, - {hipe_unified_loader,get_refs_from,2}| _]) -> 0; + {hipe_unified_loader,patch_consts,4} | _]) -> 0; check_funs({'$M_EXPR',warning_msg,2}, [{code_server,finish_on_load_report,2} | _]) -> 0; check_funs({'$M_EXPR','$F_EXPR',1}, diff --git a/lib/kernel/test/code_SUITE_data/upgrade_client.erl b/lib/kernel/test/code_SUITE_data/upgrade_client.erl index bb655e01d3..faa18e1410 100644 --- a/lib/kernel/test/code_SUITE_data/upgrade_client.erl +++ b/lib/kernel/test/code_SUITE_data/upgrade_client.erl @@ -9,6 +9,8 @@ run(Dir, Upgradee1, Upgradee2, Other1, Other2) -> %% Load version 1 of upgradee code_SUITE:compile_load(upgradee, Dir, 1, Upgradee1), + Tracer = start_tracing(), + ?line 1 = upgradee:exp1(), ?line 1 = upgradee:exp1exp2(), ?line 1 = upgradee:exp1loc2(), @@ -56,6 +58,15 @@ run(Dir, Upgradee1, Upgradee2, Other1, Other2) -> ?line {'EXIT',{undef,_}} = proxy_call(P, other, loc1), ?line {'EXIT',{undef,_}} = proxy_call(P, other, loc2), + Env1 = "Env1", + put(loc1_fun, upgradee:get_local_fun(Env1)), + ?line {1,Env1} = (get(loc1_fun))(), + + put(exp1exp2_fun, upgradee:get_exp1exp2_fun()), + ?line 1 = (get(exp1exp2_fun))(), + + ok = check_tracing(Tracer, 13), + %% %% Load version 1 of other %% @@ -78,6 +89,8 @@ run(Dir, Upgradee1, Upgradee2, Other1, Other2) -> ?line {'EXIT',{undef,_}} = proxy_call(P, other, exp2), ?line {'EXIT',{undef,_}} = proxy_call(P, other, loc2), + ok = check_tracing(Tracer, 5), + %% %% Load version 2 of upgradee %% @@ -130,6 +143,15 @@ run(Dir, Upgradee1, Upgradee2, Other1, Other2) -> ?line {'EXIT',{undef,_}} = proxy_call(P, other, exp2), ?line {'EXIT',{undef,_}} = proxy_call(P, other, loc2), + ?line {1,Env1} = (get(loc1_fun))(), + Env2 = "Env2", + put(loc2_fun, upgradee:get_local_fun(Env2)), + ?line {2,Env2} = (get(loc2_fun))(), + + ?line 2 = (get(exp1exp2_fun))(), + + ok = check_tracing(Tracer, 10), + %% %% Load version 2 of other %% @@ -182,17 +204,26 @@ run(Dir, Upgradee1, Upgradee2, Other1, Other2) -> ?line {'EXIT',{undef,_}} = proxy_call(P, other, loc1loc2), ?line {'EXIT',{undef,_}} = proxy_call(P, other, loc2), + ?line {1,Env1} = (get(loc1_fun))(), + ?line {2,Env2} = (get(loc2_fun))(), + ?line 2 = (get(exp1exp2_fun))(), + + ok = check_tracing(Tracer, 10), %% %% Upgrade proxy to version 2 %% P ! upgrade_order, - %% - io:format("Delete version 2 of 'upgradee'\n",[]), + io:format("Purge version 1 of 'upgradee'\n",[]), %% + put(loc1_fun,undefined), code:purge(upgradee), + + %% + io:format("Delete version 2 of 'upgradee'\n",[]), + %% code:delete(upgradee), ?line {'EXIT',{undef,_}} = (catch upgradee:exp2()), @@ -239,17 +270,24 @@ run(Dir, Upgradee1, Upgradee2, Other1, Other2) -> ?line {'EXIT',{undef,_}} = proxy_call(P, other, exp1loc2), ?line {'EXIT',{undef,_}} = proxy_call(P, other, loc1loc2), ?line {'EXIT',{undef,_}} = proxy_call(P, other, loc2), + + ?line {'EXIT',{undef,_}} = (catch (get(exp1exp2_fun))()), + ok = check_tracing(Tracer, 14), + unlink(P), exit(P, die_please), io:format("Purge 'upgradee'\n",[]), + put(loc2_fun,undefined), code:purge(upgradee), io:format("Delete and purge 'other'\n",[]), code:purge(other), code:delete(other), code:purge(other), + + stop_tracing(Tracer), ok. proxy_call(Pid, CallType, Func) -> @@ -257,3 +295,54 @@ proxy_call(Pid, CallType, Func) -> receive {Pid, call_result, Func, Ret} -> Ret end. + + +start_tracing() -> + Self = self(), + {Tracer,_} = spawn_opt(fun() -> tracer_loop(Self) end, [link,monitor]), + ?line 1 = erlang:trace_pattern({error_handler,undefined_function,3}, + true, [global]), + ?line 1 = erlang:trace(Self, true, [call,{tracer,Tracer}]), + Tracer. + + +tracer_loop(Receiver) -> + receive + die_please -> + ok; + {do_trace_delivered, Tracee} -> + _ = erlang:trace_delivered(Tracee), + tracer_loop(Receiver); + + Msg -> + Receiver ! Msg, + tracer_loop(Receiver) + end. + +check_tracing(Tracer, Expected) -> + Tracer ! {do_trace_delivered, self()}, + case check_tracing_loop(0,[]) of + {Expected,_} -> + ok; + {Got, MsgList} -> + io:format("Expected ~p trace msg, got ~p:\n~p\n", + [Expected, Got, lists:reverse(MsgList)]), + "Trace msg mismatch" + end. + +check_tracing_loop(N, MsgList) -> + Self = self(), + receive + {trace, _Pid, call, {_M, _F, _Args}} = Msg -> + check_tracing_loop(N+1, [Msg | MsgList]); + {trace_delivered, Self, _} -> + {N, MsgList} + end. + + +stop_tracing(Tracer) -> + erlang:trace(self(), false, [call]), + Tracer ! die_please, + receive + {'DOWN', _, process, Tracer, _} -> ok + end. diff --git a/lib/kernel/test/code_SUITE_data/upgradee.erl b/lib/kernel/test/code_SUITE_data/upgradee.erl index 62b1d95e30..8ca660c19c 100644 --- a/lib/kernel/test/code_SUITE_data/upgradee.erl +++ b/lib/kernel/test/code_SUITE_data/upgradee.erl @@ -8,6 +8,9 @@ -export([exp1/0]). % only exported in v1 -export([exp1loc2/0]). % exported in v1, local in v2 -export([exp1exp2/0]). % exported in v1 and v2 +-export([get_local_fun/1]). +-export([get_exp1exp2_fun/0]). +-export([exp1exp2_fun/0]). exp1() -> ?VERSION. loc1() -> ?VERSION. @@ -20,6 +23,9 @@ loc1() -> ?VERSION. -export([exp2/0]). -export([loc1exp2/0]). -export([exp1exp2/0]). +-export([get_local_fun/1]). +-export([get_exp1exp2_fun/0]). +-export([exp1exp2_fun/0]). exp2() -> ?VERSION. loc2() -> ?VERSION. @@ -31,6 +37,12 @@ exp1loc2() -> ?VERSION. loc1exp2() -> ?VERSION. loc1loc2() -> ?VERSION. +get_local_fun(Env) -> fun() -> {?VERSION,Env} end. +get_exp1exp2_fun() -> fun ?MODULE:exp1exp2_fun/0. + +exp1exp2_fun() -> + ?VERSION. + dispatch_loop() -> receive upgrade_order -> diff --git a/lib/kernel/test/erl_distribution_SUITE.erl b/lib/kernel/test/erl_distribution_SUITE.erl index e43be77428..f630896e03 100644 --- a/lib/kernel/test/erl_distribution_SUITE.erl +++ b/lib/kernel/test/erl_distribution_SUITE.erl @@ -230,7 +230,7 @@ time_ping(Node) -> T0 = erlang:monotonic_time(), pang = net_adm:ping(Node), T1 = erlang:monotonic_time(), - erlang:convert_time_unit(T1 - T0, native, milli_seconds). + erlang:convert_time_unit(T1 - T0, native, millisecond). %% Keep the connection with the client node up. %% This is neccessary as the client node runs with much shorter @@ -274,7 +274,7 @@ tick_cli_test1(Node) -> receive {whats_the_result, From} -> Diff = erlang:convert_time_unit(T2-T1, native, - milli_seconds), + millisecond), case Diff of T when T > 8000, T < 16000 -> From ! {tick_test, T}; diff --git a/lib/kernel/test/file_SUITE.erl b/lib/kernel/test/file_SUITE.erl index 5f049c6f99..f2094431d8 100644 --- a/lib/kernel/test/file_SUITE.erl +++ b/lib/kernel/test/file_SUITE.erl @@ -493,22 +493,13 @@ read_write_file(Config) when is_list(Config) -> %% Try writing and reading back some term SomeTerm = {"This term",{will,be},[written,$t,$o],1,file,[]}, - ok = ?FILE_MODULE:write_file(Name,term_to_binary(SomeTerm)), - {ok,Bin1} = ?FILE_MODULE:read_file(Name), - SomeTerm = binary_to_term(Bin1), + Bin1 = term_to_binary(SomeTerm), + ok = do_read_write_file(Name, Bin1), %% Try a "null" term NullTerm = [], - ok = ?FILE_MODULE:write_file(Name,term_to_binary(NullTerm)), - {ok,Bin2} = ?FILE_MODULE:read_file(Name), - NullTerm = binary_to_term(Bin2), - - %% Try some "complicated" types - BigNum = 123456789012345678901234567890, - ComplTerm = {self(),make_ref(),BigNum,3.14159}, - ok = ?FILE_MODULE:write_file(Name,term_to_binary(ComplTerm)), - {ok,Bin3} = ?FILE_MODULE:read_file(Name), - ComplTerm = binary_to_term(Bin3), + Bin2 = term_to_binary(NullTerm), + ok = do_read_write_file(Name, Bin2), %% Try reading a nonexistent file Name2 = filename:join(RootDir, @@ -519,25 +510,42 @@ read_write_file(Config) when is_list(Config) -> {error, enoent} = ?FILE_MODULE:read_file(''), %% Try writing to a bad filename - {error, enoent} = - ?FILE_MODULE:write_file("",term_to_binary(NullTerm)), + {error, enoent} = do_read_write_file("", Bin2), %% Try writing something else than a binary - {error, badarg} = ?FILE_MODULE:write_file(Name,{1,2,3}), - {error, badarg} = ?FILE_MODULE:write_file(Name,self()), + {error, badarg} = do_read_write_file(Name, {1,2,3}), + {error, badarg} = do_read_write_file(Name, self()), %% Some non-term binaries - ok = ?FILE_MODULE:write_file(Name,[]), - {ok,Bin4} = ?FILE_MODULE:read_file(Name), - 0 = byte_size(Bin4), + ok = do_read_write_file(Name, []), - ok = ?FILE_MODULE:write_file(Name,[Bin1,[],[[Bin2]]]), - {ok,Bin5} = ?FILE_MODULE:read_file(Name), - {Bin1,Bin2} = split_binary(Bin5,byte_size(Bin1)), + %% Write some iolists + ok = do_read_write_file(Name, [Bin1,[],[[Bin2]]]), + ok = do_read_write_file(Name, ["string",<<"binary">>]), + ok = do_read_write_file(Name, "pure string"), [] = flush(), ok. +do_read_write_file(Name, Data) -> + case ?FILE_MODULE:write_file(Name, Data) of + ok -> + BinData = iolist_to_binary(Data), + {ok,BinData} = ?FILE_MODULE:read_file(Name), + + ok = ?FILE_MODULE:write_file(Name, Data, []), + {ok,BinData} = ?FILE_MODULE:read_file(Name), + + ok = ?FILE_MODULE:write_file(Name, Data, [raw]), + {ok,BinData} = ?FILE_MODULE:read_file(Name), + + ok; + {error,_}=Res -> + Res = ?FILE_MODULE:write_file(Name, Data, []), + Res = ?FILE_MODULE:write_file(Name, Data, [raw]), + Res + end. + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -3730,7 +3738,7 @@ response_analysis(Module, Function, Arguments) -> {Result, Comment}. micro_ts() -> - erlang:monotonic_time(micro_seconds). + erlang:monotonic_time(microsecond). response_stat(init, Ts) -> {0, 0, Ts, 0, 0}; diff --git a/lib/kernel/test/gen_tcp_api_SUITE.erl b/lib/kernel/test/gen_tcp_api_SUITE.erl index 77ec89b4f4..92a74465b7 100644 --- a/lib/kernel/test/gen_tcp_api_SUITE.erl +++ b/lib/kernel/test/gen_tcp_api_SUITE.erl @@ -38,7 +38,7 @@ t_local_basic/1, t_local_unbound/1, t_local_fdopen/1, t_local_fdopen_listen/1, t_local_fdopen_listen_unbound/1, t_local_fdopen_connect/1, t_local_fdopen_connect_unbound/1, - t_local_abstract/1]). + t_local_abstract/1, t_accept_inet6_tclass/1]). -export([getsockfd/0,closesockfd/1]). @@ -50,6 +50,7 @@ all() -> [{group, t_accept}, {group, t_connect}, {group, t_recv}, t_shutdown_write, t_shutdown_both, t_shutdown_error, t_shutdown_async, t_fdopen, t_fdconnect, t_implicit_inet6, + t_accept_inet6_tclass, {group, t_local}]. groups() -> @@ -521,6 +522,24 @@ local_handshake(S, SAddr, C, CAddr) -> SData = ok(gen_tcp:recv(C, length(SData))), ok. +t_accept_inet6_tclass(Config) when is_list(Config) -> + TClassOpt = {tclass,8#56 bsl 2}, % Expedited forwarding + case gen_tcp:listen(0, [inet6,TClassOpt]) of + {ok,L} -> + LPort = ok(inet:port(L)), + Loopback = {0,0,0,0,0,0,0,1}, + Sa = ok(gen_tcp:connect(Loopback, LPort, [])), + Sb = ok(gen_tcp:accept(L)), + [TClassOpt] = ok(inet:getopts(Sb, [tclass])), + ok = gen_tcp:close(Sb), + ok = gen_tcp:close(Sa), + ok = gen_tcp:close(L), + ok; + {error,_} -> + {skip,"IPv6 TCLASS not supported"} + end. + + %%% Utilities %% Calls M:F/length(A), which should return a timeout error, and complete diff --git a/lib/kernel/test/gen_tcp_api_SUITE_data/gen_tcp_api_SUITE.c b/lib/kernel/test/gen_tcp_api_SUITE_data/gen_tcp_api_SUITE.c index 2990ddda41..b91dca61d4 100644 --- a/lib/kernel/test/gen_tcp_api_SUITE_data/gen_tcp_api_SUITE.c +++ b/lib/kernel/test/gen_tcp_api_SUITE_data/gen_tcp_api_SUITE.c @@ -17,7 +17,7 @@ * * %CopyrightEnd% */ -#include "erl_nif.h" +#include <erl_nif.h> #include <stdio.h> #include <string.h> diff --git a/lib/kernel/test/gen_tcp_misc_SUITE.erl b/lib/kernel/test/gen_tcp_misc_SUITE.erl index 6b64c83fc2..929f66d400 100644 --- a/lib/kernel/test/gen_tcp_misc_SUITE.erl +++ b/lib/kernel/test/gen_tcp_misc_SUITE.erl @@ -1914,7 +1914,7 @@ so_priority(Config) when is_list(Config) -> %% Accept test utilities (suites are below) millis() -> - erlang:monotonic_time(milli_seconds). + erlang:monotonic_time(millisecond). collect_accepts(0,_) -> []; collect_accepts(N,Tmo) -> diff --git a/lib/kernel/test/interactive_shell_SUITE.erl b/lib/kernel/test/interactive_shell_SUITE.erl index fc3706ba1e..298a364a91 100644 --- a/lib/kernel/test/interactive_shell_SUITE.erl +++ b/lib/kernel/test/interactive_shell_SUITE.erl @@ -711,7 +711,7 @@ toerl_loop(Port,Acc) -> end. millistamp() -> - erlang:monotonic_time(milli_seconds). + erlang:monotonic_time(millisecond). get_data_within(Port, X, Acc) when X =< 0 -> ?dbg({get_data_within, X, Acc, ?LINE}), diff --git a/lib/kernel/test/os_SUITE.erl b/lib/kernel/test/os_SUITE.erl index e76d6ec482..3cbb75a633 100644 --- a/lib/kernel/test/os_SUITE.erl +++ b/lib/kernel/test/os_SUITE.erl @@ -322,7 +322,7 @@ perf_counter_api(_Config) -> T1 = os:perf_counter(), timer:sleep(100), T2 = os:perf_counter(), - TsDiff = erlang:convert_time_unit(T2 - T1, perf_counter, nano_seconds), + TsDiff = erlang:convert_time_unit(T2 - T1, perf_counter, nanosecond), ct:pal("T1: ~p~n" "T2: ~p~n" "TsDiff: ~p~n", diff --git a/lib/kernel/test/pdict_SUITE.erl b/lib/kernel/test/pdict_SUITE.erl index 638d99176e..d105952df9 100644 --- a/lib/kernel/test/pdict_SUITE.erl +++ b/lib/kernel/test/pdict_SUITE.erl @@ -32,10 +32,13 @@ -export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1, init_per_group/2,end_per_group/2, mixed/1, + literals/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]). +-export([put_do/2, get_do/1, erase_do/1]). + init_per_testcase(_Case, Config) -> Config. @@ -48,6 +51,7 @@ suite() -> all() -> [simple, complicated, heavy, simple_all_keys, info, + literals, mixed]. groups() -> @@ -418,3 +422,59 @@ do_mixed([GoalN | _]=Goals, CurrN, Array0, C, Rand0) -> Array2 = array:resize(CurrN-1, Array1), do_mixed(Goals, CurrN-1, Array2, C+1, Rand2) end. + +%% Test hash precalculation of literal keys +literals(_Config) -> + %% Put literal -> get variable + put(1742, "1742"), + "1742" = ?MODULE:get_do(1742), + "1742" = ?MODULE:erase_do(1742), + + put(-1742, "-1742"), + "-1742" = ?MODULE:get_do(-1742), + "-1742" = ?MODULE:erase_do(-1742), + + put([], "NIL"), + "NIL" = ?MODULE:get_do([]), + "NIL" = ?MODULE:erase_do([]), + + put(<<"binary">>, "binary"), + "binary" = ?MODULE:get_do(<<"binary">>), + "binary" = ?MODULE:erase_do(<<"binary">>), + + BigBin = <<"A large binary with a lot of bytes to make it go off heap as shared and reference counted">>, + put(BigBin, "bigbin"), + "bigbin" = ?MODULE:get_do(BigBin), + "bigbin" = ?MODULE:erase_do(BigBin), + + %% Put variable -> get literal + ?MODULE:put_do(4217, "4217"), + "4217" = get(4217), + "4217" = erase(4217), + + ?MODULE:put_do(-4217, "-4217"), + "-4217" = get(-4217), + "-4217" = erase(-4217), + + ?MODULE:put_do([], "NIL"), + "NIL" = get([]), + "NIL" = erase([]), + + ?MODULE:put_do(<<"bytes">>, "bytes"), + "bytes" = get(<<"bytes">>), + "bytes" = erase(<<"bytes">>), + + ?MODULE:put_do(BigBin, "BigBin"), + "BigBin" = get(BigBin), + "BigBin" = erase(BigBin), + + ok. + +put_do(K, V) -> + put(K, V). + +get_do(K) -> + get(K). + +erase_do(K) -> + erase(K). diff --git a/lib/kernel/vsn.mk b/lib/kernel/vsn.mk index cdd200a234..d3b2d18ae5 100644 --- a/lib/kernel/vsn.mk +++ b/lib/kernel/vsn.mk @@ -1 +1 @@ -KERNEL_VSN = 5.0.2 +KERNEL_VSN = 5.1 |