diff options
Diffstat (limited to 'lib/kernel')
29 files changed, 538 insertions, 1336 deletions
diff --git a/lib/kernel/doc/src/code.xml b/lib/kernel/doc/src/code.xml index 1bd52040a0..d4c9a48901 100644 --- a/lib/kernel/doc/src/code.xml +++ b/lib/kernel/doc/src/code.xml @@ -101,30 +101,6 @@ </section> <section> - <title>Code Path Cache</title> - <p>The code server incorporates a code path cache. The cache - functionality is disabled by default. To activate it, start - the emulator with the command line flag <c>-code_path_cache</c> - or call <c>code:rehash()</c>. When the cache is created (or - updated), the code server searches for modules in the code path - directories. This may take some time if the the code path is long. - After the cache creation, the time for loading modules in a large - system (one with a large directory structure) is significantly - reduced compared to having the cache disabled. The code server - is able to look up the location of a module from the cache in - constant time instead of having to search through the code path - directories.</p> - <p>Application resource files (<c>.app</c> files) are also stored - in the code path cache. This feature is used by the application - controller (see - <seealso marker="application">application(3)</seealso>) to load - applications efficiently in large systems.</p> - <p>Note that when the code path cache is created (or updated), any - relative directory names in the code path are converted to - absolute.</p> - </section> - - <section> <title>Loading of Code From Archive Files</title> <warning><p>The support for loading of code from archive files is @@ -733,13 +709,6 @@ rpc:call(Node, code, load_binary, [Module, Filename, Binary]), </desc> </func> <func> - <name name="rehash" arity="0"/> - <fsummary>Rehash or create code path cache</fsummary> - <desc> - <p>This function creates or rehashes the code path cache.</p> - </desc> - </func> - <func> <name name="where_is_file" arity="1"/> <fsummary>Full name of a file located in the code path</fsummary> <desc> @@ -747,10 +716,7 @@ rpc:call(Node, code, load_binary, [Module, Filename, Binary]), arbitrary type. If found, the full name is returned. <c>non_existing</c> is returned if the file cannot be found. The function can be useful, for example, to locate - application resource files. If the code path cache is used, - the code server will efficiently read the full name from - the cache, provided that <c><anno>Filename</anno></c> is an object code - file or an <c>.app</c> file.</p> + application resource files.</p> </desc> </func> <func> diff --git a/lib/kernel/doc/src/notes.xml b/lib/kernel/doc/src/notes.xml index 5341a793ef..b625ddba5d 100644 --- a/lib/kernel/doc/src/notes.xml +++ b/lib/kernel/doc/src/notes.xml @@ -529,8 +529,7 @@ Erlang/OTP has been ported to the realtime operating system OSE. The port supports both smp and non-smp emulator. For details around the port and how to started - see the User's Guide in the <seealso - marker="ose:ose_intro">ose</seealso> application. </p> + see the User's Guide in the ose application. </p> <p> Note that not all parts of Erlang/OTP has been ported. </p> <p> diff --git a/lib/kernel/doc/src/os.xml b/lib/kernel/doc/src/os.xml index 682d4a2eac..165160a909 100644 --- a/lib/kernel/doc/src/os.xml +++ b/lib/kernel/doc/src/os.xml @@ -37,6 +37,7 @@ use these functions can be of help in enabling a program to run on most platforms.</p> </description> + <funcs> <func> <name name="cmd" arity="1"/> @@ -210,6 +211,30 @@ format_utc_timestamp() -> </desc> </func> <func> + <name name="perf_counter" arity="0"/> + <fsummary>Returns a performance counter</fsummary> + <desc> + <p>Returns the current performance counter value in <c>perf_counter</c> + <seealso marker="erts:erlang#type_time_unit">time unit</seealso>. + This is a highly optimized call that might not be traceable. + </p> + </desc> + </func> + <func> + <name name="perf_counter" arity="1"/> + <fsummary>Returns a performance counter</fsummary> + <desc><p>Returns a performance counter that can be used as a very fast and + high resolution timestamp. This counter is read directly from the hardware or operating + system with the same guarantees. This means that two consecutive calls + to the function are not guaranteed to be monotonic, though it most likely will be. + The performance counter till be converted to the resolution passed as an argument.</p> + <pre>1> <input>T1 = os:perf_counter(1000),receive after 10000 -> ok end,T2 = os:perf_counter(1000).</input> +176525861 +2> <input>T2 - T1.</input> +10004</pre> + </desc> + </func> + <func> <name name="type" arity="0"/> <fsummary>Return the OS family and, in some cases, OS name of the current operating system</fsummary> <desc> diff --git a/lib/kernel/doc/src/ref_man.xml.src b/lib/kernel/doc/src/ref_man.xml.src deleted file mode 100644 index 7eb48a5f1d..0000000000 --- a/lib/kernel/doc/src/ref_man.xml.src +++ /dev/null @@ -1,68 +0,0 @@ -<?xml version="1.0" encoding="utf-8" ?> -<!DOCTYPE application SYSTEM "application.dtd"> - -<application xmlns:xi="http://www.w3.org/2001/XInclude"> - <header> - <copyright> - <year>1996</year><year>2013</year> - <holder>Ericsson AB. All Rights Reserved.</holder> - </copyright> - <legalnotice> - 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. - - </legalnotice> - - <title>Kernel Reference Manual</title> - <prepared></prepared> - <docno></docno> - <date></date> - <rev></rev> - </header> - <description> - <p>The <em>Kernel</em> application has all the code necessary to run - the Erlang runtime system itself: file servers and code servers - and so on.</p> - </description> - <xi:include href="kernel_app.xml"/> - <xi:include href="application.xml"/> - <xi:include href="auth.xml"/> - <xi:include href="code.xml"/> - <xi:include href="disk_log.xml"/> - <xi:include href="erl_boot_server.xml"/> - <xi:include href="erl_ddll.xml"/> - <xi:include href="erl_prim_loader_stub.xml"/> - <xi:include href="erlang_stub.xml"/> - <xi:include href="error_handler.xml"/> - <xi:include href="error_logger.xml"/> - <xi:include href="file.xml"/> - <xi:include href="gen_tcp.xml"/> - <xi:include href="gen_udp.xml"/> - <xi:include href="gen_sctp.xml"/> - <xi:include href="global.xml"/> - <xi:include href="global_group.xml"/> - <xi:include href="heart.xml"/> - <xi:include href="inet.xml"/> - <xi:include href="inet_res.xml"/> - <xi:include href="init_stub.xml"/> - <xi:include href="net_adm.xml"/> - <xi:include href="net_kernel.xml"/> - <xi:include href="os.xml"/> - <xi:include href="pg2.xml"/> - <xi:include href="rpc.xml"/> - <xi:include href="seq_trace.xml"/> - <xi:include href="user.xml"/> - <xi:include href="wrap_log_reader.xml"/> - <xi:include href="zlib_stub.xml"/> - <xi:include href="app.xml"/> - <xi:include href="config.xml"/> -</application> diff --git a/lib/kernel/include/file.hrl b/lib/kernel/include/file.hrl index 7cf033f7f5..36112bb040 100644 --- a/lib/kernel/include/file.hrl +++ b/lib/kernel/include/file.hrl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1997-2013. All Rights Reserved. +%% Copyright Ericsson AB 1997-2015. 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. @@ -23,37 +23,40 @@ %%-------------------------------------------------------------------------- -record(file_info, - {size :: non_neg_integer(), % Size of file in bytes. - type :: 'device' | 'directory' | 'other' | 'regular' | 'symlink', - access :: 'read' | 'write' | 'read_write' | 'none', - atime :: file:date_time() | non_neg_integer(), + {size :: non_neg_integer() | 'undefined', % Size of file in bytes. + type :: 'device' | 'directory' | 'other' | 'regular' | 'symlink' + | 'undefined', + access :: 'read' | 'write' | 'read_write' | 'none' | 'undefined', + atime :: file:date_time() | non_neg_integer() | 'undefined', % The local time the file was last read: % {{Year, Mon, Day}, {Hour, Min, Sec}}. % atime, ctime, mtime may also be unix epochs() - mtime :: file:date_time() | non_neg_integer(), + mtime :: file:date_time() | non_neg_integer() | 'undefined', % The local time the file was last written. - ctime :: file:date_time() | non_neg_integer(), + ctime :: file:date_time() | non_neg_integer() | 'undefined', % The interpretation of this time field % is dependent on operating system. % On Unix it is the last time the file % or the inode was changed. On Windows, % it is the creation time. - mode :: non_neg_integer(), % File permissions. On Windows, + mode :: non_neg_integer() | 'undefined', + % File permissions. On Windows, % the owner permissions will be % duplicated for group and user. - links :: non_neg_integer(), + links :: non_neg_integer() | 'undefined', % Number of links to the file (1 if the % filesystem doesn't support links). - major_device :: non_neg_integer(), + major_device :: non_neg_integer() | 'undefined', % Identifies the file system (Unix), % or the drive number (A: = 0, B: = 1) % (Windows). %% The following are Unix specific. %% They are set to zero on other operating systems. - minor_device :: non_neg_integer(), % Only valid for devices. - inode :: non_neg_integer(), % Inode number for file. - uid :: non_neg_integer(), % User id for owner. - gid :: non_neg_integer()}). % Group id for owner. + minor_device :: non_neg_integer() | 'undefined', + % Only valid for devices. + inode :: non_neg_integer() | 'undefined', % Inode number for file. + uid :: non_neg_integer() | 'undefined', % User id for owner. + gid :: non_neg_integer() | 'undefined'}). % Group id for owner. -record(file_descriptor, diff --git a/lib/kernel/src/code.erl b/lib/kernel/src/code.erl index 7237550786..59e226df43 100644 --- a/lib/kernel/src/code.erl +++ b/lib/kernel/src/code.erl @@ -60,7 +60,7 @@ del_path/1, replace_path/2, rehash/0, - start_link/0, start_link/1, + start_link/0, which/1, where_is_file/1, where_is_file/2, @@ -68,6 +68,8 @@ clash/0, get_mode/0]). +-deprecated({rehash,0,next_major_release}). + -export_type([load_error_rsn/0, load_ret/0]). -include_lib("kernel/include/file.hrl"). @@ -294,7 +296,9 @@ replace_path(Name, Dir) when (is_atom(Name) orelse is_list(Name)), call({replace_path,Name,Dir}). -spec rehash() -> 'ok'. -rehash() -> call(rehash). +rehash() -> + cache_warning(), + ok. -spec get_mode() -> 'embedded' | 'interactive'. get_mode() -> call(get_mode). @@ -302,15 +306,11 @@ get_mode() -> call(get_mode). %%----------------------------------------------------------------- call(Req) -> - code_server:call(code_server, Req). + code_server:call(Req). -spec start_link() -> {'ok', pid()} | {'error', 'crash'}. start_link() -> - start_link([stick]). - --spec start_link(Flags :: [atom()]) -> {'ok', pid()} | {'error', 'crash'}. -start_link(Flags) -> - do_start(Flags). + do_start(). %%----------------------------------------------------------------- %% In the init phase, code must not use any modules not yet loaded, @@ -322,35 +322,21 @@ start_link(Flags) -> %% us, so the module is loaded. %%----------------------------------------------------------------- -do_start(Flags) -> +do_start() -> + maybe_warn_for_cache(), load_code_server_prerequisites(), - Mode = get_mode(Flags), - case init:get_argument(root) of - {ok,[[Root0]]} -> - Root = filename:join([Root0]), % Normalize. Use filename - case code_server:start_link([Root,Mode]) of - {ok,_Pid} = Ok2 -> - if - Mode =:= interactive -> - case lists:member(stick, Flags) of - true -> do_stick_dirs(); - _ -> ok - end; - true -> - ok - end, - %% Quietly load native code for all modules loaded so far - Architecture = erlang:system_info(hipe_architecture), - load_native_code_for_all_loaded(Architecture), - Ok2; - Other -> - Other - end; - Other -> - error_logger:error_msg("Can not start code server ~w ~n", [Other]), - {error, crash} - end. + {ok,[[Root0]]} = init:get_argument(root), + Mode = start_get_mode(), + Root = filename:join([Root0]), % Normalize. + Res = code_server:start_link([Root,Mode]), + + maybe_stick_dirs(Mode), + + %% Quietly load native code for all modules loaded so far. + Architecture = erlang:system_info(hipe_architecture), + load_native_code_for_all_loaded(Architecture), + Res. %% Make sure that all modules that the code_server process calls %% (directly or indirectly) are loaded. Otherwise the code_server @@ -370,6 +356,16 @@ load_code_server_prerequisites() -> _ = [M = M:module_info(module) || M <- Needed], ok. +maybe_stick_dirs(interactive) -> + case init:get_argument(nostick) of + {ok,[[]]} -> + ok; + _ -> + do_stick_dirs() + end; +maybe_stick_dirs(_) -> + ok. + do_stick_dirs() -> do_s(compiler), do_s(stdlib), @@ -387,19 +383,12 @@ do_s(Lib) -> ok end. -get_mode(Flags) -> - case lists:member(embedded, Flags) of - true -> +start_get_mode() -> + case init:get_argument(mode) of + {ok,[["embedded"]]} -> embedded; - _Otherwise -> - case init:get_argument(mode) of - {ok,[["embedded"]]} -> - embedded; - {ok,[["minimal"]]} -> - minimal; - _Else -> - interactive - end + _ -> + interactive end. %% Find out which version of a particular module we would @@ -453,30 +442,14 @@ which(File, Base, [Directory|Tail]) -> Filename :: file:filename(), Absname :: file:filename(). where_is_file(File) when is_list(File) -> - case call({is_cached,File}) of - no -> - Path = get_path(), - which(File, ".", Path); - Dir -> - filename:join(Dir, File) - end. + Path = get_path(), + which(File, ".", Path). -spec where_is_file(Path :: file:filename(), Filename :: file:filename()) -> file:filename() | 'non_existing'. where_is_file(Path, File) when is_list(Path), is_list(File) -> - CodePath = get_path(), - if - Path =:= CodePath -> - case call({is_cached, File}) of - no -> - which(File, ".", Path); - Dir -> - filename:join(Dir, File) - end; - true -> - which(File, ".", Path) - end. + which(File, ".", Path). -spec set_primary_archive(ArchiveFile :: file:filename(), ArchiveBin :: binary(), @@ -554,6 +527,22 @@ has_ext(Ext, Extlen, File) -> end. %%% +%%% Warning for deprecated code path cache. +%%% + +maybe_warn_for_cache() -> + case init:get_argument(code_path_cache) of + {ok, _} -> + cache_warning(); + error -> + ok + end. + +cache_warning() -> + W = "The code path cache functionality has been removed", + error_logger:warning_report(W). + +%%% %%% Silently load native code for all modules loaded so far. %%% diff --git a/lib/kernel/src/code_server.erl b/lib/kernel/src/code_server.erl index 614219794c..b52def8777 100644 --- a/lib/kernel/src/code_server.erl +++ b/lib/kernel/src/code_server.erl @@ -22,9 +22,7 @@ %% This file holds the server part of the code_server. -export([start_link/1, - call/2, - system_continue/3, - system_terminate/4, + call/1, system_code_change/4, error_msg/2, info_msg/2 ]). @@ -35,16 +33,18 @@ -define(ANY_NATIVE_CODE_LOADED, any_native_code_loaded). --record(state, {supervisor, - root, - path, - moddb, - namedb, - cache = no_cache, - mode = interactive, - on_load = []}). +-type on_load_item() :: {reference(),module(),file:name_all(),[pid()]}. + +-record(state, {supervisor :: pid(), + root :: file:name_all(), + path :: [file:name_all()], + moddb :: ets:tab(), + namedb :: ets:tab(), + mode = interactive :: 'interactive' | 'embedded', + on_load = [] :: [on_load_item()]}). -type state() :: #state{}. +-spec start_link([term()]) -> {'ok', pid()}. start_link(Args) -> Ref = make_ref(), Parent = self(), @@ -59,7 +59,7 @@ start_link(Args) -> %% Init the code_server process. %% ----------------------------------------------------------- -init(Ref, Parent, [Root,Mode0]) -> +init(Ref, Parent, [Root,Mode]) -> register(?MODULE, self()), process_flag(trap_exit, true), @@ -70,12 +70,6 @@ init(Ref, Parent, [Root,Mode0]) -> end, erlang:pre_loaded()), ets:insert(Db, init:fetch_loaded()), - Mode = - case Mode0 of - minimal -> interactive; - _ -> Mode0 - end, - IPath = case Mode of interactive -> @@ -89,24 +83,17 @@ init(Ref, Parent, [Root,Mode0]) -> end, Path = add_loader_path(IPath, Mode), - State0 = #state{root = Root, - path = Path, - moddb = Db, - namedb = init_namedb(Path), - mode = Mode}, - - State = - case init:get_argument(code_path_cache) of - {ok, _} -> - create_cache(State0); - error -> - State0 - end, + State = #state{supervisor = Parent, + root = Root, + path = Path, + moddb = Db, + namedb = init_namedb(Path), + mode = Mode}, put(?ANY_NATIVE_CODE_LOADED, false), Parent ! {Ref,{ok,self()}}, - loop(State#state{supervisor = Parent}). + loop(State). get_user_lib_dirs() -> case os:getenv("ERL_LIBS") of @@ -142,8 +129,9 @@ split_paths([C|T], S, Path, Paths) -> split_paths([], _S, Path, Paths) -> lists:reverse(Paths, [lists:reverse(Path)]). -call(Name, Req) -> - Name ! {code_call, self(), Req}, +-spec call(term()) -> term(). +call(Req) -> + ?MODULE ! {code_call, self(), Req}, receive {?MODULE, Reply} -> Reply @@ -255,59 +243,33 @@ handle_call({dir,Dir}, {_From,_Tag}, S) -> Resp = do_dir(Root,Dir,S#state.namedb), {reply,Resp,S}; -handle_call({load_file,Mod}, Caller, St) -> - case modp(Mod) of - false -> - {reply,{error,badarg},St}; - true -> - load_file(Mod, Caller, St) - end; +handle_call({load_file,Mod}, Caller, St) when is_atom(Mod) -> + load_file(Mod, Caller, St); handle_call({add_path,Where,Dir0}, {_From,_Tag}, - #state{cache=Cache0,namedb=Namedb,path=Path0}=S) -> - case Cache0 of - no_cache -> - {Resp,Path} = add_path(Where, Dir0, Path0, Namedb), - {reply,Resp,S#state{path=Path}}; - _ -> - Dir = absname(Dir0), %% Cache always expands the path - {Resp,Path} = add_path(Where, Dir, Path0, Namedb), - Cache = update_cache([Dir], Where, Cache0), - {reply,Resp,S#state{path=Path,cache=Cache}} - end; + #state{namedb=Namedb,path=Path0}=S) -> + {Resp,Path} = add_path(Where, Dir0, Path0, Namedb), + {reply,Resp,S#state{path=Path}}; handle_call({add_paths,Where,Dirs0}, {_From,_Tag}, - #state{cache=Cache0,namedb=Namedb,path=Path0}=S) -> - case Cache0 of - no_cache -> - {Resp,Path} = add_paths(Where, Dirs0, Path0, Namedb), - {reply,Resp,S#state{path=Path}}; - _ -> - %% Cache always expands the path - Dirs = [absname(Dir) || Dir <- Dirs0], - {Resp,Path} = add_paths(Where, Dirs, Path0, Namedb), - Cache=update_cache(Dirs,Where,Cache0), - {reply,Resp,S#state{cache=Cache,path=Path}} - end; + #state{namedb=Namedb,path=Path0}=S) -> + {Resp,Path} = add_paths(Where, Dirs0, Path0, Namedb), + {reply,Resp,S#state{path=Path}}; handle_call({set_path,PathList}, {_From,_Tag}, #state{path=Path0,namedb=Namedb}=S) -> {Resp,Path,NewDb} = set_path(PathList, Path0, Namedb), - {reply,Resp,rehash_cache(S#state{path=Path,namedb=NewDb})}; + {reply,Resp,S#state{path=Path,namedb=NewDb}}; handle_call({del_path,Name}, {_From,_Tag}, #state{path=Path0,namedb=Namedb}=S) -> {Resp,Path} = del_path(Name, Path0, Namedb), - {reply,Resp,rehash_cache(S#state{path=Path})}; + {reply,Resp,S#state{path=Path}}; handle_call({replace_path,Name,Dir}, {_From,_Tag}, #state{path=Path0,namedb=Namedb}=S) -> {Resp,Path} = replace_path(Name, Dir, Path0, Namedb), - {reply,Resp,rehash_cache(S#state{path=Path})}; - -handle_call(rehash, {_From,_Tag}, S0) -> - S = create_cache(S0), - {reply,ok,S}; + {reply,Resp,S#state{path=Path}}; handle_call(get_path, {_From,_Tag}, S) -> {reply,S#state.path,S}; @@ -321,7 +283,7 @@ handle_call({load_abs,File,Mod}, Caller, S) when is_atom(Mod) -> load_abs(File, Mod, Caller, S) end; -handle_call({load_binary,Mod,File,Bin}, Caller, S) -> +handle_call({load_binary,Mod,File,Bin}, Caller, S) when is_atom(Mod) -> do_load_binary(Mod, File, Bin, Caller, S); handle_call({load_native_partial,Mod,Bin}, {_From,_Tag}, S) -> @@ -337,59 +299,44 @@ handle_call({load_native_sticky,Mod,Bin,WholeModule}, {_From,_Tag}, S) -> Status = hipe_result_to_status(Result), {reply,Status,S}; -handle_call({ensure_loaded,Mod0}, Caller, St0) -> - Fun = fun (M, St) -> - case erlang:module_loaded(M) of - true -> - {reply,{module,M},St}; - false when St#state.mode =:= interactive -> - load_file(M, Caller, St); - false -> - {reply,{error,embedded},St} - end - end, - do_mod_call(Fun, Mod0, {error,badarg}, St0); - -handle_call({delete,Mod0}, {_From,_Tag}, S) -> - Fun = fun (M, St) -> - case catch erlang:delete_module(M) of - true -> - ets:delete(St#state.moddb, M), - {reply,true,St}; - _ -> - {reply,false,St} - end - end, - do_mod_call(Fun, Mod0, false, S); +handle_call({ensure_loaded,Mod}, Caller, St) when is_atom(Mod) -> + case erlang:module_loaded(Mod) of + true -> + {reply,{module,Mod},St}; + false when St#state.mode =:= interactive -> + load_file(Mod, Caller, St); + false -> + {reply,{error,embedded},St} + end; -handle_call({purge,Mod0}, {_From,_Tag}, St0) -> - do_mod_call(fun (M, St) -> - {reply,do_purge(M),St} - end, Mod0, false, St0); +handle_call({delete,Mod}, {_From,_Tag}, St) when is_atom(Mod) -> + case catch erlang:delete_module(Mod) of + true -> + ets:delete(St#state.moddb, Mod), + {reply,true,St}; + _ -> + {reply,false,St} + end; -handle_call({soft_purge,Mod0}, {_From,_Tag}, St0) -> - do_mod_call(fun (M, St) -> - {reply,do_soft_purge(M),St} - end, Mod0, true, St0); +handle_call({purge,Mod}, {_From,_Tag}, St) when is_atom(Mod) -> + {reply,do_purge(Mod),St}; -handle_call({is_loaded,Mod0}, {_From,_Tag}, St0) -> - do_mod_call(fun (M, St) -> - {reply,is_loaded(M, St#state.moddb),St} - end, Mod0, false, St0); +handle_call({soft_purge,Mod}, {_From,_Tag}, St) when is_atom(Mod) -> + {reply,do_soft_purge(Mod),St}; + +handle_call({is_loaded,Mod}, {_From,_Tag}, St) when is_atom(Mod) -> + {reply,is_loaded(Mod, St#state.moddb),St}; handle_call(all_loaded, {_From,_Tag}, S) -> Db = S#state.moddb, {reply,all_loaded(Db),S}; -handle_call({get_object_code,Mod0}, {_From,_Tag}, St0) -> - Fun = fun(M, St) -> - Path = St#state.path, - case mod_to_bin(Path, atom_to_list(M)) of - {_,Bin,FName} -> {reply,{M,Bin,FName},St}; - Error -> {reply,Error,St} - end - end, - do_mod_call(Fun, Mod0, error, St0); +handle_call({get_object_code,Mod}, {_From,_Tag}, St) when is_atom(Mod) -> + Path = St#state.path, + case mod_to_bin(Path, Mod) of + {_,Bin,FName} -> {reply,{Mod,Bin,FName},St}; + Error -> {reply,Error,St} + end; handle_call({is_sticky, Mod}, {_From,_Tag}, S) -> Db = S#state.moddb, @@ -398,9 +345,6 @@ handle_call({is_sticky, Mod}, {_From,_Tag}, S) -> handle_call(stop,{_From,_Tag}, S) -> {stop,normal,stopped,S}; -handle_call({is_cached,_File}, {_From,_Tag}, S=#state{cache=no_cache}) -> - {reply, no, S}; - handle_call({set_primary_archive, File, ArchiveBin, FileInfo, ParserFun}, {_From,_Tag}, S=#state{mode=Mode}) -> case erl_prim_loader:set_primary_archive(File, ArchiveBin, FileInfo, ParserFun) of {ok, Files} -> @@ -409,26 +353,6 @@ handle_call({set_primary_archive, File, ArchiveBin, FileInfo, ParserFun}, {_From {reply, Error, S} end; -handle_call({is_cached,File}, {_From,_Tag}, S=#state{cache=Cache}) -> - ObjExt = objfile_extension(), - Ext = filename:extension(File), - Type = case Ext of - ObjExt -> obj; - ".app" -> app; - _ -> undef - end, - if Type =:= undef -> - {reply, no, S}; - true -> - Key = {Type,list_to_atom(filename:rootname(File, Ext))}, - case ets:lookup(Cache, Key) of - [] -> - {reply, no, S}; - [{Key,Dir}] -> - {reply, Dir, S} - end - end; - handle_call(get_mode, {_From,_Tag}, S=#state{mode=Mode}) -> {reply, Mode, S}; @@ -436,80 +360,6 @@ handle_call(Other,{_From,_Tag}, S) -> error_msg(" ** Codeserver*** ignoring ~w~n ",[Other]), {noreply,S}. -do_mod_call(Action, Module, _Error, St) when is_atom(Module) -> - Action(Module, St); -do_mod_call(Action, Module, Error, St) -> - try list_to_atom(Module) of - Atom when is_atom(Atom) -> - Action(Atom, St) - catch - error:badarg -> - {reply,Error,St} - end. - -%% -------------------------------------------------------------- -%% Cache functions -%% -------------------------------------------------------------- - -create_cache(St = #state{cache = no_cache}) -> - Cache = ets:new(code_cache, [protected]), - rehash_cache(Cache, St); -create_cache(St) -> - rehash_cache(St). - -rehash_cache(St = #state{cache = no_cache}) -> - St; -rehash_cache(St = #state{cache = OldCache}) -> - ets:delete(OldCache), - Cache = ets:new(code_cache, [protected]), - rehash_cache(Cache, St). - -rehash_cache(Cache, St = #state{path = Path}) -> - Exts = [{obj,objfile_extension()}, {app,".app"}], - {Cache,NewPath} = locate_mods(lists:reverse(Path), first, Exts, Cache, []), - St#state{cache = Cache, path=NewPath}. - -update_cache(Dirs, Where, Cache0) -> - Exts = [{obj,objfile_extension()}, {app,".app"}], - {Cache, _} = locate_mods(Dirs, Where, Exts, Cache0, []), - Cache. - -locate_mods([Dir0|Path], Where, Exts, Cache, Acc) -> - Dir = absname(Dir0), %% Cache always expands the path - case erl_prim_loader:list_dir(Dir) of - {ok, Files} -> - Cache = filter_mods(Files, Where, Exts, Dir, Cache), - locate_mods(Path, Where, Exts, Cache, [Dir|Acc]); - error -> - locate_mods(Path, Where, Exts, Cache, Acc) - end; -locate_mods([], _, _, Cache, Path) -> - {Cache,Path}. - -filter_mods([File|Rest], Where, Exts, Dir, Cache) -> - Ext = filename:extension(File), - Root = list_to_atom(filename:rootname(File, Ext)), - case lists:keyfind(Ext, 2, Exts) of - {Type, _} -> - Key = {Type,Root}, - case Where of - first -> - true = ets:insert(Cache, {Key,Dir}); - last -> - case ets:lookup(Cache, Key) of - [] -> - true = ets:insert(Cache, {Key,Dir}); - _ -> - ignore - end - end; - false -> - ok - end, - filter_mods(Rest, Where, Exts, Dir, Cache); -filter_mods([], _, _, _, Cache) -> - Cache. - %% -------------------------------------------------------------- %% Path handling functions. %% -------------------------------------------------------------- @@ -1207,9 +1057,9 @@ add_paths(_,_,Path,_) -> {ok,Path}. do_load_binary(Module, File, Binary, Caller, St) -> - case modp(Module) andalso modp(File) andalso is_binary(Binary) of + case modp(File) andalso is_binary(Binary) of true -> - case erlang:module_loaded(to_atom(Module)) of + case erlang:module_loaded(Module) of true -> do_purge(Module); false -> ok end, @@ -1233,21 +1083,10 @@ load_abs(File, Mod, Caller, St) -> {reply,{error,nofile},St} end. -try_load_module(Mod, Dir, Caller, St) -> - File = filename:append(Dir, to_list(Mod) ++ - objfile_extension()), - case erl_prim_loader:get_file(File) of - error -> - {reply,error,St}; - {ok,Binary,FName} -> - try_load_module(absname(FName), Mod, Binary, Caller, St) - end. - try_load_module(File, Mod, Bin, {From,_}=Caller, St0) -> - M = to_atom(Mod), - case pending_on_load(M, From, St0) of + case pending_on_load(Mod, From, St0) of no -> - try_load_module_1(File, M, Bin, Caller, St0); + try_load_module_1(File, Mod, Bin, Caller, St0); {yes,St} -> {noreply,St} end. @@ -1266,9 +1105,10 @@ try_load_module_2(File, Mod, Bin, Caller, undefined, St) -> try_load_module_3(File, Mod, Bin, Caller, undefined, St); try_load_module_2(File, Mod, Bin, Caller, Architecture, #state{moddb=Db}=St) -> - case catch load_native_code(Mod, Bin, Architecture) of + case catch hipe_unified_loader:load_native_code(Mod, Bin, Architecture) of {module,Mod} = Module -> - ets:insert(Db, {Mod,File}), + put(?ANY_NATIVE_CODE_LOADED, true), + ets:insert(Db, {Mod,File}), {reply,Module,St}; no_native -> try_load_module_3(File, Mod, Bin, Caller, Architecture, St); @@ -1291,26 +1131,6 @@ try_load_module_3(File, Mod, Bin, Caller, Architecture, {reply,Error,St} end. -load_native_code(Mod, Bin, Architecture) -> - %% During bootstrapping of Open Source Erlang, we don't have any hipe - %% loader modules, but the Erlang emulator might be hipe enabled. - %% Therefore we must test for that the loader modules are available - %% before trying to to load native code. - case erlang:module_loaded(hipe_unified_loader) of - false -> - no_native; - true -> - Result = hipe_unified_loader:load_native_code(Mod, Bin, - Architecture), - case Result of - {module,_} -> - put(?ANY_NATIVE_CODE_LOADED, true); - _ -> - ok - end, - Result - end. - hipe_result_to_status(Result) -> case Result of {module,_} -> @@ -1333,37 +1153,22 @@ int_list([H|T]) when is_integer(H) -> int_list(T); int_list([_|_]) -> false; int_list([]) -> true. -load_file(Mod0, {From,_}=Caller, St0) -> - Mod = to_atom(Mod0), +load_file(Mod, {From,_}=Caller, St0) -> case pending_on_load(Mod, From, St0) of no -> load_file_1(Mod, Caller, St0); {yes,St} -> {noreply,St} end. -load_file_1(Mod, Caller, #state{path=Path,cache=no_cache}=St) -> +load_file_1(Mod, Caller, #state{path=Path}=St) -> case mod_to_bin(Path, Mod) of error -> {reply,{error,nofile},St}; {Mod,Binary,File} -> - try_load_module(File, Mod, Binary, Caller, St) - end; -load_file_1(Mod, Caller, #state{cache=Cache}=St0) -> - Key = {obj,Mod}, - case ets:lookup(Cache, Key) of - [] -> - St = rehash_cache(St0), - case ets:lookup(St#state.cache, Key) of - [] -> - {reply,{error,nofile},St}; - [{Key,Dir}] -> - try_load_module(Mod, Dir, Caller, St) - end; - [{Key,Dir}] -> - try_load_module(Mod, Dir, Caller, St0) + try_load_module_1(File, Mod, Binary, Caller, St) end. mod_to_bin([Dir|Tail], Mod) -> - File = filename:append(Dir, to_list(Mod) ++ objfile_extension()), + File = filename:append(Dir, atom_to_list(Mod) ++ objfile_extension()), case erl_prim_loader:get_file(File) of error -> mod_to_bin(Tail, Mod); @@ -1416,243 +1221,6 @@ absname_vr([[X, $:]|Name], _, _AbsBase) -> absname(filename:join(Name), Dcwd). -%% do_purge(Module) -%% Kill all processes running code from *old* Module, and then purge the -%% module. Return true if any processes killed, else false. - -do_purge(Mod0) -> - Mod = to_atom(Mod0), - case erlang:check_old_code(Mod) of - false -> - false; - true -> - Res = check_proc_code(erlang:processes(), Mod, true), - try - erlang:purge_module(Mod) - catch - _:_ -> ignore - end, - Res - end. - -%% do_soft_purge(Module) -%% Purge old code only if no procs remain that run old code. -%% Return true in that case, false if procs remain (in this -%% case old code is not purged) - -do_soft_purge(Mod0) -> - Mod = to_atom(Mod0), - case erlang:check_old_code(Mod) of - false -> - true; - true -> - case check_proc_code(erlang:processes(), Mod, false) of - false -> - false; - true -> - try - erlang:purge_module(Mod) - catch - _:_ -> ignore - end, - true - end - end. - -%% -%% check_proc_code(Pids, Mod, Hard) - Send asynchronous -%% requests to all processes to perform a check_process_code -%% operation. Each process will check their own state and -%% reply with the result. If 'Hard' equals -%% - true, processes that refer 'Mod' will be killed. If -%% any processes were killed true is returned; otherwise, -%% false. -%% - false, and any processes refer 'Mod', false will -%% returned; otherwise, true. -%% -%% Requests will be sent to all processes identified by -%% Pids at once, but without allowing GC to be performed. -%% Check process code operations that are aborted due to -%% GC need, will be restarted allowing GC. However, only -%% ?MAX_CPC_GC_PROCS outstanding operation allowing GC at -%% a time will be allowed. This in order not to blow up -%% memory wise. -%% -%% We also only allow ?MAX_CPC_NO_OUTSTANDING_KILLS -%% outstanding kills. This both in order to avoid flooding -%% our message queue with 'DOWN' messages and limiting the -%% amount of memory used to keep references to all -%% outstanding kills. -%% - -%% We maybe should allow more than two outstanding -%% GC requests, but for now we play it safe... --define(MAX_CPC_GC_PROCS, 2). --define(MAX_CPC_NO_OUTSTANDING_KILLS, 10). - --record(cpc_static, {hard, module, tag}). - --record(cpc_kill, {outstanding = [], - no_outstanding = 0, - waiting = [], - killed = false}). - -check_proc_code(Pids, Mod, Hard) -> - Tag = erlang:make_ref(), - CpcS = #cpc_static{hard = Hard, - module = Mod, - tag = Tag}, - check_proc_code(CpcS, cpc_init(CpcS, Pids, 0), 0, [], #cpc_kill{}, true). - -check_proc_code(#cpc_static{hard = true}, 0, 0, [], - #cpc_kill{outstanding = [], waiting = [], killed = Killed}, - true) -> - %% No outstanding requests. We did a hard check, so result is whether or - %% not we killed any processes... - Killed; -check_proc_code(#cpc_static{hard = false}, 0, 0, [], _KillState, Success) -> - %% No outstanding requests and we did a soft check... - Success; -check_proc_code(#cpc_static{hard = false, tag = Tag} = CpcS, NoReq0, NoGcReq0, - [], _KillState, false) -> - %% Failed soft check; just cleanup the remaining replies corresponding - %% to the requests we've sent... - {NoReq1, NoGcReq1} = receive - {check_process_code, {Tag, _P, GC}, _Res} -> - case GC of - false -> {NoReq0-1, NoGcReq0}; - true -> {NoReq0, NoGcReq0-1} - end - end, - check_proc_code(CpcS, NoReq1, NoGcReq1, [], _KillState, false); -check_proc_code(#cpc_static{tag = Tag} = CpcS, NoReq0, NoGcReq0, NeedGC0, - KillState0, Success) -> - - %% Check if we should request a GC operation - {NoGcReq1, NeedGC1} = case NoGcReq0 < ?MAX_CPC_GC_PROCS of - GcOpAllowed when GcOpAllowed == false; - NeedGC0 == [] -> - {NoGcReq0, NeedGC0}; - _ -> - {NoGcReq0+1, cpc_request_gc(CpcS,NeedGC0)} - end, - - %% Wait for a cpc reply or 'DOWN' message - {NoReq1, NoGcReq2, Pid, Result, KillState1} = cpc_recv(Tag, - NoReq0, - NoGcReq1, - KillState0), - - %% Check the result of the reply - case Result of - aborted -> - %% Operation aborted due to the need to GC in order to - %% determine if the process is referring the module. - %% Schedule the operation for restart allowing GC... - check_proc_code(CpcS, NoReq1, NoGcReq2, [Pid|NeedGC1], KillState1, - Success); - false -> - %% Process not referring the module; done with this process... - check_proc_code(CpcS, NoReq1, NoGcReq2, NeedGC1, KillState1, - Success); - true -> - %% Process referring the module... - case CpcS#cpc_static.hard of - false -> - %% ... and soft check. The whole operation failed so - %% no point continuing; clean up and fail... - check_proc_code(CpcS, NoReq1, NoGcReq2, [], KillState1, - false); - true -> - %% ... and hard check; schedule kill of it... - check_proc_code(CpcS, NoReq1, NoGcReq2, NeedGC1, - cpc_sched_kill(Pid, KillState1), Success) - end; - 'DOWN' -> - %% Handled 'DOWN' message - check_proc_code(CpcS, NoReq1, NoGcReq2, NeedGC1, - KillState1, Success) - end. - -cpc_recv(Tag, NoReq, NoGcReq, #cpc_kill{outstanding = []} = KillState) -> - receive - {check_process_code, {Tag, Pid, GC}, Res} -> - cpc_handle_cpc(NoReq, NoGcReq, GC, Pid, Res, KillState) - end; -cpc_recv(Tag, NoReq, NoGcReq, - #cpc_kill{outstanding = [R0, R1, R2, R3, R4 | _]} = KillState) -> - receive - {'DOWN', R, process, _, _} when R == R0; - R == R1; - R == R2; - R == R3; - R == R4 -> - cpc_handle_down(NoReq, NoGcReq, R, KillState); - {check_process_code, {Tag, Pid, GC}, Res} -> - cpc_handle_cpc(NoReq, NoGcReq, GC, Pid, Res, KillState) - end; -cpc_recv(Tag, NoReq, NoGcReq, #cpc_kill{outstanding = [R|_]} = KillState) -> - receive - {'DOWN', R, process, _, _} -> - cpc_handle_down(NoReq, NoGcReq, R, KillState); - {check_process_code, {Tag, Pid, GC}, Res} -> - cpc_handle_cpc(NoReq, NoGcReq, GC, Pid, Res, KillState) - end. - -cpc_handle_down(NoReq, NoGcReq, R, #cpc_kill{outstanding = Rs, - no_outstanding = N} = KillState) -> - {NoReq, NoGcReq, undefined, 'DOWN', - cpc_sched_kill_waiting(KillState#cpc_kill{outstanding = cpc_list_rm(R, Rs), - no_outstanding = N-1})}. - -cpc_list_rm(R, [R|Rs]) -> - Rs; -cpc_list_rm(R0, [R1|Rs]) -> - [R1|cpc_list_rm(R0, Rs)]. - -cpc_handle_cpc(NoReq, NoGcReq, false, Pid, Res, KillState) -> - {NoReq-1, NoGcReq, Pid, Res, KillState}; -cpc_handle_cpc(NoReq, NoGcReq, true, Pid, Res, KillState) -> - {NoReq, NoGcReq-1, Pid, Res, KillState}. - -cpc_sched_kill_waiting(#cpc_kill{waiting = []} = KillState) -> - KillState; -cpc_sched_kill_waiting(#cpc_kill{outstanding = Rs, - no_outstanding = N, - waiting = [P|Ps]} = KillState) -> - R = erlang:monitor(process, P), - exit(P, kill), - KillState#cpc_kill{outstanding = [R|Rs], - no_outstanding = N+1, - waiting = Ps, - killed = true}. - -cpc_sched_kill(Pid, #cpc_kill{no_outstanding = N, waiting = Pids} = KillState) - when N >= ?MAX_CPC_NO_OUTSTANDING_KILLS -> - KillState#cpc_kill{waiting = [Pid|Pids]}; -cpc_sched_kill(Pid, - #cpc_kill{outstanding = Rs, no_outstanding = N} = KillState) -> - R = erlang:monitor(process, Pid), - exit(Pid, kill), - KillState#cpc_kill{outstanding = [R|Rs], - no_outstanding = N+1, - killed = true}. - -cpc_request(#cpc_static{tag = Tag, module = Mod}, Pid, AllowGc) -> - erlang:check_process_code(Pid, Mod, [{async, {Tag, Pid, AllowGc}}, - {allow_gc, AllowGc}]). - -cpc_request_gc(CpcS, [Pid|Pids]) -> - cpc_request(CpcS, Pid, true), - Pids. - -cpc_init(_CpcS, [], NoReqs) -> - NoReqs; -cpc_init(CpcS, [Pid|Pids], NoReqs) -> - cpc_request(CpcS, Pid, false), - cpc_init(CpcS, Pids, NoReqs+1). - -% end of check_proc_code() implementation. is_loaded(M, Db) -> case ets:lookup(Db, M) of @@ -1660,6 +1228,14 @@ is_loaded(M, Db) -> [] -> false end. +do_purge(Mod) -> + {_WasOld, DidKill} = erts_code_purger:purge(Mod), + DidKill. + +do_soft_purge(Mod) -> + erts_code_purger:soft_purge(Mod). + + %% ------------------------------------------------------- %% The on_load functionality. %% ------------------------------------------------------- @@ -1754,13 +1330,13 @@ strip_mod_info([{{sticky,_},_}|T], Acc) -> strip_mod_info(T, Acc); strip_mod_info([H|T], Acc) -> strip_mod_info(T, [H|Acc]); strip_mod_info([], Acc) -> Acc. -% error_msg(Format) -> -% error_msg(Format,[]). +-spec error_msg(io:format(), [term()]) -> 'ok'. error_msg(Format, Args) -> Msg = {notify,{error, group_leader(), {self(), Format, Args}}}, error_logger ! Msg, ok. +-spec info_msg(io:format(), [term()]) -> 'ok'. info_msg(Format, Args) -> Msg = {notify,{info_msg, group_leader(), {self(), Format, Args}}}, error_logger ! Msg, @@ -1774,6 +1350,3 @@ archive_extension() -> to_list(X) when is_list(X) -> X; to_list(X) when is_atom(X) -> atom_to_list(X). - -to_atom(X) when is_atom(X) -> X; -to_atom(X) when is_list(X) -> list_to_atom(X). diff --git a/lib/kernel/src/disk_log.erl b/lib/kernel/src/disk_log.erl index f5450f30af..9b44021872 100644 --- a/lib/kernel/src/disk_log.erl +++ b/lib/kernel/src/disk_log.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1997-2013. All Rights Reserved. +%% Copyright Ericsson AB 1997-2015. 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. @@ -1310,13 +1310,20 @@ compare_arg(_Attr, _Val, _A) -> %% -> {ok, Res, log(), Cnt} | Error do_open(A) -> - L = #log{name = A#arg.name, - filename = A#arg.file, - size = A#arg.size, - head = mk_head(A#arg.head, A#arg.format), - mode = A#arg.mode, - version = A#arg.version}, - do_open2(L, A). + #arg{type = Type, format = Format, name = Name, head = Head0, + file = FName, repair = Repair, size = Size, mode = Mode, + version = V} = A, + Head = mk_head(Head0, Format), + case do_open2(Type, Format, Name, FName, Repair, Size, Mode, Head, V) of + {ok, Ret, Extra, FormatType, NoItems} -> + L = #log{name = Name, type = Type, format = Format, + filename = FName, size = Size, + format_type = FormatType, head = Head, mode = Mode, + version = V, extra = Extra}, + {ok, Ret, L, NoItems}; + Error -> + Error + end. mk_head({head, Term}, internal) -> {ok, term_to_binary(Term)}; mk_head({head, Bytes}, external) -> {ok, check_bytes(Bytes)}; @@ -1432,57 +1439,44 @@ do_inc_wrap_file(L) -> %%----------------------------------------------------------------- %% -> {ok, Reply, log(), Cnt} | Error %% Note: the header is always written, even if the log size is too small. -do_open2(L, #arg{type = halt, format = internal, name = Name, - file = FName, repair = Repair, size = Size, mode = Mode}) -> - case catch disk_log_1:int_open(FName, Repair, Mode, L#log.head) of +do_open2(halt, internal, Name, FName, Repair, Size, Mode, Head, _V) -> + case catch disk_log_1:int_open(FName, Repair, Mode, Head) of {ok, {_Alloc, FdC, {NoItems, _NoBytes}, FileSize}} -> Halt = #halt{fdc = FdC, curB = FileSize, size = Size}, - {ok, {ok, Name}, L#log{format_type = halt_int, extra = Halt}, - NoItems}; + {ok, {ok, Name}, Halt, halt_int, NoItems}; {repaired, FdC, Rec, Bad, FileSize} -> Halt = #halt{fdc = FdC, curB = FileSize, size = Size}, {ok, {repaired, Name, {recovered, Rec}, {badbytes, Bad}}, - L#log{format_type = halt_int, extra = Halt}, - Rec}; + Halt, halt_int, Rec}; Error -> Error end; -do_open2(L, #arg{type = wrap, format = internal, size = {MaxB, MaxF}, - name = Name, repair = Repair, file = FName, mode = Mode, - version = V}) -> +do_open2(wrap, internal, Name, FName, Repair, Size, Mode, Head, V) -> + {MaxB, MaxF} = Size, case catch - disk_log_1:mf_int_open(FName, MaxB, MaxF, Repair, Mode, L#log.head, V) of + disk_log_1:mf_int_open(FName, MaxB, MaxF, Repair, Mode, Head, V) of {ok, Handle, Cnt} -> - {ok, {ok, Name}, L#log{type = wrap, - format_type = wrap_int, - extra = Handle}, Cnt}; + {ok, {ok, Name}, Handle, wrap_int, Cnt}; {repaired, Handle, Rec, Bad, Cnt} -> {ok, {repaired, Name, {recovered, Rec}, {badbytes, Bad}}, - L#log{type = wrap, format_type = wrap_int, extra = Handle}, Cnt}; + Handle, wrap_int, Cnt}; Error -> Error end; -do_open2(L, #arg{type = halt, format = external, file = FName, name = Name, - size = Size, repair = Repair, mode = Mode}) -> - case catch disk_log_1:ext_open(FName, Repair, Mode, L#log.head) of +do_open2(halt, external, Name, FName, Repair, Size, Mode, Head, _V) -> + case catch disk_log_1:ext_open(FName, Repair, Mode, Head) of {ok, {_Alloc, FdC, {NoItems, _NoBytes}, FileSize}} -> Halt = #halt{fdc = FdC, curB = FileSize, size = Size}, - {ok, {ok, Name}, - L#log{format_type = halt_ext, format = external, extra = Halt}, - NoItems}; + {ok, {ok, Name}, Halt, halt_ext, NoItems}; Error -> Error end; -do_open2(L, #arg{type = wrap, format = external, size = {MaxB, MaxF}, - name = Name, file = FName, repair = Repair, mode = Mode, - version = V}) -> +do_open2(wrap, external, Name, FName, Repair, Size, Mode, Head, V) -> + {MaxB, MaxF} = Size, case catch - disk_log_1:mf_ext_open(FName, MaxB, MaxF, Repair, Mode, L#log.head, V) of + disk_log_1:mf_ext_open(FName, MaxB, MaxF, Repair, Mode, Head, V) of {ok, Handle, Cnt} -> - {ok, {ok, Name}, L#log{type = wrap, - format_type = wrap_ext, - extra = Handle, - format = external}, Cnt}; + {ok, {ok, Name}, Handle, wrap_ext, Cnt}; Error -> Error end. diff --git a/lib/kernel/src/disk_log.hrl b/lib/kernel/src/disk_log.hrl index 6c0aea070f..3262d979ee 100644 --- a/lib/kernel/src/disk_log.hrl +++ b/lib/kernel/src/disk_log.hrl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1997-2012. All Rights Reserved. +%% Copyright Ericsson AB 1997-2015. 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. @@ -152,8 +152,8 @@ users = 0 :: non_neg_integer(), %% non-linked users filename :: file:filename(), %% real name of the file owners = [] :: [{pid(), boolean()}],%% [{pid, notify}] - type = halt :: dlog_type(), - format = internal :: dlog_format(), + type :: dlog_type(), + format :: dlog_format(), format_type :: dlog_format_type(), head = none, %% none | {head, H} | {M,F,A} %% called when wraplog wraps diff --git a/lib/kernel/src/erts_debug.erl b/lib/kernel/src/erts_debug.erl index 39308c0043..8e2b5ad214 100644 --- a/lib/kernel/src/erts_debug.erl +++ b/lib/kernel/src/erts_debug.erl @@ -34,7 +34,8 @@ -export([breakpoint/2, disassemble/1, display/1, dist_ext_to_term/2, dump_monitors/1, dump_links/1, flat_size/1, get_internal_state/1, instructions/0, lock_counters/1, - map_info/1, same/2, set_internal_state/2]). + map_info/1, same/2, set_internal_state/2, + size_shared/1, copy_shared/1]). -spec breakpoint(MFA, Flag) -> non_neg_integer() when MFA :: {Module :: module(), @@ -86,6 +87,18 @@ dump_links(_) -> flat_size(_) -> erlang:nif_error(undef). +-spec size_shared(Term) -> non_neg_integer() when + Term :: term(). + +size_shared(_) -> + erlang:nif_error(undef). + +-spec copy_shared(Term) -> term() when + Term :: term(). + +copy_shared(_) -> + erlang:nif_error(undef). + -spec get_internal_state(W) -> term() when W :: reds_left | node_and_dist_references | monitoring_nodes | next_pid | 'DbTable_words' | check_io_debug @@ -230,7 +243,7 @@ map_size(Map,Seen0,Sum0) -> %% is not allowed to leak anywhere. They are only allowed in %% containers (cons cells and tuples, not maps), in gc and %% in erts_debug:same/2 - case erts_internal:map_type(Map) of + case erts_internal:term_type(Map) of flatmap -> Kt = erts_internal:map_to_tuple_keys(Map), Vs = maps:values(Map), diff --git a/lib/kernel/src/global.erl b/lib/kernel/src/global.erl index 2be1efaf24..0c73ead7c5 100644 --- a/lib/kernel/src/global.erl +++ b/lib/kernel/src/global.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2014. All Rights Reserved. +%% Copyright Ericsson AB 1996-2015. 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. @@ -459,17 +459,17 @@ init([]) -> no_trace end, + Ca = case init:get_argument(connect_all) of + {ok, [["false"]]} -> + false; + _ -> + true + end, S = #state{the_locker = start_the_locker(DoTrace), trace = T0, - the_registrar = start_the_registrar()}, - S1 = trace_message(S, {init, node()}, []), - - case init:get_argument(connect_all) of - {ok, [["false"]]} -> - {ok, S1#state{connect_all = false}}; - _ -> - {ok, S1#state{connect_all = true}} - end. + the_registrar = start_the_registrar(), + connect_all = Ca}, + {ok, trace_message(S, {init, node()}, [])}. %%----------------------------------------------------------------- %% Connection algorithm @@ -2068,23 +2068,17 @@ get_known() -> gen_server:call(global_name_server, get_known, infinity). random_sleep(Times) -> - case (Times rem 10) of - 0 -> erase(random_seed); - _ -> ok - end, - case get(random_seed) of - undefined -> - _ = random:seed(erlang:phash2([erlang:node()]), - erlang:monotonic_time(), - erlang:unique_integer()), - ok; - _ -> ok - end, + _ = case Times rem 10 of + 0 -> + _ = rand:seed(exsplus); + _ -> + ok + end, %% First time 1/4 seconds, then doubling each time up to 8 seconds max. Tmax = if Times > 5 -> 8000; true -> ((1 bsl Times) * 1000) div 8 end, - T = random:uniform(Tmax), + T = rand:uniform(Tmax), ?trace({random_sleep, {me,self()}, {times,Times}, {t,T}, {tmax,Tmax}}), receive after T -> ok end. diff --git a/lib/kernel/src/global_group.erl b/lib/kernel/src/global_group.erl index 848df13c39..e71f83f9d3 100644 --- a/lib/kernel/src/global_group.erl +++ b/lib/kernel/src/global_group.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1998-2013. All Rights Reserved. +%% Copyright Ericsson AB 1998-2015. 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. @@ -273,7 +273,7 @@ init([]) -> {ok, #state{publish_type = PT, group_publish_type = PubTpGrp, sync_state = synced, group_name = DefGroupName, no_contact = lists:sort(DefNodes), - other_grps = DefOther}} + other_grps = DefOther, connect_all = Ca}} end. diff --git a/lib/kernel/src/inet_config.erl b/lib/kernel/src/inet_config.erl index 803fae846e..a0d5344f11 100644 --- a/lib/kernel/src/inet_config.erl +++ b/lib/kernel/src/inet_config.erl @@ -188,9 +188,6 @@ do_load_resolv({win32,Type}, longnames) -> win32_load_from_registry(Type), inet_db:set_lookup([native]); -do_load_resolv({ose,_}, _) -> - inet_db:set_lookup([file]); - do_load_resolv(_, _) -> inet_db:set_lookup([native]). diff --git a/lib/kernel/src/kernel.erl b/lib/kernel/src/kernel.erl index 5f33f25a0d..40544da6c3 100644 --- a/lib/kernel/src/kernel.erl +++ b/lib/kernel/src/kernel.erl @@ -98,7 +98,7 @@ init([]) -> {kernel_config, start_link, []}, permanent, 2000, worker, [kernel_config]}, Code = {code_server, - {code, start_link, get_code_args()}, + {code, start_link, []}, permanent, 2000, worker, [code]}, File = {file_server_2, {file_server, start_link, []}, @@ -158,12 +158,6 @@ init(safe) -> {ok, {SupFlags, Boot ++ DiskLog ++ Pg2}}. -get_code_args() -> - case init:get_argument(nostick) of - {ok, [[]]} -> [[nostick]]; - _ -> [] - end. - start_dist_ac() -> Spec = [{dist_ac,{dist_ac,start_link,[]},permanent,2000,worker,[dist_ac]}], case application:get_env(kernel, start_dist_ac) of diff --git a/lib/kernel/src/os.erl b/lib/kernel/src/os.erl index 3330b38d84..4947088635 100644 --- a/lib/kernel/src/os.erl +++ b/lib/kernel/src/os.erl @@ -27,7 +27,9 @@ %%% BIFs --export([getenv/0, getenv/1, getenv/2, getpid/0, putenv/2, system_time/0, system_time/1, +-export([getenv/0, getenv/1, getenv/2, getpid/0, + perf_counter/0, perf_counter/1, + putenv/2, system_time/0, system_time/1, timestamp/0, unsetenv/1]). -spec getenv() -> [string()]. @@ -60,6 +62,18 @@ getenv(VarName, DefaultValue) -> getpid() -> erlang:nif_error(undef). +-spec perf_counter() -> Counter when + Counter :: integer(). + +perf_counter() -> + erlang:nif_error(undef). + +-spec perf_counter(Unit) -> integer() when + Unit :: erlang:time_unit(). + +perf_counter(Unit) -> + erlang:convert_time_unit(os:perf_counter(), perf_counter, Unit). + -spec putenv(VarName, Value) -> true when VarName :: string(), Value :: string(). @@ -93,7 +107,7 @@ unsetenv(_) -> %%% End of BIFs -spec type() -> {Osfamily, Osname} when - Osfamily :: unix | win32 | ose, + Osfamily :: unix | win32, Osname :: atom(). type() -> @@ -212,174 +226,33 @@ extensions() -> Command :: atom() | io_lib:chars(). cmd(Cmd) -> validate(Cmd), - Bytes = case type() of - {unix, _} -> - unix_cmd(Cmd); - {win32, Wtype} -> - Command0 = case {os:getenv("COMSPEC"),Wtype} of - {false,windows} -> lists:concat(["command.com /c", Cmd]); - {false,_} -> lists:concat(["cmd /c", Cmd]); - {Cspec,_} -> lists:concat([Cspec," /c",Cmd]) - end, - %% open_port/2 awaits string() in Command, but io_lib:chars() can be - %% deep lists according to io_lib module description. - Command = lists:flatten(Command0), - Port = open_port({spawn, Command}, [stream, in, eof, hide]), - get_data(Port, []) - end, - String = unicode:characters_to_list(list_to_binary(Bytes)), + {SpawnCmd, SpawnOpts, SpawnInput} = mk_cmd(os:type(), Cmd), + Port = open_port({spawn, SpawnCmd}, [binary, stderr_to_stdout, + stream, in, eof, hide | SpawnOpts]), + true = port_command(Port, SpawnInput), + Bytes = get_data(Port, []), + String = unicode:characters_to_list(Bytes), if %% Convert to unicode list if possible otherwise return bytes is_list(String) -> String; - true -> Bytes - end. - -unix_cmd(Cmd) -> - Tag = make_ref(), - {Pid,Mref} = erlang:spawn_monitor( - fun() -> - process_flag(trap_exit, true), - Port = start_port(), - erlang:port_command(Port, mk_cmd(Cmd)), - exit({Tag,unix_get_data(Port)}) - end), - receive - {'DOWN',Mref,_,Pid,{Tag,Result}} -> - Result; - {'DOWN',Mref,_,Pid,Reason} -> - exit(Reason) + true -> binary_to_list(Bytes) end. -%% The -s flag implies that only the positional parameters are set, -%% and the commands are read from standard input. We set the -%% $1 parameter for easy identification of the resident shell. -%% --define(ROOT, "/"). --define(ROOT_ANDROID, "/system"). --define(SHELL, "bin/sh -s unix:cmd 2>&1"). --define(PORT_CREATOR_NAME, os_cmd_port_creator). - -%% -%% Serializing open_port through a process to avoid smp lock contention -%% when many concurrent os:cmd() want to do vfork (OTP-7890). -%% --spec start_port() -> port(). -start_port() -> - Ref = make_ref(), - Request = {Ref,self()}, - {Pid, Mon} = case whereis(?PORT_CREATOR_NAME) of - undefined -> - spawn_monitor(fun() -> - start_port_srv(Request) - end); - P -> - P ! Request, - M = erlang:monitor(process, P), - {P, M} - end, - receive - {Ref, Port} when is_port(Port) -> - erlang:demonitor(Mon, [flush]), - Port; - {Ref, Error} -> - erlang:demonitor(Mon, [flush]), - exit(Error); - {'DOWN', Mon, process, Pid, _Reason} -> - start_port() - end. - -start_port_srv(Request) -> - %% We don't want a group leader of some random application. Use - %% kernel_sup's group leader. - {group_leader, GL} = process_info(whereis(kernel_sup), - group_leader), - true = group_leader(GL, self()), - process_flag(trap_exit, true), - StayAlive = try register(?PORT_CREATOR_NAME, self()) - catch - error:_ -> false - end, - start_port_srv_handle(Request), - case StayAlive of - true -> start_port_srv_loop(); - false -> exiting - end. - -start_port_srv_handle({Ref,Client}) -> - Path = case lists:reverse(erlang:system_info(system_architecture)) of - % androideabi - "ibaediordna" ++ _ -> filename:join([?ROOT_ANDROID, ?SHELL]); - _ -> filename:join([?ROOT, ?SHELL]) - end, - Reply = try open_port({spawn, Path},[stream]) of - Port when is_port(Port) -> - (catch port_connect(Port, Client)), - unlink(Port), - Port - catch - error:Reason -> - {Reason,erlang:get_stacktrace()} - end, - Client ! {Ref,Reply}, - ok. - -start_port_srv_loop() -> - receive - {Ref, Client} = Request when is_reference(Ref), - is_pid(Client) -> - start_port_srv_handle(Request); - _Junk -> - ok - end, - start_port_srv_loop(). - -%% -%% unix_get_data(Port) -> Result -%% -unix_get_data(Port) -> - unix_get_data(Port, []). - -unix_get_data(Port, Sofar) -> - receive - {Port,{data, Bytes}} -> - case eot(Bytes) of - {done, Last} -> - lists:flatten([Sofar|Last]); - more -> - unix_get_data(Port, [Sofar|Bytes]) - end; - {'EXIT', Port, _} -> - lists:flatten(Sofar) - end. - -%% -%% eot(String) -> more | {done, Result} -%% -eot(Bs) -> - eot(Bs, []). - -eot([4| _Bs], As) -> - {done, lists:reverse(As)}; -eot([B| Bs], As) -> - eot(Bs, [B| As]); -eot([], _As) -> - more. - -%% -%% mk_cmd(Cmd) -> {ok, ShellCommandString} | {error, ErrorString} -%% -%% We do not allow any input to Cmd (hence commands that want -%% to read from standard input will return immediately). -%% Standard error is redirected to standard output. -%% -%% We use ^D (= EOT = 4) to mark the end of the stream. -%% -mk_cmd(Cmd) when is_atom(Cmd) -> % backward comp. - mk_cmd(atom_to_list(Cmd)); -mk_cmd(Cmd) -> - %% We insert a new line after the command, in case the command - %% contains a comment character. - [$(, unicode:characters_to_binary(Cmd), "\n) </dev/null; echo \"\^D\"\n"]. - +mk_cmd({win32,Wtype}, Cmd) -> + Command = case {os:getenv("COMSPEC"),Wtype} of + {false,windows} -> lists:concat(["command.com /c", Cmd]); + {false,_} -> lists:concat(["cmd /c", Cmd]); + {Cspec,_} -> lists:concat([Cspec," /c",Cmd]) + end, + {Command, [], []}; +mk_cmd(OsType,Cmd) when is_atom(Cmd) -> + mk_cmd(OsType, atom_to_list(Cmd)); +mk_cmd(_,Cmd) -> + %% Have to send command in like this in order to make sh commands like + %% cd and ulimit available + {"/bin/sh -s unix:cmd", [out], + %% We insert a new line after the command, in case the command + %% contains a comment character. + ["(", unicode:characters_to_binary(Cmd), "\n); exit\n"]}. validate(Atom) when is_atom(Atom) -> ok; @@ -397,7 +270,7 @@ validate1([]) -> get_data(Port, Sofar) -> receive {Port, {data, Bytes}} -> - get_data(Port, [Sofar|Bytes]); + get_data(Port, [Sofar,Bytes]); {Port, eof} -> Port ! {self(), close}, receive @@ -410,5 +283,5 @@ get_data(Port, Sofar) -> after 1 -> % force context switch ok end, - lists:flatten(Sofar) + iolist_to_binary(Sofar) end. diff --git a/lib/kernel/test/code_SUITE.erl b/lib/kernel/test/code_SUITE.erl index 2b77ec8972..2a8468942c 100644 --- a/lib/kernel/test/code_SUITE.erl +++ b/lib/kernel/test/code_SUITE.erl @@ -30,8 +30,7 @@ upgrade/1, sticky_dir/1, pa_pz_option/1, add_del_path/1, dir_disappeared/1, ext_mod_dep/1, clash/1, - load_cached/1, start_node_with_cache/1, add_and_rehash/1, - where_is_file_cached/1, where_is_file_no_cache/1, + where_is_file/1, purge_stacktrace/1, mult_lib_roots/1, bad_erl_libs/1, code_archive/1, code_archive2/1, on_load/1, on_load_binary/1, on_load_embedded/1, on_load_errors/1, big_boot_embedded/1, @@ -56,9 +55,8 @@ all() -> load_binary, dir_req, object_code, set_path_file, upgrade, sticky_dir, pa_pz_option, add_del_path, dir_disappeared, - ext_mod_dep, clash, load_cached, start_node_with_cache, - add_and_rehash, where_is_file_no_cache, - where_is_file_cached, purge_stacktrace, mult_lib_roots, + ext_mod_dep, clash, where_is_file, + purge_stacktrace, mult_lib_roots, bad_erl_libs, code_archive, code_archive2, on_load, on_load_binary, on_load_embedded, on_load_errors, big_boot_embedded, native_early_modules, get_mode]. @@ -383,8 +381,23 @@ purge(Config) when is_list(Config) -> purge_many_exits(Config) when is_list(Config) -> OldFlag = process_flag(trap_exit, true), + code:purge(code_b_test), {'EXIT',_} = (catch code:purge({})), + + CodePurgeF = fun(M, Exp) -> Exp = code:purge(M) end, + purge_many_exits_do(CodePurgeF), + + %% Let's repeat test for erlang:purge_module as it does the same thing + %% now in erts-8.0 (except for return value). + ErlangPurgeF = fun(M, _Exp) -> erlang:purge_module(M) end, + purge_many_exits_do(ErlangPurgeF), + + process_flag(trap_exit, OldFlag), + ok. + + +purge_many_exits_do(PurgeF) -> false = code:purge(code_b_test), TPids = lists:map(fun (_) -> {code_b_test:do_spawn(), @@ -403,7 +416,7 @@ purge_many_exits(Config) when is_list(Config) -> false = code_b_test:check_exit(Pid1), true = erlang:is_process_alive(Pid2) end, TPids), - true = code:purge(code_b_test), + PurgeF(code_b_test, true), lists:foreach(fun ({Pid1, Pid2}) -> false = erlang:is_process_alive(Pid1), true = code_b_test:check_exit(Pid1), @@ -412,9 +425,7 @@ purge_many_exits(Config) when is_list(Config) -> end, TPids), lists:foreach(fun ({_Pid1, Pid2}) -> receive {'EXIT', Pid2, _} -> ok end - end, TPids), - process_flag(trap_exit, OldFlag), - ok. + end, TPids). soft_purge(suite) -> []; @@ -769,6 +780,7 @@ analyse([], [This={M,F,A}|Path], Visited, ErrCnt0) -> OK = [erlang, os, prim_file, erl_prim_loader, init, ets, code_server, lists, lists_sort, unicode, binary, filename, gb_sets, gb_trees, hipe_unified_loader, hipe_bifs, + erts_code_purger, prim_zip, zlib], ErrCnt1 = case lists:member(M, OK) or erlang:is_builtin(M,F,A) of @@ -839,18 +851,7 @@ check_funs({'$M_EXPR','$F_EXPR',1}, {code_server,start_link,1}]) -> 0; check_funs({'$M_EXPR','$F_EXPR',1}, [{lists,filter,2}, - {code_server,try_archive_subdirs,3}, - {code_server,all_archive_subdirs,1}, - {code_server,archive_subdirs,1}, - {code_server,insert_name,3}, - {code_server,replace_name,2}, - {code_server,update,2}, - {code_server,maybe_update,2}, - {code_server,do_add,4}, - {code_server,add_path,4}, - {code_server,handle_call,3}, - {code_server,loop,1}, - {code_server,system_continue,3}]) -> 0; + {code_server,try_archive_subdirs,3}|_]) -> 0; check_funs({'$M_EXPR','$F_EXPR',_}, [{erlang,apply,2}, {erlang,spawn_link,1}, @@ -905,140 +906,7 @@ uniq([H|T],A) -> uniq(T,[H|A]). -load_cached(suite) -> - []; -load_cached(doc) -> - []; -load_cached(Config) when is_list(Config) -> - Priv = ?config(priv_dir, Config), - WD = filename:dirname(code:which(?MODULE)), - {ok,Node} = - ?t:start_node(code_cache_node, peer, [{args, - "-pa \"" ++ WD ++ "\""}, - {erl, [this]}]), - CCTabCreated = fun(Tab) -> - case ets:info(Tab, name) of - code_cache -> true; - _ -> false - end - end, - Tabs = rpc:call(Node, ets, all, []), - case rpc:call(Node, lists, any, [CCTabCreated,Tabs]) of - true -> - ?t:stop_node(Node), - ?t:fail("Code cache should not be active!"); - false -> - ok - end, - rpc:call(Node, code, del_path, [Priv]), - rpc:call(Node, code, add_pathz, [Priv]), - - FullModName = Priv ++ "/code_cache_test", - {ok,Dev} = file:open(FullModName ++ ".erl", [write]), - io:format(Dev, "-module(code_cache_test). -export([a/0]). a() -> ok.~n", []), - ok = file:close(Dev), - {ok,code_cache_test} = compile:file(FullModName, [{outdir,Priv}]), - - F = fun load_loop/2, - N = 1000, - {T0,T1} = rpc:call(Node, erlang, apply, [F, [N,code_cache_test]]), - TNoCache = now_diff(T1, T0), - rpc:call(Node, code, rehash, []), - {T2,T3} = rpc:call(Node, erlang, apply, [F, [N,code_cache_test]]), - TCache = now_diff(T3, T2), - AvgNoCache = TNoCache/N, - AvgCache = TCache/N, - io:format("Avg. load time (no_cache/cache): ~w/~w~n", [AvgNoCache,AvgCache]), - ?t:stop_node(Node), - if AvgNoCache =< AvgCache -> - ?t:fail("Cache not working properly."); - true -> - ok - end. - -load_loop(N, M) -> - load_loop(N, M, now()). -load_loop(0, _M, T0) -> - {T0,now()}; -load_loop(N, M, T0) -> - code:load_file(M), - code:delete(M), - code:purge(M), - load_loop(N-1, M, T0). - -now_diff({A2, B2, C2}, {A1, B1, C1}) -> - ((A2-A1)*1000000 + B2-B1)*1000000 + C2-C1. - -start_node_with_cache(suite) -> - []; -start_node_with_cache(doc) -> - []; -start_node_with_cache(Config) when is_list(Config) -> - {ok,Node} = - ?t:start_node(code_cache_node, peer, [{args, - "-code_path_cache"}, - {erl, [this]}]), - Tabs = rpc:call(Node, ets, all, []), - io:format("Tabs: ~w~n", [Tabs]), - CCTabCreated = fun(Tab) -> - case rpc:call(Node, ets, info, [Tab,name]) of - code_cache -> true; - _ -> false - end - end, - true = lists:any(CCTabCreated, Tabs), - ?t:stop_node(Node), - ok. - -add_and_rehash(suite) -> - []; -add_and_rehash(doc) -> - []; -add_and_rehash(Config) when is_list(Config) -> - Priv = ?config(priv_dir, Config), - WD = filename:dirname(code:which(?MODULE)), - {ok,Node} = - ?t:start_node(code_cache_node, peer, [{args, - "-pa \"" ++ WD ++ "\""}, - {erl, [this]}]), - CCTabCreated = fun(Tab) -> - case ets:info(Tab, name) of - code_cache -> true; - _ -> false - end - end, - Tabs0 = rpc:call(Node, ets, all, []), - case rpc:call(Node, lists, any, [CCTabCreated,Tabs0]) of - true -> - ?t:stop_node(Node), - ?t:fail("Code cache should not be active!"); - false -> - ok - end, - ok = rpc:call(Node, code, rehash, []), % create cache - Tabs1 = rpc:call(Node, ets, all, []), - true = rpc:call(Node, lists, any, [CCTabCreated,Tabs1]), % cache table created - ok = rpc:call(Node, code, rehash, []), - OkDir = filename:join(Priv, ""), - BadDir = filename:join(Priv, "guggemuffsussiputt"), - CP = [OkDir | rpc:call(Node, code, get_path, [])], - true = rpc:call(Node, code, set_path, [CP]), - CP1 = [BadDir | CP], - {error,_} = rpc:call(Node, code, set_path, [CP1]), - true = rpc:call(Node, code, del_path, [OkDir]), - true = rpc:call(Node, code, add_path, [OkDir]), - true = rpc:call(Node, code, add_path, [OkDir]), - {error,_} = rpc:call(Node, code, add_path, [BadDir]), - ok = rpc:call(Node, code, rehash, []), - - ?t:stop_node(Node), - ok. - -where_is_file_no_cache(suite) -> - []; -where_is_file_no_cache(doc) -> - []; -where_is_file_no_cache(Config) when is_list(Config) -> +where_is_file(Config) when is_list(Config) -> {T,KernelBeamFile} = timer:tc(code, where_is_file, ["kernel.beam"]), io:format("Load time: ~w ms~n", [T]), KernelEbinDir = filename:dirname(KernelBeamFile), @@ -1047,35 +915,6 @@ where_is_file_no_cache(Config) when is_list(Config) -> non_existing = code:where_is_file("kernel"), % no such file ok. -where_is_file_cached(suite) -> - []; -where_is_file_cached(doc) -> - []; -where_is_file_cached(Config) when is_list(Config) -> - {ok,Node} = - ?t:start_node(code_cache_node, peer, [{args, - "-code_path_cache"}, - {erl, [this]}]), - Tabs = rpc:call(Node, ets, all, []), - io:format("Tabs: ~w~n", [Tabs]), - CCTabCreated = fun(Tab) -> - case rpc:call(Node, ets, info, [Tab,name]) of - code_cache -> true; - _ -> false - end - end, - true = lists:any(CCTabCreated, Tabs), - KernelBeamFile = rpc:call(Node, code, where_is_file, ["kernel.beam"]), - {T,KernelBeamFile} = rpc:call(Node, timer, tc, [code,where_is_file,["kernel.beam"]]), - io:format("Load time: ~w ms~n", [T]), - KernelEbinDir = rpc:call(Node, filename, dirname, [KernelBeamFile]), - AppFile = rpc:call(Node, filename, join, [KernelEbinDir,"kernel.app"]), - AppFile = rpc:call(Node, code, where_is_file, ["kernel.app"]), - non_existing = rpc:call(Node, code, where_is_file, ["kernel"]), % no such file - ?t:stop_node(Node), - ok. - - purge_stacktrace(suite) -> []; purge_stacktrace(doc) -> diff --git a/lib/kernel/test/erl_prim_loader_SUITE.erl b/lib/kernel/test/erl_prim_loader_SUITE.erl index 0803cf428f..72b00e22da 100644 --- a/lib/kernel/test/erl_prim_loader_SUITE.erl +++ b/lib/kernel/test/erl_prim_loader_SUITE.erl @@ -133,14 +133,8 @@ inet_existing(doc) -> ["Start a node using the 'inet' loading method, ", "from an already started boot server."]; inet_existing(Config) when is_list(Config) -> Name = erl_prim_test_inet_existing, - Host = host(), - Cookie = atom_to_list(erlang:get_cookie()), - IpStr = ip_str(Host), - LFlag = get_loader_flag(os:type()), - Args = LFlag ++ " -hosts " ++ IpStr ++ - " -setcookie " ++ Cookie, - {ok, BootPid} = erl_boot_server:start_link([Host]), - {ok, Node} = start_node(Name, Args), + BootPid = start_boot_server(), + Node = start_node_using_inet(Name), {ok,[["inet"]]} = rpc:call(Node, init, get_argument, [loader]), stop_node(Node), unlink(BootPid), @@ -151,19 +145,11 @@ inet_coming_up(doc) -> ["Start a node using the 'inet' loading method, ", "but start the boot server afterwards."]; inet_coming_up(Config) when is_list(Config) -> Name = erl_prim_test_inet_coming_up, - Cookie = atom_to_list(erlang:get_cookie()), - Host = host(), - IpStr = ip_str(Host), - LFlag = get_loader_flag(os:type()), - Args = LFlag ++ - " -hosts " ++ IpStr ++ - " -setcookie " ++ Cookie, - {ok, Node} = start_node(Name, Args, [{wait, false}]), + Node = start_node_using_inet(Name, [{wait,false}]), %% Wait a while, then start boot server, and wait for node to start. test_server:sleep(test_server:seconds(6)), - io:format("erl_boot_server:start_link([~p]).", [Host]), - {ok, BootPid} = erl_boot_server:start_link([Host]), + BootPid = start_boot_server(), wait_really_started(Node, 25), %% Check loader argument, then cleanup. @@ -191,24 +177,19 @@ inet_disconnects(Config) when is_list(Config) -> true -> {skip,"erl_boot_server is native"}; false -> - ?line Name = erl_prim_test_inet_disconnects, - ?line Host = host(), - ?line Cookie = atom_to_list(erlang:get_cookie()), - ?line IpStr = ip_str(Host), - ?line LFlag = get_loader_flag(os:type()), - ?line Args = LFlag ++ " -hosts " ++ IpStr ++ - " -setcookie " ++ Cookie, + Name = erl_prim_test_inet_disconnects, - ?line {ok, BootPid} = erl_boot_server:start([Host]), + BootPid = start_boot_server(), + unlink(BootPid), Self = self(), %% This process shuts down the boot server during loading. - ?line Stopper = spawn_link(fun() -> stop_boot(BootPid, Self) end), - ?line receive - {Stopper,ready} -> ok - end, + Stopper = spawn_link(fun() -> stop_boot(BootPid, Self) end), + receive + {Stopper,ready} -> ok + end, %% Let the loading begin... - ?line {ok, Node} = start_node(Name, Args, [{wait, false}]), + Node = start_node_using_inet(Name, [{wait,false}]), %% When the stopper is ready, the slave node should be %% looking for a boot server again. @@ -222,12 +203,12 @@ inet_disconnects(Config) when is_list(Config) -> end, %% Start new boot server to see that loading is continued. - ?line {ok, BootPid2} = erl_boot_server:start_link([Host]), - ?line wait_really_started(Node, 25), - ?line {ok,[["inet"]]} = rpc:call(Node, init, get_argument, [loader]), - ?line stop_node(Node), - ?line unlink(BootPid2), - ?line exit(BootPid2, kill), + BootPid2 = start_boot_server(), + wait_really_started(Node, 25), + {ok,[["inet"]]} = rpc:call(Node, init, get_argument, [loader]), + stop_node(Node), + unlink(BootPid2), + exit(BootPid2, kill), ok end. @@ -260,46 +241,38 @@ multiple_slaves(doc) -> ["Start nodes in parallell, all using the 'inet' loading method, ", "verify that the boot server manages"]; multiple_slaves(Config) when is_list(Config) -> - case os:type() of - {ose,_} -> - {comment, "OSE: multiple nodes not supported"}; - _ -> - ?line Name = erl_prim_test_multiple_slaves, - ?line Host = host(), - ?line Cookie = atom_to_list(erlang:get_cookie()), - ?line IpStr = ip_str(Host), - ?line LFlag = get_loader_flag(os:type()), - ?line Args = LFlag ++ " -hosts " ++ IpStr ++ - " -setcookie " ++ Cookie, - - NoOfNodes = 10, % no of slave nodes to be started - - NamesAndNodes = - lists:map(fun(N) -> - NameN = atom_to_list(Name) ++ - integer_to_list(N), - NodeN = NameN ++ "@" ++ Host, - {list_to_atom(NameN),list_to_atom(NodeN)} - end, lists:seq(1, NoOfNodes)), - - ?line Nodes = start_multiple_nodes(NamesAndNodes, Args, []), - - %% "queue up" the nodes to wait for the boot server to respond - %% (note: test_server supervises each node start by accept() - %% on a socket, the timeout value for the accept has to be quite - %% long for this test to work). - ?line test_server:sleep(test_server:seconds(5)), - %% start the code loading circus! - ?line {ok,BootPid} = erl_boot_server:start_link([Host]), - %% give the nodes a chance to boot up before attempting to stop them - ?line test_server:sleep(test_server:seconds(10)), - - ?line wait_and_shutdown(lists:reverse(Nodes), 30), - - ?line unlink(BootPid), - ?line exit(BootPid, kill), - ok - end. + ?line Name = erl_prim_test_multiple_slaves, + ?line Host = host(), + ?line IpStr = ip_str(Host), + Args = " -loader inet -hosts " ++ IpStr, + + NoOfNodes = 10, % no of slave nodes to be started + + NamesAndNodes = + lists:map(fun(N) -> + NameN = atom_to_list(Name) ++ + integer_to_list(N), + NodeN = NameN ++ "@" ++ Host, + {list_to_atom(NameN),list_to_atom(NodeN)} + end, lists:seq(1, NoOfNodes)), + + ?line Nodes = start_multiple_nodes(NamesAndNodes, Args, []), + + %% "queue up" the nodes to wait for the boot server to respond + %% (note: test_server supervises each node start by accept() + %% on a socket, the timeout value for the accept has to be quite + %% long for this test to work). + ?line test_server:sleep(test_server:seconds(5)), + %% start the code loading circus! + BootPid = start_boot_server(), + %% give the nodes a chance to boot up before attempting to stop them + ?line test_server:sleep(test_server:seconds(10)), + + ?line wait_and_shutdown(lists:reverse(Nodes), 30), + + ?line unlink(BootPid), + ?line exit(BootPid, kill), + ok. start_multiple_nodes([{Name,Node} | NNs], Args, Started) -> ?line {ok,Node} = start_node(Name, Args, [{wait, false}]), @@ -367,20 +340,6 @@ file_requests(Config) when is_list(Config) -> ?line exit(BootPid, kill), ok. -complete_start_node(Name) -> - ?line Host = host(), - ?line Cookie = atom_to_list(erlang:get_cookie()), - ?line IpStr = ip_str(Host), - ?line LFlag = get_loader_flag(os:type()), - ?line Args = LFlag ++ " -hosts " ++ IpStr ++ - " -setcookie " ++ Cookie, - - ?line {ok,BootPid} = erl_boot_server:start_link([Host]), - - ?line {ok,Node} = start_node(Name, Args), - ?line wait_really_started(Node, 25), - {ok, Node, BootPid}. - local_archive(suite) -> []; local_archive(doc) -> @@ -397,7 +356,7 @@ local_archive(Config) when is_list(Config) -> ?line ok = test_archive(Node, Archive, KernelDir, BeamName), %% Cleanup - ?line ok = rpc:call(Node, erl_prim_loader, release_archives, []), + ok = rpc:call(Node, erl_prim_loader, purge_archive_cache, []), ?line ok = file:delete(Archive), ok. @@ -555,11 +514,41 @@ virtual_dir_in_archive(Config) when is_list(Config) -> ?line {ok, [EbinBase]} = erl_prim_loader:list_dir(AppDir), %% Cleanup - ?line ok = erl_prim_loader:release_archives(), + ok = erl_prim_loader:purge_archive_cache(), ?line ok = file:delete(Archive), ok. -%% Misc. functions +%%% +%%% Helper functions. +%%% + +complete_start_node(Name) -> + BootPid = start_boot_server(), + Node = start_node_using_inet(Name), + wait_really_started(Node, 25), + {ok, Node, BootPid}. + +start_boot_server() -> + %% Many linux systems define: + %% 127.0.0.1 localhost + %% 127.0.1.1 somehostname + %% Therefore, to allow the tests to work on those kind of systems, + %% also include "localhost" in the list of allowed hosts. + + Hosts = [host(),ip_str("localhost")], + {ok,BootPid} = erl_boot_server:start_link(Hosts), + BootPid. + +start_node_using_inet(Name) -> + start_node_using_inet(Name, []). + +start_node_using_inet(Name, Opts) -> + Host = host(), + IpStr = ip_str(Host), + Args = " -loader inet -hosts " ++ IpStr, + {ok,Node} = start_node(Name, Args, Opts), + Node. + ip_str({A, B, C, D}) -> lists:concat([A, ".", B, ".", C, ".", D]); @@ -585,9 +574,6 @@ host() -> stop_node(Node) -> test_server:stop_node(Node). -get_loader_flag(_) -> - " -loader inet ". - compile_app(TopDir, AppName) -> AppDir = filename:join([TopDir, AppName]), SrcDir = filename:join([AppDir, "src"]), diff --git a/lib/kernel/test/file_SUITE.erl b/lib/kernel/test/file_SUITE.erl index 09d9a45197..8f5027c91b 100644 --- a/lib/kernel/test/file_SUITE.erl +++ b/lib/kernel/test/file_SUITE.erl @@ -168,12 +168,7 @@ init_per_suite(Config) when is_list(Config) -> ok -> [{sasl,started}] end, - ok = case os:type() of - {ose,_} -> - ok; - _ -> - application:start(os_mon) - end, + application:start(os_mon), case os:type() of {win32, _} -> @@ -199,12 +194,7 @@ end_per_suite(Config) when is_list(Config) -> ok end, - case os:type() of - {ose,_} -> - ok; - _ -> - application:stop(os_mon) - end, + application:stop(os_mon), case proplists:get_value(sasl, Config) of started -> application:stop(sasl); @@ -889,10 +879,7 @@ open1(Config) when is_list(Config) -> ?line io:format(Fd1,Str,[]), ?line {ok,0} = ?FILE_MODULE:position(Fd1,bof), ?line Str = io:get_line(Fd1,''), - ?line case io:get_line(Fd2,'') of - Str -> Str; - eof -> Str - end, + ?line Str = io:get_line(Fd2,''), ?line ok = ?FILE_MODULE:close(Fd2), ?line {ok,0} = ?FILE_MODULE:position(Fd1,bof), ?line ok = ?FILE_MODULE:truncate(Fd1), @@ -2368,9 +2355,6 @@ e_rename(Config) when is_list(Config) -> %% At least Windows NT can %% successfully move a file to %% another drive. - ok; - {ose, _} -> - %% disabled for now ok end, [] = flush(), diff --git a/lib/kernel/test/file_name_SUITE.erl b/lib/kernel/test/file_name_SUITE.erl index 32006d893e..4c422c9e0a 100644 --- a/lib/kernel/test/file_name_SUITE.erl +++ b/lib/kernel/test/file_name_SUITE.erl @@ -159,7 +159,7 @@ normalize(suite) -> normalize(doc) -> ["Check that filename normalization works"]; normalize(Config) when is_list(Config) -> - random:seed({1290,431421,830412}), + rand:seed(exsplus, {1290,431421,830412}), try ?line UniMode = file:native_name_encoding() =/= latin1, if @@ -845,7 +845,7 @@ conv(L) -> rand_comp_decomp(Max) -> - N = random:uniform(Max), + N = rand:uniform(Max), L = [ rand_decomp() || _ <- lists:seq(1,N) ], LC = [ A || {A,_} <- L], LD = lists:flatten([B || {_,B} <- L]), @@ -855,7 +855,7 @@ rand_comp_decomp(Max) -> rand_decomp() -> BT = bigtup(), SZ = tuple_size(BT), - element(random:uniform(SZ),BT). + element(rand:uniform(SZ),BT). bigtup() -> {{192,[65,768]}, {200,[69,768]}, diff --git a/lib/kernel/test/gen_tcp_echo_SUITE.erl b/lib/kernel/test/gen_tcp_echo_SUITE.erl index 6dcb21758b..b5ed16ec34 100644 --- a/lib/kernel/test/gen_tcp_echo_SUITE.erl +++ b/lib/kernel/test/gen_tcp_echo_SUITE.erl @@ -442,14 +442,7 @@ random_char(Chars) -> lists:nth(uniform(length(Chars)), Chars). uniform(N) -> - case get(random_seed) of - undefined -> - {X, Y, Z} = time(), - random:seed(X, Y, Z); - _ -> - ok - end, - random:uniform(N). + rand:uniform(N). put_int32(X, big, List) -> [ (X bsr 24) band 16#ff, diff --git a/lib/kernel/test/gen_tcp_misc_SUITE.erl b/lib/kernel/test/gen_tcp_misc_SUITE.erl index 81c6dcd0fd..3adca83ec9 100644 --- a/lib/kernel/test/gen_tcp_misc_SUITE.erl +++ b/lib/kernel/test/gen_tcp_misc_SUITE.erl @@ -58,14 +58,6 @@ oct_acceptor/1, otp_7731_server/1, zombie_server/2, do_iter_max_socks/2]). -init_per_testcase(wrapping_oct, Config) when is_list(Config) -> - Dog = case os:type() of - {ose,_} -> - test_server:timetrap(test_server:minutes(20)); - _Else -> - test_server:timetrap(test_server:seconds(600)) - end, - [{watchdog, Dog}|Config]; init_per_testcase(iter_max_socks, Config) when is_list(Config) -> Dog = case os:type() of {win32,_} -> @@ -74,14 +66,6 @@ init_per_testcase(iter_max_socks, Config) when is_list(Config) -> test_server:timetrap(test_server:seconds(240)) end, [{watchdog, Dog}|Config]; -init_per_testcase(accept_system_limit, Config) when is_list(Config) -> - case os:type() of - {ose,_} -> - {skip,"Skip in OSE"}; - _ -> - Dog = test_server:timetrap(test_server:seconds(240)), - [{watchdog,Dog}|Config] - end; init_per_testcase(wrapping_oct, Config) when is_list(Config) -> Dog = test_server:timetrap(test_server:seconds(600)), [{watchdog, Dog}|Config]; diff --git a/lib/kernel/test/global_SUITE.erl b/lib/kernel/test/global_SUITE.erl index 73ee86eba4..c0e24e17fe 100644 --- a/lib/kernel/test/global_SUITE.erl +++ b/lib/kernel/test/global_SUITE.erl @@ -2931,7 +2931,7 @@ sync_until(LogFile) -> timer:sleep(Time). shuffle(L) -> - [E || {_, E} <- lists:keysort(1, [{random:uniform(), E} || E <- L])]. + [E || {_, E} <- lists:keysort(1, [{rand:uniform(), E} || E <- L])]. sync_0(suite) -> []; sync_0(doc) -> diff --git a/lib/kernel/test/inet_SUITE.erl b/lib/kernel/test/inet_SUITE.erl index 5ba06bb032..d64a52fc2c 100644 --- a/lib/kernel/test/inet_SUITE.erl +++ b/lib/kernel/test/inet_SUITE.erl @@ -868,7 +868,6 @@ gethostnative_control_2(Seq, Interval, Delay, Cnt, N, Hosts) -> ?line Lookupers = [spawn_link( fun () -> - random:seed(), lookup_loop(Hosts, Delay, Tag, Parent, Cnt, Hosts) end) || _ <- lists:seq(1, N)], @@ -929,7 +928,7 @@ lookup_loop([H|Hs], Delay, Tag, Parent, Cnt, Hosts) -> Parent ! {Tag,Error} end, receive - after random:uniform(Delay) -> + after rand:uniform(Delay) -> lookup_loop(Hs, Delay, Tag, Parent, Cnt-1, Hosts) end. diff --git a/lib/kernel/test/inet_res_SUITE.erl b/lib/kernel/test/inet_res_SUITE.erl index ace4ccb8bd..6e575c2f95 100644 --- a/lib/kernel/test/inet_res_SUITE.erl +++ b/lib/kernel/test/inet_res_SUITE.erl @@ -120,7 +120,7 @@ ns_init(ZoneDir, PrivDir, DataDir) -> {unix,_} -> PortNum = case {os:type(),os:version()} of {{unix,solaris},{M,V,_}} when M =< 5, V < 10 -> - 11895 + random:uniform(100); + 11895 + rand:uniform(100); _ -> {ok,S} = gen_udp:open(0, [{reuseaddr,true}]), {ok,PNum} = inet:port(S), diff --git a/lib/kernel/test/init_SUITE.erl b/lib/kernel/test/init_SUITE.erl index 54ab5aa566..f90eb69ef1 100644 --- a/lib/kernel/test/init_SUITE.erl +++ b/lib/kernel/test/init_SUITE.erl @@ -307,8 +307,8 @@ create_boot(Config) -> is_real_system(KernelVsn, StdlibVsn) -> LibDir = code:lib_dir(), - filelib:is_dir(filename:join(LibDir, "kernel"++KernelVsn)) andalso - filelib:is_dir(filename:join(LibDir, "stdlib"++StdlibVsn)). + filelib:is_dir(filename:join(LibDir, "kernel-"++KernelVsn)) andalso + filelib:is_dir(filename:join(LibDir, "stdlib-"++StdlibVsn)). %% ------------------------------------------------ %% Slave executes erlang:halt() on master nodedown. @@ -401,6 +401,7 @@ restart(Config) when is_list(Config) -> %% Ok, the node is up, now the real test test begins. ?line erlang:monitor_node(Node, true), ?line InitPid = rpc:call(Node, erlang, whereis, [init]), + ?line PurgerPid = rpc:call(Node, erlang, whereis, [erts_code_purger]), ?line Procs = rpc:call(Node, erlang, processes, []), ?line MaxPid = lists:last(Procs), ?line ok = rpc:call(Node, init, restart, []), @@ -418,8 +419,13 @@ restart(Config) when is_list(Config) -> InitP = pid_to_list(InitPid), ?line InitP = pid_to_list(InitPid1), + %% and same purger process! + ?line PurgerPid1 = rpc:call(Node, erlang, whereis, [erts_code_purger]), + PurgerP = pid_to_list(PurgerPid), + ?line PurgerP = pid_to_list(PurgerPid1), + ?line NewProcs0 = rpc:call(Node, erlang, processes, []), - NewProcs = lists:delete(InitPid1, NewProcs0), + NewProcs = NewProcs0 -- [InitPid1, PurgerPid1], ?line case check_processes(NewProcs, MaxPid) of true -> ok; diff --git a/lib/kernel/test/os_SUITE.erl b/lib/kernel/test/os_SUITE.erl index 29d8d10262..e6e8568394 100644 --- a/lib/kernel/test/os_SUITE.erl +++ b/lib/kernel/test/os_SUITE.erl @@ -20,9 +20,11 @@ -module(os_SUITE). -export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1, - init_per_group/2,end_per_group/2]). + init_per_group/2,end_per_group/2, + init_per_testcase/2,end_per_testcase/2]). -export([space_in_cwd/1, quoting/1, cmd_unicode/1, space_in_name/1, bad_command/1, - find_executable/1, unix_comment_in_command/1, deep_list_command/1, evil/1]). + find_executable/1, unix_comment_in_command/1, deep_list_command/1, + large_output_command/1, perf_counter_api/1]). -include_lib("test_server/include/test_server.hrl"). @@ -30,7 +32,8 @@ suite() -> [{ct_hooks,[ts_install_cth]}]. all() -> [space_in_cwd, quoting, cmd_unicode, space_in_name, bad_command, - find_executable, unix_comment_in_command, deep_list_command, evil]. + find_executable, unix_comment_in_command, deep_list_command, + large_output_command, perf_counter_api]. groups() -> []. @@ -47,6 +50,11 @@ init_per_group(_GroupName, Config) -> end_per_group(_GroupName, Config) -> Config. +init_per_testcase(_TC,Config) -> + Config. + +end_per_testcase(_,_Config) -> + ok. space_in_cwd(doc) -> "Test that executing a command in a current working directory " @@ -267,50 +275,48 @@ deep_list_command(Config) when is_list(Config) -> %% FYI: [$e, $c, "ho"] =:= io_lib:format("ec~s", ["ho"]) ok. - --define(EVIL_PROCS, 100). --define(EVIL_LOOPS, 100). --define(PORT_CREATOR, os_cmd_port_creator). -evil(Config) when is_list(Config) -> - Dog = test_server:timetrap(test_server:minutes(5)), - Parent = self(), - Ps = lists:map(fun (N) -> - spawn_link(fun () -> - evil_loop(Parent, ?EVIL_LOOPS,N) - end) - end, lists:seq(1, ?EVIL_PROCS)), - Devil = spawn_link(fun () -> devil(hd(Ps), hd(lists:reverse(Ps))) end), - lists:foreach(fun (P) -> receive {P, done} -> ok end end, Ps), - unlink(Devil), - exit(Devil, kill), - test_server:timetrap_cancel(Dog), - ok. - -devil(P1, P2) -> - erlang:display({?PORT_CREATOR, whereis(?PORT_CREATOR)}), - (catch ?PORT_CREATOR ! lists:seq(1,1000000)), - (catch ?PORT_CREATOR ! lists:seq(1,666)), - (catch ?PORT_CREATOR ! grrrrrrrrrrrrrrrr), - (catch ?PORT_CREATOR ! {'EXIT', P1, buhuuu}), - (catch ?PORT_CREATOR ! {'EXIT', hd(erlang:ports()), buhuuu}), - (catch ?PORT_CREATOR ! {'EXIT', P2, arggggggg}), - receive after 500 -> ok end, - (catch exit(whereis(?PORT_CREATOR), kill)), - (catch ?PORT_CREATOR ! ">8|"), - receive after 500 -> ok end, - (catch exit(whereis(?PORT_CREATOR), diiiiiiiiiiiiiiiiiiiie)), - receive after 100 -> ok end, - devil(P1, P2). - -evil_loop(Parent, Loops, N) -> - Res = integer_to_list(N), - evil_loop(Parent, Loops, Res, "echo " ++ Res). - -evil_loop(Parent, 0, _Res, _Cmd) -> - Parent ! {self(), done}; -evil_loop(Parent, Loops, Res, Cmd) -> - comp(Res, os:cmd(Cmd)), - evil_loop(Parent, Loops-1, Res, Cmd). +large_output_command(doc) -> + "Test to take sure that the correct data is" + "received when doing large commands"; +large_output_command(suite) -> []; +large_output_command(Config) when is_list(Config) -> + %% Maximum allowed on windows is 8192, so we test well below that + AAA = lists:duplicate(7000, $a), + comp(AAA,os:cmd("echo " ++ AAA)). + +%% Test that the os:perf_counter api works as expected +perf_counter_api(_Config) -> + + true = is_integer(os:perf_counter()), + true = os:perf_counter() > 0, + + T1 = os:perf_counter(), + timer:sleep(100), + T2 = os:perf_counter(), + TsDiff = erlang:convert_time_unit(T2 - T1, perf_counter, nano_seconds), + ct:pal("T1: ~p~n" + "T2: ~p~n" + "TsDiff: ~p~n", + [T1,T2,TsDiff]), + + %% We allow a 15% diff + true = TsDiff < 115000000, + true = TsDiff > 85000000, + + T1Ms = os:perf_counter(1000), + timer:sleep(100), + T2Ms = os:perf_counter(1000), + MsDiff = T2Ms - T1Ms, + ct:pal("T1Ms: ~p~n" + "T2Ms: ~p~n" + "MsDiff: ~p~n", + [T1Ms,T2Ms,MsDiff]), + + %% We allow a 15% diff + true = MsDiff < 115, + true = MsDiff > 85. + +%% Util functions comp(Expected, Got) -> case strip_nl(Got) of diff --git a/lib/kernel/test/pdict_SUITE.erl b/lib/kernel/test/pdict_SUITE.erl index 6de4ff9f77..b096296fa1 100644 --- a/lib/kernel/test/pdict_SUITE.erl +++ b/lib/kernel/test/pdict_SUITE.erl @@ -32,6 +32,7 @@ -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, 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]). @@ -47,7 +48,8 @@ end_per_testcase(_Case, Config) -> suite() -> [{ct_hooks,[ts_install_cth]}]. all() -> - [simple, complicated, heavy, simple_all_keys, info]. + [simple, complicated, heavy, simple_all_keys, info, + mixed]. groups() -> []. @@ -369,3 +371,60 @@ match_keys(All) -> Ks = lists:sort([K||{K,_}<-All]), Ks = lists:sort(erlang:get_keys()), ok. + + +%% Do random mixed put/erase to test grow/shrink +%% Written for a temporary bug in gc during shrink +mixed(_Config) -> + Rand0 = rand:seed_s(exsplus), + io:format("Random seed = ~p\n\n", [rand:export_seed_s(Rand0)]), + + erts_debug:set_internal_state(available_internal_state, true), + try + C = do_mixed([10,0,100,50,1000,500,600,100,150,1,11,2,30,0], + 0, + array:new(), + 1, + Rand0), + io:format("\nDid total of ~p operations\n", [C]) + after + erts_debug:set_internal_state(available_internal_state, false) + end. + +do_mixed([], _, _, C, _) -> + C; +do_mixed([GoalN | Tail], GoalN, Array, C, Rand0) -> + io:format("Reached goal of ~p keys in dict after ~p mixed ops\n",[GoalN, C]), + GoalN = array:size(Array), + do_mixed(Tail, GoalN, Array, C, Rand0); +do_mixed([GoalN | _]=Goals, CurrN, Array0, C, Rand0) -> + CurrN = array:size(Array0), + GrowPercent = case GoalN > CurrN of + true when CurrN == 0 -> 100; + true -> 75; + false -> 25 + end, + {R, Rand1} = rand:uniform_s(100, Rand0), + case R of + _ when R =< GrowPercent -> %%%%%%%%%%%%% GROW + {Key, Rand2} = rand:uniform_s(10000, Rand1), + case put(Key, {Key,C}) of + undefined -> + Array1 = array:set(CurrN, Key, Array0), + do_mixed(Goals, CurrN+1, Array1, C+1, Rand2); + _ -> + do_mixed(Goals, CurrN, Array0, C+1, Rand2) + end; + + _ -> %%%%%%%%%% SHRINK + {Kix, Rand2} = rand:uniform_s(CurrN, Rand1), + Key = array:get(Kix-1, Array0), + + %% provoke GC during shrink + erts_debug:set_internal_state(fill_heap, true), + + {Key, _} = erase(Key), + Array1 = array:set(Kix-1, array:get(CurrN-1, Array0), Array0), + Array2 = array:resize(CurrN-1, Array1), + do_mixed(Goals, CurrN-1, Array2, C+1, Rand2) + end. diff --git a/lib/kernel/test/prim_file_SUITE.erl b/lib/kernel/test/prim_file_SUITE.erl index 3e6d8492f7..366231d2cc 100644 --- a/lib/kernel/test/prim_file_SUITE.erl +++ b/lib/kernel/test/prim_file_SUITE.erl @@ -455,10 +455,7 @@ open1(Config) when is_list(Config) -> ?line ?PRIM_FILE:write(Fd1,Str), ?line {ok,0} = ?PRIM_FILE:position(Fd1,bof), ?line {ok, Str} = ?PRIM_FILE:read(Fd1,Length), - ?line case ?PRIM_FILE:read(Fd2,Length) of - {ok,Str} -> Str; - eof -> Str - end, + ?line {ok, Str} = ?PRIM_FILE:read(Fd2,Length), ?line ok = ?PRIM_FILE:close(Fd2), ?line {ok,0} = ?PRIM_FILE:position(Fd1,bof), ?line ok = ?PRIM_FILE:truncate(Fd1), @@ -1629,7 +1626,7 @@ e_rename(Config) when is_list(Config) -> %% successfully move a file to %% another drive. ok; - {unix, _ } -> + _ -> OtherFs = "/tmp", ?line NameOnOtherFs = filename:join(OtherFs, @@ -1653,10 +1650,7 @@ e_rename(Config) when is_list(Config) -> Else -> Else end, - Com; - {ose, _} -> - %% disabled for now - ok + Com end, ?line test_server:timetrap_cancel(Dog), Comment. diff --git a/lib/kernel/test/zlib_SUITE.erl b/lib/kernel/test/zlib_SUITE.erl index 6aaa024a82..77fdabe73c 100644 --- a/lib/kernel/test/zlib_SUITE.erl +++ b/lib/kernel/test/zlib_SUITE.erl @@ -912,7 +912,7 @@ smp(Config) -> FnAList = lists:map(fun(F) -> {F,?MODULE:F({get_arg,Config})} end, Funcs), - Pids = [spawn_link(?MODULE, worker, [random:uniform(9999), + Pids = [spawn_link(?MODULE, worker, [rand:uniform(9999), list_to_tuple(FnAList), self()]) || _ <- lists:seq(1,NumOfProcs)], @@ -925,7 +925,7 @@ smp(Config) -> worker(Seed, FnATpl, Parent) -> io:format("smp worker ~p, seed=~p~n",[self(),Seed]), - random:seed(Seed,Seed,Seed), + rand:seed(exsplus, {Seed,Seed,Seed}), worker_loop(100, FnATpl), Parent ! self(). @@ -933,7 +933,7 @@ worker_loop(0, _FnATpl) -> large_deflate_do(), % the time consuming one as finale ok; worker_loop(N, FnATpl) -> - {F,A} = element(random:uniform(size(FnATpl)),FnATpl), + {F,A} = element(rand:uniform(tuple_size(FnATpl)), FnATpl), ?MODULE:F(A), worker_loop(N-1, FnATpl). |