aboutsummaryrefslogtreecommitdiffstats
path: root/lib/kernel/src
diff options
context:
space:
mode:
Diffstat (limited to 'lib/kernel/src')
-rw-r--r--lib/kernel/src/code.erl45
-rw-r--r--lib/kernel/src/code_server.erl556
-rw-r--r--lib/kernel/src/erts_debug.erl17
-rw-r--r--lib/kernel/src/file_io_server.erl122
-rw-r--r--lib/kernel/src/global.erl20
-rw-r--r--lib/kernel/src/inet.erl14
-rw-r--r--lib/kernel/src/kernel.appup.src4
-rw-r--r--lib/kernel/src/os.erl191
8 files changed, 230 insertions, 739 deletions
diff --git a/lib/kernel/src/code.erl b/lib/kernel/src/code.erl
index 352c02562b..ae28c97b47 100644
--- a/lib/kernel/src/code.erl
+++ b/lib/kernel/src/code.erl
@@ -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").
@@ -293,7 +295,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).
@@ -322,6 +326,7 @@ start_link(Flags) ->
%%-----------------------------------------------------------------
do_start(Flags) ->
+ maybe_warn_for_cache(),
load_code_server_prerequisites(),
Mode = get_mode(Flags),
@@ -452,30 +457,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(),
@@ -553,6 +542,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 e461c95d19..3fbbb98b94 100644
--- a/lib/kernel/src/code_server.erl
+++ b/lib/kernel/src/code_server.erl
@@ -40,7 +40,6 @@
path,
moddb,
namedb,
- cache = no_cache,
mode = interactive,
on_load = []}).
-type state() :: #state{}.
@@ -89,19 +88,11 @@ 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{root = Root,
+ path = Path,
+ moddb = Db,
+ namedb = init_namedb(Path),
+ mode = Mode},
put(?ANY_NATIVE_CODE_LOADED, false),
@@ -255,59 +246,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 +286,7 @@ handle_call({load_abs,File,Mod}, Caller, S) ->
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 +302,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({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({purge,Mod0}, {_From,_Tag}, St0) ->
- do_mod_call(fun (M, St) ->
- {reply,do_purge(M),St}
- end, Mod0, false, St0);
+handle_call({purge,Mod}, {_From,_Tag}, St) when is_atom(Mod) ->
+ {reply,do_purge(Mod),St};
-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({soft_purge,Mod}, {_From,_Tag}, St) when is_atom(Mod) ->
+ {reply,do_soft_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({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 +348,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 +356,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 +363,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 +1060,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,
@@ -1238,21 +1091,10 @@ load_abs(File, Mod0, 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.
@@ -1271,9 +1113,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);
@@ -1296,26 +1139,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,_} ->
@@ -1338,37 +1161,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);
@@ -1421,243 +1229,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
@@ -1665,6 +1236,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.
%% -------------------------------------------------------
@@ -1779,6 +1358,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/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/file_io_server.erl b/lib/kernel/src/file_io_server.erl
index bf8b9e2747..deb7b315b1 100644
--- a/lib/kernel/src/file_io_server.erl
+++ b/lib/kernel/src/file_io_server.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2000-2013. All Rights Reserved.
+%% Copyright Ericsson AB 2000-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.
@@ -206,8 +206,8 @@ io_reply(From, ReplyAs, Reply) ->
file_request({advise,Offset,Length,Advise},
#state{handle=Handle}=State) ->
case ?PRIM_FILE:advise(Handle, Offset, Length, Advise) of
- {error,_}=Reply ->
- {stop,normal,Reply,State};
+ {error,Reason}=Reply ->
+ {stop,Reason,Reply,State};
Reply ->
{reply,Reply,State}
end;
@@ -215,62 +215,91 @@ file_request({allocate, Offset, Length},
#state{handle = Handle} = State) ->
Reply = ?PRIM_FILE:allocate(Handle, Offset, Length),
{reply, Reply, State};
+file_request({pread,At,Sz}, State)
+ when At =:= cur;
+ At =:= {cur,0} ->
+ case get_chars(Sz, latin1, State) of
+ {reply,Reply,NewState}
+ when is_list(Reply);
+ is_binary(Reply) ->
+ {reply,{ok,Reply},NewState};
+ Other ->
+ Other
+ end;
file_request({pread,At,Sz},
- #state{handle=Handle,buf=Buf,read_mode=ReadMode}=State) ->
+ #state{handle=Handle,buf=Buf}=State) ->
case position(Handle, At, Buf) of
- {ok,_Offs} ->
- case ?PRIM_FILE:read(Handle, Sz) of
- {ok,Bin} when ReadMode =:= list ->
- std_reply({ok,binary_to_list(Bin)}, State);
- Reply ->
- std_reply(Reply, State)
- end;
- Reply ->
- std_reply(Reply, State)
+ {error,_} = Reply ->
+ {error,Reply,State};
+ _ ->
+ case get_chars(Sz, latin1, State#state{buf= <<>>}) of
+ {reply,Reply,NewState}
+ when is_list(Reply);
+ is_binary(Reply) ->
+ {reply,{ok,Reply},NewState};
+ Other ->
+ Other
+ end
end;
+file_request({pwrite,At,Data},
+ #state{buf= <<>>}=State)
+ when At =:= cur;
+ At =:= {cur,0} ->
+ put_chars(Data, latin1, State);
file_request({pwrite,At,Data},
#state{handle=Handle,buf=Buf}=State) ->
case position(Handle, At, Buf) of
- {ok,_Offs} ->
- std_reply(?PRIM_FILE:write(Handle, Data), State);
- Reply ->
- std_reply(Reply, State)
+ {error,_} = Reply ->
+ {error,Reply,State};
+ _ ->
+ put_chars(Data, latin1, State)
end;
file_request(datasync,
#state{handle=Handle}=State) ->
case ?PRIM_FILE:datasync(Handle) of
- {error,_}=Reply ->
- {stop,normal,Reply,State};
+ {error,Reason}=Reply ->
+ {stop,Reason,Reply,State};
Reply ->
{reply,Reply,State}
end;
file_request(sync,
#state{handle=Handle}=State) ->
case ?PRIM_FILE:sync(Handle) of
- {error,_}=Reply ->
- {stop,normal,Reply,State};
+ {error,Reason}=Reply ->
+ {stop,Reason,Reply,State};
Reply ->
{reply,Reply,State}
end;
file_request(close,
#state{handle=Handle}=State) ->
- {stop,normal,?PRIM_FILE:close(Handle),State#state{buf= <<>>}};
+ case ?PRIM_FILE:close(Handle) of
+ {error,Reason}=Reply ->
+ {stop,Reason,Reply,State#state{buf= <<>>}};
+ Reply ->
+ {stop,normal,Reply,State#state{buf= <<>>}}
+ end;
file_request({position,At},
#state{handle=Handle,buf=Buf}=State) ->
- std_reply(position(Handle, At, Buf), State);
+ case position(Handle, At, Buf) of
+ {error,_} = Reply ->
+ {error,Reply,State};
+ Reply ->
+ std_reply(Reply, State)
+ end;
file_request(truncate,
#state{handle=Handle}=State) ->
case ?PRIM_FILE:truncate(Handle) of
- {error,_Reason}=Reply ->
- {stop,normal,Reply,State#state{buf= <<>>}};
+ {error,Reason}=Reply ->
+ {stop,Reason,Reply,State#state{buf= <<>>}};
Reply ->
- {reply,Reply,State}
+ std_reply(Reply, State)
end;
file_request(Unknown,
#state{}=State) ->
Reason = {request, Unknown},
{error,{error,Reason},State}.
+%% Standard reply and clear buffer
std_reply({error,_}=Reply, State) ->
{error,Reply,State#state{buf= <<>>}};
std_reply(Reply, State) ->
@@ -286,8 +315,8 @@ io_request({put_chars, Enc, Chars},
io_request({put_chars, Enc, Chars},
#state{handle=Handle,buf=Buf}=State) ->
case position(Handle, cur, Buf) of
- {error,_}=Reply ->
- {stop,normal,Reply,State#state{buf= <<>>}};
+ {error,Reason}=Reply ->
+ {stop,Reason,Reply,State};
_ ->
put_chars(Chars, Enc, State#state{buf= <<>>})
end;
@@ -368,23 +397,27 @@ io_request_loop([Request|Tail],
%% I/O request put_chars
%%
put_chars(Chars, latin1, #state{handle=Handle, unic=latin1}=State) ->
+ NewState = State#state{buf = <<>>},
case ?PRIM_FILE:write(Handle, Chars) of
- {error,_}=Reply ->
- {stop,normal,Reply,State};
+ {error,Reason}=Reply ->
+ {stop,Reason,Reply,NewState};
Reply ->
- {reply,Reply,State}
+ {reply,Reply,NewState}
end;
put_chars(Chars, InEncoding, #state{handle=Handle, unic=OutEncoding}=State) ->
+ NewState = State#state{buf = <<>>},
case unicode:characters_to_binary(Chars,InEncoding,OutEncoding) of
Bin when is_binary(Bin) ->
case ?PRIM_FILE:write(Handle, Bin) of
- {error,_}=Reply ->
- {stop,normal,Reply,State};
+ {error,Reason}=Reply ->
+ {stop,Reason,Reply,NewState};
Reply ->
- {reply,Reply,State}
+ {reply,Reply,NewState}
end;
{error,_,_} ->
- {stop,normal,{error,{no_translation, InEncoding, OutEncoding}},State}
+ {stop,no_translation,
+ {error,{no_translation, InEncoding, OutEncoding}},
+ NewState}
end.
get_line(S, {<<>>, Cont}, OutEnc,
@@ -884,11 +917,14 @@ cbv({utf32,little},_) ->
%% Compensates ?PRIM_FILE:position/2 for the number of bytes
%% we have buffered
-
-position(Handle, cur, Buf) ->
- position(Handle, {cur, 0}, Buf);
-position(Handle, {cur, Offs}, Buf) when is_binary(Buf) ->
- ?PRIM_FILE:position(Handle, {cur, Offs-byte_size(Buf)});
-position(Handle, At, _Buf) ->
- ?PRIM_FILE:position(Handle, At).
-
+position(Handle, At, Buf) ->
+ ?PRIM_FILE:position(
+ Handle,
+ case At of
+ cur ->
+ {cur, -byte_size(Buf)};
+ {cur, Offs} ->
+ {cur, Offs-byte_size(Buf)};
+ _ ->
+ At
+ end).
diff --git a/lib/kernel/src/global.erl b/lib/kernel/src/global.erl
index dcabeb5e49..0c73ead7c5 100644
--- a/lib/kernel/src/global.erl
+++ b/lib/kernel/src/global.erl
@@ -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/inet.erl b/lib/kernel/src/inet.erl
index 855c6377a3..b573112445 100644
--- a/lib/kernel/src/inet.erl
+++ b/lib/kernel/src/inet.erl
@@ -692,6 +692,7 @@ connect_options(Opts, Family) ->
case con_opt(Opts, BaseOpts, connect_options()) of
{ok, R} ->
{ok, R#connect_opts {
+ opts = lists:reverse(R#connect_opts.opts),
ifaddr = translate_ip(R#connect_opts.ifaddr, Family)
}};
Error -> Error
@@ -762,6 +763,7 @@ listen_options(Opts, Family) ->
case list_opt(Opts, BaseOpts, listen_options()) of
{ok, R} ->
{ok, R#listen_opts {
+ opts = lists:reverse(R#listen_opts.opts),
ifaddr = translate_ip(R#listen_opts.ifaddr, Family)
}};
Error -> Error
@@ -820,6 +822,7 @@ udp_options(Opts, Family) ->
case udp_opt(Opts, #udp_opts { }, udp_options()) of
{ok, R} ->
{ok, R#udp_opts {
+ opts = lists:reverse(R#udp_opts.opts),
ifaddr = translate_ip(R#udp_opts.ifaddr, Family)
}};
Error -> Error
@@ -893,9 +896,12 @@ sctp_options() ->
sctp_options(Opts, Mod) ->
case sctp_opt(Opts, Mod, #sctp_opts{}, sctp_options()) of
{ok,#sctp_opts{ifaddr=undefined}=SO} ->
- {ok,SO#sctp_opts{ifaddr=Mod:translate_ip(?SCTP_DEF_IFADDR)}};
- {ok,_}=OK ->
- OK;
+ {ok,
+ SO#sctp_opts{
+ opts=lists:reverse(SO#sctp_opts.opts),
+ ifaddr=Mod:translate_ip(?SCTP_DEF_IFADDR)}};
+ {ok,SO} ->
+ {ok,SO#sctp_opts{opts=lists:reverse(SO#sctp_opts.opts)}};
Error -> Error
end.
@@ -967,6 +973,8 @@ add_opt(Name, Val, Opts, As) ->
case lists:member(Name, As) of
true ->
case prim_inet:is_sockopt_val(Name, Val) of
+ true when Name =:= raw ->
+ {ok, [{Name,Val} | Opts]};
true ->
Opts1 = lists:keydelete(Name, 1, Opts),
{ok, [{Name,Val} | Opts1]};
diff --git a/lib/kernel/src/kernel.appup.src b/lib/kernel/src/kernel.appup.src
index 3fda55d1a9..860d3640d0 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
- [{<<"4\\.0(\\.[0-9]+)*">>,[restart_new_emulator]}, % OTP-18.0.*
+ [{<<"4\\.[0-1](\\.[0-9]+)*">>,[restart_new_emulator]}, % OTP-18.*
{<<"3\\.[0-2](\\.[0-9]+)*">>,[restart_new_emulator]}], % OTP-17
%% Down to - max one major revision back
- [{<<"4\\.0(\\.[0-9]+)*">>,[restart_new_emulator]}, % OTP-18.0.*
+ [{<<"4\\.[0-1](\\.[0-9]+)*">>,[restart_new_emulator]}, % OTP-18.*
{<<"3\\.[0-2](\\.[0-9]+)*">>,[restart_new_emulator]}] % OTP-17
}.
diff --git a/lib/kernel/src/os.erl b/lib/kernel/src/os.erl
index ffb899e5ca..0022959c11 100644
--- a/lib/kernel/src/os.erl
+++ b/lib/kernel/src/os.erl
@@ -212,174 +212,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
+ true -> binary_to_list(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)
- 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 +256,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 +269,5 @@ get_data(Port, Sofar) ->
after 1 -> % force context switch
ok
end,
- lists:flatten(Sofar)
+ iolist_to_binary(Sofar)
end.