diff options
Diffstat (limited to 'lib/kernel/src')
27 files changed, 519 insertions, 313 deletions
diff --git a/lib/kernel/src/Makefile b/lib/kernel/src/Makefile index 9db6014a7d..54f21eb2b8 100644 --- a/lib/kernel/src/Makefile +++ b/lib/kernel/src/Makefile @@ -1,7 +1,7 @@ # # %CopyrightBegin% # -# Copyright Ericsson AB 1996-2010. All Rights Reserved. +# Copyright Ericsson AB 1996-2011. All Rights Reserved. # # The contents of this file are subject to the Erlang Public License, # Version 1.1, (the "License"); you may not use this file except in @@ -118,11 +118,14 @@ MODULES = \ user_sup \ wrap_log_reader -HRL_FILES= ../include/file.hrl ../include/inet.hrl ../include/inet_sctp.hrl +HRL_FILES= ../include/file.hrl ../include/inet.hrl ../include/inet_sctp.hrl \ + ../include/dist.hrl ../include/dist_util.hrl \ + ../include/net_address.hrl + INTERNAL_HRL_FILES= application_master.hrl disk_log.hrl \ - net_address.hrl inet_dns.hrl inet_res.hrl \ + inet_dns.hrl inet_res.hrl \ inet_boot.hrl inet_config.hrl inet_int.hrl \ - dist.hrl dist_util.hrl inet_dns_record_adts.hrl + inet_dns_record_adts.hrl ERL_FILES= $(MODULES:%=%.erl) @@ -215,7 +218,7 @@ $(EBIN)/code_server.beam: ../include/file.hrl $(EBIN)/disk_log.beam: disk_log.hrl $(EBIN)/disk_log_1.beam: disk_log.hrl ../include/file.hrl $(EBIN)/disk_log_server.beam: disk_log.hrl -$(EBIN)/dist_util.beam: dist_util.hrl dist.hrl +$(EBIN)/dist_util.beam: ../include/dist_util.hrl ../include/dist.hrl $(EBIN)/erl_boot_server.beam: inet_boot.hrl $(EBIN)/erl_epmd.beam: inet_int.hrl erl_epmd.hrl $(EBIN)/file.beam: ../include/file.hrl @@ -226,7 +229,7 @@ $(EBIN)/global.beam: ../../stdlib/include/ms_transform.hrl $(EBIN)/hipe_unified_loader.beam: ../../hipe/main/hipe.hrl hipe_ext_format.hrl $(EBIN)/inet.beam: ../include/inet.hrl inet_int.hrl ../include/inet_sctp.hrl $(EBIN)/inet6_tcp.beam: inet_int.hrl -$(EBIN)/inet6_tcp_dist.beam: net_address.hrl dist.hrl dist_util.hrl +$(EBIN)/inet6_tcp_dist.beam: ../include/net_address.hrl ../include/dist.hrl ../include/dist_util.hrl $(EBIN)/inet6_udp.beam: inet_int.hrl $(EBIN)/inet6_sctp.beam: inet_int.hrl $(EBIN)/inet_config.beam: inet_config.hrl ../include/inet.hrl @@ -237,10 +240,10 @@ $(EBIN)/inet_hosts.beam: ../include/inet.hrl $(EBIN)/inet_parse.beam: ../include/file.hrl $(EBIN)/inet_res.beam: ../include/inet.hrl inet_res.hrl inet_dns.hrl inet_int.hrl $(EBIN)/inet_tcp.beam: inet_int.hrl -$(EBIN)/inet_udp_dist.beam: net_address.hrl dist.hrl dist_util.hrl +$(EBIN)/inet_udp_dist.beam: ../include/net_address.hrl ../include/dist.hrl ../include/dist_util.hrl $(EBIN)/inet_udp.beam: inet_int.hrl $(EBIN)/inet_sctp.beam: inet_int.hrl ../include/inet_sctp.hrl -$(EBIN)/net_kernel.beam: net_address.hrl +$(EBIN)/net_kernel.beam: ../include/net_address.hrl $(EBIN)/os.beam: ../include/file.hrl $(EBIN)/ram_file.beam: ../include/file.hrl $(EBIN)/wrap_log_reader.beam: disk_log.hrl ../include/file.hrl diff --git a/lib/kernel/src/application.erl b/lib/kernel/src/application.erl index fa3a4c3d36..c299fb085c 100644 --- a/lib/kernel/src/application.erl +++ b/lib/kernel/src/application.erl @@ -28,8 +28,6 @@ -export([get_application/0, get_application/1, info/0]). -export([start_type/0]). --export([behaviour_info/1]). - %%%----------------------------------------------------------------- -type start_type() :: 'normal' @@ -59,12 +57,12 @@ %%------------------------------------------------------------------ --spec behaviour_info(atom()) -> 'undefined' | [{atom(), byte()}]. +-callback start(StartType :: normal | {takeover, node()} | {failover, node()}, + StartArgs :: term()) -> + {'ok', pid()} | {'ok', pid(), State :: term()} | {'error', Reason :: term()}. -behaviour_info(callbacks) -> - [{start,2},{stop,1}]; -behaviour_info(_Other) -> - undefined. +-callback stop(State :: term()) -> + term(). %%%----------------------------------------------------------------- %%% This module is API towards application_controller and diff --git a/lib/kernel/src/application_controller.erl b/lib/kernel/src/application_controller.erl index 42f527f400..ebfe84463a 100644 --- a/lib/kernel/src/application_controller.erl +++ b/lib/kernel/src/application_controller.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2010. All Rights Reserved. +%% Copyright Ericsson AB 1996-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -1180,10 +1180,27 @@ terminate(Reason, S) -> _ -> ok end, + ShutdownTimeout = + case application:get_env(kernel, shutdown_timeout) of + undefined -> infinity; + {ok,T} -> T + end, foreach(fun({_AppName, Id}) when is_pid(Id) -> + Ref = erlang:monitor(process, Id), + unlink(Id), exit(Id, shutdown), receive + %% Proc died before link {'EXIT', Id, _} -> ok + after 0 -> + receive + {'DOWN', Ref, process, Id, _} -> ok + after ShutdownTimeout -> + exit(Id, kill), + receive + {'DOWN', Ref, process, Id, _} -> ok + end + end end; (_) -> ok end, diff --git a/lib/kernel/src/code.erl b/lib/kernel/src/code.erl index 882e9625fe..b7fda69ce0 100644 --- a/lib/kernel/src/code.erl +++ b/lib/kernel/src/code.erl @@ -324,15 +324,7 @@ start_link(Flags) -> %%----------------------------------------------------------------- do_start(Flags) -> - %% The following module_info/1 calls are here to ensure - %% that these modules are loaded prior to their use elsewhere in - %% the code_server. - %% Otherwise a deadlock may occur when the code_server is starting. - code_server = code_server:module_info(module), - packages = packages:module_info(module), - catch hipe_unified_loader:load_hipe_modules(), - Modules2 = [gb_sets, gb_trees, ets, os, binary, unicode, filename, lists], - lists:foreach(fun (M) -> M = M:module_info(module) end, Modules2), + load_code_server_prerequisites(), Mode = get_mode(Flags), case init:get_argument(root) of @@ -360,6 +352,25 @@ do_start(Flags) -> {error, crash} end. +%% Make sure that all modules that the code_server process calls +%% (directly or indirectly) are loaded. Otherwise the code_server +%% process will deadlock. + +load_code_server_prerequisites() -> + %% Please keep the alphabetical order. + Needed = [binary, + ets, + filename, + gb_sets, + gb_trees, + hipe_unified_loader, + lists, + os, + packages, + unicode], + [M = M:module_info(module) || M <- Needed], + ok. + do_stick_dirs() -> do_s(compiler), do_s(stdlib), diff --git a/lib/kernel/src/code_server.erl b/lib/kernel/src/code_server.erl index e3d22e7999..5d4f2eb70c 100644 --- a/lib/kernel/src/code_server.erl +++ b/lib/kernel/src/code_server.erl @@ -32,6 +32,8 @@ -import(lists, [foreach/2]). +-define(ANY_NATIVE_CODE_LOADED, any_native_code_loaded). + -record(state, {supervisor, root, path, @@ -97,6 +99,8 @@ init(Ref, Parent, [Root,Mode0]) -> State0 end, + put(?ANY_NATIVE_CODE_LOADED, false), + Parent ! {Ref,{ok,self()}}, loop(State#state{supervisor = Parent}). @@ -1278,35 +1282,56 @@ load_native_code(Mod, Bin) -> %% 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 -> hipe_unified_loader:load_native_code(Mod, Bin) + false -> + no_native; + true -> + Result = hipe_unified_loader:load_native_code(Mod, Bin), + case Result of + {module,_} -> + put(?ANY_NATIVE_CODE_LOADED, true); + _ -> + ok + end, + Result end. hipe_result_to_status(Result) -> case Result of - {module,_} -> Result; - _ -> {error,Result} + {module,_} -> + put(?ANY_NATIVE_CODE_LOADED, true), + Result; + _ -> + {error,Result} end. post_beam_load(Mod) -> - case erlang:module_loaded(hipe_unified_loader) of - false -> ok; - true -> hipe_unified_loader:post_beam_load(Mod) + %% post_beam_load/1 can potentially be very expensive because it + %% blocks multi-scheduling; thus we want to avoid the call if we + %% know that it is not needed. + case get(?ANY_NATIVE_CODE_LOADED) of + true -> hipe_unified_loader:post_beam_load(Mod); + false -> ok end. 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), + case pending_on_load(Mod, From, St0) of + no -> load_file_1(Mod, Caller, St0); + {yes,St} -> {noreply,St} + end. -load_file(Mod, Caller, #state{path=Path,cache=no_cache}=St) -> +load_file_1(Mod, Caller, #state{path=Path,cache=no_cache}=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(Mod, Caller, #state{cache=Cache}=St0) -> +load_file_1(Mod, Caller, #state{cache=Cache}=St0) -> Key = {obj,Mod}, case ets:lookup(Cache, Key) of [] -> diff --git a/lib/kernel/src/disk_log.erl b/lib/kernel/src/disk_log.erl index 9b8d2db437..fb9415d440 100644 --- a/lib/kernel/src/disk_log.erl +++ b/lib/kernel/src/disk_log.erl @@ -64,7 +64,7 @@ %%-define(PROFILE(C), C). -define(PROFILE(C), void). --compile({inline,[{log_loop,4},{log_end_sync,2},{replies,2},{rflat,1}]}). +-compile({inline,[{log_loop,5},{log_end_sync,2},{replies,2},{rflat,1}]}). %%%---------------------------------------------------------------------- %%% Contract type specifications @@ -685,7 +685,7 @@ handle({From, {log, B}}, S) -> L when L#log.mode =:= read_only -> reply(From, {error, {read_only_mode, L#log.name}}, S); L when L#log.status =:= ok, L#log.format =:= internal -> - log_loop(S, From, [B], []); + log_loop(S, From, [B], [], iolist_size(B)); L when L#log.status =:= ok, L#log.format =:= external -> reply(From, {error, {format_external, L#log.name}}, S); L when L#log.status =:= {blocked, false} -> @@ -700,7 +700,7 @@ handle({From, {blog, B}}, S) -> L when L#log.mode =:= read_only -> reply(From, {error, {read_only_mode, L#log.name}}, S); L when L#log.status =:= ok -> - log_loop(S, From, [B], []); + log_loop(S, From, [B], [], iolist_size(B)); L when L#log.status =:= {blocked, false} -> reply(From, {error, {blocked_log, L#log.name}}, S); L when L#log.blocked_by =:= From -> @@ -714,7 +714,7 @@ handle({alog, B}, S) -> notify_owners({read_only,B}), loop(S); L when L#log.status =:= ok, L#log.format =:= internal -> - log_loop(S, [], [B], []); + log_loop(S, [], [B], [], iolist_size(B)); L when L#log.status =:= ok -> notify_owners({format_external, B}), loop(S); @@ -730,7 +730,7 @@ handle({balog, B}, S) -> notify_owners({read_only,B}), loop(S); L when L#log.status =:= ok -> - log_loop(S, [], [B], []); + log_loop(S, [], [B], [], iolist_size(B)); L when L#log.status =:= {blocked, false} -> notify_owners({blocked_log, B}), loop(S); @@ -1029,38 +1029,42 @@ handle(_, S) -> loop(S). sync_loop(From, S) -> - log_loop(S, [], [], From). + log_loop(S, [], [], From, 0). + +-define(MAX_LOOK_AHEAD, 64*1024). %% Inlined. -log_loop(S, Pids, _Bins, _Sync) when S#state.cache_error =/= ok -> +log_loop(S, Pids, _Bins, _Sync, _Sz) when S#state.cache_error =/= ok -> loop(cache_error(S, Pids)); -log_loop(S, Pids, Bins, Sync) when S#state.messages =:= [] -> +log_loop(#state{messages = []}=S, Pids, Bins, Sync, Sz) + when Sz > ?MAX_LOOK_AHEAD -> + loop(log_end(S, Pids, Bins, Sync)); +log_loop(#state{messages = []}=S, Pids, Bins, Sync, Sz) -> receive Message -> - log_loop(Message, Pids, Bins, Sync, S, get(log)) + log_loop(Message, Pids, Bins, Sync, Sz, S, get(log)) after 0 -> loop(log_end(S, Pids, Bins, Sync)) end; -log_loop(S, Pids, Bins, Sync) -> +log_loop(S, Pids, Bins, Sync, Sz) -> [M | Ms] = S#state.messages, S1 = S#state{messages = Ms}, - log_loop(M, Pids, Bins, Sync, S1, get(log)). + log_loop(M, Pids, Bins, Sync, Sz, S1, get(log)). %% Items logged after the last sync request found are sync:ed as well. -log_loop({alog,B}, Pids, Bins, Sync, S, L) when L#log.format =:= internal -> +log_loop({alog,B}, Pids, Bins, Sync, Sz, S, #log{format = internal}) -> %% {alog, _} allowed for the internal format only. - log_loop(S, Pids, [B | Bins], Sync); -log_loop({balog, B}, Pids, Bins, Sync, S, _L) -> - log_loop(S, Pids, [B | Bins], Sync); -log_loop({From, {log, B}}, Pids, Bins, Sync, S, L) - when L#log.format =:= internal -> + log_loop(S, Pids, [B | Bins], Sync, Sz+iolist_size(B)); +log_loop({balog, B}, Pids, Bins, Sync, Sz, S, _L) -> + log_loop(S, Pids, [B | Bins], Sync, Sz+iolist_size(B)); +log_loop({From, {log, B}}, Pids, Bins, Sync, Sz, S, #log{format = internal}) -> %% {log, _} allowed for the internal format only. - log_loop(S, [From | Pids], [B | Bins], Sync); -log_loop({From, {blog, B}}, Pids, Bins, Sync, S, _L) -> - log_loop(S, [From | Pids], [B | Bins], Sync); -log_loop({From, sync}, Pids, Bins, Sync, S, _L) -> - log_loop(S, Pids, Bins, [From | Sync]); -log_loop(Message, Pids, Bins, Sync, S, _L) -> + log_loop(S, [From | Pids], [B | Bins], Sync, Sz+iolist_size(B)); +log_loop({From, {blog, B}}, Pids, Bins, Sync, Sz, S, _L) -> + log_loop(S, [From | Pids], [B | Bins], Sync, Sz+iolist_size(B)); +log_loop({From, sync}, Pids, Bins, Sync, Sz, S, _L) -> + log_loop(S, Pids, Bins, [From | Sync], Sz); +log_loop(Message, Pids, Bins, Sync, _Sz, S, _L) -> NS = log_end(S, Pids, Bins, Sync), handle(Message, NS). @@ -1240,20 +1244,29 @@ is_owner(Pid, L) -> %% ok | throw(Error) rename_file(File, NewFile, halt) -> - file:rename(File, NewFile); + case file:rename(File, NewFile) of + ok -> + ok; + Else -> + file_error(NewFile, Else) + end; rename_file(File, NewFile, wrap) -> rename_file(wrap_file_extensions(File), File, NewFile, ok). -rename_file([Ext|Exts], File, NewFile, Res) -> - NRes = case file:rename(add_ext(File, Ext), add_ext(NewFile, Ext)) of +rename_file([Ext|Exts], File, NewFile0, Res) -> + NewFile = add_ext(NewFile0, Ext), + NRes = case file:rename(add_ext(File, Ext), NewFile) of ok -> Res; Else -> - Else + file_error(NewFile, Else) end, - rename_file(Exts, File, NewFile, NRes); + rename_file(Exts, File, NewFile0, NRes); rename_file([], _File, _NewFiles, Res) -> Res. +file_error(FileName, {error, Error}) -> + {error, {file_error, FileName, Error}}. + %% "Old" error messages have been kept, arg_mismatch has been added. %%-spec compare_arg(dlog_options(), #arg{}, compare_arg([], _A, none, _OrigHead) -> @@ -1947,7 +1960,8 @@ monitor_request(Pid, Req) -> receive {'DOWN', Ref, process, Pid, _Info} -> {error, no_such_log}; - {disk_log, Pid, Reply} -> + {disk_log, Pid, Reply} when not is_tuple(Reply) orelse + element(2, Reply) =/= disk_log_stopped -> erlang:demonitor(Ref), receive {'DOWN', Ref, process, Pid, _Reason} -> diff --git a/lib/kernel/src/dist.hrl b/lib/kernel/src/dist.hrl deleted file mode 100644 index aea1ab81ba..0000000000 --- a/lib/kernel/src/dist.hrl +++ /dev/null @@ -1,38 +0,0 @@ -%% -%% %CopyrightBegin% -%% -%% Copyright Ericsson AB 1999-2009. All Rights Reserved. -%% -%% The contents of this file are subject to the Erlang Public License, -%% Version 1.1, (the "License"); you may not use this file except in -%% compliance with the License. You should have received a copy of the -%% Erlang Public License along with this software. If not, it can be -%% retrieved online at http://www.erlang.org/. -%% -%% Software distributed under the License is distributed on an "AS IS" -%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -%% the License for the specific language governing rights and limitations -%% under the License. -%% -%% %CopyrightEnd% -%% - -%% -%% Distribution capabilities flags (corresponds with dist.h). -%% - --define(DFLAG_PUBLISHED,1). --define(DFLAG_ATOM_CACHE,2). --define(DFLAG_EXTENDED_REFERENCES,4). --define(DFLAG_DIST_MONITOR,8). --define(DFLAG_FUN_TAGS,16#10). --define(DFLAG_DIST_MONITOR_NAME,16#20). --define(DFLAG_HIDDEN_ATOM_CACHE,16#40). --define(DFLAG_NEW_FUN_TAGS,16#80). --define(DFLAG_EXTENDED_PIDS_PORTS,16#100). --define(DFLAG_EXPORT_PTR_TAG,16#200). --define(DFLAG_BIT_BINARIES,16#400). --define(DFLAG_NEW_FLOATS,16#800). --define(DFLAG_UNICODE_IO,16#1000). --define(DFLAG_DIST_HDR_ATOM_CACHE,16#2000). --define(DFLAG_SMALL_ATOM_TAGS, 16#4000). diff --git a/lib/kernel/src/dist_util.hrl b/lib/kernel/src/dist_util.hrl deleted file mode 100644 index f2b0598532..0000000000 --- a/lib/kernel/src/dist_util.hrl +++ /dev/null @@ -1,87 +0,0 @@ -%% -%% %CopyrightBegin% -%% -%% Copyright Ericsson AB 1999-2009. All Rights Reserved. -%% -%% The contents of this file are subject to the Erlang Public License, -%% Version 1.1, (the "License"); you may not use this file except in -%% compliance with the License. You should have received a copy of the -%% Erlang Public License along with this software. If not, it can be -%% retrieved online at http://www.erlang.org/. -%% -%% Software distributed under the License is distributed on an "AS IS" -%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -%% the License for the specific language governing rights and limitations -%% under the License. -%% -%% %CopyrightEnd% -%% -%% uncomment this if tracing of handshake etc is wanted -%%-define(dist_trace, true). -%%-define(dist_debug, true). - - --ifdef(dist_debug). --define(debug(Term), erlang:display(Term)). --else. --define(debug(Term), ok). --endif. - --ifdef(dist_trace). --define(trace(Fmt,Args), io:format("~p ~p:~s",[erlang:now(),node(),lists:flatten(io_lib:format(Fmt, Args))])). -% Use the one below for config-file (early boot) connection tracing -%-define(trace(Fmt,Args), erlang:display([erlang:now(),node(),lists:flatten(io_lib:format(Fmt, Args))])). --define(trace_factor,8). --else. --define(trace(Fmt,Args), ok). --define(trace_factor,1). --endif. - --define(shutdown(Data), dist_util:shutdown(?MODULE, ?LINE, Data)). --define(shutdown2(Data, Reason), dist_util:shutdown(?MODULE, ?LINE, Data, Reason)). - -%% Handshake state structure --record(hs_data, { - kernel_pid, %% Pid of net_kernel - other_node, %% Name of peer - this_node, %% my nodename - socket, %% The connection "socket" - timer, %% The setup timer - %% (stream_dist_handshake:start_timer) - this_flags, %% Flags my node should use - allowed, %% Allowed nodes list - other_version, %% The other nodes distribution version - other_flags, %% The other nodes flags. - other_started, %% True if the other node initiated. - f_send, %% Fun that behaves like gen_tcp:send - f_recv, %% Fun that behaves like gen_tcp:recv - f_setopts_pre_nodeup, %% Sets "socket" options before - %% nodeup is delivered to net_kernel - f_setopts_post_nodeup, %% Sets "socket" options after - %% nodeup is delivered - f_getll, %% Get low level port or pid. - f_address, %% The address of the "socket", - %% generated from Socket,Node - %% These two are used in the tick loop, - %% so they are not fun's to avoid holding old code. - mf_tick, %% Takes the socket as parameters and - %% sends a tick, this is no fun, it - %% is a tuple {M,F}. - %% Is should place {tcp_closed, Socket} - %% in the message queue on failure. - mf_getstat, %% Returns - %% {ok, RecvCnt, SendCnt, SendPend} for - %% a given socket. This is a {M,F}, - %% returning {error, Reason on failure} - request_type = normal -}). - - -%% The following should be filled in upon enter of... -%% - handshake_we_started: -%% kernel_pid, other_node, this_node, socket, timer, -%% this_flags, other_version, All fun's/mf's. -%% - handshake_other_started: -%% kernel_pid, this_node, socket, timer, -%% this_flags, allowed, All fun's/mf's. - diff --git a/lib/kernel/src/error_handler.erl b/lib/kernel/src/error_handler.erl index e1f99bf417..a67b11a888 100644 --- a/lib/kernel/src/error_handler.erl +++ b/lib/kernel/src/error_handler.erl @@ -88,12 +88,12 @@ int() -> int. -spec crash(atom(), [term()]) -> no_return(). crash(Fun, Args) -> - crash({Fun,Args}). + crash({Fun,Args,[]}). -spec crash(atom(), atom(), arity()) -> no_return(). crash(M, F, A) -> - crash({M,F,A}). + crash({M,F,A,[]}). -spec crash(tuple()) -> no_return(). @@ -101,7 +101,8 @@ crash(Tuple) -> try erlang:error(undef) catch error:undef -> - erlang:raise(error, undef, [Tuple|tl(erlang:get_stacktrace())]) + Stk = [Tuple|tl(erlang:get_stacktrace())], + erlang:raise(error, undef, Stk) end. %% If the code_server has not been started yet dynamic code loading @@ -127,7 +128,7 @@ ensure_loaded(Module) -> -spec stub_function(atom(), atom(), [_]) -> no_return(). stub_function(Mod, Func, Args) -> - exit({undef,[{Mod,Func,Args}]}). + exit({undef,[{Mod,Func,Args,[]}]}). check_inheritance(Module, Args) -> Attrs = erlang:get_module_info(Module, attributes), diff --git a/lib/kernel/src/file.erl b/lib/kernel/src/file.erl index 5e4e1b0ba8..4028dd4f0b 100644 --- a/lib/kernel/src/file.erl +++ b/lib/kernel/src/file.erl @@ -28,9 +28,11 @@ %% File system and metadata. -export([get_cwd/0, get_cwd/1, set_cwd/1, delete/1, rename/2, make_dir/1, del_dir/1, list_dir/1, - read_file_info/1, write_file_info/2, + read_file_info/1, read_file_info/2, + write_file_info/2, write_file_info/3, altname/1, - read_link_info/1, read_link/1, + read_link_info/1, read_link_info/2, + read_link/1, make_link/2, make_symlink/2, read_file/1, write_file/2, write_file/3]). %% Specialized @@ -51,6 +53,9 @@ -export([pid2name/1]). +%% Sendfile functions +-export([sendfile/2,sendfile/5]). + %%% Obsolete exported functions -export([raw_read_file_info/1, raw_write_file_info/2]). @@ -103,6 +108,10 @@ -type date_time() :: calendar:datetime(). -type posix_file_advise() :: 'normal' | 'sequential' | 'random' | 'no_reuse' | 'will_need' | 'dont_need'. +-type sendfile_option() :: {chunk_size, non_neg_integer()}. +-type file_info_option() :: {'time', 'local'} | {'time', 'universal'} + | {'time', 'posix'}. + %%%----------------------------------------------------------------- %%% General functions @@ -211,6 +220,15 @@ del_dir(Name) -> read_file_info(Name) -> check_and_call(read_file_info, [file_name(Name)]). +-spec read_file_info(Filename, Opts) -> {ok, FileInfo} | {error, Reason} when + Filename :: name(), + Opts :: [file_info_option()], + FileInfo :: file_info(), + Reason :: posix() | badarg. + +read_file_info(Name, Opts) when is_list(Opts) -> + check_and_call(read_file_info, [file_name(Name), Opts]). + -spec altname(Name :: name()) -> any(). altname(Name) -> @@ -224,6 +242,16 @@ altname(Name) -> read_link_info(Name) -> check_and_call(read_link_info, [file_name(Name)]). +-spec read_link_info(Name, Opts) -> {ok, FileInfo} | {error, Reason} when + Name :: name(), + Opts :: [file_info_option()], + FileInfo :: file_info(), + Reason :: posix() | badarg. + +read_link_info(Name, Opts) when is_list(Opts) -> + check_and_call(read_link_info, [file_name(Name),Opts]). + + -spec read_link(Name) -> {ok, Filename} | {error, Reason} when Name :: name(), Filename :: filename(), @@ -240,6 +268,15 @@ read_link(Name) -> write_file_info(Name, Info = #file_info{}) -> check_and_call(write_file_info, [file_name(Name), Info]). +-spec write_file_info(Filename, FileInfo, Opts) -> ok | {error, Reason} when + Filename :: name(), + Opts :: [file_info_option()], + FileInfo :: file_info(), + Reason :: posix() | badarg. + +write_file_info(Name, Info = #file_info{}, Opts) when is_list(Opts) -> + check_and_call(write_file_info, [file_name(Name), Info, Opts]). + -spec list_dir(Dir) -> {ok, Filenames} | {error, Reason} when Dir :: name(), Filenames :: [filename()], @@ -264,9 +301,9 @@ read_file(Name) -> make_link(Old, New) -> check_and_call(make_link, [file_name(Old), file_name(New)]). --spec make_symlink(Name1, Name2) -> ok | {error, Reason} when - Name1 :: name(), - Name2 :: name(), +-spec make_symlink(Existing, New) -> ok | {error, Reason} when + Existing :: name(), + New :: name(), Reason :: posix() | badarg. make_symlink(Old, New) -> @@ -1100,8 +1137,9 @@ change_group(Name, GroupId) Mtime :: date_time(), Reason :: posix() | badarg. -change_time(Name, Time) - when is_tuple(Time) -> +change_time(Name, {{Y, M, D}, {H, Min, Sec}}=Time) + when is_integer(Y), is_integer(M), is_integer(D), + is_integer(H), is_integer(Min), is_integer(Sec)-> write_file_info(Name, #file_info{mtime=Time}). -spec change_time(Filename, Atime, Mtime) -> ok | {error, Reason} when @@ -1110,10 +1148,150 @@ change_time(Name, Time) Mtime :: date_time(), Reason :: posix() | badarg. -change_time(Name, Atime, Mtime) - when is_tuple(Atime), is_tuple(Mtime) -> +change_time(Name, {{AY, AM, AD}, {AH, AMin, ASec}}=Atime, + {{MY, MM, MD}, {MH, MMin, MSec}}=Mtime) + when is_integer(AY), is_integer(AM), is_integer(AD), + is_integer(AH), is_integer(AMin), is_integer(ASec), + is_integer(MY), is_integer(MM), is_integer(MD), + is_integer(MH), is_integer(MMin), is_integer(MSec)-> write_file_info(Name, #file_info{atime=Atime, mtime=Mtime}). +%% +%% Send data using sendfile +%% + +-define(MAX_CHUNK_SIZE, (1 bsl 20)*20). %% 20 MB, has to fit in primary memory + +-spec sendfile(RawFile, Socket, Offset, Bytes, Opts) -> + {'ok', non_neg_integer()} | {'error', inet:posix() | + closed | badarg | not_owner} when + RawFile :: file:fd(), + Socket :: inet:socket(), + Offset :: non_neg_integer(), + Bytes :: non_neg_integer(), + Opts :: [sendfile_option()]. +sendfile(File, _Sock, _Offet, _Bytes, _Opts) when is_pid(File) -> + {error, badarg}; +sendfile(File, Sock, Offset, Bytes, []) -> + sendfile(File, Sock, Offset, Bytes, ?MAX_CHUNK_SIZE, [], [], + false, false, false); +sendfile(File, Sock, Offset, Bytes, Opts) -> + ChunkSize0 = proplists:get_value(chunk_size, Opts, ?MAX_CHUNK_SIZE), + ChunkSize = if ChunkSize0 > ?MAX_CHUNK_SIZE -> + ?MAX_CHUNK_SIZE; + true -> ChunkSize0 + end, + %% Support for headers, trailers and options has been removed because the + %% Darwin and BSD API for using it does not play nice with + %% non-blocking sockets. See unix_efile.c for more info. + sendfile(File, Sock, Offset, Bytes, ChunkSize, [], [], + false,false,false). + +%% sendfile/2 +-spec sendfile(Filename, Socket) -> + {'ok', non_neg_integer()} | {'error', inet:posix() | + closed | badarg | not_owner} + when Filename :: file:name(), + Socket :: inet:socket(). +sendfile(Filename, Sock) -> + case file:open(Filename, [read, raw, binary]) of + {error, Reason} -> + {error, Reason}; + {ok, Fd} -> + Res = sendfile(Fd, Sock, 0, 0, []), + file:close(Fd), + Res + end. + +%% Internal sendfile functions +sendfile(#file_descriptor{ module = Mod } = Fd, Sock, Offset, Bytes, + ChunkSize, Headers, Trailers, Nodiskio, MNowait, Sync) + when is_port(Sock) -> + case Mod:sendfile(Fd, Sock, Offset, Bytes, ChunkSize, Headers, Trailers, + Nodiskio, MNowait, Sync) of + {error, enotsup} -> + sendfile_fallback(Fd, Sock, Offset, Bytes, ChunkSize, + Headers, Trailers); + Else -> + Else + end; +sendfile(_,_,_,_,_,_,_,_,_,_) -> + {error, badarg}. + +%%% +%% Sendfile Fallback +%%% +sendfile_fallback(File, Sock, Offset, Bytes, ChunkSize, + Headers, Trailers) + when Headers == []; is_integer(Headers) -> + case sendfile_fallback(File, Sock, Offset, Bytes, ChunkSize) of + {ok, BytesSent} when is_list(Trailers), + Trailers =/= [], + is_integer(Headers) -> + sendfile_send(Sock, Trailers, BytesSent+Headers); + {ok, BytesSent} when is_list(Trailers), Trailers =/= [] -> + sendfile_send(Sock, Trailers, BytesSent); + {ok, BytesSent} when is_integer(Headers) -> + {ok, BytesSent + Headers}; + Else -> + Else + end; +sendfile_fallback(File, Sock, Offset, Bytes, ChunkSize, Headers, Trailers) -> + case sendfile_send(Sock, Headers, 0) of + {ok, BytesSent} -> + sendfile_fallback(File, Sock, Offset, Bytes, ChunkSize, BytesSent, + Trailers); + Else -> + Else + end. + + +sendfile_fallback(File, Sock, Offset, Bytes, ChunkSize) -> + {ok, CurrPos} = file:position(File, {cur, 0}), + {ok, _NewPos} = file:position(File, {bof, Offset}), + Res = sendfile_fallback_int(File, Sock, Bytes, ChunkSize, 0), + file:position(File, {bof, CurrPos}), + Res. + + +sendfile_fallback_int(File, Sock, Bytes, ChunkSize, BytesSent) + when Bytes > BytesSent; Bytes == 0 -> + Size = if Bytes == 0 -> + ChunkSize; + (Bytes - BytesSent + ChunkSize) > 0 -> + Bytes - BytesSent; + true -> + ChunkSize + end, + case file:read(File, Size) of + {ok, Data} -> + case sendfile_send(Sock, Data, BytesSent) of + {ok,NewBytesSent} -> + sendfile_fallback_int( + File, Sock, Bytes, ChunkSize, + NewBytesSent); + Error -> + Error + end; + eof -> + {ok, BytesSent}; + Error -> + Error + end; +sendfile_fallback_int(_File, _Sock, BytesSent, _ChunkSize, BytesSent) -> + {ok, BytesSent}. + +sendfile_send(Sock, Data, Old) -> + Len = iolist_size(Data), + case gen_tcp:send(Sock, Data) of + ok -> + {ok, Len+Old}; + Else -> + Else + end. + + + %%%----------------------------------------------------------------- %%% Helpers @@ -1163,7 +1341,7 @@ path_open_first([Path|Rest], Name, Mode, LastError) -> {error, _} = Error -> Error; FilePath -> - FileName = filename:join(FilePath, Name), + FileName = fname_join(FilePath, Name), case open(FileName, Mode) of {ok, Fd} -> {ok, Fd, FileName}; @@ -1176,6 +1354,11 @@ path_open_first([Path|Rest], Name, Mode, LastError) -> path_open_first([], _Name, _Mode, LastError) -> {error, LastError}. +fname_join(".", Name) -> + Name; +fname_join(Dir, Name) -> + filename:join(Dir, Name). + %%%----------------------------------------------------------------- %%% Utility functions. diff --git a/lib/kernel/src/file_server.erl b/lib/kernel/src/file_server.erl index 64c61ba3ac..fc6cd823c9 100644 --- a/lib/kernel/src/file_server.erl +++ b/lib/kernel/src/file_server.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2000-2010. All Rights Reserved. +%% Copyright Ericsson AB 2000-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -147,15 +147,24 @@ handle_call({get_cwd, Name}, _From, Handle) -> handle_call({read_file_info, Name}, _From, Handle) -> {reply, ?PRIM_FILE:read_file_info(Handle, Name), Handle}; +handle_call({read_file_info, Name, Opts}, _From, Handle) -> + {reply, ?PRIM_FILE:read_file_info(Handle, Name, Opts), Handle}; + handle_call({altname, Name}, _From, Handle) -> {reply, ?PRIM_FILE:altname(Handle, Name), Handle}; handle_call({write_file_info, Name, Info}, _From, Handle) -> {reply, ?PRIM_FILE:write_file_info(Handle, Name, Info), Handle}; +handle_call({write_file_info, Name, Info, Opts}, _From, Handle) -> + {reply, ?PRIM_FILE:write_file_info(Handle, Name, Info, Opts), Handle}; + handle_call({read_link_info, Name}, _From, Handle) -> {reply, ?PRIM_FILE:read_link_info(Handle, Name), Handle}; +handle_call({read_link_info, Name, Opts}, _From, Handle) -> + {reply, ?PRIM_FILE:read_link_info(Handle, Name, Opts), Handle}; + handle_call({read_link, Name}, _From, Handle) -> {reply, ?PRIM_FILE:read_link(Handle, Name), Handle}; diff --git a/lib/kernel/src/gen_sctp.erl b/lib/kernel/src/gen_sctp.erl index 6cebb7ab97..d8954f0cf7 100644 --- a/lib/kernel/src/gen_sctp.erl +++ b/lib/kernel/src/gen_sctp.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2007-2011. All Rights Reserved. +%% Copyright Ericsson AB 2007-2012. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -27,7 +27,8 @@ -include("inet_sctp.hrl"). -export([open/0,open/1,open/2,close/1]). --export([listen/2,connect/4,connect/5,connect_init/4,connect_init/5]). +-export([listen/2,peeloff/2]). +-export([connect/4,connect/5,connect_init/4,connect_init/5]). -export([eof/2,abort/2]). -export([send/3,send/4,recv/1,recv/2]). -export([error_string/1]). @@ -109,9 +110,11 @@ open() -> | {ifaddr,IP} | inet:address_family() | {port,Port} + | {type,SockType} | option(), IP :: inet:ip_address() | any | loopback, Port :: inet:port_number(), + SockType :: seqpacket | stream, Socket :: sctp_socket(). open(Opts) when is_list(Opts) -> @@ -134,9 +137,11 @@ open(X) -> | {ifaddr,IP} | inet:address_family() | {port,Port} + | {type,SockType} | option(), IP :: inet:ip_address() | any | loopback, Port :: inet:port_number(), + SockType :: seqpacket | stream, Socket :: sctp_socket(). open(Port, Opts) when is_integer(Port), is_list(Opts) -> @@ -161,17 +166,38 @@ close(S) -> -spec listen(Socket, IsServer) -> ok | {error, Reason} when Socket :: sctp_socket(), IsServer :: boolean(), + Reason :: term(); + (Socket, Backlog) -> ok | {error, Reason} when + Socket :: sctp_socket(), + Backlog :: integer(), Reason :: term(). -listen(S, Flag) when is_port(S), is_boolean(Flag) -> +listen(S, Backlog) + when is_port(S), is_boolean(Backlog); + is_port(S), is_integer(Backlog) -> case inet_db:lookup_socket(S) of {ok,Mod} -> - Mod:listen(S, Flag); + Mod:listen(S, Backlog); Error -> Error end; listen(S, Flag) -> erlang:error(badarg, [S,Flag]). +-spec peeloff(Socket, Assoc) -> {ok, NewSocket} | {error, Reason} when + Socket :: sctp_socket(), + Assoc :: #sctp_assoc_change{} | assoc_id(), + NewSocket :: sctp_socket(), + Reason :: term(). + +peeloff(S, #sctp_assoc_change{assoc_id=AssocId}) when is_port(S) -> + peeloff(S, AssocId); +peeloff(S, AssocId) when is_port(S), is_integer(AssocId) -> + case inet_db:lookup_socket(S) of + {ok,Mod} -> + Mod:peeloff(S, AssocId); + Error -> Error + end. + -spec connect(Socket, Addr, Port, Opts) -> {ok, Assoc} | {error, inet:posix()} when Socket :: sctp_socket(), Addr :: inet:ip_address() | inet:hostname(), @@ -288,7 +314,7 @@ eof_or_abort(S, AssocId, Action) -> -spec send(Socket, SndRcvInfo, Data) -> ok | {error, Reason} when Socket :: sctp_socket(), SndRcvInfo :: #sctp_sndrcvinfo{}, - Data :: binary | iolist(), + Data :: binary() | iolist(), Reason :: term(). %% Full-featured send. Rarely needed. @@ -305,7 +331,7 @@ send(S, SRI, Data) -> Socket :: sctp_socket(), Assoc :: #sctp_assoc_change{} | assoc_id(), Stream :: integer(), - Data :: binary | iolist(), + Data :: binary() | iolist(), Reason :: term(). send(S, #sctp_assoc_change{assoc_id=AssocId}, Stream, Data) diff --git a/lib/kernel/src/gen_tcp.erl b/lib/kernel/src/gen_tcp.erl index 8ab18c01b4..4d6c7f5f1d 100644 --- a/lib/kernel/src/gen_tcp.erl +++ b/lib/kernel/src/gen_tcp.erl @@ -27,6 +27,7 @@ -export([fdopen/2]). -include("inet_int.hrl"). +-include("file.hrl"). -type option() :: {active, true | false | once} | @@ -302,7 +303,7 @@ unrecv(S, Data) when is_port(S) -> Mod:unrecv(S, Data); Error -> Error - end. + end. %% %% Set controlling process @@ -354,3 +355,4 @@ mod([_|Opts], Address) -> mod(Opts, Address); mod([], Address) -> mod(Address). + diff --git a/lib/kernel/src/global.erl b/lib/kernel/src/global.erl index 7d15f8bf83..fa97614eca 100644 --- a/lib/kernel/src/global.erl +++ b/lib/kernel/src/global.erl @@ -28,7 +28,7 @@ %% External exports -export([start/0, start_link/0, stop/0, sync/0, sync/1, - safe_whereis_name/1, whereis_name/1, register_name/2, + whereis_name/1, register_name/2, register_name/3, register_name_external/2, register_name_external/3, unregister_name_external/1,re_register_name/2, re_register_name/3, unregister_name/1, registered_names/0, send/2, node_disconnected/1, @@ -203,10 +203,6 @@ send(Name, Msg) -> whereis_name(Name) -> where(Name). --spec safe_whereis_name(term()) -> pid() | 'undefined'. -safe_whereis_name(Name) -> - gen_server:call(global_name_server, {whereis, Name}, infinity). - node_disconnected(Node) -> global_name_server ! {nodedown, Node}. @@ -510,8 +506,7 @@ init([]) -> %% delay can sometimes be quite substantial. Global guarantees that %% the name will eventually be removed, but there is no %% synchronization between nodes; the name can be removed from some -%% node(s) long before it is removed from other nodes. Using -%% safe_whereis_name is no cure. +%% node(s) long before it is removed from other nodes. %% %% - Global cannot handle problems with the distribution very well. %% Depending on the value of the kernel variable 'net_ticktime' long @@ -589,10 +584,6 @@ init([]) -> {'reply', term(), state()} | {'stop', 'normal', 'stopped', state()}. -handle_call({whereis, Name}, From, S) -> - do_whereis(Name, From), - {noreply, S}; - handle_call({registrar, Fun}, From, S) -> S#state.the_registrar ! {trans_all_known, Fun, From}, {noreply, S}; @@ -1235,7 +1226,15 @@ ins_name_ext(Name, Pid, Method, RegNode, FromPidOrNode, ExtraInfo, S0) -> where(Name) -> case ets:lookup(global_names, Name) of - [{_Name, Pid, _Method, _RPid, _Ref}] -> Pid; + [{_Name, Pid, _Method, _RPid, _Ref}] -> + if node(Pid) == node() -> + case is_process_alive(Pid) of + true -> Pid; + false -> undefined + end; + true -> + Pid + end; [] -> undefined end. diff --git a/lib/kernel/src/hipe_unified_loader.erl b/lib/kernel/src/hipe_unified_loader.erl index 1d3eb926ca..8b3aa0286d 100644 --- a/lib/kernel/src/hipe_unified_loader.erl +++ b/lib/kernel/src/hipe_unified_loader.erl @@ -36,7 +36,6 @@ -export([chunk_name/1, %% Only the code and code_server modules may call the entries below! - load_hipe_modules/0, load_native_code/2, post_beam_load/1, load_module/3, @@ -78,16 +77,6 @@ chunk_name(Architecture) -> %%======================================================================== --spec load_hipe_modules() -> 'ok'. -%% @doc -%% Ensures HiPE's loader modules are loaded. -%% Called from code.erl at start-up. - -load_hipe_modules() -> - ok. - -%%======================================================================== - -spec load_native_code(Mod, binary()) -> 'no_native' | {'module', Mod} when is_subtype(Mod, atom()). %% @doc diff --git a/lib/kernel/src/inet.erl b/lib/kernel/src/inet.erl index 48a6f3db65..49f64a9236 100644 --- a/lib/kernel/src/inet.erl +++ b/lib/kernel/src/inet.erl @@ -36,10 +36,14 @@ -export([i/0, i/1, i/2]). --export([getll/1, getfd/1, open/7, fdopen/5]). +-export([getll/1, getfd/1, open/8, fdopen/6]). -export([tcp_controlling_process/2, udp_controlling_process/2, tcp_close/1, udp_close/1]). + +%% used by sendfile +-export([lock_socket/2]). + %% used by socks5 -export([setsockname/2, setpeername/2]). @@ -115,7 +119,8 @@ 'mtu' | 'netmask' | 'flags' |'hwaddr'. -type address_family() :: 'inet' | 'inet6'. --type protocol_option() :: 'tcp' | 'udp' | 'sctp'. +-type socket_protocol() :: 'tcp' | 'udp' | 'sctp'. +-type socket_type() :: 'stream' | 'dgram' | 'seqpacket'. -type stat_option() :: 'recv_cnt' | 'recv_max' | 'recv_avg' | 'recv_oct' | 'recv_dvi' | 'send_cnt' | 'send_max' | 'send_avg' | 'send_oct' | 'send_pend'. @@ -748,6 +753,8 @@ sctp_opt([Opt|Opts], Mod, R, As) -> sctp_opt(Opts, Mod, R#sctp_opts{port=P}, As); Error -> Error end; + {type,Type} when Type =:= seqpacket; Type =:= stream -> + sctp_opt(Opts, Mod, R#sctp_opts{type=Type}, As); binary -> sctp_opt (Opts, Mod, R, As, mode, binary); list -> sctp_opt (Opts, Mod, R, As, mode, list); {sctp_module,_} -> sctp_opt (Opts, Mod, R, As); % Done with @@ -996,13 +1003,14 @@ gethostbyaddr_tm_native(Addr, Timer, Opts) -> Addr :: ip_address(), Port :: port_number(), Opts :: [socket_setopt()], - Protocol :: protocol_option(), - Family :: 'inet' | 'inet6', + Protocol :: socket_protocol(), + Family :: address_family(), + Type :: socket_type(), Module :: atom()) -> {'ok', socket()} | {'error', posix()}. -open(Fd, Addr, Port, Opts, Protocol, Family, Module) when Fd < 0 -> - case prim_inet:open(Protocol, Family) of +open(Fd, Addr, Port, Opts, Protocol, Family, Type, Module) when Fd < 0 -> + case prim_inet:open(Protocol, Family, Type) of {ok,S} -> case prim_inet:setopts(S, Opts) of ok -> @@ -1029,18 +1037,19 @@ open(Fd, Addr, Port, Opts, Protocol, Family, Module) when Fd < 0 -> Error -> Error end; -open(Fd, _Addr, _Port, Opts, Protocol, Family, Module) -> - fdopen(Fd, Opts, Protocol, Family, Module). +open(Fd, _Addr, _Port, Opts, Protocol, Family, Type, Module) -> + fdopen(Fd, Opts, Protocol, Family, Type, Module). -spec fdopen(Fd :: non_neg_integer(), Opts :: [socket_setopt()], - Protocol :: protocol_option(), + Protocol :: socket_protocol(), Family :: address_family(), + Type :: socket_type(), Module :: atom()) -> {'ok', socket()} | {'error', posix()}. -fdopen(Fd, Opts, Protocol, Family, Module) -> - case prim_inet:fdopen(Protocol, Fd, Family) of +fdopen(Fd, Opts, Protocol, Family, Type, Module) -> + case prim_inet:fdopen(Protocol, Family, Type, Fd) of {ok, S} -> case prim_inet:setopts(S, Opts) of ok -> @@ -1056,18 +1065,24 @@ fdopen(Fd, Opts, Protocol, Family, Module) -> %% socket stat %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -i() -> i(tcp), i(udp). +i() -> i(tcp), i(udp), i(sctp). i(Proto) -> i(Proto, [port, module, recv, sent, owner, - local_address, foreign_address, state]). + local_address, foreign_address, state, type]). i(tcp, Fs) -> ii(tcp_sockets(), Fs, tcp); i(udp, Fs) -> - ii(udp_sockets(), Fs, udp). + ii(udp_sockets(), Fs, udp); +i(sctp, Fs) -> + ii(sctp_sockets(), Fs, sctp). ii(Ss, Fs, Proto) -> - LLs = [h_line(Fs) | info_lines(Ss, Fs, Proto)], + LLs = + case info_lines(Ss, Fs, Proto) of + [] -> []; + InfoLines -> [h_line(Fs) | InfoLines] + end, Maxs = foldl( fun(Line,Max0) -> smax(Max0,Line) end, duplicate(length(Fs),0),LLs), @@ -1135,6 +1150,7 @@ info(S, F, Proto) -> case prim_inet:gettype(S) of {ok,{_,stream}} -> "STREAM"; {ok,{_,dgram}} -> "DGRAM"; + {ok,{_,seqpacket}} -> "SEQPACKET"; _ -> " " end; fd -> @@ -1186,6 +1202,7 @@ fmt_port(N, Proto) -> %% Return a list of all tcp sockets tcp_sockets() -> port_list("tcp_inet"). udp_sockets() -> port_list("udp_inet"). +sctp_sockets() -> port_list("sctp_inet"). %% Return all ports having the name 'Name' port_list(Name) -> @@ -1340,3 +1357,14 @@ stop_timer(Timer) -> end; T -> T end. + + +lock_socket(S,Val) -> + case erlang:port_info(S, connected) of + {connected, Pid} when Pid =/= self() -> + {error, not_owner}; + undefined -> + {error, einval}; + _ -> + prim_inet:ignorefd(S,Val) + end. diff --git a/lib/kernel/src/inet6_sctp.erl b/lib/kernel/src/inet6_sctp.erl index 5bf3fca647..c47483bbdd 100644 --- a/lib/kernel/src/inet6_sctp.erl +++ b/lib/kernel/src/inet6_sctp.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2007-2010. All Rights Reserved. +%% Copyright Ericsson AB 2007-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -32,7 +32,8 @@ -define(FAMILY, inet6). -export([getserv/1,getaddr/1,getaddr/2,translate_ip/1]). --export([open/1,close/1,listen/2,connect/5,sendmsg/3,send/4,recv/2]). +-export([open/1,close/1,listen/2,peeloff/2,connect/5]). +-export([sendmsg/3,send/4,recv/2]). @@ -54,8 +55,8 @@ translate_ip(IP) -> open(Opts) -> case inet:sctp_options(Opts, ?MODULE) of - {ok,#sctp_opts{fd=Fd,ifaddr=Addr,port=Port,opts=SOs}} -> - inet:open(Fd, Addr, Port, SOs, sctp, ?FAMILY, ?MODULE); + {ok,#sctp_opts{fd=Fd,ifaddr=Addr,port=Port,type=Type,opts=SOs}} -> + inet:open(Fd, Addr, Port, SOs, sctp, ?FAMILY, Type, ?MODULE); Error -> Error end. @@ -65,6 +66,14 @@ close(S) -> listen(S, Flag) -> prim_inet:listen(S, Flag). +peeloff(S, AssocId) -> + case prim_inet:peeloff(S, AssocId) of + {ok, NewS}=Result -> + inet_db:register_socket(NewS, ?MODULE), + Result; + Error -> Error + end. + connect(S, Addr, Port, Opts, Timer) -> inet_sctp:connect(S, Addr, Port, Opts, Timer). diff --git a/lib/kernel/src/inet6_tcp.erl b/lib/kernel/src/inet6_tcp.erl index cc45f6c7f6..c714b2bee0 100644 --- a/lib/kernel/src/inet6_tcp.erl +++ b/lib/kernel/src/inet6_tcp.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1997-2009. All Rights Reserved. +%% Copyright Ericsson AB 1997-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -93,7 +93,7 @@ do_connect(Addr = {A,B,C,D,E,F,G,H}, Port, Opts, Time) when port=BPort, opts=SockOpts}} when ?ip6(Ab,Bb,Cb,Db,Eb,Fb,Gb,Hb), ?port(BPort) -> - case inet:open(Fd,BAddr,BPort,SockOpts,tcp,inet6,?MODULE) of + case inet:open(Fd,BAddr,BPort,SockOpts,tcp,inet6,stream,?MODULE) of {ok, S} -> case prim_inet:connect(S, Addr, Port, Time) of ok -> {ok,S}; @@ -115,7 +115,7 @@ listen(Port, Opts) -> port=BPort, opts=SockOpts}=R} when ?ip6(A,B,C,D,E,F,G,H), ?port(BPort) -> - case inet:open(Fd,BAddr,BPort,SockOpts,tcp,inet6,?MODULE) of + case inet:open(Fd,BAddr,BPort,SockOpts,tcp,inet6,stream,?MODULE) of {ok, S} -> case prim_inet:listen(S, R#listen_opts.backlog) of ok -> {ok, S}; @@ -149,5 +149,5 @@ accept(L,Timeout) -> %% Create a port/socket from a file descriptor %% fdopen(Fd, Opts) -> - inet:fdopen(Fd, Opts, tcp, inet6, ?MODULE). + inet:fdopen(Fd, Opts, tcp, inet6, stream, ?MODULE). diff --git a/lib/kernel/src/inet6_udp.erl b/lib/kernel/src/inet6_udp.erl index e81d417151..ca43c94211 100644 --- a/lib/kernel/src/inet6_udp.erl +++ b/lib/kernel/src/inet6_udp.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1997-2009. All Rights Reserved. +%% Copyright Ericsson AB 1997-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -45,7 +45,7 @@ open(Port, Opts) -> port=BPort, opts=SockOpts}} when ?ip6(A,B,C,D,E,F,G,H), ?port(BPort) -> - inet:open(Fd,BAddr,BPort,SockOpts,udp,inet6,?MODULE); + inet:open(Fd,BAddr,BPort,SockOpts,udp,inet6,dgram,?MODULE); {ok, _} -> exit(badarg) end. @@ -84,4 +84,4 @@ controlling_process(Socket, NewOwner) -> %% Create a port/socket from a file descriptor %% fdopen(Fd, Opts) -> - inet:fdopen(Fd, Opts, udp, inet6, ?MODULE). + inet:fdopen(Fd, Opts, udp, inet6, dgram, ?MODULE). diff --git a/lib/kernel/src/inet_int.hrl b/lib/kernel/src/inet_int.hrl index 6f1688c6a2..cf893c73eb 100644 --- a/lib/kernel/src/inet_int.hrl +++ b/lib/kernel/src/inet_int.hrl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1997-2010. All Rights Reserved. +%% Copyright Ericsson AB 1997-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -29,7 +29,7 @@ -define(INET_AF_ANY, 3). % Fake for ANY in any address family -define(INET_AF_LOOPBACK, 4). % Fake for LOOPBACK in any address family -%% type codes (gettype, INET_REQ_GETTYPE) +%% type codes to open and gettype - INET_REQ_GETTYPE -define(INET_TYPE_STREAM, 1). -define(INET_TYPE_DGRAM, 2). -define(INET_TYPE_SEQPACKET, 3). @@ -83,16 +83,21 @@ -define(INET_REQ_IFSET, 23). -define(INET_REQ_SUBSCRIBE, 24). -define(INET_REQ_GETIFADDRS, 25). +-define(INET_REQ_ACCEPT, 26). +-define(INET_REQ_LISTEN, 27). +-define(INET_REQ_IGNOREFD, 28). + %% TCP requests --define(TCP_REQ_ACCEPT, 40). --define(TCP_REQ_LISTEN, 41). +%%-define(TCP_REQ_ACCEPT, 40). MOVED +%%-define(TCP_REQ_LISTEN, 41). MERGED -define(TCP_REQ_RECV, 42). -define(TCP_REQ_UNRECV, 43). -define(TCP_REQ_SHUTDOWN, 44). %% UDP and SCTP requests -define(PACKET_REQ_RECV, 60). --define(SCTP_REQ_LISTEN, 61). +%%-define(SCTP_REQ_LISTEN, 61). MERGED -define(SCTP_REQ_BINDX, 62). %% Multi-home SCTP bind +-define(SCTP_REQ_PEELOFF, 63). %% subscribe codes, INET_REQ_SUBSCRIBE -define(INET_SUBS_EMPTY_OUT_Q, 1). @@ -100,7 +105,7 @@ %% reply codes for *_REQ_* -define(INET_REP_ERROR, 0). -define(INET_REP_OK, 1). --define(INET_REP_SCTP, 2). +-define(INET_REP, 2). %% INET, TCP and UDP options: -define(INET_OPT_REUSEADDR, 0). @@ -399,6 +404,7 @@ ifaddr, port = 0, fd = -1, + type = seqpacket, opts = [{mode, binary}, {buffer, ?SCTP_DEF_BUFSZ}, {sndbuf, ?SCTP_DEF_BUFSZ}, diff --git a/lib/kernel/src/inet_sctp.erl b/lib/kernel/src/inet_sctp.erl index de74b573bd..2d799d79fa 100644 --- a/lib/kernel/src/inet_sctp.erl +++ b/lib/kernel/src/inet_sctp.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2007-2010. All Rights Reserved. +%% Copyright Ericsson AB 2007-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -31,7 +31,8 @@ -define(FAMILY, inet). -export([getserv/1,getaddr/1,getaddr/2,translate_ip/1]). --export([open/1,close/1,listen/2,connect/5,sendmsg/3,send/4,recv/2]). +-export([open/1,close/1,listen/2,peeloff/2,connect/5]). +-export([sendmsg/3,send/4,recv/2]). @@ -53,8 +54,8 @@ translate_ip(IP) -> open(Opts) -> case inet:sctp_options(Opts, ?MODULE) of - {ok,#sctp_opts{fd=Fd,ifaddr=Addr,port=Port,opts=SOs}} -> - inet:open(Fd, Addr, Port, SOs, sctp, ?FAMILY, ?MODULE); + {ok,#sctp_opts{fd=Fd,ifaddr=Addr,port=Port,type=Type,opts=SOs}} -> + inet:open(Fd, Addr, Port, SOs, sctp, ?FAMILY, Type, ?MODULE); Error -> Error end. @@ -64,6 +65,14 @@ close(S) -> listen(S, Flag) -> prim_inet:listen(S, Flag). +peeloff(S, AssocId) -> + case prim_inet:peeloff(S, AssocId) of + {ok, NewS}=Result -> + inet_db:register_socket(NewS, ?MODULE), + Result; + Error -> Error + end. + %% A non-blocking connect is implemented when the initial call is to %% gen_sctp:connect_init which passes the value nowait as the Timer connect(S, Addr, Port, Opts, Timer) -> @@ -102,7 +111,7 @@ connect(S, Addr, Port, Opts, Timer) -> connect_get_assoc(S, Addr, Port, false, Timer) -> case recv(S, inet:timeout(Timer)) of - {ok, {Addr, Port, [], #sctp_assoc_change{state=St}=Ev}} -> + {ok, {Addr, Port, _, #sctp_assoc_change{state=St}=Ev}} -> if St =:= comm_up -> %% Yes, successfully connected, return the whole %% sctp_assoc_change event (containing, in particular, @@ -123,7 +132,7 @@ connect_get_assoc(S, Addr, Port, false, Timer) -> connect_get_assoc(S, Addr, Port, Active, Timer) -> Timeout = inet:timeout(Timer), receive - {sctp,S,Addr,Port,{[],#sctp_assoc_change{state=St}=Ev}} -> + {sctp,S,Addr,Port,{_,#sctp_assoc_change{state=St}=Ev}} -> case Active of once -> prim_inet:setopt(S, active, once); diff --git a/lib/kernel/src/inet_tcp.erl b/lib/kernel/src/inet_tcp.erl index 6dadccd6a9..4c2db16ce3 100644 --- a/lib/kernel/src/inet_tcp.erl +++ b/lib/kernel/src/inet_tcp.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1997-2009. All Rights Reserved. +%% Copyright Ericsson AB 1997-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -95,7 +95,7 @@ do_connect({A,B,C,D}, Port, Opts, Time) when ?ip(A,B,C,D), ?port(Port) -> port=BPort, opts=SockOpts}} when ?ip(Ab,Bb,Cb,Db), ?port(BPort) -> - case inet:open(Fd,BAddr,BPort,SockOpts,tcp,inet,?MODULE) of + case inet:open(Fd,BAddr,BPort,SockOpts,tcp,inet,stream,?MODULE) of {ok, S} -> case prim_inet:connect(S, {A,B,C,D}, Port, Time) of ok -> {ok,S}; @@ -117,7 +117,7 @@ listen(Port, Opts) -> port=BPort, opts=SockOpts}=R} when ?ip(A,B,C,D), ?port(BPort) -> - case inet:open(Fd,BAddr,BPort,SockOpts,tcp,inet,?MODULE) of + case inet:open(Fd,BAddr,BPort,SockOpts,tcp,inet,stream,?MODULE) of {ok, S} -> case prim_inet:listen(S, R#listen_opts.backlog) of ok -> {ok, S}; @@ -150,4 +150,4 @@ accept(L,Timeout) -> %% Create a port/socket from a file descriptor %% fdopen(Fd, Opts) -> - inet:fdopen(Fd, Opts, tcp, inet, ?MODULE). + inet:fdopen(Fd, Opts, tcp, inet, stream, ?MODULE). diff --git a/lib/kernel/src/inet_udp.erl b/lib/kernel/src/inet_udp.erl index 60bd96f332..80d930fe10 100644 --- a/lib/kernel/src/inet_udp.erl +++ b/lib/kernel/src/inet_udp.erl @@ -52,7 +52,7 @@ open(Port, Opts) -> ifaddr=BAddr={A,B,C,D}, port=BPort, opts=SockOpts}} when ?ip(A,B,C,D), ?port(BPort) -> - inet:open(Fd,BAddr,BPort,SockOpts,udp,inet,?MODULE); + inet:open(Fd,BAddr,BPort,SockOpts,udp,inet,dgram,?MODULE); {ok, _} -> exit(badarg) end. @@ -93,7 +93,7 @@ controlling_process(Socket, NewOwner) -> fdopen(Fd, Opts) -> inet:fdopen(Fd, optuniquify([{recbuf, ?RECBUF} | Opts]), - udp, inet, ?MODULE). + udp, inet, dgram, ?MODULE). %% Remove all duplicate options from an option list. diff --git a/lib/kernel/src/kernel.appup.src b/lib/kernel/src/kernel.appup.src index 54a63833e6..bded2408a7 100644 --- a/lib/kernel/src/kernel.appup.src +++ b/lib/kernel/src/kernel.appup.src @@ -1 +1,27 @@ -{"%VSN%",[],[]}. +%% -*- erlang -*- +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 1999-2011. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +{"%VSN%", + %% Up from - max two major revisions back + [{<<"2\\.15(\\.[0-9]+)*">>,[restart_new_emulator]}, %% R15 + {<<"2\\.14(\\.[0-9]+)*">>,[restart_new_emulator]}, %% R14 + {<<"2\\.13(\\.[0-9]+)*">>,[restart_new_emulator]}],%% R13 + %% Down to - max two major revisions back + [{<<"2\\.15(\\.[0-9]+)*">>,[restart_new_emulator]}, %% R15 + {<<"2\\.14(\\.[0-9]+)*">>,[restart_new_emulator]}, %% R14 + {<<"2\\.13(\\.[0-9]+)*">>,[restart_new_emulator]}] %% R13 +}. diff --git a/lib/kernel/src/net_address.hrl b/lib/kernel/src/net_address.hrl deleted file mode 100644 index 5342076507..0000000000 --- a/lib/kernel/src/net_address.hrl +++ /dev/null @@ -1,28 +0,0 @@ -%% -%% %CopyrightBegin% -%% -%% Copyright Ericsson AB 1997-2009. All Rights Reserved. -%% -%% The contents of this file are subject to the Erlang Public License, -%% Version 1.1, (the "License"); you may not use this file except in -%% compliance with the License. You should have received a copy of the -%% Erlang Public License along with this software. If not, it can be -%% retrieved online at http://www.erlang.org/. -%% -%% Software distributed under the License is distributed on an "AS IS" -%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -%% the License for the specific language governing rights and limitations -%% under the License. -%% -%% %CopyrightEnd% -%% - -%% Generic address format - --record(net_address, - { - address, %% opaque address - host, %% host name - protocol, %% protocol - family %% address family - }). diff --git a/lib/kernel/src/user_drv.erl b/lib/kernel/src/user_drv.erl index c34f2ddeb0..8f2ca28f56 100644 --- a/lib/kernel/src/user_drv.erl +++ b/lib/kernel/src/user_drv.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2009. All Rights Reserved. +%% Copyright Ericsson AB 1996-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -117,8 +117,9 @@ server1(Iport, Oport, Shell) -> {Curr,Shell1} = case init:get_argument(remsh) of {ok,[[Node]]} -> - RShell = {list_to_atom(Node),shell,start,[]}, - RGr = group:start(self(), RShell), + ANode = list_to_atom(Node), + RShell = {ANode,shell,start,[]}, + RGr = group:start(self(), RShell, rem_sh_opts(ANode)), {RGr,RShell}; E when E =:= error ; E =:= {ok,[[]]} -> {group:start(self(), Shell),Shell} @@ -134,6 +135,9 @@ server1(Iport, Oport, Shell) -> %% Enter the server loop. server_loop(Iport, Oport, Curr, User, Gr). +rem_sh_opts(Node) -> + [{expand_fun,fun(B)-> rpc:call(Node,edlin_expand,expand,[B]) end}]. + %% start_user() %% Start a group leader process and register it as 'user', unless, %% of course, a 'user' already exists. diff --git a/lib/kernel/src/user_sup.erl b/lib/kernel/src/user_sup.erl index 35b7ff0cfe..cb50d9491d 100644 --- a/lib/kernel/src/user_sup.erl +++ b/lib/kernel/src/user_sup.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2009. All Rights Reserved. +%% Copyright Ericsson AB 1996-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -45,7 +45,7 @@ init([]) -> Pid = start_slave(Master), {ok, Pid, Pid}; {M, F, A} -> - case start_user({M, F}, A) of + case start_user(M, F, A) of {ok, Pid} -> {ok, Pid, Pid}; Error -> @@ -95,8 +95,8 @@ terminate(_Reason, UserPid) -> %% is guaranteed that the user is started. %%----------------------------------------------------------------- -start_user(Func,A) -> - apply(Func, A), +start_user(Mod, Func, A) -> + apply(Mod, Func, A), wait_for_user_p(100). wait_for_user_p(0) -> |