From 21a7806986d58480367cff8d385a12f9659c7754 Mon Sep 17 00:00:00 2001 From: Hans Bolinder Date: Mon, 22 Apr 2013 15:28:49 +0200 Subject: Fix unmatched_returns warnings in STDLIB and Kernel --- erts/preloaded/src/init.erl | 2 +- erts/preloaded/src/prim_zip.erl | 4 ++-- erts/preloaded/src/zlib.erl | 6 +++--- 3 files changed, 6 insertions(+), 6 deletions(-) (limited to 'erts/preloaded/src') diff --git a/erts/preloaded/src/init.erl b/erts/preloaded/src/init.erl index 61d8df2428..87003d096b 100644 --- a/erts/preloaded/src/init.erl +++ b/erts/preloaded/src/init.erl @@ -1045,7 +1045,7 @@ start_it({eval,Bin}) -> TsR -> reverse([{dot,1} | TsR]) end, {ok,Expr} = erl_parse:parse_exprs(Ts1), - erl_eval:exprs(Expr, erl_eval:new_bindings()), + {value, _Value, _Bs} = erl_eval:exprs(Expr, erl_eval:new_bindings()), ok; start_it([_|_]=MFA) -> Ref = make_ref(), diff --git a/erts/preloaded/src/prim_zip.erl b/erts/preloaded/src/prim_zip.erl index d29f17ae56..1d5ab52a24 100644 --- a/erts/preloaded/src/prim_zip.erl +++ b/erts/preloaded/src/prim_zip.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2011. All Rights Reserved. +%% Copyright Ericsson AB 2008-2013. 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 @@ -89,7 +89,7 @@ do_open(FilterFun, FilterAcc, F) -> {ok, PrimZip2, FilterAcc2} catch Class:Reason -> - close(PrimZip), + _ = close(PrimZip), erlang:error(erlang:raise(Class, Reason, erlang:get_stacktrace())) end. diff --git a/erts/preloaded/src/zlib.erl b/erts/preloaded/src/zlib.erl index 1faae1c1f4..2c9d55f50c 100644 --- a/erts/preloaded/src/zlib.erl +++ b/erts/preloaded/src/zlib.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2003-2012. All Rights Reserved. +%% Copyright Ericsson AB 2003-2013. 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 @@ -206,7 +206,7 @@ deflate(Z, Data) -> deflate(Z, Data, Flush) -> try port_command(Z, Data) of true -> - call(Z, ?DEFLATE, <<(arg_flush(Flush)):32>>), + _ = call(Z, ?DEFLATE, <<(arg_flush(Flush)):32>>), collect(Z) catch error:_Err -> @@ -252,7 +252,7 @@ inflateReset(Z) -> inflate(Z, Data) -> try port_command(Z, Data) of true -> - call(Z, ?INFLATE, <>), + _ = call(Z, ?INFLATE, <>), collect(Z) catch error:_Err -> -- cgit v1.2.3 From 88eea0e9a22099a1425553381cfb72f646cb2abf Mon Sep 17 00:00:00 2001 From: Siri Hansen Date: Thu, 25 Apr 2013 11:10:37 +0200 Subject: Fix unmatched_return warning in erl_prim_loader --- erts/preloaded/src/erl_prim_loader.erl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'erts/preloaded/src') diff --git a/erts/preloaded/src/erl_prim_loader.erl b/erts/preloaded/src/erl_prim_loader.erl index e8ddfc4a57..81522e293a 100644 --- a/erts/preloaded/src/erl_prim_loader.erl +++ b/erts/preloaded/src/erl_prim_loader.erl @@ -1041,7 +1041,7 @@ apply_archive(PS, Fun, Acc, Archive) -> apply_archive(PS, Fun, Acc, Archive); Error -> debug(PS, {cache, {clear, Error}}), - clear_cache(Archive, {ok, PrimZip}), + ok = clear_cache(Archive, {ok, PrimZip}), apply_archive(PS, Fun, Acc, Archive) end; {Cache, FI} -> -- cgit v1.2.3 From 0ab074b7dece920e8dcd34793b88ce14ca4534ed Mon Sep 17 00:00:00 2001 From: Siri Hansen Date: Tue, 28 May 2013 16:05:40 +0200 Subject: Allow unicode characters for boot and config in init:make_permanent When release_handler makes a release permanent, it calls init:make_permanent/2 in order to set the path to the config and boot file. The paths are coverterd to binaries, and this commit changes this conversion from using lists_to_binary/1 to using unicode:characters_to_binary/3 with the encoding set according to the file name encoding mode (+fnu/fna/fnl). --- erts/preloaded/src/init.erl | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'erts/preloaded/src') diff --git a/erts/preloaded/src/init.erl b/erts/preloaded/src/init.erl index 87003d096b..ab8464956c 100644 --- a/erts/preloaded/src/init.erl +++ b/erts/preloaded/src/init.erl @@ -465,7 +465,10 @@ make_permanent(Boot,Config,Flags0,State) -> set_flag(_Flag,false,Flags) -> {ok,Flags}; set_flag(Flag,Value,Flags) when is_list(Value) -> - case catch list_to_binary(Value) of + %% The flag here can be -boot or -config, which means the value is + %% a file name! Thus the file name encoding is used when coverting. + Encoding = file:native_name_encoding(), + case catch unicode:characters_to_binary(Value,Encoding,Encoding) of {'EXIT',_} -> {error,badarg}; AValue -> -- cgit v1.2.3 From 892fb14882ef356c90eda8aa02ca43c3db8b53da Mon Sep 17 00:00:00 2001 From: Dan Gudmundsson Date: Mon, 22 Apr 2013 13:18:29 +0200 Subject: erts: Change erlang:open_port/2 spec --- erts/preloaded/src/erlang.erl | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'erts/preloaded/src') diff --git a/erts/preloaded/src/erlang.erl b/erts/preloaded/src/erlang.erl index 6929ca3fa5..0df0768365 100644 --- a/erts/preloaded/src/erlang.erl +++ b/erts/preloaded/src/erlang.erl @@ -1714,15 +1714,15 @@ nodes(_Arg) -> erlang:nif_error(undefined). -spec open_port(PortName, PortSettings) -> port() when - PortName :: {spawn, Command :: string()} | - {spawn_driver, Command :: [byte()]} | + PortName :: {spawn, Command :: string() | binary()} | + {spawn_driver, Command :: string() | binary()} | {spawn_executable, FileName :: file:name() } | {fd, In :: non_neg_integer(), Out :: non_neg_integer()}, PortSettings :: [Opt], Opt :: {packet, N :: 1 | 2 | 4} | stream | {line, L :: non_neg_integer()} - | {cd, Dir :: string()} + | {cd, Dir :: string() | binary()} | {env, Env :: [{Name :: string(), Val :: string() | false}]} | {args, [string() | binary()]} | {arg0, string() | binary()} -- cgit v1.2.3 From 31b20cac498b98d40ed2bb15bb5259cb3c33a422 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn-Egil=20Dahlberg?= Date: Fri, 5 Jul 2013 14:53:01 +0200 Subject: Add erts app-file --- erts/preloaded/src/Makefile | 15 ++++++++++++--- erts/preloaded/src/erts.app.src | 41 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 53 insertions(+), 3 deletions(-) create mode 100644 erts/preloaded/src/erts.app.src (limited to 'erts/preloaded/src') diff --git a/erts/preloaded/src/Makefile b/erts/preloaded/src/Makefile index 7a7b7fb644..c1580b1495 100644 --- a/erts/preloaded/src/Makefile +++ b/erts/preloaded/src/Makefile @@ -55,9 +55,15 @@ ERL_FILES= $(PRE_LOADED_ERL_MODULES:%=%.erl) BEAM_FILES= $(PRE_LOADED_BEAM_MODULES:%=%.S) STUBS_FILES= $(PRE_LOADED_BEAM_MODULES:%=%.erl) -TARGET_FILES = $(PRE_LOADED_MODULES:%=$(EBIN)/%.$(EMULATOR)) +TARGET_FILES = $(PRE_LOADED_MODULES:%=$(EBIN)/%.$(EMULATOR)) \ + $(APP_TARGET) STATIC_TARGET_FILES = $(PRE_LOADED_MODULES:%=$(STATIC_EBIN)/%.$(EMULATOR)) +APP_FILE= erts.app +APP_SRC= $(APP_FILE).src +APP_TARGET= $(STATIC_EBIN)/$(APP_FILE) + + KERNEL_SRC=$(ERL_TOP)/lib/kernel/src KERNEL_INCLUDE=$(ERL_TOP)/lib/kernel/include STDLIB_INCLUDE=$(ERL_TOP)/lib/stdlib/include @@ -72,14 +78,17 @@ clean: copy: cp *.beam $(STATIC_EBIN) +$(APP_TARGET): $(APP_SRC) $(ERL_TOP)/erts/vsn.mk + $(vsn_verbose)sed -e 's;%VSN%;$(VSN);' $< > $@ + include $(ERL_TOP)/make/otp_release_targets.mk -release_spec: +release_spec: $(APP_TARGET) $(INSTALL_DIR) "$(RELSYSDIR)/src" $(INSTALL_DATA) $(ERL_FILES) $(BEAM_FILES) $(STUBS_FILES) "$(RELSYSDIR)/src" $(INSTALL_DIR) "$(RELSYSDIR)/ebin" - $(INSTALL_DATA) $(STATIC_TARGET_FILES) "$(RELSYSDIR)/ebin" + $(INSTALL_DATA) $(STATIC_TARGET_FILES) $(APP_TARGET) "$(RELSYSDIR)/ebin" release_docs_spec: diff --git a/erts/preloaded/src/erts.app.src b/erts/preloaded/src/erts.app.src new file mode 100644 index 0000000000..fd3e8cb692 --- /dev/null +++ b/erts/preloaded/src/erts.app.src @@ -0,0 +1,41 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2013. 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% +%% +{application, erts, [ + {description, "ERTS CXC 138 10"}, + {vsn, "%VSN%"}, + {modules, [ + %% preloaded + erlang, + erl_prim_loader, + erts_internal, + init, + otp_ring0, + prim_eval, + prim_file, + prim_inet, + prim_zip, + zlib + ]}, + {registered, []}, + {applications, []}, + {env, []}, + {mod, {erts, []}} + ]}. + +%% vim: ft=erlang -- cgit v1.2.3 From 41989072fdfa766916489088aa7eae48a7d89961 Mon Sep 17 00:00:00 2001 From: Raimo Niskanen Date: Fri, 12 Jul 2013 15:42:33 +0200 Subject: Implement emulator netns support for TCP and UDP --- erts/preloaded/src/prim_inet.erl | 37 ++++++++++++++++++++++++++----------- 1 file changed, 26 insertions(+), 11 deletions(-) (limited to 'erts/preloaded/src') diff --git a/erts/preloaded/src/prim_inet.erl b/erts/preloaded/src/prim_inet.erl index fb1269cf91..fa621681f3 100644 --- a/erts/preloaded/src/prim_inet.erl +++ b/erts/preloaded/src/prim_inet.erl @@ -25,7 +25,7 @@ %% Primitive inet_drv interface --export([open/3, fdopen/4, close/1]). +-export([open/3, open/4, fdopen/4, close/1]). -export([bind/3, listen/1, listen/2, peeloff/2]). -export([connect/3, connect/4, async_connect/4]). -export([accept/1, accept/2, async_accept/2]). @@ -64,22 +64,31 @@ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% open(Protocol, Family, Type) -> - open(Protocol, Family, Type, ?INET_REQ_OPEN, []). + open(Protocol, Family, Type, [], ?INET_REQ_OPEN, []). + +open(Protocol, Family, Type, Opts) -> + open(Protocol, Family, Type, Opts, ?INET_REQ_OPEN, []). fdopen(Protocol, Family, Type, Fd) when is_integer(Fd) -> - open(Protocol, Family, Type, ?INET_REQ_FDOPEN, ?int32(Fd)). + open(Protocol, Family, Type, [], ?INET_REQ_FDOPEN, ?int32(Fd)). -open(Protocol, Family, Type, Req, Data) -> +open(Protocol, Family, Type, Opts, Req, Data) -> Drv = protocol2drv(Protocol), AF = enc_family(Family), T = enc_type(Type), try erlang:open_port({spawn_driver,Drv}, [binary]) of S -> - case ctl_cmd(S, Req, [AF,T,Data]) of - {ok,_} -> {ok,S}; - {error,_}=Error -> + case setopts(S, Opts) of + ok -> + case ctl_cmd(S, Req, [AF,T,Data]) of + {ok,_} -> {ok,S}; + {error,_}=E1 -> + close(S), + E1 + end; + {error,_}=E2 -> close(S), - Error + E2 end catch %% The only (?) way to get here is to try to open @@ -1108,6 +1117,7 @@ enc_opt(send_timeout_close) -> ?INET_LOPT_TCP_SEND_TIMEOUT_CLOSE; enc_opt(delay_send) -> ?INET_LOPT_TCP_DELAY_SEND; enc_opt(packet_size) -> ?INET_LOPT_PACKET_SIZE; enc_opt(read_packets) -> ?INET_LOPT_READ_PACKETS; +enc_opt(netns) -> ?INET_LOPT_NETNS; enc_opt(raw) -> ?INET_OPT_RAW; % Names of SCTP opts: enc_opt(sctp_rtoinfo) -> ?SCTP_OPT_RTOINFO; @@ -1164,6 +1174,7 @@ dec_opt(?INET_LOPT_TCP_SEND_TIMEOUT_CLOSE) -> send_timeout_close; dec_opt(?INET_LOPT_TCP_DELAY_SEND) -> delay_send; dec_opt(?INET_LOPT_PACKET_SIZE) -> packet_size; dec_opt(?INET_LOPT_READ_PACKETS) -> read_packets; +dec_opt(?INET_LOPT_NETNS) -> netns; dec_opt(?INET_OPT_RAW) -> raw; dec_opt(I) when is_integer(I) -> undefined. @@ -1261,6 +1272,7 @@ type_opt_1(send_timeout_close) -> bool; type_opt_1(delay_send) -> bool; type_opt_1(packet_size) -> uint; type_opt_1(read_packets) -> uint; +type_opt_1(netns) -> binary; %% %% SCTP options (to be set). If the type is a record type, the corresponding %% record signature is returned, otherwise, an "elementary" type tag @@ -1487,9 +1499,12 @@ type_value_2({bitenumlist,List,_}, EnumList) -> Ls when is_list(Ls) -> true; false -> false end; -type_value_2(binary,Bin) when is_binary(Bin) -> true; -type_value_2(binary_or_uint,Bin) when is_binary(Bin) -> true; -type_value_2(binary_or_uint,Int) when is_integer(Int), Int >= 0 -> true; +type_value_2(binary,Bin) + when is_binary(Bin), byte_size(Bin) < (1 bsl 32) -> true; +type_value_2(binary_or_uint,Bin) + when is_binary(Bin), byte_size(Bin) < (1 bsl 32) -> true; +type_value_2(binary_or_uint,Int) + when is_integer(Int), Int >= 0 -> true; %% Type-checking of SCTP options type_value_2(sctp_assoc_id, X) when X band 16#ffffffff =:= X -> true; -- cgit v1.2.3 From 654c6a115efd5aa871cd453fb27ead8224964825 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Hoguin?= Date: Thu, 22 Aug 2013 10:35:16 +0200 Subject: Export type zlib:zstream/0 Terms of this type are returned and sometimes sit in states. Exporting it allows us to properly track the types there. --- erts/preloaded/src/zlib.erl | 2 ++ 1 file changed, 2 insertions(+) (limited to 'erts/preloaded/src') diff --git a/erts/preloaded/src/zlib.erl b/erts/preloaded/src/zlib.erl index 1faae1c1f4..54391bd945 100644 --- a/erts/preloaded/src/zlib.erl +++ b/erts/preloaded/src/zlib.erl @@ -30,6 +30,8 @@ compress/1,uncompress/1,zip/1,unzip/1, gzip/1,gunzip/1]). +-export_type([zstream/0]). + %% flush argument encoding -define(Z_NO_FLUSH, 0). -define(Z_SYNC_FLUSH, 2). -- cgit v1.2.3 From 49059dbd211987987a7e9d9ef40cc0b2484f829a Mon Sep 17 00:00:00 2001 From: Juan Jose Comellas Date: Mon, 9 Sep 2013 14:19:41 -0300 Subject: Fix incorrect values returned by integer_to_binary/2 When integer_to_binary/2 receives 0 or a negative number as an argument with a base that is different from 10, it will return incorrect values (<<>> in the case of 0) or it will crash (with negative numbers). This commit fixes these problems and adds tests to cover these cases. --- erts/preloaded/src/erlang.erl | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) (limited to 'erts/preloaded/src') diff --git a/erts/preloaded/src/erlang.erl b/erts/preloaded/src/erlang.erl index e016a50c4c..a969ef91dc 100644 --- a/erts/preloaded/src/erlang.erl +++ b/erts/preloaded/src/erlang.erl @@ -2891,22 +2891,23 @@ integer_to_binary(I, Base) when erlang:is_integer(I), erlang:is_integer(Base), Base >= 2, Base =< 1+$Z-$A+10 -> if I < 0 -> - <<"$-",(integer_to_binary(-I, Base, []))/binary>>; + <<$-,(integer_to_binary(-I, Base, <<>>))/binary>>; true -> integer_to_binary(I, Base, <<>>) end; integer_to_binary(I, Base) -> erlang:error(badarg, [I, Base]). -integer_to_binary(0, _Base, R0) -> - R0; integer_to_binary(I0, Base, R0) -> D = I0 rem Base, I1 = I0 div Base, - if D >= 10 -> - integer_to_binary(I1,Base,<<(D-10+$A),R0/binary>>); - true -> - integer_to_binary(I1,Base,<<(D+$0),R0/binary>>) + R1 = if + D >= 10 -> <<(D-10+$A),R0/binary>>; + true -> <<(D+$0),R0/binary>> + end, + if + I1 =:= 0 -> R1; + true -> integer_to_binary(I1, Base, R1) end. %% erlang:flush_monitor_message/2 is for internal use only! -- cgit v1.2.3 From 7fbf2c26ac063988818230a0e18a9df48c2fbf2d Mon Sep 17 00:00:00 2001 From: Steve Vinoski Date: Tue, 27 Aug 2013 11:42:00 -0400 Subject: add {active,N} socket option for TCP, UDP, and SCTP Add the {active,N} socket option, where N is an integer in the range -32768..32767, to allow a caller to specify the number of data messages to be delivered to the controlling process. Once the socket's delivered message count either reaches 0 or is explicitly set to 0 with inet:setopts/2 or by including {active,0} as an option when the socket is created, the socket transitions to passive ({active, false}) mode and the socket's controlling process receives a message to inform it of the transition. TCP sockets receive {tcp_passive,Socket}, UDP sockets receive {udp_passive,Socket} and SCTP sockets receive {sctp_passive,Socket}. The socket's delivered message counter defaults to 0, but it can be set using {active,N} via any gen_tcp, gen_udp, or gen_sctp function that takes socket options as arguments, or via inet:setopts/2. New N values are added to the socket's current counter value, and negative numbers can be used to reduce the counter value. Specifying a number that would cause the socket's counter value to go above 32767 causes an einval error. If a negative number is specified such that the counter value would become negative, the socket's counter value is set to 0 and the socket transitions to passive mode. If the counter value is already 0 and inet:setopts(Socket, [{active,0}]) is specified, the counter value remains at 0 but the appropriate passive mode transition message is generated for the socket. This commit contains a modified preloaded prim_inet.beam due to changes in prim_inet.erl. Add tests for {active,N} mode for TCP, UDP, and SCTP sockets. Add documentation for {active,N} mode for inet, gen_tcp, gen_udp, and gen_sctp. --- erts/preloaded/src/prim_inet.erl | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) (limited to 'erts/preloaded/src') diff --git a/erts/preloaded/src/prim_inet.erl b/erts/preloaded/src/prim_inet.erl index fa621681f3..69eed716ff 100644 --- a/erts/preloaded/src/prim_inet.erl +++ b/erts/preloaded/src/prim_inet.erl @@ -1237,7 +1237,8 @@ type_opt_1(buffer) -> int; type_opt_1(active) -> {enum,[{false, ?INET_PASSIVE}, {true, ?INET_ACTIVE}, - {once, ?INET_ONCE}]}; + {once, ?INET_ONCE}, + {multi, ?INET_MULTI}]}; type_opt_1(packet) -> {enum,[{0, ?TCP_PB_RAW}, {1, ?TCP_PB_1}, @@ -1716,11 +1717,14 @@ encode_opt_val(Opts) -> Reason -> {error,Reason} end. +%% {active, once} and {active, N} are specially optimized because they will +%% be used for every packet or every N packets, not only once when +%% initializing the socket. Measurements show that this optimization is +%% worthwhile. enc_opt_val([{active,once}|Opts], Acc) -> - %% Specially optimized because {active,once} will be used for - %% every packet, not only once when initializing the socket. - %% Measurements show that this optimization is worthwhile. enc_opt_val(Opts, [<>|Acc]); +enc_opt_val([{active,N}|Opts], Acc) when is_integer(N), N < 32768, N >= -32768 -> + enc_opt_val(Opts, [<>|Acc]); enc_opt_val([{raw,P,O,B}|Opts], Acc) -> enc_opt_val(Opts, Acc, raw, {P,O,B}); enc_opt_val([{Opt,Val}|Opts], Acc) -> @@ -1810,6 +1814,14 @@ dec_opt_val([]) -> []. dec_opt_val(Buf, raw, Type) -> {{P,O,B},T} = dec_value(Type, Buf), [{raw,P,O,B}|dec_opt_val(T)]; +dec_opt_val(Buf, active, Type) -> + case dec_value(Type, Buf) of + {multi,[M0,M1|T]} -> + <> = list_to_binary([M0,M1]), + [{active,N}|dec_opt_val(T)]; + {Val,T} -> + [{active,Val}|dec_opt_val(T)] + end; dec_opt_val(Buf, Opt, Type) -> {Val,T} = dec_value(Type, Buf), [{Opt,Val}|dec_opt_val(T)]. -- cgit v1.2.3 From 75a79e6547fd66c2194d6f488c30ad888a715f4b Mon Sep 17 00:00:00 2001 From: Steve Vinoski Date: Wed, 4 Sep 2013 10:21:47 -0400 Subject: add system_info(ets_limit) Add system_info(ets_limit) to provide a way to retrieve the runtime's maximum number of ETS tables. Add tests and documentation for it too. Also repair the alphabetical order of system_info/1 argument descriptions in the documentation and in the erlang.erl clauses. Add new preloaded erlang.erl due to that change. Also ensure all system_info/1 clauses are represented in the erlang.xml source documentation -- a couple had been inadvertently dropped in previous commits when other clauses were added. --- erts/preloaded/src/erlang.erl | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'erts/preloaded/src') diff --git a/erts/preloaded/src/erlang.erl b/erts/preloaded/src/erlang.erl index a969ef91dc..d40ee7c59a 100644 --- a/erts/preloaded/src/erlang.erl +++ b/erts/preloaded/src/erlang.erl @@ -2099,13 +2099,14 @@ tuple_to_list(_Tuple) -> (creation) -> integer(); (debug_compiled) -> boolean(); (dist) -> binary(); + (dist_buf_busy_limit) -> non_neg_integer(); (dist_ctrl) -> {Node :: node(), ControllingEntity :: port() | pid()}; (driver_version) -> string(); (dynamic_trace) -> none | dtrace | systemtap; (dynamic_trace_probes) -> boolean(); (elib_malloc) -> false; - (dist_buf_busy_limit) -> non_neg_integer(); + (ets_limit) -> pos_integer(); (fullsweep_after) -> {fullsweep_after, non_neg_integer()}; (garbage_collection) -> [{atom(), integer()}]; (heap_sizes) -> [non_neg_integer()]; -- cgit v1.2.3 From 059d8b76011f960cc5938501a33002b051b0bca2 Mon Sep 17 00:00:00 2001 From: Sverker Eriksson Date: Thu, 26 Sep 2013 22:36:34 +0200 Subject: erts: Add erts_mmap stats As part of erlang:system_info({allocator,mseg_alloc}) and erl_crash.dump --- erts/preloaded/src/erlang.erl | 2 ++ 1 file changed, 2 insertions(+) (limited to 'erts/preloaded/src') diff --git a/erts/preloaded/src/erlang.erl b/erts/preloaded/src/erlang.erl index d40ee7c59a..2b6760c675 100644 --- a/erts/preloaded/src/erlang.erl +++ b/erts/preloaded/src/erlang.erl @@ -3499,6 +3499,8 @@ mk_res_list([]) -> mk_res_list([Alloc | Rest]) -> [{Alloc, []} | mk_res_list(Rest)]. +insert_instance(I, N, Rest) when erlang:is_atom(N) -> + [{N, I} | Rest]; insert_instance(I, N, []) -> [{instance, N, I}]; insert_instance(I, N, [{instance, M, _}|_] = Rest) when N < M -> -- cgit v1.2.3 From f207cee9b667914dd93b5f4349fb86dd14bff7f6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn-Egil=20Dahlberg?= Date: Thu, 7 Nov 2013 11:04:48 +0100 Subject: preloaded: Add debug_info to preloaded Needed by Dialyzer. --- erts/preloaded/src/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'erts/preloaded/src') diff --git a/erts/preloaded/src/Makefile b/erts/preloaded/src/Makefile index c1580b1495..4ea2d41075 100644 --- a/erts/preloaded/src/Makefile +++ b/erts/preloaded/src/Makefile @@ -68,7 +68,7 @@ KERNEL_SRC=$(ERL_TOP)/lib/kernel/src KERNEL_INCLUDE=$(ERL_TOP)/lib/kernel/include STDLIB_INCLUDE=$(ERL_TOP)/lib/stdlib/include -ERL_COMPILE_FLAGS += +warn_obsolete_guard -I$(KERNEL_SRC) -I$(KERNEL_INCLUDE) +ERL_COMPILE_FLAGS += +warn_obsolete_guard +debug_info -I$(KERNEL_SRC) -I$(KERNEL_INCLUDE) debug opt: $(TARGET_FILES) -- cgit v1.2.3 From bb52546e9a671ed0fd55d2e5274f299a853bed51 Mon Sep 17 00:00:00 2001 From: Raimo Niskanen Date: Tue, 5 Nov 2013 15:52:56 +0100 Subject: Implement prim_inet:socknames/1,2 and prim_inet:peernames/1,2 --- erts/preloaded/src/prim_inet.erl | 70 ++++++++++++++++++++++++++++++++++++++-- 1 file changed, 68 insertions(+), 2 deletions(-) (limited to 'erts/preloaded/src') diff --git a/erts/preloaded/src/prim_inet.erl b/erts/preloaded/src/prim_inet.erl index fa621681f3..aa700c5194 100644 --- a/erts/preloaded/src/prim_inet.erl +++ b/erts/preloaded/src/prim_inet.erl @@ -41,8 +41,8 @@ getifaddrs/1, getiflist/1, ifget/3, ifset/3, gethostname/1]). -export([getservbyname/3, getservbyport/3]). --export([peername/1, setpeername/2]). --export([sockname/1, setsockname/2]). +-export([peername/1, setpeername/2, peernames/1, peernames/2]). +-export([sockname/1, setsockname/2, socknames/1, socknames/2]). -export([attach/1, detach/1]). -include("inet_sctp.hrl"). @@ -574,6 +574,36 @@ setpeername(S, undefined) when is_port(S) -> {error,_}=Error -> Error end. +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% +%% PEERNAMES(insock()) -> {ok, [{IP, Port}, ...]} | {error, Reason} +%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +peernames(S) when is_port(S) -> + peernames(S, undefined). + +peernames(S, #sctp_assoc_change{assoc_id=AssocId}) when is_port(S) -> + peernames(S, AssocId); +peernames(S, AssocId) + when is_port(S), is_integer(AssocId); + is_port(S), AssocId =:= undefined -> + Q = get, + Type = [[sctp_assoc_id,0]], + case type_value(Q, Type, AssocId) of + true -> + case ctl_cmd + (S, ?INET_REQ_GETPADDRS, + enc_value(Q, Type, AssocId)) of + {ok,Addrs} -> + {ok,get_addrs(Addrs)}; + Error -> + Error + end; + false -> + {error,einval} + end. + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% %% SOCKNAME(insock()) -> {ok, {IP, Port}} | {error, Reason} @@ -599,6 +629,36 @@ setsockname(S, undefined) when is_port(S) -> {error,_}=Error -> Error end. +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% +%% SOCKNAMES(insock()) -> {ok, [{IP, Port}, ...]} | {error, Reason} +%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +socknames(S) when is_port(S) -> + socknames(S, undefined). + +socknames(S, #sctp_assoc_change{assoc_id=AssocId}) when is_port(S) -> + socknames(S, AssocId); +socknames(S, AssocId) + when is_port(S), is_integer(AssocId); + is_port(S), AssocId =:= undefined -> + Q = get, + Type = [[sctp_assoc_id,0]], + case type_value(Q, Type, AssocId) of + true -> + case ctl_cmd + (S, ?INET_REQ_GETLADDRS, + enc_value(Q, Type, AssocId)) of + {ok,Addrs} -> + {ok,get_addrs(Addrs)}; + Error -> + Error + end; + false -> + {error,einval} + end. + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% %% SETOPT(insock(), Opt, Value) -> ok | {error, Reason} @@ -2213,6 +2273,12 @@ ip6_to_bytes({A,B,C,D,E,F,G,H}) -> [?int16(A), ?int16(B), ?int16(C), ?int16(D), ?int16(E), ?int16(F), ?int16(G), ?int16(H)]. +get_addrs([]) -> + []; +get_addrs([F,P1,P0|Addr]) -> + {IP,Addrs} = get_ip(F, Addr), + [{IP,?u16(P1, P0)}|get_addrs(Addrs)]. + get_ip(?INET_AF_INET, Addr) -> get_ip4(Addr); get_ip(?INET_AF_INET6, Addr) -> get_ip6(Addr). -- cgit v1.2.3 From 9315ebe52626e7320e1de14d704ec5e3c7d72d1c Mon Sep 17 00:00:00 2001 From: Siri Hansen Date: Fri, 15 Nov 2013 10:52:14 +0100 Subject: Fix bug with backslash in erl_prim_loader:normalize/1 This function normalizes a path: * convert atoms to strings * flatten strings * convert backslash to a forward slash The bugfix is to only convert backslashes to forward slashes on windows and not on any other platforms. --- erts/preloaded/src/erl_prim_loader.erl | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'erts/preloaded/src') diff --git a/erts/preloaded/src/erl_prim_loader.erl b/erts/preloaded/src/erl_prim_loader.erl index e8ddfc4a57..fc43d1d4fa 100644 --- a/erts/preloaded/src/erl_prim_loader.erl +++ b/erts/preloaded/src/erl_prim_loader.erl @@ -1439,7 +1439,12 @@ normalize(Name, Acc) -> [Atom | Rest] when is_atom(Atom) -> normalize(atom_to_list(Atom) ++ Rest, Acc); [$\\ | Chars] -> - normalize(Chars, [$/ | Acc]); + case erlang:system_info(os_type) of + {win32, _} -> + normalize(Chars, [$/ | Acc]); + _ -> + normalize(Chars, [$\\ | Acc]) + end; [Char | Chars] -> normalize(Chars, [Char | Acc]); [] -> -- cgit v1.2.3 From f47c818746c1df4055b1de8aabf47364f502274c Mon Sep 17 00:00:00 2001 From: Joseph Blomstedt Date: Thu, 29 Nov 2012 14:50:42 -0800 Subject: Add sync option to file:open/2 The sync option adds the POSIX O_SYNC flag to the open system call on platforms that support the flag or its equivalent, e.g., FILE_FLAG_WRITE_THROUGH on Windows. For platforms that don't support it, file:open/2 returns {error, enotsup} if the sync option is passed in. The semantics of O_SYNC are platform-specific. For example, not all platforms guarantee that all file metadata are written to the disk along with the file data when the flag is in effect. This issue is noted in the documentation this commit adds for the sync option. Add a test for the sync option. Note however that the underlying OS semantics for O_SYNC can't be tested automatically in any practical way, so the test assumes the OS does the right thing with the flag when present. For manual verification, dtruss on OS X and strace on Linux were both run against beam processes to watch calls to open(), and file:open/2 was called in Erlang shells to open files for writing, both with and without the sync option. Both the dtruss output and the strace output showed that the O_SYNC flag was present in the open() calls when sync was specified and was clear when sync was not specified. --- erts/preloaded/src/prim_file.erl | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'erts/preloaded/src') diff --git a/erts/preloaded/src/prim_file.erl b/erts/preloaded/src/prim_file.erl index 489e8ca4ea..5999e98340 100644 --- a/erts/preloaded/src/prim_file.erl +++ b/erts/preloaded/src/prim_file.erl @@ -123,9 +123,11 @@ -define(EFILE_MODE_APPEND, 4). -define(EFILE_COMPRESSED, 8). -define(EFILE_MODE_EXCL, 16). +%% Note: bit 5 (32) is used internally for VxWorks +-define(EFILE_MODE_SYNC, 64). %% Use this mask to get just the mode bits to be passed to the driver. --define(EFILE_MODE_MASK, 31). +-define(EFILE_MODE_MASK, 127). %% Seek modes for the driver's seek function. -define(EFILE_SEEK_SET, 0). @@ -1197,6 +1199,8 @@ open_mode([append|Rest], Mode, Portopts, Setopts) -> Portopts, Setopts); open_mode([exclusive|Rest], Mode, Portopts, Setopts) -> open_mode(Rest, Mode bor ?EFILE_MODE_EXCL, Portopts, Setopts); +open_mode([sync|Rest], Mode, Portopts, Setopts) -> + open_mode(Rest, Mode bor ?EFILE_MODE_SYNC, Portopts, Setopts); open_mode([delayed_write|Rest], Mode, Portopts, Setopts) -> open_mode([{delayed_write, 64*1024, 2000}|Rest], Mode, Portopts, Setopts); -- cgit v1.2.3 From 1a6347e868d375bb4bd9cb4e6651c82ea57bc220 Mon Sep 17 00:00:00 2001 From: Lukas Larsson Date: Mon, 18 Nov 2013 09:54:12 +0100 Subject: erts: Fix naming in erlang:monitor spec --- erts/preloaded/src/erlang.erl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'erts/preloaded/src') diff --git a/erts/preloaded/src/erlang.erl b/erts/preloaded/src/erlang.erl index 2b6760c675..291926578e 100644 --- a/erts/preloaded/src/erlang.erl +++ b/erts/preloaded/src/erlang.erl @@ -1073,8 +1073,8 @@ module_loaded(_Module) -> %% monitor/2 -spec monitor(Type, Item) -> MonitorRef when Type :: process, - Item :: pid() | Module | {Module, Node}, - Module :: module(), + Item :: pid() | RegName | {RegName, Node}, + RegName :: module(), Node :: node(), MonitorRef :: reference(). monitor(_Type, _Item) -> -- cgit v1.2.3 From ca0425c6ff85262bc15367f5fd9cbc51cde52b20 Mon Sep 17 00:00:00 2001 From: Rickard Green Date: Wed, 2 Oct 2013 10:07:27 +0200 Subject: Execution of system tasks in context of another process A process requesting a system task to be executed in the context of another process will be notified by a message when the task has executed. This message will be on the form: {RequestType, RequestId, Pid, Result}. A process requesting a system task to be executed can set priority on the system task. The requester typically set the same priority on the task as its own process priority, and by this avoiding priority inversion. A request for execution of a system task is made by calling the statically linked in NIF erts_internal:request_system_task(Pid, Prio, Request). This is an undocumented ERTS internal function that should remain so. It should *only* be called from BIF implementations. Currently defined system tasks are: * garbage_collect * check_process_code Further system tasks can and will be implemented in the future. The erlang:garbage_collect/[1,2] and erlang:check_process_code/[2,3] BIFs are now implemented using system tasks. Both the 'garbage_collect' and the 'check_process_code' operations perform or may perform garbage_collections. By doing these via the system task functionality all garbage collect operations in the system will be performed solely in the context of the process being garbage collected. This makes it possible to later implement functionality for disabling garbage collection of a process over context switches. Newly introduced BIFs: * erlang:garbage_collect/2 - The new second argument is an option list. Introduced option: * {async, RequestId} - making it possible for users to issue asynchronous garbage collect requests. * erlang:check_process_code/3 - The new third argument is an option list. Introduced options: * {async, RequestId} - making it possible for users to issue asynchronous check process code requests. * {allow_gc, boolean()} - making it possible to issue requests that aren't allowed to garbage collect (operation will abort if gc should be needed). These options have been introduced as a preparation for parallelization of check_process_code operations when the code_server is about to purge a module. --- erts/preloaded/src/erlang.erl | 132 ++++++++++++++++++++++++++++++++--- erts/preloaded/src/erts_internal.erl | 21 ++++++ 2 files changed, 143 insertions(+), 10 deletions(-) (limited to 'erts/preloaded/src') diff --git a/erts/preloaded/src/erlang.erl b/erts/preloaded/src/erlang.erl index a969ef91dc..e521c6fc3d 100644 --- a/erts/preloaded/src/erlang.erl +++ b/erts/preloaded/src/erlang.erl @@ -81,7 +81,8 @@ -export([binary_to_list/3, binary_to_term/1, binary_to_term/2]). -export([bit_size/1, bitsize/1, bitstr_to_list/1, bitstring_to_list/1]). -export([bump_reductions/1, byte_size/1, call_on_load_function/1]). --export([cancel_timer/1, check_old_code/1, check_process_code/2, crc32/1]). +-export([cancel_timer/1, check_old_code/1, check_process_code/2, + check_process_code/3, crc32/1]). -export([crc32/2, crc32_combine/3, date/0, decode_packet/3]). -export([delete_element/2]). -export([delete_module/1, demonitor/1, demonitor/2, display/1]). @@ -91,7 +92,7 @@ -export([float_to_binary/1, float_to_binary/2, float_to_list/1, float_to_list/2]). -export([fun_info/2, fun_to_list/1, function_exported/3]). --export([garbage_collect/0, garbage_collect/1]). +-export([garbage_collect/0, garbage_collect/1, garbage_collect/2]). -export([garbage_collect_message_area/0, get/0, get/1, get_keys/1]). -export([get_module_info/1, get_stacktrace/0, group_leader/0]). -export([group_leader/2, halt/0, halt/1, halt/2, hash/2, hibernate/3]). @@ -429,11 +430,71 @@ check_old_code(_Module) -> erlang:nif_error(undefined). %% check_process_code/2 --spec check_process_code(Pid, Module) -> boolean() when +-spec check_process_code(Pid, Module) -> CheckResult when Pid :: pid(), - Module :: module(). -check_process_code(_Pid, _Module) -> - erlang:nif_error(undefined). + Module :: module(), + CheckResult :: boolean(). +check_process_code(Pid, Module) -> + try + erlang:check_process_code(Pid, Module, [{allow_gc, true}]) + catch + error:Error -> erlang:error(Error, [Pid, Module]) + end. + +%% check_process_code/3 +-spec check_process_code(Pid, Module, OptionList) -> CheckResult | async when + Pid :: pid(), + Module :: module(), + RequestId :: term(), + Option :: {async, RequestId} | {allow_gc, boolean()}, + OptionList :: [Option], + CheckResult :: boolean() | aborted. +check_process_code(Pid, Module, OptionList) -> + try + {Async, AllowGC} = get_cpc_opts(OptionList, sync, true), + case Async of + {async, ReqId} -> + {priority, Prio} = erlang:process_info(erlang:self(), + priority), + erts_internal:request_system_task(Pid, + Prio, + {check_process_code, + ReqId, + Module, + AllowGC}), + async; + sync -> + case Pid == erlang:self() of + true -> + erts_internal:check_process_code(Module, + [{allow_gc, AllowGC}]); + false -> + {priority, Prio} = erlang:process_info(erlang:self(), + priority), + ReqId = erlang:make_ref(), + erts_internal:request_system_task(Pid, + Prio, + {check_process_code, + ReqId, + Module, + AllowGC}), + receive + {check_process_code, ReqId, CheckResult} -> + CheckResult + end + end + end + catch + error:Error -> erlang:error(Error, [Pid, Module, OptionList]) + end. + +% gets async and allow_gc opts and verify valid option list +get_cpc_opts([{async, _ReqId} = AsyncTuple | Options], _OldAsync, AllowGC) -> + get_cpc_opts(Options, AsyncTuple, AllowGC); +get_cpc_opts([{allow_gc, AllowGC} | Options], Async, _OldAllowGC) -> + get_cpc_opts(Options, Async, AllowGC); +get_cpc_opts([], Async, AllowGC) -> + {Async, AllowGC}. %% crc32/1 -spec erlang:crc32(Data) -> non_neg_integer() when @@ -793,10 +854,61 @@ garbage_collect() -> erlang:nif_error(undefined). %% garbage_collect/1 --spec garbage_collect(Pid) -> boolean() when - Pid :: pid(). -garbage_collect(_Pid) -> - erlang:nif_error(undefined). +-spec garbage_collect(Pid) -> GCResult when + Pid :: pid(), + GCResult :: boolean(). +garbage_collect(Pid) -> + try + erlang:garbage_collect(Pid, []) + catch + error:Error -> erlang:error(Error, [Pid]) + end. + +%% garbage_collect/2 +-spec garbage_collect(Pid, OptionList) -> GCResult | async when + Pid :: pid(), + RequestId :: term(), + Option :: {async, RequestId}, + OptionList :: [Option], + GCResult :: boolean(). +garbage_collect(Pid, OptionList) -> + try + Async = get_gc_opts(OptionList, sync), + case Async of + {async, ReqId} -> + {priority, Prio} = erlang:process_info(erlang:self(), + priority), + erts_internal:request_system_task(Pid, + Prio, + {garbage_collect, ReqId}), + async; + sync -> + case Pid == erlang:self() of + true -> + erlang:garbage_collect(); + false -> + {priority, Prio} = erlang:process_info(erlang:self(), + priority), + ReqId = erlang:make_ref(), + erts_internal:request_system_task(Pid, + Prio, + {garbage_collect, + ReqId}), + receive + {garbage_collect, ReqId, GCResult} -> + GCResult + end + end + end + catch + error:Error -> erlang:error(Error, [Pid, OptionList]) + end. + +% gets async opt and verify valid option list +get_gc_opts([{async, _ReqId} = AsyncTuple | Options], _OldAsync) -> + get_gc_opts(Options, AsyncTuple); +get_gc_opts([], Async) -> + Async. %% garbage_collect_message_area/0 -spec erlang:garbage_collect_message_area() -> boolean(). diff --git a/erts/preloaded/src/erts_internal.erl b/erts/preloaded/src/erts_internal.erl index 8a8cd52d64..c8e8e7e069 100644 --- a/erts/preloaded/src/erts_internal.erl +++ b/erts/preloaded/src/erts_internal.erl @@ -33,6 +33,10 @@ -export([port_command/3, port_connect/2, port_close/1, port_control/3, port_call/3, port_info/1, port_info/2]). +-export([request_system_task/3]). + +-export([check_process_code/2]). + %% %% Await result of send to port %% @@ -139,3 +143,20 @@ port_info(_Result) -> port_info(_Result, _Item) -> erlang:nif_error(undefined). + +-spec request_system_task(Pid, Prio, Request) -> 'ok' when + Prio :: 'max' | 'high' | 'normal' | 'low', + Request :: {'garbage_collect', term()} + | {'check_process_code', term(), module(), boolean()}, + Pid :: pid(). + +request_system_task(_Pid, _Prio, _Request) -> + erlang:nif_error(undefined). + +-spec check_process_code(Module, OptionList) -> boolean() when + Module :: module(), + Option :: {allow_gc, boolean()}, + OptionList :: [Option]. +check_process_code(_Module, _OptionList) -> + erlang:nif_error(undefined). + -- cgit v1.2.3 From d5b6c6f0bd96108d788cdfb9be15059125b3d87f Mon Sep 17 00:00:00 2001 From: Sverker Eriksson Date: Wed, 16 Oct 2013 16:28:21 +0200 Subject: erts: Add erlang wrappers to binary_to_term to not expose the trapping BIF in the stacktrace when it throws badarg. --- erts/preloaded/src/erlang.erl | 18 ++++++++++++++---- erts/preloaded/src/erts_internal.erl | 12 +++++++++++- 2 files changed, 25 insertions(+), 5 deletions(-) (limited to 'erts/preloaded/src') diff --git a/erts/preloaded/src/erlang.erl b/erts/preloaded/src/erlang.erl index e521c6fc3d..7b59f6c8b4 100644 --- a/erts/preloaded/src/erlang.erl +++ b/erts/preloaded/src/erlang.erl @@ -362,15 +362,25 @@ binary_to_list(_Binary, _Start, _Stop) -> %% binary_to_term/1 -spec binary_to_term(Binary) -> term() when Binary :: ext_binary(). -binary_to_term(_Binary) -> - erlang:nif_error(undefined). +binary_to_term(Binary) -> + %% This BIF may throw badarg while trapping + try + erts_internal:binary_to_term(Binary) + catch + error:Reason -> erlang:error(Reason,[Binary]) + end. %% binary_to_term/2 -spec binary_to_term(Binary, Opts) -> term() when Binary :: ext_binary(), Opts :: [safe]. -binary_to_term(_Binary, _Opts) -> - erlang:nif_error(undefined). +binary_to_term(Binary, Opts) -> + %% This BIF may throw badarg while trapping + try + erts_internal:binary_to_term(Binary,Opts) + catch + error:Reason -> erlang:error(Reason,[Binary,Opts]) + end. %% bit_size/1 %% Shadowed by erl_bif_types: erlang:bit_size/1 diff --git a/erts/preloaded/src/erts_internal.erl b/erts/preloaded/src/erts_internal.erl index c8e8e7e069..d6a185482e 100644 --- a/erts/preloaded/src/erts_internal.erl +++ b/erts/preloaded/src/erts_internal.erl @@ -29,7 +29,7 @@ -module(erts_internal). -export([await_port_send_result/3]). - +-export([binary_to_term/1, binary_to_term/2]). -export([port_command/3, port_connect/2, port_close/1, port_control/3, port_call/3, port_info/1, port_info/2]). @@ -160,3 +160,13 @@ request_system_task(_Pid, _Prio, _Request) -> check_process_code(_Module, _OptionList) -> erlang:nif_error(undefined). +-spec binary_to_term(Binary) -> term() when + Binary :: binary(). +binary_to_term(_Binary) -> + erlang:nif_error(undefined). + +-spec binary_to_term(Binary, Opts) -> term() when + Binary :: binary(), + Opts :: [safe]. +binary_to_term(_Binary, _Opts) -> + erlang:nif_error(undefined). -- cgit v1.2.3 From e16f564fe0d64017d5cfcf56255f0a6965a6a471 Mon Sep 17 00:00:00 2001 From: Rickard Green Date: Mon, 25 Nov 2013 15:34:27 +0100 Subject: Fix prim_inet:close/1 --- erts/preloaded/src/prim_inet.erl | 28 ++-------------------------- 1 file changed, 2 insertions(+), 26 deletions(-) (limited to 'erts/preloaded/src') diff --git a/erts/preloaded/src/prim_inet.erl b/erts/preloaded/src/prim_inet.erl index aa700c5194..a9df75327c 100644 --- a/erts/preloaded/src/prim_inet.erl +++ b/erts/preloaded/src/prim_inet.erl @@ -186,32 +186,8 @@ close_pend_loop(S, N) -> end. close_port(S) -> - case erlang:process_info(self(), trap_exit) of - {trap_exit,true} -> - %% Ensure exit message and consume it - link(S), - %% This is still not a perfect solution. - %% - %% The problem is to close the port and consume any exit - %% message while not knowing if this process traps exit - %% nor if this process has a link to the port. Here we - %% just knows that this process traps exit. - %% - %% If we right here get killed for some reason that exit - %% signal will propagate to the port and onwards to anyone - %% that is linked to the port. E.g when we close a socket - %% that is not ours. - %% - %% The problem can be solved with lists:member on our link - %% list but we deem that as potentially too expensive. We - %% need an is_linked/1 function or guard, or we need - %% a port_close function that can atomically unlink... - catch erlang:port_close(S), - receive {'EXIT',S,_} -> ok end; - {trap_exit,false} -> - catch erlang:port_close(S), - ok - end. + catch erlang:port_close(S), + receive {'EXIT',S,_} -> ok after 0 -> ok end. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% -- cgit v1.2.3 From 47979206defa9429458e419b691138ab1b519833 Mon Sep 17 00:00:00 2001 From: Rickard Green Date: Thu, 9 Jan 2014 12:50:28 +0100 Subject: Fix issues with new versioning --- erts/preloaded/src/erlang.erl | 1 + 1 file changed, 1 insertion(+) (limited to 'erts/preloaded/src') diff --git a/erts/preloaded/src/erlang.erl b/erts/preloaded/src/erlang.erl index 0ed677c3d8..f99d5bfdd0 100644 --- a/erts/preloaded/src/erlang.erl +++ b/erts/preloaded/src/erlang.erl @@ -2246,6 +2246,7 @@ tuple_to_list(_Tuple) -> (modified_timing_level) -> integer() | undefined; (multi_scheduling) -> disabled | blocked | enabled; (multi_scheduling_blockers) -> [PID :: pid()]; + (otp_correction_package) -> string(); (otp_release) -> string(); (port_count) -> non_neg_integer(); (port_limit) -> pos_integer(); -- cgit v1.2.3 From 1101fcb3e61634f1be92e1b9ba9fad5a11b8554a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Gustavsson?= Date: Thu, 16 Jan 2014 12:16:39 +0100 Subject: Add the 'rle' zstrategy --- erts/preloaded/src/zlib.erl | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'erts/preloaded/src') diff --git a/erts/preloaded/src/zlib.erl b/erts/preloaded/src/zlib.erl index 3d85533b80..df7b2e6198 100644 --- a/erts/preloaded/src/zlib.erl +++ b/erts/preloaded/src/zlib.erl @@ -47,6 +47,7 @@ %% compresssion strategy -define(Z_FILTERED, 1). -define(Z_HUFFMAN_ONLY, 2). +-define(Z_RLE, 3). -define(Z_DEFAULT_STRATEGY, 0). %% deflate compression method @@ -125,7 +126,7 @@ -type zmethod() :: 'deflated'. -type zwindowbits() :: -15..-9 | 9..47. -type zmemlevel() :: 1..9. --type zstrategy() :: 'default' | 'filtered' | 'huffman_only'. +-type zstrategy() :: 'default' | 'filtered' | 'huffman_only' | 'rle'. %%------------------------------------------------------------------------ @@ -486,6 +487,7 @@ arg_level(_) -> erlang:error(badarg). arg_strategy(filtered) -> ?Z_FILTERED; arg_strategy(huffman_only) -> ?Z_HUFFMAN_ONLY; +arg_strategy(rle) -> ?Z_RLE; arg_strategy(default) -> ?Z_DEFAULT_STRATEGY; arg_strategy(_) -> erlang:error(badarg). -- cgit v1.2.3 From 0b36ce01e81744f4c0b41bfe1f62b4bf5d0ece97 Mon Sep 17 00:00:00 2001 From: Lukas Larsson Date: Mon, 27 Jan 2014 12:01:45 +0100 Subject: erts/kernel: sendfile no longer uses async threads This has been done because a slow client attack is possible if the async thread pool is used. The scenario is: Client does a request for a file and then slowly receives the file one byte at a time. This will eventually fill the async thread pool with blocking sendfile operations and thus starving the vm of all file operations. If you still want to use the async threads pool for sendfile an option to enable it has been introduced. --- erts/preloaded/src/prim_file.erl | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) (limited to 'erts/preloaded/src') diff --git a/erts/preloaded/src/prim_file.erl b/erts/preloaded/src/prim_file.erl index 5999e98340..34679404a2 100644 --- a/erts/preloaded/src/prim_file.erl +++ b/erts/preloaded/src/prim_file.erl @@ -27,7 +27,7 @@ %% Generic file contents operations -export([open/2, close/1, datasync/1, sync/1, advise/4, position/2, truncate/1, write/2, pwrite/2, pwrite/3, read/2, read_line/1, pread/2, pread/3, - copy/3, sendfile/10, allocate/3]). + copy/3, sendfile/8, allocate/3]). %% Specialized file operations -export([open/1, open/3]). @@ -149,6 +149,9 @@ -define(POSIX_FADV_DONTNEED, 4). -define(POSIX_FADV_NOREUSE, 5). +%% Sendfile flags +-define(EFILE_SENDFILE_USE_THREADS, 1). + %%% BIFs @@ -582,13 +585,14 @@ write_file(_, _) -> % {error, enotsup}; sendfile(#file_descriptor{module = ?MODULE, data = {Port, _}}, Dest, Offset, Bytes, _ChunkSize, Headers, Trailers, - _Nodiskio, _MNowait, _Sync) -> + Flags) -> case erlang:port_get_data(Dest) of Data when Data == inet_tcp; Data == inet6_tcp -> ok = inet:lock_socket(Dest,true), {ok, DestFD} = prim_inet:getfd(Dest), + IntFlags = translate_sendfile_flags(Flags), try drv_command(Port, [< + ?EFILE_SENDFILE_USE_THREADS bor translate_sendfile_flags(T); +translate_sendfile_flags([_|T]) -> + translate_sendfile_flags(T); +translate_sendfile_flags([]) -> + 0. + %%%----------------------------------------------------------------- %%% Functions operating on files without handle to the file. ?DRV. -- cgit v1.2.3 From c1c03ae4ee50e58b7669ea88ec4d29c6b2b67c7b Mon Sep 17 00:00:00 2001 From: Steve Vinoski Date: Thu, 9 Jan 2014 21:22:45 -0500 Subject: initial support for dirty schedulers and dirty NIFs Add initial support for dirty schedulers. There are two types of dirty schedulers: CPU schedulers and I/O schedulers. By default, there are as many dirty CPU schedulers as there are normal schedulers and as many dirty CPU schedulers online as normal schedulers online. There are 10 dirty I/O schedulers (similar to the choice of 10 as the default for async threads). By default, dirty schedulers are disabled and conditionally compiled out. To enable them, you must pass --enable-dirty-schedulers to the top-level configure script when building Erlang/OTP. Current dirty scheduler support requires the emulator to be built with SMP support. This restriction will be lifted in the future. You can specify the number of dirty schedulers with the command-line options +SDcpu (for dirty CPU schedulers) and +SDio (for dirty I/O schedulers). The +SDcpu option is similar to the +S option in that it takes two numbers separated by a colon: C1:C2, where C1 specifies the number of dirty schedulers available and C2 specifies the number of dirty schedulers online. The +SDPcpu option allows numbers of dirty CPU schedulers available and dirty CPU schedulers online to be specified as percentages, similar to the existing +SP option for normal schedulers. The number of dirty CPU schedulers created and dirty CPU schedulers online may not exceed the number of normal schedulers created and normal schedulers online, respectively. The +SDio option takes only a single number specifying the number of dirty I/O schedulers available and online. There is no support yet for programmatically changing at run time the number of dirty CPU schedulers online via erlang:system_flag/2. Also, changing the number of normal schedulers online via erlang:system_flag(schedulers_online, NewSchedulersOnline) should ensure that there are no more dirty CPU schedulers than normal schedulers, but this is not yet implemented. You can retrieve the number of dirty schedulers by passing dirty_cpu_schedulers, dirty_cpu_schedulers_online, or dirty_io_schedulers to erlang:system_info/1. Currently only NIFs are able to access dirty scheduler functionality. Neither drivers nor BIFs currently support dirty schedulers. This restriction will be addressed in the future. If dirty scheduler support is present in the runtime, the initial status line Erlang prints before presenting its interactive prompt will include the indicator "[ds:C1:C2:I]" where "ds" indicates "dirty schedulers", "C1" indicates the number of dirty CPU schedulers available, "C2" indicates the number of dirty CPU schedulers online, and "I" indicates the number of dirty I/O schedulers. Document The dirty NIF API in the erl_nif man page. The API closely follows Rickard Green's presentation slides from his talk "Future Extensions to the Native Interface", presented at the 2011 Erlang Factory held in the San Francisco Bay Area. Rickard's slides are available online at http://bit.ly/1m34UHB . Document the new erl command-line options, the additions to erlang:system_info/1, and also add the erlang:system_flag/2 dirty scheduler documentation even though it's not yet implemented. To determine whether the dirty NIF API is available, native code can check to see whether the C preprocessor macro ERL_NIF_DIRTY_SCHEDULER_SUPPORT is defined. To check if dirty schedulers are available at run time, native code can call the boolean enif_have_dirty_schedulers() function, and Erlang code can call erlang:system_info(dirty_cpu_schedulers), which raises badarg if no dirty scheduler support is available. Add a simple dirty NIF test to the emulator NIF suite. --- erts/preloaded/src/erlang.erl | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'erts/preloaded/src') diff --git a/erts/preloaded/src/erlang.erl b/erts/preloaded/src/erlang.erl index f99d5bfdd0..ee5bd3e515 100644 --- a/erts/preloaded/src/erlang.erl +++ b/erts/preloaded/src/erlang.erl @@ -2090,6 +2090,10 @@ subtract(_,_) -> (cpu_topology, CpuTopology) -> OldCpuTopology when CpuTopology :: cpu_topology(), OldCpuTopology :: cpu_topology(); + (dirty_cpu_schedulers_online, DirtyCPUSchedulersOnline) -> + OldDirtyCPUSchedulersOnline when + DirtyCPUSchedulersOnline :: pos_integer(), + OldDirtyCPUSchedulersOnline :: pos_integer(); (fullsweep_after, Number) -> OldNumber when Number :: non_neg_integer(), OldNumber :: non_neg_integer(); @@ -2220,6 +2224,9 @@ tuple_to_list(_Tuple) -> CpuTopology :: cpu_topology(); (creation) -> integer(); (debug_compiled) -> boolean(); + (dirty_cpu_schedulers) -> non_neg_integer(); + (dirty_cpu_schedulers_online) -> non_neg_integer(); + (dirty_io_schedulers) -> non_neg_integer(); (dist) -> binary(); (dist_buf_busy_limit) -> non_neg_integer(); (dist_ctrl) -> {Node :: node(), -- cgit v1.2.3 From 72146c6675aaff02b2452c2fd2026c111e641f35 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn-Egil=20Dahlberg?= Date: Fri, 11 Oct 2013 18:11:12 +0200 Subject: erts: Specs for Map BIFs --- erts/preloaded/src/erlang.erl | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) (limited to 'erts/preloaded/src') diff --git a/erts/preloaded/src/erlang.erl b/erts/preloaded/src/erlang.erl index ee5bd3e515..ff0f9d0ead 100644 --- a/erts/preloaded/src/erlang.erl +++ b/erts/preloaded/src/erlang.erl @@ -60,6 +60,7 @@ -export_type([timestamp/0]). -type ext_binary() :: binary(). +-type map() :: term(). %% FIXME: remove when handled internally. -type timestamp() :: {MegaSecs :: non_neg_integer(), Secs :: non_neg_integer(), MicroSecs :: non_neg_integer()}. @@ -104,10 +105,9 @@ -export([list_to_bitstring/1, list_to_existing_atom/1, list_to_float/1]). -export([list_to_integer/1, list_to_integer/2]). -export([list_to_pid/1, list_to_tuple/1, loaded/0]). --export([localtime/0, make_ref/0, match_spec_test/3, md5/1, md5_final/1]). +-export([localtime/0, make_ref/0, map_size/1, match_spec_test/3, md5/1, md5_final/1]). -export([md5_init/0, md5_update/2, module_loaded/1, monitor/2]). --export([monitor_node/2, monitor_node/3, nif_error/1, nif_error/2 -]). +-export([monitor_node/2, monitor_node/3, nif_error/1, nif_error/2]). -export([node/0, node/1, now/0, phash/2, phash2/1, phash2/2]). -export([pid_to_list/1, port_close/1, port_command/2, port_command/3]). -export([port_connect/2, port_control/3, port_get_data/1]). @@ -128,7 +128,7 @@ -export([abs/1, append/2, element/2, get_module_info/2, hd/1, is_atom/1, is_binary/1, is_bitstring/1, is_boolean/1, is_float/1, is_function/1, is_function/2, is_integer/1, - is_list/1, is_number/1, is_pid/1, is_port/1, is_record/2, + is_list/1, is_map/1, is_number/1, is_pid/1, is_port/1, is_record/2, is_record/3, is_reference/1, is_tuple/1, load_module/2, load_nif/2, localtime_to_universaltime/2, make_fun/3, make_tuple/2, make_tuple/3, nodes/1, open_port/2, @@ -1149,6 +1149,12 @@ localtime() -> make_ref() -> erlang:nif_error(undefined). +%% Shadowed by erl_bif_types: erlang:map_size/1 +-spec map_size(Map) -> non_neg_integer() when + Map :: map(). +map_size(_Map) -> + erlang:nif_error(undefined). + %% match_spec_test/3 -spec erlang:match_spec_test(P1, P2, P3) -> TestResult when P1 :: [term()] | tuple(), @@ -1739,6 +1745,12 @@ is_number(_Term) -> is_pid(_Term) -> erlang:nif_error(undefined). +%% Shadowed by erl_bif_types: erlang:is_map/1 +-spec is_map(Map) -> boolean() when + Map :: map(). +is_map(_Map) -> + erlang:nif_error(undefined). + %% Shadowed by erl_bif_types: erlang:is_port/1 -spec is_port(Term) -> boolean() when Term :: term(). -- cgit v1.2.3 From b313f455be0def48b85c905efd98308aefb5bbc2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn-Egil=20Dahlberg?= Date: Thu, 24 Oct 2013 14:40:12 +0200 Subject: preloaded: Remove bogus map type --- erts/preloaded/src/erlang.erl | 1 - 1 file changed, 1 deletion(-) (limited to 'erts/preloaded/src') diff --git a/erts/preloaded/src/erlang.erl b/erts/preloaded/src/erlang.erl index ff0f9d0ead..fbc37bd955 100644 --- a/erts/preloaded/src/erlang.erl +++ b/erts/preloaded/src/erlang.erl @@ -60,7 +60,6 @@ -export_type([timestamp/0]). -type ext_binary() :: binary(). --type map() :: term(). %% FIXME: remove when handled internally. -type timestamp() :: {MegaSecs :: non_neg_integer(), Secs :: non_neg_integer(), MicroSecs :: non_neg_integer()}. -- cgit v1.2.3 From 76b8ea8ab1eb4ce099f88ccb8d1721c438d0ada4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn-Egil=20Dahlberg?= Date: Thu, 12 Dec 2013 10:58:59 +0100 Subject: erts: Add BIF erts_internal:cmp_term/2 Compares terms where integer() < float(). --- erts/preloaded/src/erts_internal.erl | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'erts/preloaded/src') diff --git a/erts/preloaded/src/erts_internal.erl b/erts/preloaded/src/erts_internal.erl index d6a185482e..88eb317f1d 100644 --- a/erts/preloaded/src/erts_internal.erl +++ b/erts/preloaded/src/erts_internal.erl @@ -170,3 +170,13 @@ binary_to_term(_Binary) -> Opts :: [safe]. binary_to_term(_Binary, _Opts) -> erlang:nif_error(undefined). + +%% term compare where integer() < float() = true + +-spec cmp_term(A,B) -> Result when + A :: term(), + B :: term(), + Result :: -1 | 0 | 1. + +cmp_term(_A,_B) -> + erlang:nif_error(undefined). -- cgit v1.2.3 From 3645dc6b15d4fdd79768b92bb598c264005a8689 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn-Egil=20Dahlberg?= Date: Tue, 14 Jan 2014 12:30:51 +0100 Subject: preloaded: Fixup export cmp_term in erts_internal --- erts/preloaded/src/erts_internal.erl | 1 + 1 file changed, 1 insertion(+) (limited to 'erts/preloaded/src') diff --git a/erts/preloaded/src/erts_internal.erl b/erts/preloaded/src/erts_internal.erl index 88eb317f1d..edcd50c77e 100644 --- a/erts/preloaded/src/erts_internal.erl +++ b/erts/preloaded/src/erts_internal.erl @@ -30,6 +30,7 @@ -export([await_port_send_result/3]). -export([binary_to_term/1, binary_to_term/2]). +-export([cmp_term/2]). -export([port_command/3, port_connect/2, port_close/1, port_control/3, port_call/3, port_info/1, port_info/2]). -- cgit v1.2.3 From 200fbe924466720bd2a8c5eb05b05d67b0a2414c Mon Sep 17 00:00:00 2001 From: Lukas Larsson Date: Thu, 14 Mar 2013 15:42:19 +0100 Subject: Added support for ENEA OSE This port has support for both non-smp and smp. It contains a new way to do io checking in which erts_poll_wait receives the payload of the polled entity. This has implications for all linked-in drivers. --- erts/preloaded/src/erl_prim_loader.erl | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'erts/preloaded/src') diff --git a/erts/preloaded/src/erl_prim_loader.erl b/erts/preloaded/src/erl_prim_loader.erl index 4b9e901c6d..578913b633 100644 --- a/erts/preloaded/src/erl_prim_loader.erl +++ b/erts/preloaded/src/erl_prim_loader.erl @@ -262,6 +262,8 @@ check_file_result(_, _, {error,enoent}) -> error; check_file_result(_, _, {error,enotdir}) -> error; +check_file_result(_, _, {error,einval}) -> + error; check_file_result(Func, Target, {error,Reason}) -> case (catch atom_to_list(Reason)) of {'EXIT',_} -> % exit trapped @@ -1392,6 +1394,8 @@ absname_vr([Drive, $\: | NameRest], _) -> %% Assumes normalized name pathtype(Name) when is_list(Name) -> case erlang:system_info(os_type) of + {ose, _} -> + unix_pathtype(Name); {unix, _} -> unix_pathtype(Name); {win32, _} -> -- cgit v1.2.3 From e6ff6cce0dba69ed495f098921d8ed6115007816 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn-Egil=20Dahlberg?= Date: Sun, 16 Mar 2014 23:19:19 +0100 Subject: erts: Fix is_map/1 spec --- erts/preloaded/src/erlang.erl | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'erts/preloaded/src') diff --git a/erts/preloaded/src/erlang.erl b/erts/preloaded/src/erlang.erl index fbc37bd955..cabbbd191f 100644 --- a/erts/preloaded/src/erlang.erl +++ b/erts/preloaded/src/erlang.erl @@ -1745,9 +1745,9 @@ is_pid(_Term) -> erlang:nif_error(undefined). %% Shadowed by erl_bif_types: erlang:is_map/1 --spec is_map(Map) -> boolean() when - Map :: map(). -is_map(_Map) -> +-spec is_map(Term) -> boolean() when + Term :: term(). +is_map(_Term) -> erlang:nif_error(undefined). %% Shadowed by erl_bif_types: erlang:is_port/1 -- cgit v1.2.3 From 22ff87a0c8db877e3ce53b6ff915dcc6a75c5c0c Mon Sep 17 00:00:00 2001 From: Rickard Green Date: Mon, 10 Mar 2014 17:15:38 +0100 Subject: Introduce runtime_dependencies in .app files Most dependencies introduced are exactly the dependencies to other applications found by xref. That is, there might be real dependencies missing. There might also be pure debug dependencies listed that probably should be removed. Each application has to be manually inspected in order to ensure that all real dependencies are listed. All dependencies introduced are to application versions used in OTP 17.0. This since the previously used version scheme wasn't designed for this, and in order to minimize the work of introducing the dependencies. --- erts/preloaded/src/erts.app.src | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'erts/preloaded/src') diff --git a/erts/preloaded/src/erts.app.src b/erts/preloaded/src/erts.app.src index fd3e8cb692..a15da3a421 100644 --- a/erts/preloaded/src/erts.app.src +++ b/erts/preloaded/src/erts.app.src @@ -35,7 +35,8 @@ {registered, []}, {applications, []}, {env, []}, - {mod, {erts, []}} + {mod, {erts, []}}, + {runtime_dependencies, ["stdlib-2.0", "kernel-3.0", "sasl-2.4"]} ]}. %% vim: ft=erlang -- cgit v1.2.3 From 44648ef43dc7cf2929a9df34025e93369776747f Mon Sep 17 00:00:00 2001 From: Rickard Green Date: Thu, 10 Apr 2014 03:00:19 +0200 Subject: Fixed type spec of erlang:system_info/1 --- erts/preloaded/src/erlang.erl | 1 - 1 file changed, 1 deletion(-) (limited to 'erts/preloaded/src') diff --git a/erts/preloaded/src/erlang.erl b/erts/preloaded/src/erlang.erl index cabbbd191f..1508eed9ee 100644 --- a/erts/preloaded/src/erlang.erl +++ b/erts/preloaded/src/erlang.erl @@ -2264,7 +2264,6 @@ tuple_to_list(_Tuple) -> (modified_timing_level) -> integer() | undefined; (multi_scheduling) -> disabled | blocked | enabled; (multi_scheduling_blockers) -> [PID :: pid()]; - (otp_correction_package) -> string(); (otp_release) -> string(); (port_count) -> non_neg_integer(); (port_limit) -> pos_integer(); -- cgit v1.2.3 From 338698874e1f57a38c469e6e5b876d12ee14a0fb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Gustavsson?= Date: Fri, 11 Apr 2014 15:22:23 +0200 Subject: The encoding for '-eval Program' should be UTF-8 If file:name_native_encoding() returns 'utf8', any arguments following the -run option are assumed to be encoded in UTF-8. -eval should treat is argument the same way. --- erts/preloaded/src/init.erl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'erts/preloaded/src') diff --git a/erts/preloaded/src/init.erl b/erts/preloaded/src/init.erl index ab8464956c..e95e11b3e6 100644 --- a/erts/preloaded/src/init.erl +++ b/erts/preloaded/src/init.erl @@ -1041,7 +1041,7 @@ start_em([]) -> ok. start_it([]) -> ok; start_it({eval,Bin}) -> - Str = binary_to_list(Bin), + Str = b2s(Bin), {ok,Ts,_} = erl_scan:string(Str), Ts1 = case reverse(Ts) of [{dot,_}|_] -> Ts; -- cgit v1.2.3 From e492b43c3e4366e865e5f1c34d0834df2a91d490 Mon Sep 17 00:00:00 2001 From: Eiichi Tsukata Date: Wed, 23 Apr 2014 21:46:21 +0900 Subject: Add erlang:system_info(tolerant_timeofday) Add erlang:system_info(tolerant_timeofday), an API to check whether compensation for sudden changes of system time is enabled or not. --- erts/preloaded/src/erlang.erl | 1 + 1 file changed, 1 insertion(+) (limited to 'erts/preloaded/src') diff --git a/erts/preloaded/src/erlang.erl b/erts/preloaded/src/erlang.erl index cabbbd191f..23dbd37a8f 100644 --- a/erts/preloaded/src/erlang.erl +++ b/erts/preloaded/src/erlang.erl @@ -2287,6 +2287,7 @@ tuple_to_list(_Tuple) -> (system_architecture) -> string(); (threads) -> boolean(); (thread_pool_size) -> non_neg_integer(); + (tolerant_timeofday) -> enabled | disabled; (trace_control_word) -> non_neg_integer(); (update_cpu_info) -> changed | unchanged; (version) -> string(); -- cgit v1.2.3 From 5b62ab3db6292a731fccfc31eafec7e9fb0906df Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn-Egil=20Dahlberg?= Date: Fri, 9 May 2014 18:32:05 +0200 Subject: erts: Add spec for erts_internal:map_to_tuple_keys/1 --- erts/preloaded/src/erts_internal.erl | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'erts/preloaded/src') diff --git a/erts/preloaded/src/erts_internal.erl b/erts/preloaded/src/erts_internal.erl index edcd50c77e..764d7730aa 100644 --- a/erts/preloaded/src/erts_internal.erl +++ b/erts/preloaded/src/erts_internal.erl @@ -31,6 +31,7 @@ -export([await_port_send_result/3]). -export([binary_to_term/1, binary_to_term/2]). -export([cmp_term/2]). +-export([map_to_tuple_keys/1]). -export([port_command/3, port_connect/2, port_close/1, port_control/3, port_call/3, port_info/1, port_info/2]). @@ -181,3 +182,11 @@ binary_to_term(_Binary, _Opts) -> cmp_term(_A,_B) -> erlang:nif_error(undefined). + +%% return the internal key tuple for map keys +-spec map_to_tuple_keys(M) -> Keys when + M :: map(), + Keys :: tuple(). + +map_to_tuple_keys(_M) -> + erlang:nif_error(undefined). -- cgit v1.2.3 From fdb350a4c98f070c264b8bd4ea9eca2513352f21 Mon Sep 17 00:00:00 2001 From: Richard Carlsson Date: Wed, 14 May 2014 14:46:46 +0200 Subject: Add 'md5' entry for module_info/0/1 functions. --- erts/preloaded/src/erlang.erl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'erts/preloaded/src') diff --git a/erts/preloaded/src/erlang.erl b/erts/preloaded/src/erlang.erl index cabbbd191f..bcc1250abd 100644 --- a/erts/preloaded/src/erlang.erl +++ b/erts/preloaded/src/erlang.erl @@ -1664,7 +1664,7 @@ element(_N, _Tuple) -> %% Not documented -spec erlang:get_module_info(Module, Item) -> ModuleInfo when Module :: atom(), - Item :: module | imports | exports | functions | attributes | compile | native_addresses, + Item :: module | imports | exports | functions | attributes | compile | native_addresses | md5, ModuleInfo :: atom() | [] | [{atom(), arity()}] | [{atom(), term()}] | [{atom(), arity(), integer()}]. get_module_info(_Module, _Item) -> erlang:nif_error(undefined). -- cgit v1.2.3 From 82c048745efcb5d811ec0489858b821ef39ea387 Mon Sep 17 00:00:00 2001 From: Rickard Green Date: Mon, 19 May 2014 18:09:13 +0200 Subject: Replace erlang:binary_to_term() Erlang wrappers Replace the 'erlang:binary_to_term/1' and 'erlang:binary_to_term/2' Erlang wrappers taking care of failure after yield with management of this in the hidden yield BIF. --- erts/preloaded/src/erlang.erl | 18 ++++-------------- erts/preloaded/src/erts_internal.erl | 12 ------------ 2 files changed, 4 insertions(+), 26 deletions(-) (limited to 'erts/preloaded/src') diff --git a/erts/preloaded/src/erlang.erl b/erts/preloaded/src/erlang.erl index 1508eed9ee..2fe85287b6 100644 --- a/erts/preloaded/src/erlang.erl +++ b/erts/preloaded/src/erlang.erl @@ -361,25 +361,15 @@ binary_to_list(_Binary, _Start, _Stop) -> %% binary_to_term/1 -spec binary_to_term(Binary) -> term() when Binary :: ext_binary(). -binary_to_term(Binary) -> - %% This BIF may throw badarg while trapping - try - erts_internal:binary_to_term(Binary) - catch - error:Reason -> erlang:error(Reason,[Binary]) - end. +binary_to_term(_Binary) -> + erlang:nif_error(undefined). %% binary_to_term/2 -spec binary_to_term(Binary, Opts) -> term() when Binary :: ext_binary(), Opts :: [safe]. -binary_to_term(Binary, Opts) -> - %% This BIF may throw badarg while trapping - try - erts_internal:binary_to_term(Binary,Opts) - catch - error:Reason -> erlang:error(Reason,[Binary,Opts]) - end. +binary_to_term(_Binary, _Opts) -> + erlang:nif_error(undefined). %% bit_size/1 %% Shadowed by erl_bif_types: erlang:bit_size/1 diff --git a/erts/preloaded/src/erts_internal.erl b/erts/preloaded/src/erts_internal.erl index edcd50c77e..e9044503b3 100644 --- a/erts/preloaded/src/erts_internal.erl +++ b/erts/preloaded/src/erts_internal.erl @@ -29,7 +29,6 @@ -module(erts_internal). -export([await_port_send_result/3]). --export([binary_to_term/1, binary_to_term/2]). -export([cmp_term/2]). -export([port_command/3, port_connect/2, port_close/1, port_control/3, port_call/3, port_info/1, port_info/2]). @@ -161,17 +160,6 @@ request_system_task(_Pid, _Prio, _Request) -> check_process_code(_Module, _OptionList) -> erlang:nif_error(undefined). --spec binary_to_term(Binary) -> term() when - Binary :: binary(). -binary_to_term(_Binary) -> - erlang:nif_error(undefined). - --spec binary_to_term(Binary, Opts) -> term() when - Binary :: binary(), - Opts :: [safe]. -binary_to_term(_Binary, _Opts) -> - erlang:nif_error(undefined). - %% term compare where integer() < float() = true -spec cmp_term(A,B) -> Result when -- cgit v1.2.3 From d23496206b4892dae0efd053104d16904d1d8eab Mon Sep 17 00:00:00 2001 From: Rickard Green Date: Tue, 20 May 2014 21:12:45 +0200 Subject: Remove invalid 'bitstr' exports in erlang.erl The dummy BIF exports 'erlang:bitstr_to_list/1' and 'erlang:list_to_bitstr/1' seem to have appeared as a result of a copy-paste error and are now removed. --- erts/preloaded/src/erlang.erl | 16 ++-------------- 1 file changed, 2 insertions(+), 14 deletions(-) (limited to 'erts/preloaded/src') diff --git a/erts/preloaded/src/erlang.erl b/erts/preloaded/src/erlang.erl index 2fe85287b6..67099093c5 100644 --- a/erts/preloaded/src/erlang.erl +++ b/erts/preloaded/src/erlang.erl @@ -79,7 +79,7 @@ -export([binary_to_integer/1,binary_to_integer/2]). -export([binary_to_list/1]). -export([binary_to_list/3, binary_to_term/1, binary_to_term/2]). --export([bit_size/1, bitsize/1, bitstr_to_list/1, bitstring_to_list/1]). +-export([bit_size/1, bitsize/1, bitstring_to_list/1]). -export([bump_reductions/1, byte_size/1, call_on_load_function/1]). -export([cancel_timer/1, check_old_code/1, check_process_code/2, check_process_code/3, crc32/1]). @@ -100,7 +100,7 @@ -export([integer_to_binary/1, integer_to_list/1]). -export([iolist_size/1, iolist_to_binary/1]). -export([is_alive/0, is_builtin/3, is_process_alive/1, length/1, link/1]). --export([list_to_atom/1, list_to_binary/1, list_to_bitstr/1]). +-export([list_to_atom/1, list_to_binary/1]). -export([list_to_bitstring/1, list_to_existing_atom/1, list_to_float/1]). -export([list_to_integer/1, list_to_integer/2]). -export([list_to_pid/1, list_to_tuple/1, loaded/0]). @@ -384,12 +384,6 @@ bit_size(_Bitstring) -> bitsize(_P1) -> erlang:nif_error(undefined). -%% bitstr_to_list/1 --spec erlang:bitstr_to_list(P1) -> [byte() | bitstring()] when - P1 :: bitstring(). -bitstr_to_list(_P1) -> - erlang:nif_error(undefined). - %% bitstring_to_list/1 -spec bitstring_to_list(Bitstring) -> [byte() | bitstring()] when Bitstring :: bitstring(). @@ -1072,12 +1066,6 @@ list_to_atom(_String) -> list_to_binary(_IoList) -> erlang:nif_error(undefined). -%% list_to_bitstr/1 --spec erlang:list_to_bitstr(P1) -> bitstring() when - P1 :: bitstring_list(). -list_to_bitstr(_P1) -> - erlang:nif_error(undefined). - %% list_to_bitstring/1 -spec list_to_bitstring(BitstringList) -> bitstring() when BitstringList :: bitstring_list(). -- cgit v1.2.3 From ab8c6675511cb1968c57fab3dd8e47cc48037c06 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Gustavsson?= Date: Fri, 13 Jun 2014 12:57:35 +0200 Subject: add_abstract_code: Remove 'from_asm' option The purpose of add_abstract_code is to give Dialyzer some abstract code so that it will not fail fatally when analysing prim_eval which was compiled from BEAM assembly. But if Dialyzer were to pass along the compiler options that the module was compiled with when translating the abstract code to Core Erlang, the 'from_asm' option would crash the compilation. Thus, since we are already cheating, we should cheat a little bit more and also remove the 'from_asm' option. --- erts/preloaded/src/add_abstract_code | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) (limited to 'erts/preloaded/src') diff --git a/erts/preloaded/src/add_abstract_code b/erts/preloaded/src/add_abstract_code index e670156d21..211a60c930 100644 --- a/erts/preloaded/src/add_abstract_code +++ b/erts/preloaded/src/add_abstract_code @@ -27,8 +27,18 @@ main([BeamFile,AbstrFile]) -> {ok,_,Chunks0} = beam_lib:all_chunks(BeamFile), {ok,Abstr} = file:consult(AbstrFile), - Chunks = lists:keyreplace("Abst", 1, Chunks0, - {"Abst",term_to_binary({raw_abstract_v1,Abstr})}), + Chunks1 = lists:keyreplace("Abst", 1, Chunks0, + {"Abst",term_to_binary({raw_abstract_v1,Abstr})}), + {"CInf",CInf0} = lists:keyfind("CInf", 1, Chunks1), + CInf = fix_options(CInf0), + Chunks = lists:keyreplace("CInf", 1, Chunks1, {"CInf",CInf}), {ok,Module} = beam_lib:build_module(Chunks), ok = file:write_file(BeamFile, Module), init:stop(). + +fix_options(CInf0) -> + CInf1 = binary_to_term(CInf0), + {options,Opts0} = lists:keyfind(options, 1, CInf1), + Opts = Opts0 -- [from_asm], + CInf = lists:keyreplace(options, 1, CInf1, {options,Opts}), + term_to_binary(CInf). -- cgit v1.2.3 From ab50e4e5121c2c29b8a49916f8ac89e42e37a978 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luis=20Rasc=C3=A3o?= Date: Fri, 27 Jun 2014 00:08:07 +0100 Subject: fix escript archive symlinked across drives real_path method used while prim loading archive files was not taking into account the fact that windows directory symlinks can be across different drives (eg. c:\tmp\test is a symlink to j:\tmp\test). when performing a path split the drive precedes the symlink, but that has be rewritten also since it's different. This issue never arises in Unix since obviously there are no drives --- erts/preloaded/src/erl_prim_loader.erl | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'erts/preloaded/src') diff --git a/erts/preloaded/src/erl_prim_loader.erl b/erts/preloaded/src/erl_prim_loader.erl index 578913b633..dfd6151b69 100644 --- a/erts/preloaded/src/erl_prim_loader.erl +++ b/erts/preloaded/src/erl_prim_loader.erl @@ -1487,7 +1487,12 @@ real_path(Name,[Path|Paths],Acc,Links) -> [""|_] = LinkPaths -> real_path(Name,LinkPaths++Paths,[],[ThisFile|Links]); LinkPaths -> - real_path(Name,LinkPaths++Paths,Acc,[ThisFile|Links]) + case erlang:system_info(os_type) of + {win32, _} -> + real_path(Name,LinkPaths++Paths,[],[ThisFile|Links]); + _ -> + real_path(Name,LinkPaths++Paths,Acc,[ThisFile|Links]) + end end; _ -> real_path(Name,Paths,This,Links) -- cgit v1.2.3 From de2fb97f15ac98aa1d1c5533aacca378334f4778 Mon Sep 17 00:00:00 2001 From: Anthony Ramine Date: Tue, 1 Jul 2014 00:58:26 +0200 Subject: Fix handling of broken symlinks in filelib This fixes a bug introduced in f11aabdc9fec593c31e6c4f3fa25c1707e9c35df where filelib:eval_read_file_info/2 was made to use file:read_link_info/1 to never follow symlinks. This fixed wildcard/1 but broke every other function using eval_read_file_info/2. Reported-by: Louis-Philippe Gauthier Reported-by: Danil Zagoskin --- erts/preloaded/src/erl_prim_loader.erl | 38 ++++++++++++++++++++++++++-------- 1 file changed, 29 insertions(+), 9 deletions(-) (limited to 'erts/preloaded/src') diff --git a/erts/preloaded/src/erl_prim_loader.erl b/erts/preloaded/src/erl_prim_loader.erl index 578913b633..466e0b0020 100644 --- a/erts/preloaded/src/erl_prim_loader.erl +++ b/erts/preloaded/src/erl_prim_loader.erl @@ -42,11 +42,11 @@ %% Public -export([start/3, set_path/1, get_path/0, get_file/1, get_files/2, - list_dir/1, read_file_info/1, get_cwd/0, get_cwd/1]). + list_dir/1, read_file_info/1, read_link_info/1, get_cwd/0, get_cwd/1]). %% Used by erl_boot_server -export([prim_init/0, prim_get_file/2, prim_list_dir/2, - prim_read_file_info/2, prim_get_cwd/2]). + prim_read_file_info/3, prim_get_cwd/2]). %% Used by escript and code -export([set_primary_archive/4, release_archives/0]). @@ -223,6 +223,12 @@ list_dir(Dir) -> read_file_info(File) -> check_file_result(read_file_info, File, request({read_file_info,File})). +-spec read_link_info(Filename) -> {'ok', FileInfo} | 'error' when + Filename :: string(), + FileInfo :: file:file_info(). +read_link_info(File) -> + check_file_result(read_link_info, File, request({read_link_info,File})). + -spec get_cwd() -> {'ok', string()} | 'error'. get_cwd() -> check_file_result(get_cwd, [], request({get_cwd,[]})). @@ -325,6 +331,9 @@ loop(State, Parent, Paths) -> {read_file_info,File} -> {Res,State1} = handle_read_file_info(State, File), {Res,State1,Paths}; + {read_link_info,File} -> + {Res,State1} = handle_read_link_info(State, File), + {Res,State1,Paths}; {get_cwd,[]} -> {Res,State1} = handle_get_cwd(State, []), {Res,State1,Paths}; @@ -387,10 +396,15 @@ handle_list_dir(State = #state{loader = inet}, Dir) -> ?SAFE2(inet_list_dir(State, Dir), State). handle_read_file_info(State = #state{loader = efile}, File) -> - ?SAFE2(efile_read_file_info(State, File), State); + ?SAFE2(efile_read_file_info(State, File, true), State); handle_read_file_info(State = #state{loader = inet}, File) -> ?SAFE2(inet_read_file_info(State, File), State). +handle_read_link_info(State = #state{loader = efile}, File) -> + ?SAFE2(efile_read_file_info(State, File, false), State); +handle_read_link_info(State = #state{loader = inet}, File) -> + ?SAFE2(inet_read_link_info(State, File), State). + handle_get_cwd(State = #state{loader = efile}, Drive) -> ?SAFE2(efile_get_cwd(State, Drive), State); handle_get_cwd(State = #state{loader = inet}, Drive) -> @@ -514,8 +528,8 @@ efile_list_dir(#state{prim_state = PS} = State, Dir) -> {Res, PS2} = prim_list_dir(PS, Dir), {Res, State#state{prim_state = PS2}}. -efile_read_file_info(#state{prim_state = PS} = State, File) -> - {Res, PS2} = prim_read_file_info(PS, File), +efile_read_file_info(#state{prim_state = PS} = State, File, FollowLinks) -> + {Res, PS2} = prim_read_file_info(PS, File, FollowLinks), {Res, State#state{prim_state = PS2}}. efile_get_cwd(#state{prim_state = PS} = State, Drive) -> @@ -718,6 +732,10 @@ inet_list_dir(State, Dir) -> inet_read_file_info(State, File) -> inet_send_and_rcv({read_file_info,File}, read_file_info, State). +%% -> {{ok,Info},State} | {{error,Reason},State} +inet_read_link_info(State, File) -> + inet_send_and_rcv({read_link_info,File}, read_link_info, State). + %% -> {{ok,Cwd},State} | {{error,Reason},State} inet_get_cwd(State, []) -> inet_send_and_rcv(get_cwd, get_cwd, State); @@ -951,16 +969,18 @@ prim_list_dir(PS, Dir) -> debug(PS, {return, Res2}), {Res2, PS3}. --spec prim_read_file_info(prim_state(), file:filename()) -> +-spec prim_read_file_info(prim_state(), file:filename(), boolean()) -> {{'ok', #file_info{}}, prim_state()} | {{'error', term()}, prim_state()}. -prim_read_file_info(PS, File) -> +prim_read_file_info(PS, File, FollowLinks) -> debug(PS, {read_file_info, File}), {Res2, PS2} = case name_split(PS#prim_state.primary_archive, File) of {file, PrimFile} -> - Res = prim_file:read_file_info(PrimFile), - {Res, PS}; + case FollowLinks of + true -> {prim_file:read_file_info(PrimFile), PS}; + false -> {prim_file:read_link_info(PrimFile), PS} + end; {archive, ArchiveFile, []} -> %% Fake top directory debug(PS, {archive_read_file_info, ArchiveFile}), -- cgit v1.2.3 From e1f903d5210fb5b91ff47229fb57bf3b0edeb79e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn-Egil=20Dahlberg?= Date: Wed, 11 Jun 2014 23:27:06 +0200 Subject: erts: Introduce erlang:fun_info_mfa/1 Introduced for proc_lib:init_p/3 --- erts/preloaded/src/erlang.erl | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) (limited to 'erts/preloaded/src') diff --git a/erts/preloaded/src/erlang.erl b/erts/preloaded/src/erlang.erl index 4ff0513321..98d7a942a6 100644 --- a/erts/preloaded/src/erlang.erl +++ b/erts/preloaded/src/erlang.erl @@ -91,7 +91,7 @@ -export([external_size/2, finish_after_on_load/2, finish_loading/1, float/1]). -export([float_to_binary/1, float_to_binary/2, float_to_list/1, float_to_list/2]). --export([fun_info/2, fun_to_list/1, function_exported/3]). +-export([fun_info/2, fun_info_mfa/1, fun_to_list/1, function_exported/3]). -export([garbage_collect/0, garbage_collect/1, garbage_collect/2]). -export([garbage_collect_message_area/0, get/0, get/1, get_keys/1]). -export([get_module_info/1, get_stacktrace/0, group_leader/0]). @@ -827,6 +827,15 @@ float_to_list(_Float, _Options) -> fun_info(_Fun, _Item) -> erlang:nif_error(undefined). +%% fun_info_mfa/1 +-spec erlang:fun_info_mfa(Fun) -> {Mod, Name, Arity} when + Fun :: function(), + Mod :: atom(), + Name :: atom(), + Arity :: non_neg_integer(). +fun_info_mfa(_Fun) -> + erlang:nif_error(undefined). + %% fun_to_list/1 -spec erlang:fun_to_list(Fun) -> string() when Fun :: function(). -- cgit v1.2.3 From 8a6390613225ec3f3e2d5bbf537d2e0737342e87 Mon Sep 17 00:00:00 2001 From: Lukas Larsson Date: Fri, 11 Jul 2014 10:46:37 +0200 Subject: kernel: When doing an fdopen we now also bind the fd to the specified addr/port --- erts/preloaded/src/prim_inet.erl | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) (limited to 'erts/preloaded/src') diff --git a/erts/preloaded/src/prim_inet.erl b/erts/preloaded/src/prim_inet.erl index a9df75327c..e3ba8a328a 100644 --- a/erts/preloaded/src/prim_inet.erl +++ b/erts/preloaded/src/prim_inet.erl @@ -25,7 +25,7 @@ %% Primitive inet_drv interface --export([open/3, open/4, fdopen/4, close/1]). +-export([open/3, open/4, fdopen/4, fdopen/5, close/1]). -export([bind/3, listen/1, listen/2, peeloff/2]). -export([connect/3, connect/4, async_connect/4]). -export([accept/1, accept/2, async_accept/2]). @@ -70,7 +70,12 @@ open(Protocol, Family, Type, Opts) -> open(Protocol, Family, Type, Opts, ?INET_REQ_OPEN, []). fdopen(Protocol, Family, Type, Fd) when is_integer(Fd) -> - open(Protocol, Family, Type, [], ?INET_REQ_FDOPEN, ?int32(Fd)). + fdopen(Protocol, Family, Type, Fd, true). + +fdopen(Protocol, Family, Type, Fd, Bound) + when is_integer(Fd), Bound == true orelse Bound == false -> + open(Protocol, Family, Type, [], ?INET_REQ_FDOPEN, + [?int32(Fd), enc_value_2(bool, Bound)]). open(Protocol, Family, Type, Opts, Req, Data) -> Drv = protocol2drv(Protocol), -- cgit v1.2.3 From 81c2cd3755b4adb60d498b2763ee32279f3cfc0b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luis=20Rasc=C3=A3o?= Date: Tue, 12 Aug 2014 22:40:28 +0100 Subject: fix indentation, add comment describing windows symlink creation assumption --- erts/preloaded/src/erl_prim_loader.erl | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'erts/preloaded/src') diff --git a/erts/preloaded/src/erl_prim_loader.erl b/erts/preloaded/src/erl_prim_loader.erl index dfd6151b69..6953db533c 100644 --- a/erts/preloaded/src/erl_prim_loader.erl +++ b/erts/preloaded/src/erl_prim_loader.erl @@ -1487,11 +1487,13 @@ real_path(Name,[Path|Paths],Acc,Links) -> [""|_] = LinkPaths -> real_path(Name,LinkPaths++Paths,[],[ThisFile|Links]); LinkPaths -> + % windows currently does not allow creation of relative symlinks + % across different drives case erlang:system_info(os_type) of - {win32, _} -> - real_path(Name,LinkPaths++Paths,[],[ThisFile|Links]); - _ -> - real_path(Name,LinkPaths++Paths,Acc,[ThisFile|Links]) + {win32, _} -> + real_path(Name,LinkPaths++Paths,[],[ThisFile|Links]); + _ -> + real_path(Name,LinkPaths++Paths,Acc,[ThisFile|Links]) end end; _ -> -- cgit v1.2.3 From 7cd4ac96cb8e8bef78c6eebfadb2e9590f88055d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn-Egil=20Dahlberg?= Date: Mon, 16 Jun 2014 15:53:11 +0200 Subject: erts: Add spec for erlang:get_keys/0 --- erts/preloaded/src/erlang.erl | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'erts/preloaded/src') diff --git a/erts/preloaded/src/erlang.erl b/erts/preloaded/src/erlang.erl index 7903901b81..b96a601792 100644 --- a/erts/preloaded/src/erlang.erl +++ b/erts/preloaded/src/erlang.erl @@ -93,7 +93,7 @@ float_to_list/1, float_to_list/2]). -export([fun_info/2, fun_info_mfa/1, fun_to_list/1, function_exported/3]). -export([garbage_collect/0, garbage_collect/1, garbage_collect/2]). --export([garbage_collect_message_area/0, get/0, get/1, get_keys/1]). +-export([garbage_collect_message_area/0, get/0, get/1, get_keys/0, get_keys/1]). -export([get_module_info/1, get_stacktrace/0, group_leader/0]). -export([group_leader/2, halt/0, halt/1, halt/2, hash/2, hibernate/3]). -export([insert_element/3]). @@ -931,6 +931,12 @@ get() -> get(_Key) -> erlang:nif_error(undefined). +%% get_keys/0 +-spec get_keys() -> [Key] when + Key :: term(). +get_keys() -> + erlang:nif_error(undefined). + %% get_keys/1 -spec get_keys(Val) -> [Key] when Val :: term(), -- cgit v1.2.3 From bee90407de17bfe6e32439321b4e99effb25384d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn-Egil=20Dahlberg?= Date: Tue, 16 Sep 2014 15:24:17 +0200 Subject: erts: Fix erts app-file --- erts/preloaded/src/erts.app.src | 1 - 1 file changed, 1 deletion(-) (limited to 'erts/preloaded/src') diff --git a/erts/preloaded/src/erts.app.src b/erts/preloaded/src/erts.app.src index a15da3a421..345a6ae3be 100644 --- a/erts/preloaded/src/erts.app.src +++ b/erts/preloaded/src/erts.app.src @@ -35,7 +35,6 @@ {registered, []}, {applications, []}, {env, []}, - {mod, {erts, []}}, {runtime_dependencies, ["stdlib-2.0", "kernel-3.0", "sasl-2.4"]} ]}. -- cgit v1.2.3 From 6084a42a24fca52a5de2bc487c0cd2be46dcc21f Mon Sep 17 00:00:00 2001 From: Rickard Green Date: Tue, 26 Aug 2014 17:26:31 +0200 Subject: Introduce support for eager check I/O scheduling --- erts/preloaded/src/erlang.erl | 1 + 1 file changed, 1 insertion(+) (limited to 'erts/preloaded/src') diff --git a/erts/preloaded/src/erlang.erl b/erts/preloaded/src/erlang.erl index 291926578e..58c08fcb34 100644 --- a/erts/preloaded/src/erlang.erl +++ b/erts/preloaded/src/erlang.erl @@ -2106,6 +2106,7 @@ tuple_to_list(_Tuple) -> (dynamic_trace) -> none | dtrace | systemtap; (dynamic_trace_probes) -> boolean(); (elib_malloc) -> false; + (eager_check_io) -> boolean(); (ets_limit) -> pos_integer(); (fullsweep_after) -> {fullsweep_after, non_neg_integer()}; (garbage_collection) -> [{atom(), integer()}]; -- cgit v1.2.3 From 1bc59d68f5d22650fa18aa064ed8e50fc9a6a216 Mon Sep 17 00:00:00 2001 From: Peter Lemenkov Date: Sun, 2 Nov 2014 19:49:55 +0300 Subject: Expose NIF version This patch allows checking for NIF API version in a way similar to driver version. E.g. by calling erlang:system_info(nif_version). Signed-off-by: Peter Lemenkov --- erts/preloaded/src/erlang.erl | 1 + 1 file changed, 1 insertion(+) (limited to 'erts/preloaded/src') diff --git a/erts/preloaded/src/erlang.erl b/erts/preloaded/src/erlang.erl index 4ba623d921..611a568014 100644 --- a/erts/preloaded/src/erlang.erl +++ b/erts/preloaded/src/erlang.erl @@ -2252,6 +2252,7 @@ tuple_to_list(_Tuple) -> (modified_timing_level) -> integer() | undefined; (multi_scheduling) -> disabled | blocked | enabled; (multi_scheduling_blockers) -> [PID :: pid()]; + (nif_version) -> string(); (otp_release) -> string(); (port_count) -> non_neg_integer(); (port_limit) -> pos_integer(); -- cgit v1.2.3 From b24651c3bb6fef59c0e92c24e69151d1a92c4b08 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=A1=D0=B5=D1=80=D0=B3=D0=B5=D0=B9=20=D0=9F=D1=80=D0=BE?= =?UTF-8?q?=D1=85=D0=BE=D1=80=D0=BE=D0=B2?= Date: Mon, 19 Jan 2015 05:06:53 +0300 Subject: Add zlib limited output buffer size functionality This functionality may be useful for compressed streams with high compression ratio (in case of gzip it may be up to x1000), when small amount of compressed data will produce large amount of uncompressed output. This may lead to DoS attacks, because server easily goes out of memory. Example of such high compression ratio stream: ``` dd if=/dev/zero of=sparse.bin bs=1MB count=100 # 100mb of zeroes gzip sparse.bin # 95kb sparse.bin.gz $ erl > {ok, Compressed} = file:read_file("sparse.bin.gz"), > 97082 = size(Compressed), > Uncompressed = zlib:gunzip(Compressed), > 100000000 = iolist_size(Uncompressed). ``` --- erts/preloaded/src/zlib.erl | 39 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 38 insertions(+), 1 deletion(-) (limited to 'erts/preloaded/src') diff --git a/erts/preloaded/src/zlib.erl b/erts/preloaded/src/zlib.erl index df7b2e6198..5ebc67dcaa 100644 --- a/erts/preloaded/src/zlib.erl +++ b/erts/preloaded/src/zlib.erl @@ -24,6 +24,7 @@ deflate/2,deflate/3,deflateEnd/1, inflateInit/1,inflateInit/2,inflateSetDictionary/2, inflateSync/1,inflateReset/1,inflate/2,inflateEnd/1, + inflateChunk/1, inflateChunk/2, setBufSize/2,getBufSize/1, crc32/1,crc32/2,crc32/3,adler32/2,adler32/3,getQSize/1, crc32_combine/4,adler32_combine/4, @@ -100,6 +101,7 @@ -define(INFLATE_RESET, 12). -define(INFLATE_END, 13). -define(INFLATE, 14). +-define(INFLATE_CHUNK, 25). -define(CRC32_0, 15). -define(CRC32_1, 16). @@ -263,6 +265,39 @@ inflate(Z, Data) -> erlang:error(badarg) end. +-spec inflateChunk(Z, Data) -> Decompressed | {more, Decompressed} when + Z :: zstream(), + Data :: iodata(), + Decompressed :: iolist(). +inflateChunk(Z, Data) -> + try port_command(Z, Data) of + true -> + inflateChunk(Z) + catch + error:_Err -> + flush(Z), + erlang:error(badarg) + end. + +-spec inflateChunk(Z) -> Decompressed | {more, Decompressed} when + Z :: zstream(), + Decompressed :: iolist(). +inflateChunk(Z) -> + Status = call(Z, ?INFLATE_CHUNK, []), + Data = receive + {Z, {data, Bin}} -> + Bin + after 0 -> + [] + end, + + case Status of + Good when (Good == ok) orelse (Good == stream_end) -> + Data; + inflate_has_more -> + {more, Data} + end. + -spec inflateEnd(Z) -> 'ok' when Z :: zstream(). inflateEnd(Z) -> @@ -514,7 +549,9 @@ call(Z, Cmd, Arg) -> [2,A,B,C,D] -> (A bsl 24)+(B bsl 16)+(C bsl 8)+D; [3,A,B,C,D] -> - erlang:error({need_dictionary,(A bsl 24)+(B bsl 16)+(C bsl 8)+D}) + erlang:error({need_dictionary,(A bsl 24)+(B bsl 16)+(C bsl 8)+D}); + [4, _, _, _, _] -> + inflate_has_more catch error:badarg -> %% Rethrow loses port_control from stacktrace. erlang:error(badarg) -- cgit v1.2.3 From af4957d6224bfa529fb3a2087f41035eb13b2c16 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Hoguin?= Date: Tue, 3 Mar 2015 20:00:49 +0100 Subject: Export useful types from zlib module --- erts/preloaded/src/zlib.erl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'erts/preloaded/src') diff --git a/erts/preloaded/src/zlib.erl b/erts/preloaded/src/zlib.erl index df7b2e6198..f028495a30 100644 --- a/erts/preloaded/src/zlib.erl +++ b/erts/preloaded/src/zlib.erl @@ -30,7 +30,7 @@ compress/1,uncompress/1,zip/1,unzip/1, gzip/1,gunzip/1]). --export_type([zstream/0]). +-export_type([zstream/0, zlevel/0, zwindowbits/0, zmemlevel/0, zstrategy/0]). %% flush argument encoding -define(Z_NO_FLUSH, 0). -- cgit v1.2.3 From 7d82a632f4837764ac79dfb4986d102060bd3080 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Hoguin?= Date: Tue, 3 Mar 2015 18:55:22 +0100 Subject: Update zlib:zwindowbits/0 type to accept 8 and -8 Commit 7e8f5a776cbfa376e03369d058a90c8dd9f217fc (importing R11B-3) updated zlib, which had changed what values it accepts for window bits from 9-15 to 8-15. From deflate.c: - windowBits < 9 || windowBits > 15 || level < 0 || level > 9 || - strategy < 0 || strategy > Z_HUFFMAN_ONLY) { + windowBits < 8 || windowBits > 15 || level < 0 || level > 9 || + strategy < 0 || strategy > Z_FIXED) { return Z_STREAM_ERROR; } + if (windowBits == 8) windowBits = 9; /* until 256-byte window bug fixed */ In inflate.c 8 was already an accepted value. This commit updates OTP to also accept the values 8 and -8. --- erts/preloaded/src/zlib.erl | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'erts/preloaded/src') diff --git a/erts/preloaded/src/zlib.erl b/erts/preloaded/src/zlib.erl index df7b2e6198..988d837e3a 100644 --- a/erts/preloaded/src/zlib.erl +++ b/erts/preloaded/src/zlib.erl @@ -124,7 +124,7 @@ -type zlevel() :: 'none' | 'default' | 'best_compression' | 'best_speed' | 0..9. -type zmethod() :: 'deflated'. --type zwindowbits() :: -15..-9 | 9..47. +-type zwindowbits() :: -15..-8 | 8..47. -type zmemlevel() :: 1..9. -type zstrategy() :: 'default' | 'filtered' | 'huffman_only' | 'rle'. @@ -496,8 +496,8 @@ arg_method(_) -> erlang:error(badarg). -spec arg_bitsz(zwindowbits()) -> zwindowbits(). arg_bitsz(Bits) when is_integer(Bits) andalso - ((8 < Bits andalso Bits < 48) orelse - (-15 =< Bits andalso Bits < -8)) -> + ((8 =< Bits andalso Bits < 48) orelse + (-15 =< Bits andalso Bits =< -8)) -> Bits; arg_bitsz(_) -> erlang:error(badarg). -- cgit v1.2.3 From 7a9b4fe58c17c95c9be0ad13d33fce5042db24b2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn-Egil=20Dahlberg?= Date: Mon, 16 Mar 2015 14:45:17 +0100 Subject: erts: Add map decomposition wrappers * erts_internal:map_type/1 * erts_internal:map_hashmap_children/1 --- erts/preloaded/src/erts_internal.erl | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) (limited to 'erts/preloaded/src') diff --git a/erts/preloaded/src/erts_internal.erl b/erts/preloaded/src/erts_internal.erl index 2c5bd82cf0..5756d80424 100644 --- a/erts/preloaded/src/erts_internal.erl +++ b/erts/preloaded/src/erts_internal.erl @@ -30,7 +30,7 @@ -export([await_port_send_result/3]). -export([cmp_term/2]). --export([map_to_tuple_keys/1]). +-export([map_to_tuple_keys/1, map_type/1, map_hashmap_children/1]). -export([port_command/3, port_connect/2, port_close/1, port_control/3, port_call/3, port_info/1, port_info/2]). @@ -178,3 +178,20 @@ cmp_term(_A,_B) -> map_to_tuple_keys(_M) -> erlang:nif_error(undefined). + +%% return the internal map type +-spec map_type(M) -> Type when + M :: map(), + Type :: 'flatmap' | 'hashmap' | 'hashmap_node'. + +map_type(_M) -> + erlang:nif_error(undefined). + +%% return the internal hashmap sub-nodes from +%% a hashmap node +-spec map_hashmap_children(M) -> Children when + M :: map(), %% hashmap node + Children :: [map() | nonempty_improper_list(term(),term())]. + +map_hashmap_children(_M) -> + erlang:nif_error(undefined). -- cgit v1.2.3 From 6487aac5977cf470bc6a2cd0964da2850ee38717 Mon Sep 17 00:00:00 2001 From: Rickard Green Date: Thu, 30 Oct 2014 23:57:01 +0100 Subject: Introduce a new time API The old time API is based on erlang:now/0. The major issue with erlang:now/0 is that it was intended to be used for so many unrelated things. This tied these unrelated operations together and unnecessarily caused performance, scalability as well as accuracy, and precision issues for operations that do not need to have such issues. The new API spreads different functionality over multiple functions in order to improve on this. The new API consists of a number of new BIFs: - erlang:convert_time_unit/3 - erlang:monotonic_time/0 - erlang:monotonic_time/1 - erlang:system_time/0 - erlang:system_time/1 - erlang:time_offset/0 - erlang:time_offset/1 - erlang:timestamp/0 - erlang:unique_integer/0 - erlang:unique_integer/1 - os:system_time/0 - os:system_time/1 and a number of extensions of existing BIFs: - erlang:monitor(time_offset, clock_service) - erlang:system_flag(time_offset, finalize) - erlang:system_info(os_monotonic_time_source) - erlang:system_info(time_offset) - erlang:system_info(time_warp_mode) - erlang:system_info(time_correction) - erlang:system_info(start_time) See the "Time and Time Correction in Erlang" chapter of the ERTS User's Guide for more information. --- erts/preloaded/src/erlang.erl | 136 ++++++++++++++++++++++++++++++----- erts/preloaded/src/erts_internal.erl | 30 ++++++++ 2 files changed, 148 insertions(+), 18 deletions(-) (limited to 'erts/preloaded/src') diff --git a/erts/preloaded/src/erlang.erl b/erts/preloaded/src/erlang.erl index 611a568014..79eb60f362 100644 --- a/erts/preloaded/src/erlang.erl +++ b/erts/preloaded/src/erlang.erl @@ -38,7 +38,6 @@ -export([integer_to_list/2]). -export([integer_to_binary/2]). --export([flush_monitor_message/2]). -export([set_cpu_topology/1, format_cpu_topology/1]). -export([await_proc_exit/3]). -export([memory/0, memory/1]). @@ -48,7 +47,7 @@ await_sched_wall_time_modifications/2, gather_gc_info_result/1]). --deprecated([hash/2]). +-deprecated([hash/2, now/0]). %% Get rid of autoimports of spawn to avoid clashes with ourselves. -compile({no_auto_import,[spawn_link/1]}). @@ -58,12 +57,21 @@ -compile({no_auto_import,[spawn_opt/5]}). -export_type([timestamp/0]). +-export_type([time_unit/0]). -type ext_binary() :: binary(). -type timestamp() :: {MegaSecs :: non_neg_integer(), Secs :: non_neg_integer(), MicroSecs :: non_neg_integer()}. +-type time_unit() :: + pos_integer() + | 'seconds' + | 'milli_seconds' + | 'micro_seconds' + | 'nano_seconds' + | 'native'. + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% Native code BIF stubs and their types %% (BIF's actually implemented in this module goes last in the file) @@ -104,7 +112,8 @@ -export([list_to_bitstring/1, list_to_existing_atom/1, list_to_float/1]). -export([list_to_integer/1, list_to_integer/2]). -export([list_to_pid/1, list_to_tuple/1, loaded/0]). --export([localtime/0, make_ref/0, map_size/1, match_spec_test/3, md5/1, md5_final/1]). +-export([localtime/0, make_ref/0]). +-export([map_size/1, match_spec_test/3, md5/1, md5_final/1]). -export([md5_init/0, md5_update/2, module_loaded/1, monitor/2]). -export([monitor_node/2, monitor_node/3, nif_error/1, nif_error/2]). -export([node/0, node/1, now/0, phash/2, phash2/1, phash2/2]). @@ -112,6 +121,11 @@ -export([port_connect/2, port_control/3, port_get_data/1]). -export([port_set_data/2, port_to_list/1, ports/0]). -export([posixtime_to_universaltime/1, pre_loaded/0, prepare_loading/2]). +-export([monotonic_time/0, monotonic_time/1]). +-export([system_time/0, system_time/1]). +-export([convert_time_unit/3]). +-export([unique_integer/0, unique_integer/1]). +-export([time_offset/0, time_offset/1, timestamp/0]). -export([process_display/2]). -export([process_flag/3, process_info/1, processes/0, purge_module/1]). -export([put/2, raise/3, read_timer/1, ref_to_list/1, register/2]). @@ -1184,13 +1198,18 @@ md5_update(_Context, _Data) -> module_loaded(_Module) -> erlang:nif_error(undefined). +-type registered_name() :: atom(). + +-type registered_process_identifier() :: registered_name() | {registered_name(), node()}. + +-type monitor_process_identifier() :: pid() | registered_process_identifier(). + %% monitor/2 --spec monitor(Type, Item) -> MonitorRef when - Type :: process, - Item :: pid() | RegName | {RegName, Node}, - RegName :: module(), - Node :: node(), +-spec monitor(process, monitor_process_identifier()) -> MonitorRef when + MonitorRef :: reference(); + (time_offset, clock_service) -> MonitorRef when MonitorRef :: reference(). + monitor(_Type, _Item) -> erlang:nif_error(undefined). @@ -1292,6 +1311,90 @@ ports() -> posixtime_to_universaltime(_P1) -> erlang:nif_error(undefined). +-spec erlang:unique_integer(ModifierList) -> integer() when + ModifierList :: [Modifier], + Modifier :: positive | monotonic. + +unique_integer(_ModifierList) -> + erlang:nif_error(undefined). + +-spec erlang:unique_integer() -> integer(). + +unique_integer() -> + erlang:nif_error(undefined). + +-spec erlang:monotonic_time() -> integer(). + +monotonic_time() -> + erlang:nif_error(undefined). + +-spec erlang:monotonic_time(Unit) -> integer() when + Unit :: time_unit(). + +monotonic_time(_Unit) -> + erlang:nif_error(undefined). + +-spec erlang:system_time() -> integer(). + +system_time() -> + erlang:nif_error(undefined). + +-spec erlang:system_time(Unit) -> integer() when + Unit :: time_unit(). + +system_time(_Unit) -> + erlang:nif_error(undefined). + +-spec erlang:convert_time_unit(Time, FromUnit, ToUnit) -> ConvertedTime when + Time :: integer(), + ConvertedTime :: integer(), + FromUnit :: time_unit(), + ToUnit :: time_unit(). + +convert_time_unit(Time, FromUnit, ToUnit) -> + try + FU = case FromUnit of + native -> erts_internal:time_unit(); + nano_seconds -> 1000*1000*1000; + micro_seconds -> 1000*1000; + milli_seconds -> 1000; + seconds -> 1; + _ when FromUnit > 0 -> FromUnit + end, + TU = case ToUnit of + native -> erts_internal:time_unit(); + nano_seconds -> 1000*1000*1000; + micro_seconds -> 1000*1000; + milli_seconds -> 1000; + seconds -> 1; + _ when ToUnit > 0 -> ToUnit + end, + case Time < 0 of + true -> TU*Time - (FU - 1); + false -> TU*Time + end div FU + catch + _ : _ -> + erlang:error(badarg, [Time, FromUnit, ToUnit]) + end. + +-spec erlang:time_offset() -> integer(). + +time_offset() -> + erlang:nif_error(undefined). + +-spec erlang:time_offset(Unit) -> integer() when + Unit :: time_unit(). + +time_offset(_Unit) -> + erlang:nif_error(undefined). + +-spec erlang:timestamp() -> Timestamp when + Timestamp :: timestamp(). + +timestamp() -> + erlang:nif_error(undefined). + %% prepare_loading/2 -spec erlang:prepare_loading(Module, Code) -> PreparedCode | {error, Reason} when Module :: module(), @@ -2118,6 +2221,8 @@ subtract(_,_) -> (trace_control_word, TCW) -> OldTCW when TCW :: non_neg_integer(), OldTCW :: non_neg_integer(); + (time_offset, finalize) -> OldState when + OldState :: preliminary | final | volatile; %% These are deliberately not documented (internal_cpu_topology, term()) -> term(); (sequential_tracer, pid() | port() | false) -> pid() | port() | false; @@ -2254,6 +2359,7 @@ tuple_to_list(_Tuple) -> (multi_scheduling_blockers) -> [PID :: pid()]; (nif_version) -> string(); (otp_release) -> string(); + (os_monotonic_time_source) -> [{atom(),term()}]; (port_count) -> non_neg_integer(); (port_limit) -> pos_integer(); (process_count) -> pos_integer(); @@ -2271,10 +2377,14 @@ tuple_to_list(_Tuple) -> (scheduler_id) -> SchedulerId :: pos_integer(); (schedulers | schedulers_online) -> pos_integer(); (smp_support) -> boolean(); + (start_time) -> integer(); (system_version) -> string(); (system_architecture) -> string(); (threads) -> boolean(); (thread_pool_size) -> non_neg_integer(); + (time_correction) -> true | false; + (time_offset) -> preliminary | final | volatile; + (time_warp_mode) -> no_time_warp | single_time_warp | multi_time_warp; (tolerant_timeofday) -> enabled | disabled; (trace_control_word) -> non_neg_integer(); (update_cpu_info) -> changed | unchanged; @@ -3041,16 +3151,6 @@ integer_to_binary(I0, Base, R0) -> true -> integer_to_binary(I1, Base, R1) end. -%% erlang:flush_monitor_message/2 is for internal use only! -%% -%% erlang:demonitor(Ref, [flush]) traps to -%% erlang:flush_monitor_message(Ref, Res) when -%% it needs to flush a monitor message. -flush_monitor_message(Ref, Res) when erlang:is_reference(Ref), - erlang:is_atom(Res) -> - receive {_, Ref, _, _, _} -> ok after 0 -> ok end, - Res. - -record(cpu, {node = -1, processor = -1, processor_node = -1, diff --git a/erts/preloaded/src/erts_internal.erl b/erts/preloaded/src/erts_internal.erl index 2c5bd82cf0..30df75b406 100644 --- a/erts/preloaded/src/erts_internal.erl +++ b/erts/preloaded/src/erts_internal.erl @@ -38,6 +38,10 @@ -export([check_process_code/2]). +-export([flush_monitor_messages/3]). + +-export([time_unit/0]). + %% %% Await result of send to port %% @@ -178,3 +182,29 @@ cmp_term(_A,_B) -> map_to_tuple_keys(_M) -> erlang:nif_error(undefined). + +-spec erts_internal:flush_monitor_messages(Ref, Multi, Res) -> term() when + Ref :: reference(), + Multi :: boolean(), + Res :: term(). + +%% erlang:demonitor(Ref, [flush]) traps to +%% erts_internal:flush_monitor_messages(Ref, Res) when +%% it needs to flush monitor messages. +flush_monitor_messages(Ref, Multi, Res) when is_reference(Ref) -> + receive + {_, Ref, _, _, _} -> + case Multi of + false -> + Res; + _ -> + flush_monitor_messages(Ref, Multi, Res) + end + after 0 -> + Res + end. + +-spec erts_internal:time_unit() -> pos_integer(). + +time_unit() -> + erlang:nif_error(undefined). -- cgit v1.2.3 From 6b1921d767de5cd1a980234f83b36dbfa13d9fc7 Mon Sep 17 00:00:00 2001 From: Rickard Green Date: Fri, 13 Feb 2015 00:25:57 +0100 Subject: Erlang based BIF timer implementation for scalability --- erts/preloaded/src/erlang.erl | 191 ++++++++++++++++++++++++-- erts/preloaded/src/erts_internal.erl | 251 +++++++++++++++++++++++++++++++++++ erts/preloaded/src/init.erl | 32 ++++- 3 files changed, 459 insertions(+), 15 deletions(-) (limited to 'erts/preloaded/src') diff --git a/erts/preloaded/src/erlang.erl b/erts/preloaded/src/erlang.erl index 79eb60f362..83010b17d2 100644 --- a/erts/preloaded/src/erlang.erl +++ b/erts/preloaded/src/erlang.erl @@ -89,7 +89,7 @@ -export([binary_to_list/3, binary_to_term/1, binary_to_term/2]). -export([bit_size/1, bitsize/1, bitstring_to_list/1]). -export([bump_reductions/1, byte_size/1, call_on_load_function/1]). --export([cancel_timer/1, check_old_code/1, check_process_code/2, +-export([cancel_timer/1, cancel_timer/2, check_old_code/1, check_process_code/2, check_process_code/3, crc32/1]). -export([crc32/2, crc32_combine/3, date/0, decode_packet/3]). -export([delete_element/2]). @@ -128,7 +128,7 @@ -export([time_offset/0, time_offset/1, timestamp/0]). -export([process_display/2]). -export([process_flag/3, process_info/1, processes/0, purge_module/1]). --export([put/2, raise/3, read_timer/1, ref_to_list/1, register/2]). +-export([put/2, raise/3, read_timer/1, read_timer/2, ref_to_list/1, register/2]). -export([registered/0, resume_process/1, round/1, self/0, send_after/3]). -export([seq_trace/2, seq_trace_print/1, seq_trace_print/2, setnode/2]). -export([setnode/3, size/1, spawn/3, spawn_link/3, split_binary/2]). @@ -427,8 +427,77 @@ call_on_load_function(_P1) -> -spec erlang:cancel_timer(TimerRef) -> Time | false when TimerRef :: reference(), Time :: non_neg_integer(). -cancel_timer(_TimerRef) -> - erlang:nif_error(undefined). +cancel_timer(TimerRef) -> + try + case erts_internal:access_bif_timer(TimerRef) of + undefined -> + false; + {BTR, TSrv} -> + Req = erlang:make_ref(), + TSrv ! {cancel_timeout, BTR, erlang:self(), + true, Req, TimerRef}, + receive + {cancel_timer, Req, Result} -> + Result + end + end + catch + _:_ -> erlang:error(badarg, [TimerRef]) + end. + +%% cancel_timer/2 +-spec erlang:cancel_timer(TimerRef, Options) -> Time | false | ok when + TimerRef :: reference(), + Option :: {async, boolean()} | {info, boolean()}, + Options :: [Option], + Time :: non_neg_integer(). +cancel_timer(TimerRef, Options) -> + try + {Async, Info} = get_cancel_timer_options(Options, false, true), + case erts_internal:access_bif_timer(TimerRef) of + undefined -> + case {Async, Info} of + {true, true} -> + erlang:self() ! {cancel_timer, TimerRef, false}, ok; + {false, true} -> + false; + _ -> + ok + end; + {BTR, TSrv} -> + case Async of + true -> + TSrv ! {cancel_timeout, BTR, erlang:self(), + Info, TimerRef, TimerRef}, + ok; + false -> + Req = erlang:make_ref(), + TSrv ! {cancel_timeout, BTR, erlang:self(), + true, Req, TimerRef}, + receive + {cancel_timer, Req, Result} -> + case Info of + true -> Result; + false -> ok + end + end + end + end + catch + _:_ -> erlang:error(badarg, [TimerRef, Options]) + end. + +get_cancel_timer_options([], Async, Info) -> + {Async, Info}; +get_cancel_timer_options([{async, Bool} | Opts], + _Async, Info) when Bool == true; + Bool == false -> + get_cancel_timer_options(Opts, Bool, Info); +get_cancel_timer_options([{info, Bool} | Opts], + Async, _Info) when Bool == true; + Bool == false -> + get_cancel_timer_options(Opts, Async, Bool). + %% check_old_code/1 -spec check_old_code(Module) -> boolean() when @@ -1462,8 +1531,53 @@ raise(_Class, _Reason, _Stacktrace) -> %% read_timer/1 -spec erlang:read_timer(TimerRef) -> non_neg_integer() | false when TimerRef :: reference(). -read_timer(_TimerRef) -> - erlang:nif_error(undefined). + +read_timer(TimerRef) -> + read_timer(TimerRef, []). + +%% read_timer/2 +-spec erlang:read_timer(TimerRef, Options) -> non_neg_integer() | false | ok when + TimerRef :: reference(), + Option :: {async, boolean()}, + Options :: [Option]. + +read_timer(TimerRef, Options) -> + try + Async = get_read_timer_options(Options, false), + case erts_internal:access_bif_timer(TimerRef) of + undefined -> + case Async of + true -> + erlang:self() ! {read_timer, TimerRef, false}, + ok; + false -> + false + end; + {BTR, TSrv} -> + case Async of + true -> + TSrv ! {read_timeout, BTR, erlang:self(), + TimerRef, TimerRef}, + ok; + false -> + Req = erlang:make_ref(), + TSrv ! {read_timeout, BTR, erlang:self(), + Req, TimerRef}, + receive + {read_timer, Req, Result} -> + Result + end + end + end + catch + _:_ -> erlang:error(badarg, [TimerRef]) + end. + +get_read_timer_options([], Async) -> + Async; +get_read_timer_options([{async, Bool} | Opts], + _Async) when Bool == true; Bool == false -> + get_read_timer_options(Opts, Bool). %% ref_to_list/1 -spec erlang:ref_to_list(Ref) -> string() when @@ -1509,8 +1623,36 @@ self() -> Dest :: pid() | atom(), Msg :: term(), TimerRef :: reference(). -send_after(_Time, _Dest, _Msg) -> - erlang:nif_error(undefined). + +send_after(0, Dest, Msg) -> + try + true = ((erlang:is_pid(Dest) + andalso erlang:node(Dest) == erlang:node()) + orelse (erlang:is_atom(Dest) + andalso Dest /= undefined)), + try Dest ! Msg catch _:_ -> ok end, + erlang:make_ref() + catch + _:_ -> + erlang:error(badarg, [0, Dest, Msg]) + end; +send_after(Time, Dest, Msg) -> + Now = erlang:monotonic_time(), + try + true = ((erlang:is_pid(Dest) + andalso erlang:node(Dest) == erlang:node()) + orelse (erlang:is_atom(Dest) + andalso Dest /= undefined)), + true = Time > 0, + true = Time < (1 bsl 32), % Maybe lift this restriction... + TO = Now + (erts_internal:time_unit()*Time) div 1000, + {BTR, TSrv, TRef} = erts_internal:create_bif_timer(), + TSrv ! {set_timeout, BTR, Dest, TO, TRef, Msg}, + TRef + catch + _:_ -> + erlang:error(badarg, [Time, Dest, Msg]) + end. %% seq_trace/2 -spec erlang:seq_trace(P1, P2) -> seq_trace_info_returns() | {term(), term(), term(), term(), term()} when @@ -1583,8 +1725,37 @@ split_binary(_Bin, _Pos) -> Dest :: pid() | atom(), Msg :: term(), TimerRef :: reference(). -start_timer(_Time, _Dest, _Msg) -> - erlang:nif_error(undefined). +start_timer(0, Dest, Msg) -> + try + true = ((erlang:is_pid(Dest) + andalso erlang:node(Dest) == erlang:node()) + orelse (erlang:is_atom(Dest) + andalso Dest /= undefined)), + TimerRef = erlang:make_ref(), + try Dest ! {timeout, TimerRef, Msg} catch _:_ -> ok end, + TimerRef + catch + _:_ -> + erlang:error(badarg, [0, Dest, Msg]) + end; +start_timer(Time, Dest, Msg) -> + Now = erlang:monotonic_time(), + try + true = ((erlang:is_pid(Dest) + andalso erlang:node(Dest) == erlang:node()) + orelse (erlang:is_atom(Dest) + andalso Dest /= undefined)), + true = Time > 0, + true = Time < (1 bsl 32), % Maybe lift this restriction... + TO = Now + (erts_internal:time_unit()*Time) div 1000, + {BTR, TSrv, TimerRef} = erts_internal:create_bif_timer(), + TSrv ! {set_timeout, BTR, Dest, TO, TimerRef, + {timeout, TimerRef, Msg}}, + TimerRef + catch + _:_ -> + erlang:error(badarg, [Time, Dest, Msg]) + end. %% suspend_process/2 -spec erlang:suspend_process(Suspendee, OptList) -> boolean() when diff --git a/erts/preloaded/src/erts_internal.erl b/erts/preloaded/src/erts_internal.erl index 30df75b406..2c701d75e4 100644 --- a/erts/preloaded/src/erts_internal.erl +++ b/erts/preloaded/src/erts_internal.erl @@ -42,6 +42,14 @@ -export([time_unit/0]). +-export([bif_timer_server/2]). + +-export([get_bif_timer_servers/0, create_bif_timer/0, access_bif_timer/1]). + +-export([monitor_process/2]). + +-export([is_system_process/1]). + %% %% Await result of send to port %% @@ -208,3 +216,246 @@ flush_monitor_messages(Ref, Multi, Res) when is_reference(Ref) -> time_unit() -> erlang:nif_error(undefined). + +-spec erts_internal:get_bif_timer_servers() -> Pids when + Pid :: pid(), + Pids :: [Pid]. + +get_bif_timer_servers() -> + erlang:nif_error(undefined). + +-spec erts_internal:create_bif_timer() -> Res when + Res :: {reference(), pid(), reference()}. + +create_bif_timer() -> + erlang:nif_error(undefined). + +-spec erts_internal:access_bif_timer(Ref) -> Res when + Ref :: reference(), + Res :: {reference(), pid(), reference()}. + +access_bif_timer(_Ref) -> + erlang:nif_error(undefined). + +-spec erts_internal:monitor_process(Pid, Ref) -> boolean() when + Pid :: pid(), + Ref :: reference(). + +monitor_process(_Pid, _Ref) -> + erlang:nif_error(undefined). + +-spec erts_internal:is_system_process(Pid) -> boolean() when + Pid :: pid(). + +is_system_process(_Pid) -> + erlang:nif_error(undefined). + +%% +%% BIF timer servers +%% + +-record(tsrv_state, {rtab, + ttab, + btr, + unit, + next}). + +bif_timer_server(N, BTR) -> + try + tsrv_loop(tsrv_init_static_state(N, BTR), infinity) + catch + Type:Reason -> + erlang:display({'BIF_timer_server', + {Type, Reason}, + erlang:get_stacktrace()}), + exit(Reason) + end. + +tsrv_init_static_state(N, BTR) -> + process_flag(trap_exit, true), + NList = integer_to_list(N), + RTabName = list_to_atom("BIF_timer_reference_table_" ++ NList), + TTabName = list_to_atom("BIF_timer_time_table_" ++ NList), + #tsrv_state{rtab = ets:new(RTabName, + [set, private, {keypos, 2}]), + ttab = ets:new(TTabName, + [ordered_set, private, {keypos, 1}]), + btr = BTR, + unit = erts_internal:time_unit(), + next = infinity}. + + +tsrv_loop(#tsrv_state{unit = Unit} = StaticState, Nxt) -> + CallTime = erlang:monotonic_time(), + %% 'infinity' is greater than all integers... + NewNxt = case CallTime >= Nxt of + true -> + tsrv_handle_timeout(CallTime, StaticState); + false -> + TMO = try + (1000*(Nxt - CallTime - 1)) div Unit + 1 + catch + error:badarith when Nxt == infinity -> infinity + end, + receive + Msg -> + tsrv_handle_msg(Msg, StaticState, Nxt) + after TMO -> + Nxt + end + end, + tsrv_loop(StaticState, NewNxt). + +tsrv_handle_msg({set_timeout, BTR, Proc, Time, TRef, Msg}, + #tsrv_state{rtab = RTab, + ttab = TTab, + btr = BTR}, + Nxt) when erlang:is_integer(Time) -> + RcvTime = erlang:monotonic_time(), + case Time =< RcvTime of + true -> + try Proc ! Msg catch _:_ -> ok end, + Nxt; + false -> + Ins = case erlang:is_atom(Proc) of + true -> + true; + false -> + try + erts_internal:monitor_process(Proc, TRef) + catch + _:_ -> false + end + end, + case Ins of + false -> + Nxt; + true -> + TKey = {Time, TRef}, + true = ets:insert(RTab, TKey), + true = ets:insert(TTab, {TKey, Proc, Msg}), + case Time < Nxt of + true -> Time; + false -> Nxt + end + end + end; +tsrv_handle_msg({cancel_timeout, BTR, From, Reply, Req, TRef}, + #tsrv_state{rtab = RTab, + ttab = TTab, + unit = Unit, + btr = BTR}, + Nxt) -> + case ets:lookup(RTab, TRef) of + [] -> + case Reply of + false -> + ok; + _ -> + try From ! {cancel_timer, Req, false} catch _:_ -> ok end + end, + Nxt; + [{Time, TRef} = TKey] -> + ets:delete(RTab, TRef), + ets:delete(TTab, TKey), + erlang:demonitor(TRef), + case Reply of + false -> + ok; + _ -> + RcvTime = erlang:monotonic_time(), + RT = case Time =< RcvTime of + true -> + 0; + false -> + ((1000*(Time - RcvTime)) div Unit) + end, + try From ! {cancel_timer, Req, RT} catch _:_ -> ok end + end, + case Time =:= Nxt of + false -> + Nxt; + true -> + case ets:first(TTab) of + '$end_of_table' -> infinity; + {NextTime, _TRef} -> NextTime + end + end + end; +tsrv_handle_msg({read_timeout, BTR, From, Req, TRef}, + #tsrv_state{rtab = RTab, + unit = Unit, + btr = BTR}, + Nxt) -> + case ets:lookup(RTab, TRef) of + [] -> + try From ! {read_timer, Req, false} catch _:_ -> ok end; + [{Time, TRef}] -> + RcvTime = erlang:monotonic_time(), + RT = case Time =< RcvTime of + true -> 0; + false -> (1000*(Time - RcvTime)) div Unit + end, + try From ! {read_timer, Req, RT} catch _:_ -> ok end + end, + Nxt; +tsrv_handle_msg({'DOWN', TRef, process, _, _}, + #tsrv_state{rtab = RTab, + ttab = TTab}, + Nxt) -> + case ets:lookup(RTab, TRef) of + [] -> + Nxt; + [{Time, TRef} = TKey] -> + ets:delete(RTab, TRef), + ets:delete(TTab, TKey), + case Time =:= Nxt of + false -> + Nxt; + true -> + case ets:first(TTab) of + '$end_of_table' -> infinity; + {NextTime, _} -> NextTime + end + end + end; +tsrv_handle_msg({cancel_all_timeouts, BTR, From, Ref}, + #tsrv_state{rtab = RTab, + ttab = TTab, + btr = BTR}, + _Nxt) -> + tsrv_delete_monitor_objects(RTab), + ets:delete_all_objects(TTab), + try From ! {canceled_all_timeouts, Ref} catch _:_ -> ok end, + infinity; +tsrv_handle_msg(_GarbageMsg, _StaticState, Nxt) -> + Nxt. + +tsrv_delete_monitor_objects(RTab) -> + case ets:first(RTab) of + '$end_of_table' -> + ok; + TRef -> + erlang:demonitor(TRef), + ets:delete(RTab, TRef), + tsrv_delete_monitor_objects(RTab) + end. + +tsrv_handle_timeout(CallTime, #tsrv_state{rtab = RTab, + ttab = TTab} = S) -> + case ets:first(TTab) of + '$end_of_table' -> + infinity; + {Time, _TRef} when Time > CallTime -> + Time; + {_Time, TRef} = TKey -> + [{TKey, Proc, Msg}] = ets:lookup(TTab, TKey), + case erlang:is_pid(Proc) of + false -> ok; + _ -> erlang:demonitor(TRef) + end, + ets:delete(TTab, TKey), + ets:delete(RTab, TRef), + try Proc ! Msg catch _:_ -> ok end, + tsrv_handle_timeout(CallTime, S) + end. diff --git a/erts/preloaded/src/init.erl b/erts/preloaded/src/init.erl index e95e11b3e6..48c5c37717 100644 --- a/erts/preloaded/src/init.erl +++ b/erts/preloaded/src/init.erl @@ -522,6 +522,7 @@ shutdown_pids(Heart,BootPid,State) -> Timer = shutdown_timer(State#state.flags), catch shutdown(State#state.kernel,BootPid,Timer,State), kill_all_pids(Heart), % Even the shutdown timer. + cancel_all_bif_timeouts(), kill_all_ports(Heart), flush_timout(Timer). @@ -580,6 +581,30 @@ resend([ExitMsg|Exits]) -> resend(_) -> ok. + +cancel_all_bif_timeouts() -> + TSrvs = erts_internal:get_bif_timer_servers(), + Ref = make_ref(), + {BTR, _TSrv} = erts_internal:access_bif_timer(Ref), %% Cheat... + request_cancel_all_bif_timeouts(Ref, BTR, TSrvs), + wait_response_cancel_all_bif_timeouts(Ref, BTR, TSrvs), + ok. + +request_cancel_all_bif_timeouts(_Ref, _BTR, []) -> + ok; +request_cancel_all_bif_timeouts(Ref, BTR, [TSrv|TSrvs]) -> + TSrv ! {cancel_all_timeouts, BTR, self(), {Ref, TSrv}}, + request_cancel_all_bif_timeouts(Ref, BTR, TSrvs). + +wait_response_cancel_all_bif_timeouts(_Ref, _BTR, []) -> + ok; +wait_response_cancel_all_bif_timeouts(Ref, BTR, [TSrv|TSrvs]) -> + receive + {canceled_all_timeouts, {Ref, TSrv}} -> + wait_response_cancel_all_bif_timeouts(Ref, BTR, TSrvs) + end. + + %% %% Kill all existing pids in the system (except init and heart). kill_all_pids(Heart) -> @@ -591,12 +616,9 @@ kill_all_pids(Heart) -> kill_all_pids(Heart) % Continue until all are really killed. end. -%% All except zombies. -alive_processes() -> - [P || P <- processes(), erlang:is_process_alive(P)]. - +%% All except system processes. get_pids(Heart) -> - Pids = alive_processes(), + Pids = [P || P <- processes(), not erts_internal:is_system_process(P)], delete(Heart,self(),Pids). delete(Heart,Init,[Heart|Pids]) -> delete(Heart,Init,Pids); -- cgit v1.2.3 From c20482023b70768bd84d25f1e34dbbc2fe09cf31 Mon Sep 17 00:00:00 2001 From: Rickard Green Date: Tue, 24 Mar 2015 15:28:11 +0100 Subject: Better OS system time implementation --- erts/preloaded/src/erlang.erl | 1 + 1 file changed, 1 insertion(+) (limited to 'erts/preloaded/src') diff --git a/erts/preloaded/src/erlang.erl b/erts/preloaded/src/erlang.erl index 83010b17d2..c5dc40f5d1 100644 --- a/erts/preloaded/src/erlang.erl +++ b/erts/preloaded/src/erlang.erl @@ -2531,6 +2531,7 @@ tuple_to_list(_Tuple) -> (nif_version) -> string(); (otp_release) -> string(); (os_monotonic_time_source) -> [{atom(),term()}]; + (os_system_time_source) -> [{atom(),term()}]; (port_count) -> non_neg_integer(); (port_limit) -> pos_integer(); (process_count) -> pos_integer(); -- cgit v1.2.3 From 2e016f6cde89bf471269c89f0fd2bb40422ce204 Mon Sep 17 00:00:00 2001 From: Rickard Green Date: Thu, 26 Mar 2015 12:07:00 +0100 Subject: Misc fixes --- erts/preloaded/src/erlang.erl | 2 +- erts/preloaded/src/erts_internal.erl | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) (limited to 'erts/preloaded/src') diff --git a/erts/preloaded/src/erlang.erl b/erts/preloaded/src/erlang.erl index c5dc40f5d1..60ca02861a 100644 --- a/erts/preloaded/src/erlang.erl +++ b/erts/preloaded/src/erlang.erl @@ -1732,7 +1732,7 @@ start_timer(0, Dest, Msg) -> orelse (erlang:is_atom(Dest) andalso Dest /= undefined)), TimerRef = erlang:make_ref(), - try Dest ! {timeout, TimerRef, Msg} catch _:_ -> ok end, + _ = try Dest ! {timeout, TimerRef, Msg} catch _:_ -> ok end, TimerRef catch _:_ -> diff --git a/erts/preloaded/src/erts_internal.erl b/erts/preloaded/src/erts_internal.erl index 2c701d75e4..3580fb542d 100644 --- a/erts/preloaded/src/erts_internal.erl +++ b/erts/preloaded/src/erts_internal.erl @@ -232,7 +232,7 @@ create_bif_timer() -> -spec erts_internal:access_bif_timer(Ref) -> Res when Ref :: reference(), - Res :: {reference(), pid(), reference()}. + Res :: {reference(), pid()} | 'undefined'. access_bif_timer(_Ref) -> erlang:nif_error(undefined). @@ -352,7 +352,7 @@ tsrv_handle_msg({cancel_timeout, BTR, From, Reply, Req, TRef}, false -> ok; _ -> - try From ! {cancel_timer, Req, false} catch _:_ -> ok end + _ = try From ! {cancel_timer, Req, false} catch _:_ -> ok end end, Nxt; [{Time, TRef} = TKey] -> @@ -370,7 +370,7 @@ tsrv_handle_msg({cancel_timeout, BTR, From, Reply, Req, TRef}, false -> ((1000*(Time - RcvTime)) div Unit) end, - try From ! {cancel_timer, Req, RT} catch _:_ -> ok end + _ = try From ! {cancel_timer, Req, RT} catch _:_ -> ok end end, case Time =:= Nxt of false -> @@ -389,14 +389,14 @@ tsrv_handle_msg({read_timeout, BTR, From, Req, TRef}, Nxt) -> case ets:lookup(RTab, TRef) of [] -> - try From ! {read_timer, Req, false} catch _:_ -> ok end; + _ = try From ! {read_timer, Req, false} catch _:_ -> ok end; [{Time, TRef}] -> RcvTime = erlang:monotonic_time(), RT = case Time =< RcvTime of true -> 0; false -> (1000*(Time - RcvTime)) div Unit end, - try From ! {read_timer, Req, RT} catch _:_ -> ok end + _ = try From ! {read_timer, Req, RT} catch _:_ -> ok end end, Nxt; tsrv_handle_msg({'DOWN', TRef, process, _, _}, @@ -456,6 +456,6 @@ tsrv_handle_timeout(CallTime, #tsrv_state{rtab = RTab, end, ets:delete(TTab, TKey), ets:delete(RTab, TRef), - try Proc ! Msg catch _:_ -> ok end, + _ = try Proc ! Msg catch _:_ -> ok end, tsrv_handle_timeout(CallTime, S) end. -- cgit v1.2.3 From 8b85c571f7c31bda6695c8179ef286c30862ce54 Mon Sep 17 00:00:00 2001 From: Richard Carlsson Date: Fri, 17 Apr 2015 13:21:29 +0200 Subject: Remove 'imports' key from spec of get_module_info() --- erts/preloaded/src/erlang.erl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'erts/preloaded/src') diff --git a/erts/preloaded/src/erlang.erl b/erts/preloaded/src/erlang.erl index fd11c101bc..629702fc1c 100644 --- a/erts/preloaded/src/erlang.erl +++ b/erts/preloaded/src/erlang.erl @@ -1931,7 +1931,7 @@ element(_N, _Tuple) -> %% Not documented -spec erlang:get_module_info(Module, Item) -> ModuleInfo when Module :: atom(), - Item :: module | imports | exports | functions | attributes | compile | native_addresses | md5, + Item :: module | exports | functions | attributes | compile | native_addresses | md5, ModuleInfo :: atom() | [] | [{atom(), arity()}] | [{atom(), term()}] | [{atom(), arity(), integer()}]. get_module_info(_Module, _Item) -> erlang:nif_error(undefined). -- cgit v1.2.3 From 9c78f149517dc02457d4c59e90bc9b03d411e28c Mon Sep 17 00:00:00 2001 From: Rickard Green Date: Tue, 5 May 2015 20:05:00 +0200 Subject: Optimized timer implementation --- erts/preloaded/src/erlang.erl | 205 ++++++---------------------- erts/preloaded/src/erts_internal.erl | 255 ++--------------------------------- erts/preloaded/src/init.erl | 25 ---- 3 files changed, 53 insertions(+), 432 deletions(-) (limited to 'erts/preloaded/src') diff --git a/erts/preloaded/src/erlang.erl b/erts/preloaded/src/erlang.erl index fd11c101bc..6aea2c08e4 100644 --- a/erts/preloaded/src/erlang.erl +++ b/erts/preloaded/src/erlang.erl @@ -129,10 +129,11 @@ -export([process_display/2]). -export([process_flag/3, process_info/1, processes/0, purge_module/1]). -export([put/2, raise/3, read_timer/1, read_timer/2, ref_to_list/1, register/2]). --export([registered/0, resume_process/1, round/1, self/0, send_after/3]). +-export([send_after/3, send_after/4, start_timer/3, start_timer/4]). +-export([registered/0, resume_process/1, round/1, self/0]). -export([seq_trace/2, seq_trace_print/1, seq_trace_print/2, setnode/2]). -export([setnode/3, size/1, spawn/3, spawn_link/3, split_binary/2]). --export([start_timer/3, suspend_process/2, system_monitor/0]). +-export([suspend_process/2, system_monitor/0]). -export([system_monitor/1, system_monitor/2, system_profile/0]). -export([system_profile/2, throw/1, time/0, trace/3, trace_delivered/1]). -export([trace_info/2, trunc/1, tuple_size/1, universaltime/0]). @@ -427,23 +428,9 @@ call_on_load_function(_P1) -> -spec erlang:cancel_timer(TimerRef) -> Time | false when TimerRef :: reference(), Time :: non_neg_integer(). -cancel_timer(TimerRef) -> - try - case erts_internal:access_bif_timer(TimerRef) of - undefined -> - false; - {BTR, TSrv} -> - Req = erlang:make_ref(), - TSrv ! {cancel_timeout, BTR, erlang:self(), - true, Req, TimerRef}, - receive - {cancel_timer, Req, Result} -> - Result - end - end - catch - _:_ -> erlang:error(badarg, [TimerRef]) - end. + +cancel_timer(_TimerRef) -> + erlang:nif_error(undefined). %% cancel_timer/2 -spec erlang:cancel_timer(TimerRef, Options) -> Time | false | ok when @@ -451,53 +438,9 @@ cancel_timer(TimerRef) -> Option :: {async, boolean()} | {info, boolean()}, Options :: [Option], Time :: non_neg_integer(). -cancel_timer(TimerRef, Options) -> - try - {Async, Info} = get_cancel_timer_options(Options, false, true), - case erts_internal:access_bif_timer(TimerRef) of - undefined -> - case {Async, Info} of - {true, true} -> - erlang:self() ! {cancel_timer, TimerRef, false}, ok; - {false, true} -> - false; - _ -> - ok - end; - {BTR, TSrv} -> - case Async of - true -> - TSrv ! {cancel_timeout, BTR, erlang:self(), - Info, TimerRef, TimerRef}, - ok; - false -> - Req = erlang:make_ref(), - TSrv ! {cancel_timeout, BTR, erlang:self(), - true, Req, TimerRef}, - receive - {cancel_timer, Req, Result} -> - case Info of - true -> Result; - false -> ok - end - end - end - end - catch - _:_ -> erlang:error(badarg, [TimerRef, Options]) - end. -get_cancel_timer_options([], Async, Info) -> - {Async, Info}; -get_cancel_timer_options([{async, Bool} | Opts], - _Async, Info) when Bool == true; - Bool == false -> - get_cancel_timer_options(Opts, Bool, Info); -get_cancel_timer_options([{info, Bool} | Opts], - Async, _Info) when Bool == true; - Bool == false -> - get_cancel_timer_options(Opts, Async, Bool). - +cancel_timer(_TimerRef, _Options) -> + erlang:nif_error(undefined). %% check_old_code/1 -spec check_old_code(Module) -> boolean() when @@ -1538,8 +1481,8 @@ raise(_Class, _Reason, _Stacktrace) -> -spec erlang:read_timer(TimerRef) -> non_neg_integer() | false when TimerRef :: reference(). -read_timer(TimerRef) -> - read_timer(TimerRef, []). +read_timer(_TimerRef) -> + erlang:nif_error(undefined). %% read_timer/2 -spec erlang:read_timer(TimerRef, Options) -> non_neg_integer() | false | ok when @@ -1547,43 +1490,8 @@ read_timer(TimerRef) -> Option :: {async, boolean()}, Options :: [Option]. -read_timer(TimerRef, Options) -> - try - Async = get_read_timer_options(Options, false), - case erts_internal:access_bif_timer(TimerRef) of - undefined -> - case Async of - true -> - erlang:self() ! {read_timer, TimerRef, false}, - ok; - false -> - false - end; - {BTR, TSrv} -> - case Async of - true -> - TSrv ! {read_timeout, BTR, erlang:self(), - TimerRef, TimerRef}, - ok; - false -> - Req = erlang:make_ref(), - TSrv ! {read_timeout, BTR, erlang:self(), - Req, TimerRef}, - receive - {read_timer, Req, Result} -> - Result - end - end - end - catch - _:_ -> erlang:error(badarg, [TimerRef]) - end. - -get_read_timer_options([], Async) -> - Async; -get_read_timer_options([{async, Bool} | Opts], - _Async) when Bool == true; Bool == false -> - get_read_timer_options(Opts, Bool). +read_timer(_TimerRef, _Options) -> + erlang:nif_error(undefined). %% ref_to_list/1 -spec erlang:ref_to_list(Ref) -> string() when @@ -1630,35 +1538,20 @@ self() -> Msg :: term(), TimerRef :: reference(). -send_after(0, Dest, Msg) -> - try - true = ((erlang:is_pid(Dest) - andalso erlang:node(Dest) == erlang:node()) - orelse (erlang:is_atom(Dest) - andalso Dest /= undefined)), - try Dest ! Msg catch _:_ -> ok end, - erlang:make_ref() - catch - _:_ -> - erlang:error(badarg, [0, Dest, Msg]) - end; -send_after(Time, Dest, Msg) -> - Now = erlang:monotonic_time(), - try - true = ((erlang:is_pid(Dest) - andalso erlang:node(Dest) == erlang:node()) - orelse (erlang:is_atom(Dest) - andalso Dest /= undefined)), - true = Time > 0, - true = Time < (1 bsl 32), % Maybe lift this restriction... - TO = Now + (erts_internal:time_unit()*Time) div 1000, - {BTR, TSrv, TRef} = erts_internal:create_bif_timer(), - TSrv ! {set_timeout, BTR, Dest, TO, TRef, Msg}, - TRef - catch - _:_ -> - erlang:error(badarg, [Time, Dest, Msg]) - end. +send_after(_Time, _Dest, _Msg) -> + erlang:nif_error(undefined). + +%% send_after/4 +-spec erlang:send_after(Time, Dest, Msg, Options) -> TimerRef when + Time :: integer(), + Dest :: pid() | atom(), + Msg :: term(), + Options :: [Option], + Option :: {abs, boolean()} | {accessor, pid()}, + TimerRef :: reference(). + +send_after(_Time, _Dest, _Msg, _Options) -> + erlang:nif_error(undefined). %% seq_trace/2 -spec erlang:seq_trace(P1, P2) -> seq_trace_info_returns() | {term(), term(), term(), term(), term()} when @@ -1731,37 +1624,21 @@ split_binary(_Bin, _Pos) -> Dest :: pid() | atom(), Msg :: term(), TimerRef :: reference(). -start_timer(0, Dest, Msg) -> - try - true = ((erlang:is_pid(Dest) - andalso erlang:node(Dest) == erlang:node()) - orelse (erlang:is_atom(Dest) - andalso Dest /= undefined)), - TimerRef = erlang:make_ref(), - _ = try Dest ! {timeout, TimerRef, Msg} catch _:_ -> ok end, - TimerRef - catch - _:_ -> - erlang:error(badarg, [0, Dest, Msg]) - end; -start_timer(Time, Dest, Msg) -> - Now = erlang:monotonic_time(), - try - true = ((erlang:is_pid(Dest) - andalso erlang:node(Dest) == erlang:node()) - orelse (erlang:is_atom(Dest) - andalso Dest /= undefined)), - true = Time > 0, - true = Time < (1 bsl 32), % Maybe lift this restriction... - TO = Now + (erts_internal:time_unit()*Time) div 1000, - {BTR, TSrv, TimerRef} = erts_internal:create_bif_timer(), - TSrv ! {set_timeout, BTR, Dest, TO, TimerRef, - {timeout, TimerRef, Msg}}, - TimerRef - catch - _:_ -> - erlang:error(badarg, [Time, Dest, Msg]) - end. + +start_timer(_Time, _Dest, _Msg) -> + erlang:nif_error(undefined). + +%% start_timer/4 +-spec erlang:start_timer(Time, Dest, Msg, Options) -> TimerRef when + Time :: integer(), + Dest :: pid() | atom(), + Msg :: term(), + Options :: [Option], + Option :: {abs, boolean()} | {accessor, pid()}, + TimerRef :: reference(). + +start_timer(_Time, _Dest, _Msg, _Options) -> + erlang:nif_error(undefined). %% suspend_process/2 -spec erlang:suspend_process(Suspendee, OptList) -> boolean() when diff --git a/erts/preloaded/src/erts_internal.erl b/erts/preloaded/src/erts_internal.erl index e489001532..65a1f1ed3a 100644 --- a/erts/preloaded/src/erts_internal.erl +++ b/erts/preloaded/src/erts_internal.erl @@ -40,13 +40,9 @@ -export([flush_monitor_messages/3]). --export([time_unit/0]). - --export([bif_timer_server/2]). - --export([get_bif_timer_servers/0, create_bif_timer/0, access_bif_timer/1]). +-export([await_result/1]). --export([monitor_process/2]). +-export([time_unit/0]). -export([is_system_process/1]). @@ -60,6 +56,16 @@ await_port_send_result(Ref, Busy, Ok) -> {Ref, _} -> Ok end. +%% +%% Await result... +%% + +await_result(Ref) when is_reference(Ref) -> + receive + {Ref, Result} -> + Result + end. + %% %% Statically linked port NIFs %% @@ -234,245 +240,8 @@ flush_monitor_messages(Ref, Multi, Res) when is_reference(Ref) -> time_unit() -> erlang:nif_error(undefined). --spec erts_internal:get_bif_timer_servers() -> Pids when - Pid :: pid(), - Pids :: [Pid]. - -get_bif_timer_servers() -> - erlang:nif_error(undefined). - --spec erts_internal:create_bif_timer() -> Res when - Res :: {reference(), pid(), reference()}. - -create_bif_timer() -> - erlang:nif_error(undefined). - --spec erts_internal:access_bif_timer(Ref) -> Res when - Ref :: reference(), - Res :: {reference(), pid()} | 'undefined'. - -access_bif_timer(_Ref) -> - erlang:nif_error(undefined). - --spec erts_internal:monitor_process(Pid, Ref) -> boolean() when - Pid :: pid(), - Ref :: reference(). - -monitor_process(_Pid, _Ref) -> - erlang:nif_error(undefined). - -spec erts_internal:is_system_process(Pid) -> boolean() when Pid :: pid(). is_system_process(_Pid) -> erlang:nif_error(undefined). - -%% -%% BIF timer servers -%% - --record(tsrv_state, {rtab, - ttab, - btr, - unit, - next}). - -bif_timer_server(N, BTR) -> - try - tsrv_loop(tsrv_init_static_state(N, BTR), infinity) - catch - Type:Reason -> - erlang:display({'BIF_timer_server', - {Type, Reason}, - erlang:get_stacktrace()}), - exit(Reason) - end. - -tsrv_init_static_state(N, BTR) -> - process_flag(trap_exit, true), - NList = integer_to_list(N), - RTabName = list_to_atom("BIF_timer_reference_table_" ++ NList), - TTabName = list_to_atom("BIF_timer_time_table_" ++ NList), - #tsrv_state{rtab = ets:new(RTabName, - [set, private, {keypos, 2}]), - ttab = ets:new(TTabName, - [ordered_set, private, {keypos, 1}]), - btr = BTR, - unit = erts_internal:time_unit(), - next = infinity}. - - -tsrv_loop(#tsrv_state{unit = Unit} = StaticState, Nxt) -> - CallTime = erlang:monotonic_time(), - %% 'infinity' is greater than all integers... - NewNxt = case CallTime >= Nxt of - true -> - tsrv_handle_timeout(CallTime, StaticState); - false -> - TMO = try - (1000*(Nxt - CallTime - 1)) div Unit + 1 - catch - error:badarith when Nxt == infinity -> infinity - end, - receive - Msg -> - tsrv_handle_msg(Msg, StaticState, Nxt) - after TMO -> - Nxt - end - end, - tsrv_loop(StaticState, NewNxt). - -tsrv_handle_msg({set_timeout, BTR, Proc, Time, TRef, Msg}, - #tsrv_state{rtab = RTab, - ttab = TTab, - btr = BTR}, - Nxt) when erlang:is_integer(Time) -> - RcvTime = erlang:monotonic_time(), - case Time =< RcvTime of - true -> - try Proc ! Msg catch _:_ -> ok end, - Nxt; - false -> - Ins = case erlang:is_atom(Proc) of - true -> - true; - false -> - try - erts_internal:monitor_process(Proc, TRef) - catch - _:_ -> false - end - end, - case Ins of - false -> - Nxt; - true -> - TKey = {Time, TRef}, - true = ets:insert(RTab, TKey), - true = ets:insert(TTab, {TKey, Proc, Msg}), - case Time < Nxt of - true -> Time; - false -> Nxt - end - end - end; -tsrv_handle_msg({cancel_timeout, BTR, From, Reply, Req, TRef}, - #tsrv_state{rtab = RTab, - ttab = TTab, - unit = Unit, - btr = BTR}, - Nxt) -> - case ets:lookup(RTab, TRef) of - [] -> - case Reply of - false -> - ok; - _ -> - _ = try From ! {cancel_timer, Req, false} catch _:_ -> ok end - end, - Nxt; - [{Time, TRef} = TKey] -> - ets:delete(RTab, TRef), - ets:delete(TTab, TKey), - erlang:demonitor(TRef), - case Reply of - false -> - ok; - _ -> - RcvTime = erlang:monotonic_time(), - RT = case Time =< RcvTime of - true -> - 0; - false -> - ((1000*(Time - RcvTime)) div Unit) - end, - _ = try From ! {cancel_timer, Req, RT} catch _:_ -> ok end - end, - case Time =:= Nxt of - false -> - Nxt; - true -> - case ets:first(TTab) of - '$end_of_table' -> infinity; - {NextTime, _TRef} -> NextTime - end - end - end; -tsrv_handle_msg({read_timeout, BTR, From, Req, TRef}, - #tsrv_state{rtab = RTab, - unit = Unit, - btr = BTR}, - Nxt) -> - case ets:lookup(RTab, TRef) of - [] -> - _ = try From ! {read_timer, Req, false} catch _:_ -> ok end; - [{Time, TRef}] -> - RcvTime = erlang:monotonic_time(), - RT = case Time =< RcvTime of - true -> 0; - false -> (1000*(Time - RcvTime)) div Unit - end, - _ = try From ! {read_timer, Req, RT} catch _:_ -> ok end - end, - Nxt; -tsrv_handle_msg({'DOWN', TRef, process, _, _}, - #tsrv_state{rtab = RTab, - ttab = TTab}, - Nxt) -> - case ets:lookup(RTab, TRef) of - [] -> - Nxt; - [{Time, TRef} = TKey] -> - ets:delete(RTab, TRef), - ets:delete(TTab, TKey), - case Time =:= Nxt of - false -> - Nxt; - true -> - case ets:first(TTab) of - '$end_of_table' -> infinity; - {NextTime, _} -> NextTime - end - end - end; -tsrv_handle_msg({cancel_all_timeouts, BTR, From, Ref}, - #tsrv_state{rtab = RTab, - ttab = TTab, - btr = BTR}, - _Nxt) -> - tsrv_delete_monitor_objects(RTab), - ets:delete_all_objects(TTab), - try From ! {canceled_all_timeouts, Ref} catch _:_ -> ok end, - infinity; -tsrv_handle_msg(_GarbageMsg, _StaticState, Nxt) -> - Nxt. - -tsrv_delete_monitor_objects(RTab) -> - case ets:first(RTab) of - '$end_of_table' -> - ok; - TRef -> - erlang:demonitor(TRef), - ets:delete(RTab, TRef), - tsrv_delete_monitor_objects(RTab) - end. - -tsrv_handle_timeout(CallTime, #tsrv_state{rtab = RTab, - ttab = TTab} = S) -> - case ets:first(TTab) of - '$end_of_table' -> - infinity; - {Time, _TRef} when Time > CallTime -> - Time; - {_Time, TRef} = TKey -> - [{TKey, Proc, Msg}] = ets:lookup(TTab, TKey), - case erlang:is_pid(Proc) of - false -> ok; - _ -> erlang:demonitor(TRef) - end, - ets:delete(TTab, TKey), - ets:delete(RTab, TRef), - _ = try Proc ! Msg catch _:_ -> ok end, - tsrv_handle_timeout(CallTime, S) - end. diff --git a/erts/preloaded/src/init.erl b/erts/preloaded/src/init.erl index 48c5c37717..bb56c9ff73 100644 --- a/erts/preloaded/src/init.erl +++ b/erts/preloaded/src/init.erl @@ -522,7 +522,6 @@ shutdown_pids(Heart,BootPid,State) -> Timer = shutdown_timer(State#state.flags), catch shutdown(State#state.kernel,BootPid,Timer,State), kill_all_pids(Heart), % Even the shutdown timer. - cancel_all_bif_timeouts(), kill_all_ports(Heart), flush_timout(Timer). @@ -581,30 +580,6 @@ resend([ExitMsg|Exits]) -> resend(_) -> ok. - -cancel_all_bif_timeouts() -> - TSrvs = erts_internal:get_bif_timer_servers(), - Ref = make_ref(), - {BTR, _TSrv} = erts_internal:access_bif_timer(Ref), %% Cheat... - request_cancel_all_bif_timeouts(Ref, BTR, TSrvs), - wait_response_cancel_all_bif_timeouts(Ref, BTR, TSrvs), - ok. - -request_cancel_all_bif_timeouts(_Ref, _BTR, []) -> - ok; -request_cancel_all_bif_timeouts(Ref, BTR, [TSrv|TSrvs]) -> - TSrv ! {cancel_all_timeouts, BTR, self(), {Ref, TSrv}}, - request_cancel_all_bif_timeouts(Ref, BTR, TSrvs). - -wait_response_cancel_all_bif_timeouts(_Ref, _BTR, []) -> - ok; -wait_response_cancel_all_bif_timeouts(Ref, BTR, [TSrv|TSrvs]) -> - receive - {canceled_all_timeouts, {Ref, TSrv}} -> - wait_response_cancel_all_bif_timeouts(Ref, BTR, TSrvs) - end. - - %% %% Kill all existing pids in the system (except init and heart). kill_all_pids(Heart) -> -- cgit v1.2.3 From 849a2ed2db2bd54422ec9284468f80cc86978974 Mon Sep 17 00:00:00 2001 From: Rickard Green Date: Mon, 11 May 2015 17:56:03 +0200 Subject: Timer fixes, documentation, and test cases --- erts/preloaded/src/erlang.erl | 41 ++++++++++++++++++++++++++++------------- 1 file changed, 28 insertions(+), 13 deletions(-) (limited to 'erts/preloaded/src') diff --git a/erts/preloaded/src/erlang.erl b/erts/preloaded/src/erlang.erl index 6aea2c08e4..ba7878bd2c 100644 --- a/erts/preloaded/src/erlang.erl +++ b/erts/preloaded/src/erlang.erl @@ -425,19 +425,23 @@ call_on_load_function(_P1) -> erlang:nif_error(undefined). %% cancel_timer/1 --spec erlang:cancel_timer(TimerRef) -> Time | false when +-spec erlang:cancel_timer(TimerRef) -> Result when TimerRef :: reference(), - Time :: non_neg_integer(). + Time :: non_neg_integer(), + Result :: Time | false. cancel_timer(_TimerRef) -> erlang:nif_error(undefined). %% cancel_timer/2 --spec erlang:cancel_timer(TimerRef, Options) -> Time | false | ok when +-spec erlang:cancel_timer(TimerRef, Options) -> Result | ok when TimerRef :: reference(), - Option :: {async, boolean()} | {info, boolean()}, + Async :: boolean(), + Info :: boolean(), + Option :: {async, Async} | {info, Info}, Options :: [Option], - Time :: non_neg_integer(). + Time :: non_neg_integer(), + Result :: Time | false. cancel_timer(_TimerRef, _Options) -> erlang:nif_error(undefined). @@ -1478,17 +1482,22 @@ raise(_Class, _Reason, _Stacktrace) -> erlang:nif_error(undefined). %% read_timer/1 --spec erlang:read_timer(TimerRef) -> non_neg_integer() | false when - TimerRef :: reference(). +-spec erlang:read_timer(TimerRef) -> Result when + TimerRef :: reference(), + Time :: non_neg_integer(), + Result :: Time | false. read_timer(_TimerRef) -> erlang:nif_error(undefined). %% read_timer/2 --spec erlang:read_timer(TimerRef, Options) -> non_neg_integer() | false | ok when +-spec erlang:read_timer(TimerRef, Options) -> Result | ok when TimerRef :: reference(), - Option :: {async, boolean()}, - Options :: [Option]. + Async :: boolean(), + Option :: {async, Async}, + Options :: [Option], + Time :: non_neg_integer(), + Result :: Time | false. read_timer(_TimerRef, _Options) -> erlang:nif_error(undefined). @@ -1547,7 +1556,8 @@ send_after(_Time, _Dest, _Msg) -> Dest :: pid() | atom(), Msg :: term(), Options :: [Option], - Option :: {abs, boolean()} | {accessor, pid()}, + Abs :: boolean(), + Option :: {abs, Abs}, %% | {accessor, Accessor} undocumented feature for now, TimerRef :: reference(). send_after(_Time, _Dest, _Msg, _Options) -> @@ -1634,7 +1644,8 @@ start_timer(_Time, _Dest, _Msg) -> Dest :: pid() | atom(), Msg :: term(), Options :: [Option], - Option :: {abs, boolean()} | {accessor, pid()}, + Abs :: boolean(), + Option :: {abs, Abs}, %% | {accessor, Accessor} undocumented feature for now, TimerRef :: reference(). start_timer(_Time, _Dest, _Msg, _Options) -> @@ -3589,7 +3600,11 @@ blocks_size([], Acc) -> get_fix_proc([{ProcType, A1, U1}| Rest], {A0, U0}) when ProcType == proc; ProcType == monitor_sh; ProcType == nlink_sh; - ProcType == msg_ref -> + ProcType == msg_ref; + ProcType == ll_ptimer; + ProcType == hl_ptimer; + ProcType == bif_timer; + ProcType == accessor_bif_timer -> get_fix_proc(Rest, {A0+A1, U0+U1}); get_fix_proc([_|Rest], Acc) -> get_fix_proc(Rest, Acc); -- cgit v1.2.3 From 25bd6312491fc9153a16f74b5d1d39609426ae60 Mon Sep 17 00:00:00 2001 From: Rory Byrne Date: Wed, 15 Apr 2015 17:28:09 +0100 Subject: Fix gen_tcp:shutdown/2 by making it asynchronous If the driver queue is empty, or the user is requesting a 'read' shutdown, then the shutdown() syscall is performed synchronously, as per the old version of shutdown/2. However, if the user is requesting a 'write' or 'read_write' shutdown, and there is data in the driver queue for the socket, then the shutdown() syscall is delayed and handled asynchronously when the driver queue is written out. This version of shutdown solves a number of issues with the old version. The two main solutions it offers are: * It doesn't block when the TCP peer is idle or slow. This is the expected behaviour when shutdown() is called: the caller needs to be able to continue reading from the socket, not be prevented from doing so. * It doesn't truncate the output. The current version of gen_tcp:shutdown/2 will truncate any outbound data in the driver queue after about 10 seconds if the TCP peer is idle of slow. Worse yet, it doesn't even inform anyone that the data has been truncated: 'ok' is returned to the caller; and a FIN rather than an RST is sent to the TCP peer. For a detailed description of all the problems with the old version of shutdown, please see the EEP Light that was written to justify this patch. --- erts/preloaded/src/prim_inet.erl | 21 +-------------------- 1 file changed, 1 insertion(+), 20 deletions(-) (limited to 'erts/preloaded/src') diff --git a/erts/preloaded/src/prim_inet.erl b/erts/preloaded/src/prim_inet.erl index 79ff013c77..622e1be869 100644 --- a/erts/preloaded/src/prim_inet.erl +++ b/erts/preloaded/src/prim_inet.erl @@ -127,37 +127,18 @@ drv2protocol(_) -> undefined. %% TODO: shutdown equivalent for SCTP %% shutdown(S, read) when is_port(S) -> - shutdown_2(S, 0); + shutdown_1(S, 0); shutdown(S, write) when is_port(S) -> shutdown_1(S, 1); shutdown(S, read_write) when is_port(S) -> shutdown_1(S, 2). shutdown_1(S, How) -> - case subscribe(S, [subs_empty_out_q]) of - {ok,[{subs_empty_out_q,N}]} when N > 0 -> - shutdown_pend_loop(S, N); %% wait for pending output to be sent - _Other -> ok - end, - shutdown_2(S, How). - -shutdown_2(S, How) -> case ctl_cmd(S, ?TCP_REQ_SHUTDOWN, [How]) of {ok, []} -> ok; {error,_}=Error -> Error end. -shutdown_pend_loop(S, N0) -> - receive - {empty_out_q,S} -> ok - after ?INET_CLOSE_TIMEOUT -> - case getstat(S, [send_pend]) of - {ok,[{send_pend,N0}]} -> ok; - {ok,[{send_pend,N}]} -> shutdown_pend_loop(S, N); - _ -> ok - end - end. - %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% %% CLOSE(insock()) -> ok -- cgit v1.2.3 From db7446a0235f5379ed230a51cc1d55475549f36b Mon Sep 17 00:00:00 2001 From: Rickard Green Date: Thu, 21 May 2015 00:00:56 +0200 Subject: Update runtime dependencies --- erts/preloaded/src/erts.app.src | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'erts/preloaded/src') diff --git a/erts/preloaded/src/erts.app.src b/erts/preloaded/src/erts.app.src index 345a6ae3be..cf9a06599a 100644 --- a/erts/preloaded/src/erts.app.src +++ b/erts/preloaded/src/erts.app.src @@ -35,7 +35,7 @@ {registered, []}, {applications, []}, {env, []}, - {runtime_dependencies, ["stdlib-2.0", "kernel-3.0", "sasl-2.4"]} + {runtime_dependencies, ["stdlib-2.5", "kernel-4.0", "sasl-2.4"]} ]}. %% vim: ft=erlang -- cgit v1.2.3 From 46efe0d85bc2f55dd432f403f20d4841b07023ed Mon Sep 17 00:00:00 2001 From: Rickard Green Date: Thu, 4 Jun 2015 16:45:41 +0200 Subject: Disable accessor timer option --- erts/preloaded/src/erlang.erl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'erts/preloaded/src') diff --git a/erts/preloaded/src/erlang.erl b/erts/preloaded/src/erlang.erl index ea8a911a2c..9d9208d1b5 100644 --- a/erts/preloaded/src/erlang.erl +++ b/erts/preloaded/src/erlang.erl @@ -1557,7 +1557,7 @@ send_after(_Time, _Dest, _Msg) -> Msg :: term(), Options :: [Option], Abs :: boolean(), - Option :: {abs, Abs}, %% | {accessor, Accessor} undocumented feature for now, + Option :: {abs, Abs}, TimerRef :: reference(). send_after(_Time, _Dest, _Msg, _Options) -> @@ -1645,7 +1645,7 @@ start_timer(_Time, _Dest, _Msg) -> Msg :: term(), Options :: [Option], Abs :: boolean(), - Option :: {abs, Abs}, %% | {accessor, Accessor} undocumented feature for now, + Option :: {abs, Abs}, TimerRef :: reference(). start_timer(_Time, _Dest, _Msg, _Options) -> -- cgit v1.2.3 From 4f63e427f1345b40b484ef16f6ff5e922bf14dac Mon Sep 17 00:00:00 2001 From: Rory Byrne Date: Mon, 20 Apr 2015 10:57:53 +0100 Subject: Add 'show_econnreset' TCP socket option An ECONNRESET is a socket error which tells us that a TCP peer has sent an RST. The RST indicates that they have aborted the connection and that the payload we have received should not be considered complete. Up until now, the implementation of TCP in inet_drv.c has hidden the receipt of the RST from the user, treating it as though it was just a FIN terminating the read side of the socket. There are many cases where user code needs to be able to distinguish between a socket that was closed normally and one that was aborted. Setting the option {show_econnreset, true} enables the user to receive ECONNRESET errors on both active and passive sockets. A connected socket returned from gen_tcp:accept/1 will inherit the show_econnreset setting of the listening socket. By default this option is set to {show_econnreset, false}. Note that this patch only enables the reporting of ECONNRESET when the socket is being read from. It does not report ECONNRESET (or EPIPE) when the user tries to write to a connection when an RST has already been received. Currently the TCP implementation in inet_drv.c hides all such send errors from the user in favour of returning {error, close}. A separate patch will be needed to enable the reporting of such errors. --- erts/preloaded/src/prim_inet.erl | 3 +++ 1 file changed, 3 insertions(+) (limited to 'erts/preloaded/src') diff --git a/erts/preloaded/src/prim_inet.erl b/erts/preloaded/src/prim_inet.erl index 622e1be869..fb0f67aa8a 100644 --- a/erts/preloaded/src/prim_inet.erl +++ b/erts/preloaded/src/prim_inet.erl @@ -1140,6 +1140,7 @@ enc_opt(delay_send) -> ?INET_LOPT_TCP_DELAY_SEND; enc_opt(packet_size) -> ?INET_LOPT_PACKET_SIZE; enc_opt(read_packets) -> ?INET_LOPT_READ_PACKETS; enc_opt(netns) -> ?INET_LOPT_NETNS; +enc_opt(show_econnreset) -> ?INET_LOPT_TCP_SHOW_ECONNRESET; enc_opt(raw) -> ?INET_OPT_RAW; % Names of SCTP opts: enc_opt(sctp_rtoinfo) -> ?SCTP_OPT_RTOINFO; @@ -1197,6 +1198,7 @@ dec_opt(?INET_LOPT_TCP_DELAY_SEND) -> delay_send; dec_opt(?INET_LOPT_PACKET_SIZE) -> packet_size; dec_opt(?INET_LOPT_READ_PACKETS) -> read_packets; dec_opt(?INET_LOPT_NETNS) -> netns; +dec_opt(?INET_LOPT_TCP_SHOW_ECONNRESET) -> show_econnreset; dec_opt(?INET_OPT_RAW) -> raw; dec_opt(I) when is_integer(I) -> undefined. @@ -1296,6 +1298,7 @@ type_opt_1(delay_send) -> bool; type_opt_1(packet_size) -> uint; type_opt_1(read_packets) -> uint; type_opt_1(netns) -> binary; +type_opt_1(show_econnreset) -> bool; %% %% SCTP options (to be set). If the type is a record type, the corresponding %% record signature is returned, otherwise, an "elementary" type tag -- cgit v1.2.3 From eed21b4fd99c8ab71dcefd3802104186af1cb6b0 Mon Sep 17 00:00:00 2001 From: Rory Byrne Date: Thu, 16 Apr 2015 18:01:23 +0100 Subject: Fix socket option {linger, {true, 0}} to abort TCP connections Up until now, if {linger, {true, 0}} is set on the socket and there is data in the port driver queue, the connection is not aborted until the port queue is empty and close() is called on the underlying file descriptor. This bug allows an idle TCP client to prevent a server from terminating the connection and freeing resources. This patch fixes the problem by discarding the port queue if the socket is closed when {linger, {true, 0}} is set. --- erts/preloaded/src/prim_inet.erl | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) (limited to 'erts/preloaded/src') diff --git a/erts/preloaded/src/prim_inet.erl b/erts/preloaded/src/prim_inet.erl index fb0f67aa8a..5e0b38aa68 100644 --- a/erts/preloaded/src/prim_inet.erl +++ b/erts/preloaded/src/prim_inet.erl @@ -146,11 +146,16 @@ shutdown_1(S, How) -> %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% close(S) when is_port(S) -> - case subscribe(S, [subs_empty_out_q]) of - {ok, [{subs_empty_out_q,N}]} when N > 0 -> - close_pend_loop(S, N); %% wait for pending output to be sent + case getopt(S, linger) of + {ok,{true,0}} -> + close_port(S); _ -> - close_port(S) + case subscribe(S, [subs_empty_out_q]) of + {ok, [{subs_empty_out_q,N}]} when N > 0 -> + close_pend_loop(S, N); %% wait for pending output to be sent + _ -> + close_port(S) + end end. close_pend_loop(S, N) -> -- cgit v1.2.3 From fe1c0d26d4e6180b79fc8497b827ac2ef1f471d5 Mon Sep 17 00:00:00 2001 From: Rickard Green Date: Fri, 5 Jun 2015 17:25:22 +0200 Subject: Delayed node table GC --- erts/preloaded/src/erlang.erl | 1 + 1 file changed, 1 insertion(+) (limited to 'erts/preloaded/src') diff --git a/erts/preloaded/src/erlang.erl b/erts/preloaded/src/erlang.erl index 9d9208d1b5..cf941ea6ca 100644 --- a/erts/preloaded/src/erlang.erl +++ b/erts/preloaded/src/erlang.erl @@ -2392,6 +2392,7 @@ tuple_to_list(_Tuple) -> CpuTopology :: cpu_topology(); (creation) -> integer(); (debug_compiled) -> boolean(); + (delayed_node_table_gc) -> infinity | non_neg_integer(); (dirty_cpu_schedulers) -> non_neg_integer(); (dirty_cpu_schedulers_online) -> non_neg_integer(); (dirty_io_schedulers) -> non_neg_integer(); -- cgit v1.2.3 From 74f0d7c8ea47b363136c86de5d7ea78a48c40570 Mon Sep 17 00:00:00 2001 From: Rickard Green Date: Wed, 17 Jun 2015 00:01:14 +0200 Subject: Save IO bytes in scheduler specific data --- erts/preloaded/src/erts_internal.erl | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) (limited to 'erts/preloaded/src') diff --git a/erts/preloaded/src/erts_internal.erl b/erts/preloaded/src/erts_internal.erl index 65a1f1ed3a..cf8edefd7d 100644 --- a/erts/preloaded/src/erts_internal.erl +++ b/erts/preloaded/src/erts_internal.erl @@ -40,7 +40,7 @@ -export([flush_monitor_messages/3]). --export([await_result/1]). +-export([await_result/1, gather_io_bytes/2]). -export([time_unit/0]). @@ -66,6 +66,23 @@ await_result(Ref) when is_reference(Ref) -> Result end. +%% +%% statistics(io) end up in gather_io_bytes/2 +%% + +gather_io_bytes(Ref, No) when is_reference(Ref), + is_integer(No), + No > 0 -> + gather_io_bytes(Ref, No, 0, 0). + +gather_io_bytes(_Ref, 0, InAcc, OutAcc) -> + {{input, InAcc}, {output, OutAcc}}; +gather_io_bytes(Ref, No, InAcc, OutAcc) -> + receive + {Ref, _SchedId, In, Out} -> + gather_io_bytes(Ref, No-1, InAcc + In, OutAcc + Out) + end. + %% %% Statically linked port NIFs %% -- cgit v1.2.3 From 738c34d4bb8f1a3811acd00af8c6c12107f8315b Mon Sep 17 00:00:00 2001 From: Bruce Yinhe Date: Thu, 18 Jun 2015 11:31:02 +0200 Subject: Change license text to APLv2 --- erts/preloaded/src/Makefile | 21 +++++++++++---------- erts/preloaded/src/add_abstract_code | 19 ++++++++++--------- erts/preloaded/src/erl_prim_loader.erl | 19 ++++++++++--------- erts/preloaded/src/erlang.erl | 19 ++++++++++--------- erts/preloaded/src/erts.app.src | 21 +++++++++++---------- erts/preloaded/src/erts_internal.erl | 19 ++++++++++--------- erts/preloaded/src/init.erl | 19 ++++++++++--------- erts/preloaded/src/otp_ring0.erl | 19 ++++++++++--------- erts/preloaded/src/prim_eval.S | 19 ++++++++++--------- erts/preloaded/src/prim_eval.erl | 19 ++++++++++--------- erts/preloaded/src/prim_file.erl | 19 ++++++++++--------- erts/preloaded/src/prim_inet.erl | 21 +++++++++++---------- erts/preloaded/src/prim_zip.erl | 19 ++++++++++--------- erts/preloaded/src/zip_internal.hrl | 21 +++++++++++---------- erts/preloaded/src/zlib.erl | 19 ++++++++++--------- 15 files changed, 154 insertions(+), 139 deletions(-) (limited to 'erts/preloaded/src') diff --git a/erts/preloaded/src/Makefile b/erts/preloaded/src/Makefile index 4ea2d41075..52034a0881 100644 --- a/erts/preloaded/src/Makefile +++ b/erts/preloaded/src/Makefile @@ -3,16 +3,17 @@ # # Copyright Ericsson AB 2008-2013. 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. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. # # %CopyrightEnd% # diff --git a/erts/preloaded/src/add_abstract_code b/erts/preloaded/src/add_abstract_code index 211a60c930..4f479db2e8 100644 --- a/erts/preloaded/src/add_abstract_code +++ b/erts/preloaded/src/add_abstract_code @@ -6,16 +6,17 @@ %% %% Copyright Ericsson AB 2013. 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/. +%% Licensed under the Apache License, Version 2.0 (the "License"); +%% you may not use this file except in compliance with the License. +%% You may obtain a copy of the License at %% -%% 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. +%% http://www.apache.org/licenses/LICENSE-2.0 +%% +%% Unless required by applicable law or agreed to in writing, software +%% distributed under the License is distributed on an "AS IS" BASIS, +%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +%% See the License for the specific language governing permissions and +%% limitations under the License. %% %% %CopyrightEnd% %% diff --git a/erts/preloaded/src/erl_prim_loader.erl b/erts/preloaded/src/erl_prim_loader.erl index 6b86a427ba..9f6cba33bd 100644 --- a/erts/preloaded/src/erl_prim_loader.erl +++ b/erts/preloaded/src/erl_prim_loader.erl @@ -3,16 +3,17 @@ %% %% Copyright Ericsson AB 1996-2013. 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/. +%% Licensed under the Apache License, Version 2.0 (the "License"); +%% you may not use this file except in compliance with the License. +%% You may obtain a copy of the License at %% -%% 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. +%% http://www.apache.org/licenses/LICENSE-2.0 +%% +%% Unless required by applicable law or agreed to in writing, software +%% distributed under the License is distributed on an "AS IS" BASIS, +%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +%% See the License for the specific language governing permissions and +%% limitations under the License. %% %% %CopyrightEnd% %% diff --git a/erts/preloaded/src/erlang.erl b/erts/preloaded/src/erlang.erl index cf941ea6ca..291356c7b1 100644 --- a/erts/preloaded/src/erlang.erl +++ b/erts/preloaded/src/erlang.erl @@ -3,16 +3,17 @@ %% %% Copyright Ericsson AB 1996-2013. 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/. +%% Licensed under the Apache License, Version 2.0 (the "License"); +%% you may not use this file except in compliance with the License. +%% You may obtain a copy of the License at %% -%% 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. +%% http://www.apache.org/licenses/LICENSE-2.0 +%% +%% Unless required by applicable law or agreed to in writing, software +%% distributed under the License is distributed on an "AS IS" BASIS, +%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +%% See the License for the specific language governing permissions and +%% limitations under the License. %% %% %CopyrightEnd% %% diff --git a/erts/preloaded/src/erts.app.src b/erts/preloaded/src/erts.app.src index cf9a06599a..8442aaf7e8 100644 --- a/erts/preloaded/src/erts.app.src +++ b/erts/preloaded/src/erts.app.src @@ -3,16 +3,17 @@ %% %% Copyright Ericsson AB 2013. 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. +%% Licensed under the Apache License, Version 2.0 (the "License"); +%% you may not use this file except in compliance with the License. +%% You may obtain a copy of the License at +%% +%% http://www.apache.org/licenses/LICENSE-2.0 +%% +%% Unless required by applicable law or agreed to in writing, software +%% distributed under the License is distributed on an "AS IS" BASIS, +%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +%% See the License for the specific language governing permissions and +%% limitations under the License. %% %% %CopyrightEnd% %% diff --git a/erts/preloaded/src/erts_internal.erl b/erts/preloaded/src/erts_internal.erl index cf8edefd7d..7ed4efea4b 100644 --- a/erts/preloaded/src/erts_internal.erl +++ b/erts/preloaded/src/erts_internal.erl @@ -3,16 +3,17 @@ %% %% Copyright Ericsson AB 2012-2013. 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/. +%% Licensed under the Apache License, Version 2.0 (the "License"); +%% you may not use this file except in compliance with the License. +%% You may obtain a copy of the License at %% -%% 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. +%% http://www.apache.org/licenses/LICENSE-2.0 +%% +%% Unless required by applicable law or agreed to in writing, software +%% distributed under the License is distributed on an "AS IS" BASIS, +%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +%% See the License for the specific language governing permissions and +%% limitations under the License. %% %% %CopyrightEnd% %% diff --git a/erts/preloaded/src/init.erl b/erts/preloaded/src/init.erl index bb56c9ff73..c4e37b76f1 100644 --- a/erts/preloaded/src/init.erl +++ b/erts/preloaded/src/init.erl @@ -3,16 +3,17 @@ %% %% Copyright Ericsson AB 1996-2013. 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/. +%% Licensed under the Apache License, Version 2.0 (the "License"); +%% you may not use this file except in compliance with the License. +%% You may obtain a copy of the License at %% -%% 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. +%% http://www.apache.org/licenses/LICENSE-2.0 +%% +%% Unless required by applicable law or agreed to in writing, software +%% distributed under the License is distributed on an "AS IS" BASIS, +%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +%% See the License for the specific language governing permissions and +%% limitations under the License. %% %% %CopyrightEnd% %% diff --git a/erts/preloaded/src/otp_ring0.erl b/erts/preloaded/src/otp_ring0.erl index 2ccf142f30..3158fc7d21 100644 --- a/erts/preloaded/src/otp_ring0.erl +++ b/erts/preloaded/src/otp_ring0.erl @@ -3,16 +3,17 @@ %% %% Copyright Ericsson AB 2000-2010. 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/. +%% Licensed under the Apache License, Version 2.0 (the "License"); +%% you may not use this file except in compliance with the License. +%% You may obtain a copy of the License at %% -%% 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. +%% http://www.apache.org/licenses/LICENSE-2.0 +%% +%% Unless required by applicable law or agreed to in writing, software +%% distributed under the License is distributed on an "AS IS" BASIS, +%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +%% See the License for the specific language governing permissions and +%% limitations under the License. %% %% %CopyrightEnd% %% diff --git a/erts/preloaded/src/prim_eval.S b/erts/preloaded/src/prim_eval.S index 958a79a1da..1b7b00a7c9 100644 --- a/erts/preloaded/src/prim_eval.S +++ b/erts/preloaded/src/prim_eval.S @@ -3,16 +3,17 @@ %% %% Copyright Ericsson AB 2013. 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/. +%% Licensed under the Apache License, Version 2.0 (the "License"); +%% you may not use this file except in compliance with the License. +%% You may obtain a copy of the License at %% -%% 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. +%% http://www.apache.org/licenses/LICENSE-2.0 +%% +%% Unless required by applicable law or agreed to in writing, software +%% distributed under the License is distributed on an "AS IS" BASIS, +%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +%% See the License for the specific language governing permissions and +%% limitations under the License. %% %% %CopyrightEnd% %% diff --git a/erts/preloaded/src/prim_eval.erl b/erts/preloaded/src/prim_eval.erl index ec5af8c138..732e22468e 100644 --- a/erts/preloaded/src/prim_eval.erl +++ b/erts/preloaded/src/prim_eval.erl @@ -3,16 +3,17 @@ %% %% Copyright Ericsson AB 2013. 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/. +%% Licensed under the Apache License, Version 2.0 (the "License"); +%% you may not use this file except in compliance with the License. +%% You may obtain a copy of the License at %% -%% 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. +%% http://www.apache.org/licenses/LICENSE-2.0 +%% +%% Unless required by applicable law or agreed to in writing, software +%% distributed under the License is distributed on an "AS IS" BASIS, +%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +%% See the License for the specific language governing permissions and +%% limitations under the License. %% %% %CopyrightEnd% %% diff --git a/erts/preloaded/src/prim_file.erl b/erts/preloaded/src/prim_file.erl index 34679404a2..c87b2645ec 100644 --- a/erts/preloaded/src/prim_file.erl +++ b/erts/preloaded/src/prim_file.erl @@ -3,16 +3,17 @@ %% %% Copyright Ericsson AB 2000-2013. 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/. +%% Licensed under the Apache License, Version 2.0 (the "License"); +%% you may not use this file except in compliance with the License. +%% You may obtain a copy of the License at %% -%% 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. +%% http://www.apache.org/licenses/LICENSE-2.0 +%% +%% Unless required by applicable law or agreed to in writing, software +%% distributed under the License is distributed on an "AS IS" BASIS, +%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +%% See the License for the specific language governing permissions and +%% limitations under the License. %% %% %CopyrightEnd% %% diff --git a/erts/preloaded/src/prim_inet.erl b/erts/preloaded/src/prim_inet.erl index 5e0b38aa68..4d04e1dacb 100644 --- a/erts/preloaded/src/prim_inet.erl +++ b/erts/preloaded/src/prim_inet.erl @@ -3,16 +3,17 @@ %% %% Copyright Ericsson AB 2000-2013. 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. +%% Licensed under the Apache License, Version 2.0 (the "License"); +%% you may not use this file except in compliance with the License. +%% You may obtain a copy of the License at +%% +%% http://www.apache.org/licenses/LICENSE-2.0 +%% +%% Unless required by applicable law or agreed to in writing, software +%% distributed under the License is distributed on an "AS IS" BASIS, +%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +%% See the License for the specific language governing permissions and +%% limitations under the License. %% %% %CopyrightEnd% %% diff --git a/erts/preloaded/src/prim_zip.erl b/erts/preloaded/src/prim_zip.erl index 1d5ab52a24..c4b949afcb 100644 --- a/erts/preloaded/src/prim_zip.erl +++ b/erts/preloaded/src/prim_zip.erl @@ -3,16 +3,17 @@ %% %% Copyright Ericsson AB 2008-2013. 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/. +%% Licensed under the Apache License, Version 2.0 (the "License"); +%% you may not use this file except in compliance with the License. +%% You may obtain a copy of the License at %% -%% 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. +%% http://www.apache.org/licenses/LICENSE-2.0 +%% +%% Unless required by applicable law or agreed to in writing, software +%% distributed under the License is distributed on an "AS IS" BASIS, +%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +%% See the License for the specific language governing permissions and +%% limitations under the License. %% %% %CopyrightEnd% %% diff --git a/erts/preloaded/src/zip_internal.hrl b/erts/preloaded/src/zip_internal.hrl index a8f7b1f1b7..d5cf52fae4 100644 --- a/erts/preloaded/src/zip_internal.hrl +++ b/erts/preloaded/src/zip_internal.hrl @@ -3,16 +3,17 @@ %% %% Copyright Ericsson AB 2008-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. +%% Licensed under the Apache License, Version 2.0 (the "License"); +%% you may not use this file except in compliance with the License. +%% You may obtain a copy of the License at +%% +%% http://www.apache.org/licenses/LICENSE-2.0 +%% +%% Unless required by applicable law or agreed to in writing, software +%% distributed under the License is distributed on an "AS IS" BASIS, +%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +%% See the License for the specific language governing permissions and +%% limitations under the License. %% %% %CopyrightEnd% %% diff --git a/erts/preloaded/src/zlib.erl b/erts/preloaded/src/zlib.erl index 5d9f90ec58..473ad649c7 100644 --- a/erts/preloaded/src/zlib.erl +++ b/erts/preloaded/src/zlib.erl @@ -3,16 +3,17 @@ %% %% Copyright Ericsson AB 2003-2013. 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/. +%% Licensed under the Apache License, Version 2.0 (the "License"); +%% you may not use this file except in compliance with the License. +%% You may obtain a copy of the License at %% -%% 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. +%% http://www.apache.org/licenses/LICENSE-2.0 +%% +%% Unless required by applicable law or agreed to in writing, software +%% distributed under the License is distributed on an "AS IS" BASIS, +%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +%% See the License for the specific language governing permissions and +%% limitations under the License. %% %% %CopyrightEnd% %% -- cgit v1.2.3 From d0143499cd9ff1c1cf029ff33c65c908229536c7 Mon Sep 17 00:00:00 2001 From: Luca Favatella Date: Thu, 2 Jul 2015 23:57:37 +0100 Subject: Teach Dialyzer arity of funs with literal arity Re-insert logic for `erlang:make_fun/3` in `erl_bif_types`. It had been removed in bd941f5 while type spec-ing `erlang.erl`. Type spec in `erlang.erl` cannot express arity of returned fun based on value of argument hence re-introducing logic in `erl_bif_types`. Re-definition of logic in `erl_bif_types` follows approach in 9d870a0. --- erts/preloaded/src/erlang.erl | 1 + 1 file changed, 1 insertion(+) (limited to 'erts/preloaded/src') diff --git a/erts/preloaded/src/erlang.erl b/erts/preloaded/src/erlang.erl index 291356c7b1..b4c9de9e1e 100644 --- a/erts/preloaded/src/erlang.erl +++ b/erts/preloaded/src/erlang.erl @@ -1974,6 +1974,7 @@ localtime_to_universaltime(_Localtime, _IsDst) -> %% CHECK! Why the strange very thorough specification of the error %% condition with disallowed arity in erl_bif_types? %% Not documented +%% Shadowed by erl_bif_types: erlang:make_fun/3 -spec erlang:make_fun(Module, Function, Arity) -> function() when Module :: atom(), Function :: atom(), -- cgit v1.2.3 From 07c1d0d975fbecf295a3c9f04f7b09e7a8b6ff99 Mon Sep 17 00:00:00 2001 From: Sverker Eriksson Date: Wed, 23 Sep 2015 20:09:49 +0200 Subject: erts: Review module erlang docs --- erts/preloaded/src/erlang.erl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'erts/preloaded/src') diff --git a/erts/preloaded/src/erlang.erl b/erts/preloaded/src/erlang.erl index 291356c7b1..4e55f711b2 100644 --- a/erts/preloaded/src/erlang.erl +++ b/erts/preloaded/src/erlang.erl @@ -2423,7 +2423,7 @@ tuple_to_list(_Tuple) -> MinBinVHeapSize :: pos_integer()}; (modified_timing_level) -> integer() | undefined; (multi_scheduling) -> disabled | blocked | enabled; - (multi_scheduling_blockers) -> [PID :: pid()]; + (multi_scheduling_blockers) -> [Pid :: pid()]; (nif_version) -> string(); (otp_release) -> string(); (os_monotonic_time_source) -> [{atom(),term()}]; -- cgit v1.2.3 From a36b6aeeeb3e40a7ba1737b596ede3e321540211 Mon Sep 17 00:00:00 2001 From: Constantin Rack Date: Thu, 15 Oct 2015 20:19:33 +0200 Subject: Fix minor typo "timout" -> "timeout" --- erts/preloaded/src/prim_inet.erl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'erts/preloaded/src') diff --git a/erts/preloaded/src/prim_inet.erl b/erts/preloaded/src/prim_inet.erl index 4d04e1dacb..f9dd6c9618 100644 --- a/erts/preloaded/src/prim_inet.erl +++ b/erts/preloaded/src/prim_inet.erl @@ -232,7 +232,7 @@ bindx(S, AddFlag, Addrs) -> %% if timeout is given: %% timeout < 0 -> infinity %% 0 -> immediate connect (mostly works for loopback) -%% > 0 -> wait for timout ms if not connected then +%% > 0 -> wait for timeout ms if not connected then %% return {error, timeout} %% %% ASYNC_CONNECT(insock(), IP, Port, Timeout) -> {ok, S, Ref} | {error, Reason} @@ -273,7 +273,7 @@ async_connect(S, IP, Port, Time) -> %% if timeout is given: %% timeout < 0 -> infinity %% 0 -> immediate accept (poll) -%% > 0 -> wait for timout ms for accept if no accept then +%% > 0 -> wait for timeout ms for accept if no accept then %% return {error, timeout} %% %% ASYNC_ACCEPT(insock(), Timeout) -- cgit v1.2.3 From afac3c7136c48d8630bd400c5454e146915e634f Mon Sep 17 00:00:00 2001 From: Serge Aleynikov Date: Mon, 26 Oct 2015 14:46:54 +0100 Subject: erts: Add {line_delimiter, byte()} option to inet:setopts/2 A new {line_delimiter, byte()} option allows line-oriented TCP-based protocols to use a custom line delimiting character. It is to be used in conjunction with {packet, line}. This option also works with erlang:decode_packet/3 when its first argument is 'line'. --- erts/preloaded/src/prim_inet.erl | 3 +++ 1 file changed, 3 insertions(+) (limited to 'erts/preloaded/src') diff --git a/erts/preloaded/src/prim_inet.erl b/erts/preloaded/src/prim_inet.erl index 4d04e1dacb..d5c8fd4268 100644 --- a/erts/preloaded/src/prim_inet.erl +++ b/erts/preloaded/src/prim_inet.erl @@ -1147,6 +1147,7 @@ enc_opt(packet_size) -> ?INET_LOPT_PACKET_SIZE; enc_opt(read_packets) -> ?INET_LOPT_READ_PACKETS; enc_opt(netns) -> ?INET_LOPT_NETNS; enc_opt(show_econnreset) -> ?INET_LOPT_TCP_SHOW_ECONNRESET; +enc_opt(line_delimiter) -> ?INET_LOPT_LINE_DELIM; enc_opt(raw) -> ?INET_OPT_RAW; % Names of SCTP opts: enc_opt(sctp_rtoinfo) -> ?SCTP_OPT_RTOINFO; @@ -1205,6 +1206,7 @@ dec_opt(?INET_LOPT_PACKET_SIZE) -> packet_size; dec_opt(?INET_LOPT_READ_PACKETS) -> read_packets; dec_opt(?INET_LOPT_NETNS) -> netns; dec_opt(?INET_LOPT_TCP_SHOW_ECONNRESET) -> show_econnreset; +dec_opt(?INET_LOPT_LINE_DELIM) -> line_delimiter; dec_opt(?INET_OPT_RAW) -> raw; dec_opt(I) when is_integer(I) -> undefined. @@ -1287,6 +1289,7 @@ type_opt_1(packet) -> {httph_bin,?TCP_PB_HTTPH_BIN}, {ssl, ?TCP_PB_SSL_TLS}, % obsolete {ssl_tls, ?TCP_PB_SSL_TLS}]}; +type_opt_1(line_delimiter) -> int; type_opt_1(mode) -> {enum,[{list, ?INET_MODE_LIST}, {binary, ?INET_MODE_BINARY}]}; -- cgit v1.2.3 From f1f6ba4da602eb96727b6e9b5ac3dfdac17a1bd8 Mon Sep 17 00:00:00 2001 From: Luis Rascao Date: Sat, 12 Sep 2015 15:48:30 +0100 Subject: Fix crash on init restart On load handler process not being launched on a restart, NIF's such as asn1rt_nif require it to be present for correct loading. --- erts/preloaded/src/init.erl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'erts/preloaded/src') diff --git a/erts/preloaded/src/init.erl b/erts/preloaded/src/init.erl index c4e37b76f1..0ad5824ad1 100644 --- a/erts/preloaded/src/init.erl +++ b/erts/preloaded/src/init.erl @@ -167,7 +167,6 @@ stop(Status) -> init ! {stop,{stop,Status}}, ok. boot(BootArgs) -> register(init, self()), process_flag(trap_exit, true), - start_on_load_handler_process(), {Start0,Flags,Args} = parse_boot_args(BootArgs), Start = map(fun prepare_run_args/1, Start0), Flags0 = flags_to_atoms_again(Flags), @@ -225,6 +224,7 @@ code_path_choice() -> end. boot(Start,Flags,Args) -> + start_on_load_handler_process(), BootPid = do_boot(Flags,Start), State = #state{flags = Flags, args = Args, -- cgit v1.2.3 From 3ac08f9b668613a4292436979eacc61863c2ab94 Mon Sep 17 00:00:00 2001 From: Rickard Green Date: Wed, 16 Sep 2015 15:02:50 +0200 Subject: Fragmented young heap generation and off_heap_message_queue option * The youngest generation of the heap can now consist of multiple blocks. Heap fragments and message fragments are added to the youngest generation when needed without triggering a GC. After a GC the youngest generation is contained in one single block. * The off_heap_message_queue process flag has been added. When enabled all message data in the queue is kept off heap. When a message is selected from the queue, the message fragment (or heap fragment) containing the actual message is attached to the youngest generation. Messages stored off heap is not part of GC. --- erts/preloaded/src/erlang.erl | 44 ++++++++++++++++++++----------------------- 1 file changed, 20 insertions(+), 24 deletions(-) (limited to 'erts/preloaded/src') diff --git a/erts/preloaded/src/erlang.erl b/erts/preloaded/src/erlang.erl index 291356c7b1..e46d64eb0a 100644 --- a/erts/preloaded/src/erlang.erl +++ b/erts/preloaded/src/erlang.erl @@ -2044,6 +2044,9 @@ open_port(_PortName,_PortSettings) -> (min_bin_vheap_size, MinBinVHeapSize) -> OldMinBinVHeapSize when MinBinVHeapSize :: non_neg_integer(), OldMinBinVHeapSize :: non_neg_integer(); + (off_heap_message_queue, OHMQ) -> OldOHMQ when + OHMQ :: boolean(), + OldOHMQ :: boolean(); (priority, Level) -> OldLevel when Level :: priority_level(), OldLevel :: priority_level(); @@ -2082,6 +2085,7 @@ process_flag(_Flag, _Value) -> min_bin_vheap_size | monitored_by | monitors | + off_heap_message_queue | priority | reductions | registered_name | @@ -2123,6 +2127,7 @@ process_flag(_Flag, _Value) -> {monitors, Monitors :: [{process, Pid :: pid() | {RegName :: atom(), Node :: node()}}]} | + {off_heap_message_queue, OHMQ :: boolean()} | {priority, Level :: priority_level()} | {reductions, Number :: non_neg_integer()} | {registered_name, Atom :: atom()} | @@ -2425,6 +2430,7 @@ tuple_to_list(_Tuple) -> (multi_scheduling) -> disabled | blocked | enabled; (multi_scheduling_blockers) -> [PID :: pid()]; (nif_version) -> string(); + (off_heap_message_queue) -> boolean(); (otp_release) -> string(); (os_monotonic_time_source) -> [{atom(),term()}]; (os_system_time_source) -> [{atom(),term()}]; @@ -2552,14 +2558,19 @@ spawn_monitor(M, F, A) when erlang:is_atom(M), spawn_monitor(M, F, A) -> erlang:error(badarg, [M,F,A]). + +-type spawn_opt_option() :: + link + | monitor + | {priority, Level :: priority_level()} + | {fullsweep_after, Number :: non_neg_integer()} + | {min_heap_size, Size :: non_neg_integer()} + | {min_bin_vheap_size, VSize :: non_neg_integer()} + | {off_heap_message_queue, OHMQ :: boolean()}. + -spec spawn_opt(Fun, Options) -> pid() | {pid(), reference()} when Fun :: function(), - Options :: [Option], - Option :: link | monitor - | {priority, Level :: priority_level()} - | {fullsweep_after, Number :: non_neg_integer()} - | {min_heap_size, Size :: non_neg_integer()} - | {min_bin_vheap_size, VSize :: non_neg_integer()}. + Options :: [spawn_opt_option()]. spawn_opt(F, O) when erlang:is_function(F) -> spawn_opt(erlang, apply, [F, []], O); spawn_opt({M,F}=MF, O) when erlang:is_atom(M), erlang:is_atom(F) -> @@ -2572,12 +2583,7 @@ spawn_opt(F, O) -> -spec spawn_opt(Node, Fun, Options) -> pid() | {pid(), reference()} when Node :: node(), Fun :: function(), - Options :: [Option], - Option :: link | monitor - | {priority, Level :: priority_level()} - | {fullsweep_after, Number :: non_neg_integer()} - | {min_heap_size, Size :: non_neg_integer()} - | {min_bin_vheap_size, VSize :: non_neg_integer()}. + Options :: [spawn_opt_option()]. spawn_opt(N, F, O) when N =:= erlang:node() -> spawn_opt(F, O); spawn_opt(N, F, O) when erlang:is_function(F) -> @@ -2664,12 +2670,7 @@ spawn_link(N,M,F,A) -> Module :: module(), Function :: atom(), Args :: [term()], - Options :: [Option], - Option :: link | monitor - | {priority, Level :: priority_level()} - | {fullsweep_after, Number :: non_neg_integer()} - | {min_heap_size, Size :: non_neg_integer()} - | {min_bin_vheap_size, VSize :: non_neg_integer()}. + Options :: [spawn_opt_option()]. spawn_opt(M, F, A, Opts) -> case catch erlang:spawn_opt({M,F,A,Opts}) of {'EXIT',{Reason,_}} -> @@ -2684,12 +2685,7 @@ spawn_opt(M, F, A, Opts) -> Module :: module(), Function :: atom(), Args :: [term()], - Options :: [Option], - Option :: link | monitor - | {priority, Level :: priority_level()} - | {fullsweep_after, Number :: non_neg_integer()} - | {min_heap_size, Size :: non_neg_integer()} - | {min_bin_vheap_size, VSize :: non_neg_integer()}. + Options :: [spawn_opt_option()]. spawn_opt(N, M, F, A, O) when N =:= erlang:node(), erlang:is_atom(M), erlang:is_atom(F), erlang:is_list(A), erlang:is_list(O) -> -- cgit v1.2.3 From 9d0a5bf2c1cc564fd38268cbb5313cd8813ea138 Mon Sep 17 00:00:00 2001 From: Lukas Larsson Date: Mon, 16 Nov 2015 14:57:12 +0100 Subject: erts: Add garbage_collection_info to process_info/2 This info request returns greater details about the current gc state. This info is not included in the default process_info/1 as it would clutter the default printout with too much information. --- erts/preloaded/src/erlang.erl | 2 ++ 1 file changed, 2 insertions(+) (limited to 'erts/preloaded/src') diff --git a/erts/preloaded/src/erlang.erl b/erts/preloaded/src/erlang.erl index 6a9ec9c915..cb607a7730 100644 --- a/erts/preloaded/src/erlang.erl +++ b/erts/preloaded/src/erlang.erl @@ -2074,6 +2074,7 @@ process_flag(_Flag, _Value) -> dictionary | error_handler | garbage_collection | + garbage_collection_info | group_leader | heap_size | initial_call | @@ -2114,6 +2115,7 @@ process_flag(_Flag, _Value) -> {dictionary, Dictionary :: [{Key :: term(), Value :: term()}]} | {error_handler, Module :: module()} | {garbage_collection, GCInfo :: [{atom(),non_neg_integer()}]} | + {garbage_collection_info, GCInfo :: [{atom(),non_neg_integer()}]} | {group_leader, GroupLeader :: pid()} | {heap_size, Size :: non_neg_integer()} | {initial_call, mfa()} | -- cgit v1.2.3 From 85491375da14ab087ec99532ee3a896ff6fe0371 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn-Egil=20Dahlberg?= Date: Tue, 29 Sep 2015 15:33:18 +0200 Subject: Add erlang:copy_literals/2 spec --- erts/preloaded/src/erlang.erl | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) (limited to 'erts/preloaded/src') diff --git a/erts/preloaded/src/erlang.erl b/erts/preloaded/src/erlang.erl index 6a9ec9c915..0d5176019f 100644 --- a/erts/preloaded/src/erlang.erl +++ b/erts/preloaded/src/erlang.erl @@ -91,7 +91,7 @@ -export([bit_size/1, bitsize/1, bitstring_to_list/1]). -export([bump_reductions/1, byte_size/1, call_on_load_function/1]). -export([cancel_timer/1, cancel_timer/2, check_old_code/1, check_process_code/2, - check_process_code/3, crc32/1]). + check_process_code/3, copy_literals/2, crc32/1]). -export([crc32/2, crc32_combine/3, date/0, decode_packet/3]). -export([delete_element/2]). -export([delete_module/1, demonitor/1, demonitor/2, display/1]). @@ -520,6 +520,13 @@ get_cpc_opts([{allow_gc, AllowGC} | Options], Async, _OldAllowGC) -> get_cpc_opts([], Async, AllowGC) -> {Async, AllowGC}. +%% copy_literals/2 +-spec erlang:copy_literals(Module,Bool) -> 'true' | 'false' | 'aborted' when + Module :: module(), + Bool :: boolean(). +copy_literals(_Mod, _Bool) -> + erlang:nif_error(undefined). + %% crc32/1 -spec erlang:crc32(Data) -> non_neg_integer() when Data :: iodata(). -- cgit v1.2.3 From 2ae91c3ade0538500ff4dbda29ad539e595f64df Mon Sep 17 00:00:00 2001 From: Sverker Eriksson Date: Thu, 15 Oct 2015 20:10:46 +0200 Subject: erts: Change erts_internal:map_type/1 into term_type/1 to support other terms, not just maps --- erts/preloaded/src/erts_internal.erl | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'erts/preloaded/src') diff --git a/erts/preloaded/src/erts_internal.erl b/erts/preloaded/src/erts_internal.erl index 7ed4efea4b..023af1579f 100644 --- a/erts/preloaded/src/erts_internal.erl +++ b/erts/preloaded/src/erts_internal.erl @@ -31,7 +31,7 @@ -export([await_port_send_result/3]). -export([cmp_term/2]). --export([map_to_tuple_keys/1, map_type/1, map_hashmap_children/1]). +-export([map_to_tuple_keys/1, term_type/1, map_hashmap_children/1]). -export([port_command/3, port_connect/2, port_close/1, port_control/3, port_call/3, port_info/1, port_info/2]). @@ -215,12 +215,12 @@ cmp_term(_A,_B) -> map_to_tuple_keys(_M) -> erlang:nif_error(undefined). -%% return the internal map type --spec map_type(M) -> Type when - M :: map(), - Type :: 'flatmap' | 'hashmap' | 'hashmap_node'. +%% return the internal term type +-spec term_type(M) -> Type when + M :: term(), + Type :: 'flatmap' | 'hashmap' | 'hashmap_node' | 'small' | 'big' | 'ifloat' | 'hfloat'. -map_type(_M) -> +term_type(_M) -> erlang:nif_error(undefined). %% return the internal hashmap sub-nodes from -- cgit v1.2.3 From f6eacb9981b40604a031c9d61967b0c3a3588bdb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn-Egil=20Dahlberg?= Date: Fri, 13 Nov 2015 17:41:36 +0100 Subject: erts: Let term_type/1 encompass all types --- erts/preloaded/src/erts_internal.erl | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) (limited to 'erts/preloaded/src') diff --git a/erts/preloaded/src/erts_internal.erl b/erts/preloaded/src/erts_internal.erl index 023af1579f..ce0a6a1d9e 100644 --- a/erts/preloaded/src/erts_internal.erl +++ b/erts/preloaded/src/erts_internal.erl @@ -216,11 +216,17 @@ map_to_tuple_keys(_M) -> erlang:nif_error(undefined). %% return the internal term type --spec term_type(M) -> Type when - M :: term(), - Type :: 'flatmap' | 'hashmap' | 'hashmap_node' | 'small' | 'big' | 'ifloat' | 'hfloat'. - -term_type(_M) -> +-spec term_type(T) -> Type when + T :: term(), + Type :: 'flatmap' | 'hashmap' | 'hashmap_node' + | 'fixnum' | 'bignum' | 'hfloat' + | 'list' | 'tuple' | 'export' | 'fun' + | 'refc_binary' | 'heap_binary' | 'sub_binary' + | 'reference' | 'external_reference' + | 'pid' | 'external_pid' | 'port' | 'external_port' + | 'atom' | 'catch' | 'nil'. + +term_type(_T) -> erlang:nif_error(undefined). %% return the internal hashmap sub-nodes from -- cgit v1.2.3 From 19c4689eea86f26c5af9b8f712c227ce4f62310b Mon Sep 17 00:00:00 2001 From: Rickard Green Date: Tue, 24 Nov 2015 15:57:55 +0100 Subject: Replace off_heap_message_queue option with message_queue_data option The message_queue_data option can have the values - off_heap - on_heap - mixed --- erts/preloaded/src/erlang.erl | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) (limited to 'erts/preloaded/src') diff --git a/erts/preloaded/src/erlang.erl b/erts/preloaded/src/erlang.erl index 6a9ec9c915..7a76c95c53 100644 --- a/erts/preloaded/src/erlang.erl +++ b/erts/preloaded/src/erlang.erl @@ -2033,6 +2033,9 @@ open_port(_PortName,_PortSettings) -> -type priority_level() :: low | normal | high | max. +-type message_queue_data() :: + off_heap | on_heap | mixed. + -spec process_flag(trap_exit, Boolean) -> OldBoolean when Boolean :: boolean(), OldBoolean :: boolean(); @@ -2045,9 +2048,9 @@ open_port(_PortName,_PortSettings) -> (min_bin_vheap_size, MinBinVHeapSize) -> OldMinBinVHeapSize when MinBinVHeapSize :: non_neg_integer(), OldMinBinVHeapSize :: non_neg_integer(); - (off_heap_message_queue, OHMQ) -> OldOHMQ when - OHMQ :: boolean(), - OldOHMQ :: boolean(); + (message_queue_data, MQD) -> OldMQD when + MQD :: message_queue_data(), + OldMQD :: message_queue_data(); (priority, Level) -> OldLevel when Level :: priority_level(), OldLevel :: priority_level(); @@ -2086,7 +2089,7 @@ process_flag(_Flag, _Value) -> min_bin_vheap_size | monitored_by | monitors | - off_heap_message_queue | + message_queue_data | priority | reductions | registered_name | @@ -2128,7 +2131,7 @@ process_flag(_Flag, _Value) -> {monitors, Monitors :: [{process, Pid :: pid() | {RegName :: atom(), Node :: node()}}]} | - {off_heap_message_queue, OHMQ :: boolean()} | + {message_queue_data, MQD :: message_queue_data()} | {priority, Level :: priority_level()} | {reductions, Number :: non_neg_integer()} | {registered_name, Atom :: atom()} | @@ -2431,7 +2434,7 @@ tuple_to_list(_Tuple) -> (multi_scheduling) -> disabled | blocked | enabled; (multi_scheduling_blockers) -> [Pid :: pid()]; (nif_version) -> string(); - (off_heap_message_queue) -> boolean(); + (message_queue_data) -> message_queue_data(); (otp_release) -> string(); (os_monotonic_time_source) -> [{atom(),term()}]; (os_system_time_source) -> [{atom(),term()}]; @@ -2567,7 +2570,7 @@ spawn_monitor(M, F, A) -> | {fullsweep_after, Number :: non_neg_integer()} | {min_heap_size, Size :: non_neg_integer()} | {min_bin_vheap_size, VSize :: non_neg_integer()} - | {off_heap_message_queue, OHMQ :: boolean()}. + | {message_queue_data, MQD :: message_queue_data()}. -spec spawn_opt(Fun, Options) -> pid() | {pid(), reference()} when Fun :: function(), -- cgit v1.2.3 From 4b98e710b9c45481c1cdc7a4ee68f7ce7fca908a Mon Sep 17 00:00:00 2001 From: Lukas Larsson Date: Mon, 13 Jul 2015 15:38:41 +0200 Subject: erts: Add support for asynchronous open_port OTP-13086 --- erts/preloaded/src/erlang.erl | 10 ++++++++-- erts/preloaded/src/erts_internal.erl | 9 ++++++++- 2 files changed, 16 insertions(+), 3 deletions(-) (limited to 'erts/preloaded/src') diff --git a/erts/preloaded/src/erlang.erl b/erts/preloaded/src/erlang.erl index 7280b43502..4c22c596eb 100644 --- a/erts/preloaded/src/erlang.erl +++ b/erts/preloaded/src/erlang.erl @@ -2027,8 +2027,14 @@ nodes(_Arg) -> | eof | {parallelism, Boolean :: boolean()} | hide. -open_port(_PortName,_PortSettings) -> - erlang:nif_error(undefined). +open_port(PortName, PortSettings) -> + case case erts_internal:open_port(PortName, PortSettings) of + Ref when erlang:is_reference(Ref) -> receive {Ref, Res} -> Res end; + Res -> Res + end of + Port when erlang:is_port(Port) -> Port; + Error -> erlang:error(Error, [PortName, PortSettings]) + end. -type priority_level() :: low | normal | high | max. diff --git a/erts/preloaded/src/erts_internal.erl b/erts/preloaded/src/erts_internal.erl index 7ed4efea4b..81202ed3e2 100644 --- a/erts/preloaded/src/erts_internal.erl +++ b/erts/preloaded/src/erts_internal.erl @@ -32,7 +32,7 @@ -export([await_port_send_result/3]). -export([cmp_term/2]). -export([map_to_tuple_keys/1, map_type/1, map_hashmap_children/1]). --export([port_command/3, port_connect/2, port_close/1, +-export([open_port/2, port_command/3, port_connect/2, port_close/1, port_control/3, port_call/3, port_info/1, port_info/2]). -export([request_system_task/3]). @@ -88,6 +88,13 @@ gather_io_bytes(Ref, No, InAcc, OutAcc) -> %% Statically linked port NIFs %% +-spec erts_internal:open_port(PortName, PortSettings) -> Result when + PortName :: tuple(), + PortSettings :: term(), + Result :: port() | reference() | atom(). +open_port(_PortName, _PortSettings) -> + erlang:nif_error(undefined). + -spec erts_internal:port_command(Port, Data, OptionList) -> Result when Port :: port() | atom(), Data :: iodata(), -- cgit v1.2.3 From 27b921fef54b7410efdf756d6ad20ce2877fbc6b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Gustavsson?= Date: Thu, 8 Oct 2015 14:11:07 +0200 Subject: Clean up parsing and lookup of flags The handling of flags has been incrementally messed up over time, leading to convoluted code. Rewrite the parsing and lookup of flags. By using the appropriate data structures, the code will become simpler. --- erts/preloaded/src/init.erl | 98 ++++++++++++++++----------------------------- 1 file changed, 34 insertions(+), 64 deletions(-) (limited to 'erts/preloaded/src') diff --git a/erts/preloaded/src/init.erl b/erts/preloaded/src/init.erl index 0ad5824ad1..b166aba81d 100644 --- a/erts/preloaded/src/init.erl +++ b/erts/preloaded/src/init.erl @@ -169,8 +169,7 @@ boot(BootArgs) -> process_flag(trap_exit, true), {Start0,Flags,Args} = parse_boot_args(BootArgs), Start = map(fun prepare_run_args/1, Start0), - Flags0 = flags_to_atoms_again(Flags), - boot(Start,Flags0,Args). + boot(Start, Flags, Args). prepare_run_args({eval, [Expr]}) -> {eval,Expr}; @@ -202,16 +201,6 @@ map(_F, []) -> map(F, [X|Rest]) -> [F(X) | map(F, Rest)]. -flags_to_atoms_again([]) -> - []; -flags_to_atoms_again([{F0,L0}|Rest]) -> - L = L0, - F = b2a(F0), - [{F,L}|flags_to_atoms_again(Rest)]; -flags_to_atoms_again([{F0}|Rest]) -> - F = b2a(F0), - [{F}|flags_to_atoms_again(Rest)]. - -spec code_path_choice() -> 'relaxed' | 'strict'. code_path_choice() -> case get_argument(code_path_choice) of @@ -451,9 +440,9 @@ do_handle_msg(Msg,State) -> %%% ------------------------------------------------- make_permanent(Boot,Config,Flags0,State) -> - case set_flag('-boot',Boot,Flags0) of + case set_flag(boot, Boot, Flags0) of {ok,Flags1} -> - case set_flag('-config',Config,Flags1) of + case set_flag(config, Config, Flags1) of {ok,Flags} -> {ok,State#state{flags = Flags}}; Error -> @@ -716,10 +705,10 @@ add_to_kernel(Init,Pid) -> end. prim_load_flags(Flags) -> - PortPgm = get_flag('-loader',Flags,<<"efile">>), - Hosts = get_flag_list('-hosts', Flags, []), - Id = get_flag('-id',Flags,none), - Path = get_flag_list('-path',Flags,false), + PortPgm = get_flag(loader, Flags, <<"efile">>), + Hosts = get_flag_list(hosts, Flags, []), + Id = get_flag(id, Flags, none), + Path = get_flag_list(path, Flags, false), {PortPgm, Hosts, Id, Path}. %%% ------------------------------------------------- @@ -735,17 +724,17 @@ do_boot(Flags,Start) -> do_boot(Init,Flags,Start) -> process_flag(trap_exit,true), {Pgm0,Nodes,Id,Path} = prim_load_flags(Flags), - Root = b2s(get_flag('-root',Flags)), + Root = b2s(get_flag(root, Flags)), PathFls = path_flags(Flags), Pgm = b2s(Pgm0), _Pid = start_prim_loader(Init,b2a(Id),Pgm,bs2as(Nodes), bs2ss(Path),PathFls), BootFile = bootfile(Flags,Root), BootList = get_boot(BootFile,Root), - LoadMode = b2a(get_flag('-mode',Flags,false)), - Deb = b2a(get_flag('-init_debug',Flags,false)), + LoadMode = b2a(get_flag(mode, Flags, false)), + Deb = b2a(get_flag(init_debug, Flags, false)), catch ?ON_LOAD_HANDLER ! {init_debug_flag,Deb}, - BootVars = get_flag_args('-boot_var',Flags), + BootVars = get_flag_args(boot_var, Flags), ParallelLoad = (Pgm =:= "efile") and (erlang:system_info(thread_pool_size) > 0), @@ -760,11 +749,11 @@ do_boot(Init,Flags,Start) -> start_em(Start). bootfile(Flags,Root) -> - b2s(get_flag('-boot',Flags,concat([Root,"/bin/start"]))). + b2s(get_flag(boot, Flags, concat([Root,"/bin/start"]))). path_flags(Flags) -> - Pa = append(reverse(get_flag_args('-pa',Flags))), - Pz = append(get_flag_args('-pz',Flags)), + Pa = append(reverse(get_flag_args(pa, Flags))), + Pz = append(get_flag_args(pz, Flags)), {bs2ss(Pa),bs2ss(Pz)}. get_boot(BootFile0,Root) -> @@ -1102,7 +1091,7 @@ load_mod_code(Mod, BinCode, FullName) -> %% -------------------------------------------------------- shutdown_timer(Flags) -> - case get_flag('-shutdown_time',Flags,infinity) of + case get_flag(shutdown_time, Flags, infinity) of infinity -> self(); Time -> @@ -1152,14 +1141,10 @@ parse_boot_args([B|Bs], Ss, Fs, As) -> eval_arg -> {Expr,Rest} = get_args(Bs, []), parse_boot_args(Rest, [{eval, Expr}|Ss], Fs, As); - flag -> + {flag,A} -> {F,Rest} = get_args(Bs, []), - Fl = case F of - [] -> [B]; - FF -> [B,FF] - end, - parse_boot_args(Rest, Ss, - [list_to_tuple(Fl)|Fs], As); + Fl = {A,F}, + parse_boot_args(Rest, Ss, [Fl|Fs], As); arg -> parse_boot_args(Bs, Ss, Fs, [B|As]); end_args -> @@ -1173,12 +1158,8 @@ check(<<"-s">>) -> start_arg; check(<<"-run">>) -> start_arg2; check(<<"-eval">>) -> eval_arg; check(<<"--">>) -> end_args; -check(X) when is_binary(X) -> - case binary_to_list(X) of - [$-|_Rest] -> flag; - _Chars -> arg %Even empty atoms - end; -check(_X) -> arg. %This should never occur +check(<<"-",Flag/binary>>) -> {flag,b2a(Flag)}; +check(_) -> arg. get_args([B|Bs], As) -> case check(B) of @@ -1187,7 +1168,7 @@ get_args([B|Bs], As) -> start_arg2 -> {reverse(As), [B|Bs]}; eval_arg -> {reverse(As), [B|Bs]}; end_args -> {reverse(As), Bs}; - flag -> {reverse(As), [B|Bs]}; + {flag,_} -> {reverse(As), [B|Bs]}; arg -> get_args(Bs, [B|As]) end; @@ -1209,12 +1190,12 @@ get_flag(F,Flags,Default) -> get_flag(F,Flags) -> case search(F,Flags) of + {value,{F,[]}} -> + true; {value,{F,[V]}} -> V; {value,{F,V}} -> V; - {value,{F}} -> % Flag given! - true; _ -> exit(list_to_atom(concat(["no ",F," flag"]))) end. @@ -1246,21 +1227,15 @@ get_flag_list(F,Flags) -> %% get_flag_args(F,Flags) -> get_flag_args(F,Flags,[]). -get_flag_args(F,[{F,V}|Flags],Acc) when is_list(V) -> - get_flag_args(F,Flags,[V|Acc]); get_flag_args(F,[{F,V}|Flags],Acc) -> - get_flag_args(F,Flags,[[V]|Acc]); + get_flag_args(F,Flags,[V|Acc]); get_flag_args(F,[_|Flags],Acc) -> get_flag_args(F,Flags,Acc); get_flag_args(_,[],Acc) -> reverse(Acc). get_arguments([{F,V}|Flags]) -> - [$-|Fl] = atom_to_list(F), - [{list_to_atom(Fl),to_strings(V)}|get_arguments(Flags)]; -get_arguments([{F}|Flags]) -> - [$-|Fl] = atom_to_list(F), - [{list_to_atom(Fl),[]}|get_arguments(Flags)]; + [{F,to_strings(V)}|get_arguments(Flags)]; get_arguments([]) -> []. @@ -1268,26 +1243,21 @@ to_strings([H|T]) when is_atom(H) -> [atom_to_list(H)|to_strings(T)]; to_strings([H|T]) when is_binary(H) -> [b2s(H)|to_strings(T)]; to_strings([]) -> []. -get_argument(Arg,Flags) -> - Args = get_arguments(Flags), - case get_argument1(Arg,Args) of - [] -> - error; - Value -> - {ok,Value} +get_argument(Arg, Flags) -> + case get_argument1(Arg, Flags) of + [] -> error; + Value -> {ok,Value} end. -get_argument1(Arg,[{Arg,V}|Args]) -> - [V|get_argument1(Arg,Args)]; -get_argument1(Arg,[_|Args]) -> - get_argument1(Arg,Args); -get_argument1(_,[]) -> +get_argument1(Arg, [{Arg,V}|Args]) -> + [to_strings(V)|get_argument1(Arg, Args)]; +get_argument1(Arg, [_|Args]) -> + get_argument1(Arg, Args); +get_argument1(_, []) -> []. set_argument([{Flag,_}|Flags],Flag,Value) -> [{Flag,[Value]}|Flags]; -set_argument([{Flag}|Flags],Flag,Value) -> - [{Flag,[Value]}|Flags]; set_argument([Item|Flags],Flag,Value) -> [Item|set_argument(Flags,Flag,Value)]; set_argument([],Flag,Value) -> -- cgit v1.2.3 From e1dc0aa4100f881f4350162bd523c53d38f08b8f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Gustavsson?= Date: Mon, 12 Oct 2015 15:14:14 +0200 Subject: Simplify get_flag() and get_flag_list() The get_flag/3 function which returns a default value if the flag doesn't exist, is implemented in terms of get_flag/2 which throws an exception if the flag doesn't exist. get_flag/3 is frequently used for the flags that don't exist, which means that means that an exception will be generated and catched for no good reason. Reimplement get_flag/3 so that it doesn't have to call get_flag/2 and catch an exception. Eliminate the get_flag/2 function by writing a special purpose function for the only time it's used, that is for retrieving the value for the -root flag. As a side-effect, we will get a nicer error message if there is something wrong with the -root flag. Similarly, simplify get_flag_list/3 and remove get_flag_list/2. We can also eliminate search/3 and use the lists:keyfind/3 BIF instead. --- erts/preloaded/src/init.erl | 53 ++++++++++++++++----------------------------- 1 file changed, 19 insertions(+), 34 deletions(-) (limited to 'erts/preloaded/src') diff --git a/erts/preloaded/src/init.erl b/erts/preloaded/src/init.erl index b166aba81d..a85b41fddb 100644 --- a/erts/preloaded/src/init.erl +++ b/erts/preloaded/src/init.erl @@ -724,7 +724,7 @@ do_boot(Flags,Start) -> do_boot(Init,Flags,Start) -> process_flag(trap_exit,true), {Pgm0,Nodes,Id,Path} = prim_load_flags(Flags), - Root = b2s(get_flag(root, Flags)), + Root = get_root(Flags), PathFls = path_flags(Flags), Pgm = b2s(Pgm0), _Pid = start_prim_loader(Init,b2a(Id),Pgm,bs2as(Nodes), @@ -748,6 +748,14 @@ do_boot(Init,Flags,Start) -> start_em(Start). +get_root(Flags) -> + case get_argument(root, Flags) of + {ok,[[Root]]} -> + Root; + _ -> + exit(no_or_multiple_root_variables) + end. + bootfile(Flags,Root) -> b2s(get_flag(boot, Flags, concat([Root,"/bin/start"]))). @@ -1180,44 +1188,28 @@ get_args([], As) -> {reverse(As),[]}. %% atom() if a single arg was given. %% list(atom()) if several args were given. %% -get_flag(F,Flags,Default) -> - case catch get_flag(F,Flags) of - {'EXIT',_} -> - Default; - Value -> - Value - end. - -get_flag(F,Flags) -> - case search(F,Flags) of - {value,{F,[]}} -> +get_flag(F, Flags, Default) -> + case lists:keyfind(F, 1, Flags) of + {F,[]} -> true; - {value,{F,[V]}} -> + {F,[V]} -> V; - {value,{F,V}} -> + {F,V} -> V; _ -> - exit(list_to_atom(concat(["no ",F," flag"]))) + Default end. %% %% Internal get_flag function, with default value. %% Return: list(atom()) %% -get_flag_list(F,Flags,Default) -> - case catch get_flag_list(F,Flags) of - {'EXIT',_} -> - Default; - Value -> - Value - end. - -get_flag_list(F,Flags) -> - case search(F,Flags) of - {value,{F,V}} -> +get_flag_list(F, Flags, Default) -> + case lists:keyfind(F, 1, Flags) of + {F,[_|_]=V} -> V; _ -> - exit(list_to_atom(concat(["no ",F," flag"]))) + Default end. %% @@ -1290,13 +1282,6 @@ reverse([A, B]) -> reverse([A, B | L]) -> lists:reverse(L, [B, A]). % BIF -search(Key, [H|_T]) when is_tuple(H), element(1, H) =:= Key -> - {value, H}; -search(Key, [_|T]) -> - search(Key, T); -search(_Key, []) -> - false. - -spec objfile_extension() -> nonempty_string(). objfile_extension() -> ".beam". -- cgit v1.2.3 From 93f7c2dcdd36a31dca6bfd06e0784ed715e51f77 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Gustavsson?= Date: Mon, 12 Oct 2015 15:56:35 +0200 Subject: Remove useless 'catch' in start_it/1 The last clause in start_it/1 calls a function in some module. It goes to great length to catch any exception and pass them on unchanged, and if there was a normal return, it will just return the return value. It can been seen that the entire 'catch' construction with the reference trick is totally unnecessary. --- erts/preloaded/src/init.erl | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) (limited to 'erts/preloaded/src') diff --git a/erts/preloaded/src/init.erl b/erts/preloaded/src/init.erl index a85b41fddb..c1c0e781e7 100644 --- a/erts/preloaded/src/init.erl +++ b/erts/preloaded/src/init.erl @@ -1046,18 +1046,10 @@ start_it({eval,Bin}) -> {value, _Value, _Bs} = erl_eval:exprs(Expr, erl_eval:new_bindings()), ok; start_it([_|_]=MFA) -> - Ref = make_ref(), - case catch {Ref,case MFA of - [M] -> M:start(); - [M,F] -> M:F(); - [M,F|Args] -> M:F(Args) % Args is a list - end} of - {Ref,R} -> - R; - {'EXIT',Reason} -> - exit(Reason); - Other -> - throw(Other) + case MFA of + [M] -> M:start(); + [M,F] -> M:F(); + [M,F|Args] -> M:F(Args) % Args is a list end. %% -- cgit v1.2.3 From 4551a14515a57b9aabaa95b729ac546c91ff71f4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Gustavsson?= Date: Tue, 13 Oct 2015 10:10:25 +0200 Subject: Clean up handling of boot_vars Expansion of $ROOT in paths are handled specially compared to boot variables. There is no reason $ROOT can't be handled as a boot variable. We can simplify the expansion of boot variables if we spend a little extra effort upfront collecting all boot variables into a map. Make the error checking for -boot_var arguments stricter. Only allow -boot_var followed by exactly two arguments to help users catch errors earlier. --- erts/preloaded/src/init.erl | 53 +++++++++++++++++++++++++-------------------- 1 file changed, 29 insertions(+), 24 deletions(-) (limited to 'erts/preloaded/src') diff --git a/erts/preloaded/src/init.erl b/erts/preloaded/src/init.erl index c1c0e781e7..730aac9902 100644 --- a/erts/preloaded/src/init.erl +++ b/erts/preloaded/src/init.erl @@ -734,12 +734,12 @@ do_boot(Init,Flags,Start) -> LoadMode = b2a(get_flag(mode, Flags, false)), Deb = b2a(get_flag(init_debug, Flags, false)), catch ?ON_LOAD_HANDLER ! {init_debug_flag,Deb}, - BootVars = get_flag_args(boot_var, Flags), + BootVars = get_boot_vars(Root, Flags), ParallelLoad = (Pgm =:= "efile") and (erlang:system_info(thread_pool_size) > 0), PathChoice = code_path_choice(), - eval_script(BootList,Init,PathFls,{Root,BootVars},Path, + eval_script(BootList,Init,PathFls,BootVars,Path, {true,LoadMode,ParallelLoad},Deb,PathChoice), %% To help identifying Purify windows that pop up, @@ -756,6 +756,20 @@ get_root(Flags) -> exit(no_or_multiple_root_variables) end. +get_boot_vars(Root, Flags) -> + BootVars = get_boot_vars_1(#{}, Flags), + RootKey = <<"ROOT">>, + BootVars#{RootKey=>Root}. + +get_boot_vars_1(Vars, [{boot_var,[Key,Value]}|T]) -> + get_boot_vars_1(Vars#{Key=>Value}, T); +get_boot_vars_1(_, [{boot_var,_}|_]) -> + exit(invalid_boot_var_argument); +get_boot_vars_1(Vars, [_|T]) -> + get_boot_vars_1(Vars, T); +get_boot_vars_1(Vars, []) -> + Vars. + bootfile(Flags,Root) -> b2s(get_flag(boot, Flags, concat([Root,"/bin/start"]))). @@ -905,34 +919,25 @@ fix_path([Path|Ps], Vars) -> fix_path(_, _) -> []. -add_var("$ROOT/" ++ Path, {Root,_}) -> - concat([Root, "/", Path]); -add_var([$$|Path0], {_,VarList}) -> - {Var,Path} = extract_var(Path0,[]), - Value = b2s(get_var_value(list_to_binary(Var),VarList)), - concat([Value, "/", Path]); -add_var(Path, _) -> +add_var("$"++Path0, Vars) -> + {Var,Path} = extract_var(Path0, []), + Key = list_to_binary(Var), + case Vars of + #{Key:=Value0} -> + Value = b2s(Value0), + Value ++ "/" ++ Path; + _ -> + Error0 = "cannot expand $" ++ Var ++ " in bootfile", + Error = list_to_atom(Error0), + exit(Error) + end; +add_var(Path, _) -> Path. extract_var([$/|Path],Var) -> {reverse(Var),Path}; extract_var([H|T],Var) -> extract_var(T,[H|Var]); extract_var([],Var) -> {reverse(Var),[]}. -%% get_var_value(Var, [Vars]) where Vars == [atom()] -get_var_value(Var,[Vars|VarList]) -> - case get_var_val(Var,Vars) of - {ok, Value} -> - Value; - _ -> - get_var_value(Var,VarList) - end; -get_var_value(Var,[]) -> - exit(list_to_atom(concat(["cannot expand \$", Var, " in bootfile"]))). - -get_var_val(Var,[Var,Value|_]) -> {ok, Value}; -get_var_val(Var,[_,_|Vars]) -> get_var_val(Var,Vars); -get_var_val(_,_) -> false. - patch_path(Dirs, strict) -> Dirs; patch_path(Dirs, relaxed) -> -- cgit v1.2.3 From 657a1be6b54e9baaf8d2c7a28ac261b4086148dd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Gustavsson?= Date: Tue, 13 Oct 2015 15:53:39 +0200 Subject: Reduce the ludicrous number of arguments for eval_script() The compact wall of arguments makes it hard to see what is actually happening in eval_script(). Collect the arguments into a record. --- erts/preloaded/src/init.erl | 100 +++++++++++++++++++++++++++----------------- 1 file changed, 61 insertions(+), 39 deletions(-) (limited to 'erts/preloaded/src') diff --git a/erts/preloaded/src/init.erl b/erts/preloaded/src/init.erl index 730aac9902..cc30999ba5 100644 --- a/erts/preloaded/src/init.erl +++ b/erts/preloaded/src/init.erl @@ -75,6 +75,20 @@ subscribed = []}). -type state() :: #state{}. +%% Data for eval_script/2. +-record(es, + {init, + debug, + path, + pa, + pz, + path_choice, + prim_load, + load_mode, + par_load, + vars + }). + -define(ON_LOAD_HANDLER, init__boot__on_load_handler). debug(false, _) -> ok; @@ -725,7 +739,7 @@ do_boot(Init,Flags,Start) -> process_flag(trap_exit,true), {Pgm0,Nodes,Id,Path} = prim_load_flags(Flags), Root = get_root(Flags), - PathFls = path_flags(Flags), + {Pa,Pz} = PathFls = path_flags(Flags), Pgm = b2s(Pgm0), _Pid = start_prim_loader(Init,b2a(Id),Pgm,bs2as(Nodes), bs2ss(Path),PathFls), @@ -735,12 +749,15 @@ do_boot(Init,Flags,Start) -> Deb = b2a(get_flag(init_debug, Flags, false)), catch ?ON_LOAD_HANDLER ! {init_debug_flag,Deb}, BootVars = get_boot_vars(Root, Flags), - ParallelLoad = - (Pgm =:= "efile") and (erlang:system_info(thread_pool_size) > 0), + ParLoad = Pgm =:= "efile" andalso + erlang:system_info(thread_pool_size) > 0, PathChoice = code_path_choice(), - eval_script(BootList,Init,PathFls,BootVars,Path, - {true,LoadMode,ParallelLoad},Deb,PathChoice), + Es = #es{init=Init,debug=Deb,path=Path,pa=Pa,pz=Pz, + path_choice=PathChoice, + prim_load=true,load_mode=LoadMode,par_load=ParLoad, + vars=BootVars}, + eval_script(BootList, Es), %% To help identifying Purify windows that pop up, %% print the node name into the Purify log. @@ -818,48 +835,53 @@ get_boot(BootFile) -> %% boot process hangs (we want to ensure syncronicity). %% -eval_script([{progress,Info}|CfgL],Init,PathFs,Vars,P,Ph,Deb,PathChoice) -> - debug(Deb,{progress,Info}), +eval_script([{progress,Info}=Progress|T], #es{debug=Deb}=Es) -> + debug(Deb, Progress), init ! {self(),progress,Info}, - eval_script(CfgL,Init,PathFs,Vars,P,Ph,Deb,PathChoice); -eval_script([{preLoaded,_}|CfgL],Init,PathFs,Vars,P,Ph,Deb,PathChoice) -> - eval_script(CfgL,Init,PathFs,Vars,P,Ph,Deb,PathChoice); -eval_script([{path,Path}|CfgL],Init,{Pa,Pz},Vars,false,Ph,Deb,PathChoice) -> + eval_script(T, Es); +eval_script([{preLoaded,_}|T], #es{}=Es) -> + eval_script(T, Es); +eval_script([{path,Path}|T], #es{path=false,pa=Pa,pz=Pz, + path_choice=PathChoice, + vars=Vars}=Es) -> RealPath0 = make_path(Pa, Pz, Path, Vars), RealPath = patch_path(RealPath0, PathChoice), erl_prim_loader:set_path(RealPath), - eval_script(CfgL,Init,{Pa,Pz},Vars,false,Ph,Deb,PathChoice); -eval_script([{path,_}|CfgL],Init,PathFs,Vars,P,Ph,Deb,PathChoice) -> + eval_script(T, Es); +eval_script([{path,_}|T], #es{}=Es) -> %% Ignore, use the command line -path flag. - eval_script(CfgL,Init,PathFs,Vars,P,Ph,Deb,PathChoice); -eval_script([{kernel_load_completed}|CfgL],Init,PathFs,Vars,P,{_,embedded,Par},Deb,PathChoice) -> - eval_script(CfgL,Init,PathFs,Vars,P,{true,embedded,Par},Deb,PathChoice); -eval_script([{kernel_load_completed}|CfgL],Init,PathFs,Vars,P,{_,E,Par},Deb,PathChoice) -> - eval_script(CfgL,Init,PathFs,Vars,P,{false,E,Par},Deb,PathChoice); -eval_script([{primLoad,Mods}|CfgL],Init,PathFs,Vars,P,{true,E,Par},Deb,PathChoice) + eval_script(T, Es); +eval_script([{kernel_load_completed}|T], #es{load_mode=Mode}=Es0) -> + Es = case Mode of + embedded -> Es0; + _ -> Es0#es{prim_load=false} + end, + eval_script(T, Es); +eval_script([{primLoad,Mods}|T], #es{init=Init,prim_load=PrimLoad, + par_load=Par}=Es) when is_list(Mods) -> - if - Par =:= true -> - par_load_modules(Mods,Init); - true -> - load_modules(Mods) + case {PrimLoad,Par} of + {true,true} -> + par_load_modules(Mods, Init); + {true,false} -> + load_modules(Mods); + {false,_} -> + %% Do not load now, code_server does that dynamically! + ok end, - eval_script(CfgL,Init,PathFs,Vars,P,{true,E,Par},Deb,PathChoice); -eval_script([{primLoad,_Mods}|CfgL],Init,PathFs,Vars,P,{false,E,Par},Deb,PathChoice) -> - %% Do not load now, code_server does that dynamically! - eval_script(CfgL,Init,PathFs,Vars,P,{false,E,Par},Deb,PathChoice); -eval_script([{kernelProcess,Server,{Mod,Fun,Args}}|CfgL],Init, - PathFs,Vars,P,Ph,Deb,PathChoice) -> - debug(Deb,{start,Server}), - start_in_kernel(Server,Mod,Fun,Args,Init), - eval_script(CfgL,Init,PathFs,Vars,P,Ph,Deb,PathChoice); -eval_script([{apply,{Mod,Fun,Args}}|CfgL],Init,PathFs,Vars,P,Ph,Deb,PathChoice) -> - debug(Deb,{apply,{Mod,Fun,Args}}), - apply(Mod,Fun,Args), - eval_script(CfgL,Init,PathFs,Vars,P,Ph,Deb,PathChoice); -eval_script([],_,_,_,_,_,_,_) -> + eval_script(T, Es); +eval_script([{kernelProcess,Server,{Mod,Fun,Args}}|T], + #es{init=Init,debug=Deb}=Es) -> + debug(Deb, {start,Server}), + start_in_kernel(Server, Mod, Fun, Args, Init), + eval_script(T, Es); +eval_script([{apply,{Mod,Fun,Args}}=Apply|T], #es{debug=Deb}=Es) -> + debug(Deb, Apply), + apply(Mod, Fun, Args), + eval_script(T, Es); +eval_script([], #es{}) -> ok; -eval_script(What,_,_,_,_,_,_,_) -> +eval_script(What, #es{}) -> exit({'unexpected command in bootfile',What}). load_modules([Mod|Mods]) -> -- cgit v1.2.3 From ca72f6a938201d71baf25eeba649d7ec33628c94 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Gustavsson?= Date: Wed, 18 Nov 2015 16:11:06 +0100 Subject: prim_file: Suppress a dialyzer warning Kostis Sagonas pointed out that there is a dialyzer warning for constructing an improper list in the following clause: translate_response(?FILE_RESP_N2DATA = X, [<<_:64, _:64, _:64>> | <<>>] = Data) -> {error, {bad_response_from_port, [X | Data]}}; I don't want to change the code to somehow eliminate the warning. An improper list has already been constructed in the efile driver itself, and that would be difficult to fix. Therefore, tell dialyzer to ignore warnings for improper lists in translate_response/2. --- erts/preloaded/src/prim_file.erl | 1 + 1 file changed, 1 insertion(+) (limited to 'erts/preloaded/src') diff --git a/erts/preloaded/src/prim_file.erl b/erts/preloaded/src/prim_file.erl index c87b2645ec..2eb1b1d408 100644 --- a/erts/preloaded/src/prim_file.erl +++ b/erts/preloaded/src/prim_file.erl @@ -1276,6 +1276,7 @@ lseek_position(_) -> %% Translates the response from the driver into %% {ok, Result} or {error, Reason}. +-dialyzer({no_improper_lists, translate_response/2}). translate_response(?FILE_RESP_OK, []) -> ok; translate_response(?FILE_RESP_ERROR, List) when is_list(List) -> -- cgit v1.2.3 From afcec4ab26ef5d9d202810ed6fd8661b3b3ddfcf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Gustavsson?= Date: Tue, 15 Dec 2015 09:13:34 +0100 Subject: erl_prim_loader: Break loop/3 into two functions for readability The deep indentation makes loop/3 difficult to read and maintain. Break out the request handling code into a separate function. --- erts/preloaded/src/erl_prim_loader.erl | 102 +++++++++++++++------------------ 1 file changed, 46 insertions(+), 56 deletions(-) (limited to 'erts/preloaded/src') diff --git a/erts/preloaded/src/erl_prim_loader.erl b/erts/preloaded/src/erl_prim_loader.erl index 9f6cba33bd..d19de63b65 100644 --- a/erts/preloaded/src/erl_prim_loader.erl +++ b/erts/preloaded/src/erl_prim_loader.erl @@ -310,69 +310,59 @@ check_file_result(_, _, Other) -> %%% The main loop. %%% -------------------------------------------------------- -loop(State, Parent, Paths) -> +loop(St0, Parent, Paths) -> receive + {Pid,{set_path,NewPaths}} when is_pid(Pid) -> + Pid ! {self(),ok}, + loop(St0, Parent, to_strs(NewPaths)); {Pid,Req} when is_pid(Pid) -> - %% erlang:display(Req), - {Resp,State2,Paths2} = - case Req of - {set_path,NewPaths} -> - {ok,State,to_strs(NewPaths)}; - {get_path,_} -> - {{ok,Paths},State,Paths}; - {get_file,File} -> - {Res,State1} = handle_get_file(State, Paths, File), - {Res,State1,Paths}; - {get_files,{ModFiles,Fun}} -> - {Res,State1} = handle_get_files(State, ModFiles, Paths, Fun), - {Res,State1,Paths}; - {list_dir,Dir} -> - {Res,State1} = handle_list_dir(State, Dir), - {Res,State1,Paths}; - {read_file_info,File} -> - {Res,State1} = handle_read_file_info(State, File), - {Res,State1,Paths}; - {read_link_info,File} -> - {Res,State1} = handle_read_link_info(State, File), - {Res,State1,Paths}; - {get_cwd,[]} -> - {Res,State1} = handle_get_cwd(State, []), - {Res,State1,Paths}; - {get_cwd,[_]=Args} -> - {Res,State1} = handle_get_cwd(State, Args), - {Res,State1,Paths}; - {set_primary_archive,File,ArchiveBin,FileInfo,ParserFun} -> - {Res,State1} = - handle_set_primary_archive(State, File, - ArchiveBin, FileInfo, - ParserFun), - {Res,State1,Paths}; - release_archives -> - {Res,State1} = handle_release_archives(State), - {Res,State1,Paths}; - _Other -> - {ignore,State,Paths} - end, - if Resp =:= ignore -> ok; - true -> Pid ! {self(),Resp}, ok - end, - if - is_record(State2, state) -> - loop(State2, Parent, Paths2); - true -> - exit({bad_state, Req, State2}) + case handle_request(Req, Paths, St0) of + ignore -> + ok; + {Resp,#state{}=St1} -> + Pid ! {self(),Resp}, + loop(St1, Parent, Paths); + {_,State2,_} -> + exit({bad_state,Req,State2}) end; {'EXIT',Parent,W} -> - _State1 = handle_stop(State), + _ = handle_stop(St0), exit(W); {'EXIT',P,W} -> - State1 = handle_exit(State, P, W), - loop(State1, Parent, Paths); + St1 = handle_exit(St0, P, W), + loop(St1, Parent, Paths); _Message -> - loop(State, Parent, Paths) - after State#state.timeout -> - State1 = handle_timeout(State, Parent), - loop(State1, Parent, Paths) + loop(St0, Parent, Paths) + after St0#state.timeout -> + St1 = handle_timeout(St0, Parent), + loop(St1, Parent, Paths) + end. + +handle_request(Req, Paths, St0) -> + case Req of + {get_path,_} -> + {{ok,Paths},St0}; + {get_file,File} -> + handle_get_file(St0, Paths, File); + {get_files,{ModFiles,Fun}} -> + handle_get_files(St0, ModFiles, Paths, Fun); + {list_dir,Dir} -> + handle_list_dir(St0, Dir); + {read_file_info,File} -> + handle_read_file_info(St0, File); + {read_link_info,File} -> + handle_read_link_info(St0, File); + {get_cwd,[]} -> + handle_get_cwd(St0, []); + {get_cwd,[_]=Args} -> + handle_get_cwd(St0, Args); + {set_primary_archive,File,ArchiveBin,FileInfo,ParserFun} -> + handle_set_primary_archive(St0, File, ArchiveBin, + FileInfo, ParserFun); + release_archives -> + handle_release_archives(St0); + _ -> + ignore end. handle_get_files(State = #state{multi_get = true}, ModFiles, Paths, Fun) -> -- cgit v1.2.3 From 471d2408de06f3c93507769ce0eb0a9f42c3d119 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Gustavsson?= Date: Thu, 19 Nov 2015 10:17:28 +0100 Subject: erl_prim_loader: Remove code for handling OSE --- erts/preloaded/src/erl_prim_loader.erl | 2 -- 1 file changed, 2 deletions(-) (limited to 'erts/preloaded/src') diff --git a/erts/preloaded/src/erl_prim_loader.erl b/erts/preloaded/src/erl_prim_loader.erl index d19de63b65..07c439a990 100644 --- a/erts/preloaded/src/erl_prim_loader.erl +++ b/erts/preloaded/src/erl_prim_loader.erl @@ -1405,8 +1405,6 @@ absname_vr([Drive, $\: | NameRest], _) -> %% Assumes normalized name pathtype(Name) when is_list(Name) -> case erlang:system_info(os_type) of - {ose, _} -> - unix_pathtype(Name); {unix, _} -> unix_pathtype(Name); {win32, _} -> -- cgit v1.2.3 From af9bfce55f0df03edaab638dcd3612c8478dfcc9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Gustavsson?= Date: Wed, 16 Dec 2015 14:50:56 +0100 Subject: Remove erl_prim_loader:get_files/2 erl_prim_loader:get_files/2 was an optimization introduced before the SMP emulator (that is, before R11). The idea was to use the async threads in the efile driver to read multiple BEAM files from the disk in parallel. In a modern computer with the SMP emulator, loading a BEAM module seems to be more time-consuming than reading it from disk. To optimize loading we would need to load several modules in parallel. We could modify get_files/2 so that it would support parallel loading, but it is cleaner to first remove get_files/2 and then (in a future commit), introduce new functions to support parallel loading. --- erts/preloaded/src/erl_prim_loader.erl | 76 +--------------------------------- erts/preloaded/src/init.erl | 51 +++-------------------- 2 files changed, 6 insertions(+), 121 deletions(-) (limited to 'erts/preloaded/src') diff --git a/erts/preloaded/src/erl_prim_loader.erl b/erts/preloaded/src/erl_prim_loader.erl index 07c439a990..a8d1e4df76 100644 --- a/erts/preloaded/src/erl_prim_loader.erl +++ b/erts/preloaded/src/erl_prim_loader.erl @@ -42,7 +42,7 @@ -include("inet_boot.hrl"). %% Public --export([start/3, set_path/1, get_path/0, get_file/1, get_files/2, +-export([start/3, set_path/1, get_path/0, get_file/1, list_dir/1, read_file_info/1, read_link_info/1, get_cwd/0, get_cwd/1]). %% Used by erl_boot_server @@ -69,7 +69,6 @@ timeout :: timeout(), % idle timeout %% Number of timeouts before archives are released n_timeouts :: non_neg_integer(), - multi_get = false :: boolean(), prim_state :: prim_state()}). % state for efile code loader -define(IDLE_TIMEOUT, 60000). %% tear inet connection after 1 minutes @@ -162,16 +161,11 @@ start_it("efile", Id, Pid, _Hosts) -> _ -> init_ack(Pid) end, - MultiGet = case erlang:system_info(thread_pool_size) of - 0 -> false; - _ -> true - end, PS = prim_init(), State = #state {loader = efile, id = Id, data = Port, timeout = infinity, - multi_get = MultiGet, prim_state = PS}, loop(State, Pid, []). @@ -198,20 +192,6 @@ get_file(File) when is_atom(File) -> get_file(File) -> check_file_result(get_file, File, request({get_file,File})). --spec get_files([{atom(), string()}], - fun((atom(),binary(),string()) -> 'ok' | {'error', atom()})) -> - 'ok' | {'error', atom()}. -get_files(ModFiles, Fun) -> - case request({get_files,{ModFiles,Fun}}) of - E = {error,_M} -> - E; - {error,Reason,M} -> - check_file_result(get_files, M, {error,Reason}), - {error,M}; - ok -> - ok - end. - -spec list_dir(Dir) -> {'ok', Filenames} | 'error' when Dir :: string(), Filenames :: [Filename :: string()]. @@ -344,8 +324,6 @@ handle_request(Req, Paths, St0) -> {{ok,Paths},St0}; {get_file,File} -> handle_get_file(St0, Paths, File); - {get_files,{ModFiles,Fun}} -> - handle_get_files(St0, ModFiles, Paths, Fun); {list_dir,Dir} -> handle_list_dir(St0, Dir); {read_file_info,File} -> @@ -365,11 +343,6 @@ handle_request(Req, Paths, St0) -> ignore end. -handle_get_files(State = #state{multi_get = true}, ModFiles, Paths, Fun) -> - ?SAFE2(efile_multi_get_file_from_port(State, ModFiles, Paths, Fun), State); -handle_get_files(State, _ModFiles, _Paths, _Fun) -> % no multi get - {{error,no_multi_get},State}. - handle_get_file(State = #state{loader = efile}, Paths, File) -> ?SAFE2(efile_get_file_from_port(State, File, Paths), State); handle_get_file(State = #state{loader = inet}, Paths, File) -> @@ -420,53 +393,6 @@ handle_timeout(State = #state{loader = inet}, Parent) -> %%% Functions which handle efile as prim_loader (default). %%% -------------------------------------------------------- -%%% Reading many files in parallel is an optimization. -%%% See also comment in init.erl. - -%% -> {ok,State} | {{error,Module},State} | {{error,Reason,Module},State} -efile_multi_get_file_from_port(State, ModFiles, Paths, Fun) -> - Ref = make_ref(), - %% More than 200 processes is no gain. - Max = erlang:min(200, erlang:system_info(thread_pool_size)), - efile_multi_get_file_from_port2(ModFiles, 0, Max, State, Paths, Fun, Ref, ok). - -efile_multi_get_file_from_port2([MF | MFs], Out, Max, State, Paths, Fun, Ref, Ret) when Out < Max -> - Self = self(), - _Pid = spawn(fun() -> efile_par_get_file(Ref, State, MF, Paths, Self, Fun) end), - efile_multi_get_file_from_port2(MFs, Out+1, Max, State, Paths, Fun, Ref, Ret); -efile_multi_get_file_from_port2(MFs, Out, Max, _State, Paths, Fun, Ref, Ret) when Out > 0 -> - receive - {Ref, ok, State1} -> - efile_multi_get_file_from_port2(MFs, Out-1, Max, State1, Paths, Fun, Ref, Ret); - {Ref, {error,_Mod} = Error, State1} -> - efile_multi_get_file_from_port2(MFs, Out-1, Max, State1, Paths, Fun, Ref, Error); - {Ref, MF, {error,emfile,State1}} -> - %% Max can take negative values. Out cannot. - efile_multi_get_file_from_port2([MF | MFs], Out-1, Max-1, State1, Paths, Fun, Ref, Ret); - {Ref, {M,_F}, {error,Error,State1}} -> - efile_multi_get_file_from_port2(MFs, Out-1, 0, State1, Paths, Fun, Ref, {error,Error,M}) - end; -efile_multi_get_file_from_port2(_MFs, 0, _Max, State, _Paths, _Fun, _Ref, Ret) -> - {Ret,State}. - -efile_par_get_file(Ref, State, {Mod,File} = MF, Paths, Pid, Fun) -> - %% One port for each file read in "parallel": - case prim_file:start() of - {ok, Port} -> - Port0 = State#state.data, - State1 = State#state{data = Port}, - R = case efile_get_file_from_port(State1, File, Paths) of - {{error,Reason},State2} -> - {Ref,MF,{error,Reason,State2}}; - {{ok,BinFile,Full},State2} -> - %% Fun(...) -> ok | {error,Mod} - {Ref,Fun(Mod, BinFile, Full),State2#state{data=Port0}} - end, - prim_file:close(Port), - Pid ! R; - {error, Error} -> - Pid ! {Ref,MF,{error,Error,State}} - end. %% -> {{ok,BinFile,File},State} | {{error,Reason},State} efile_get_file_from_port(State, File, Paths) -> diff --git a/erts/preloaded/src/init.erl b/erts/preloaded/src/init.erl index cc30999ba5..b5c1d46e60 100644 --- a/erts/preloaded/src/init.erl +++ b/erts/preloaded/src/init.erl @@ -85,7 +85,6 @@ path_choice, prim_load, load_mode, - par_load, vars }). @@ -749,13 +748,11 @@ do_boot(Init,Flags,Start) -> Deb = b2a(get_flag(init_debug, Flags, false)), catch ?ON_LOAD_HANDLER ! {init_debug_flag,Deb}, BootVars = get_boot_vars(Root, Flags), - ParLoad = Pgm =:= "efile" andalso - erlang:system_info(thread_pool_size) > 0, PathChoice = code_path_choice(), Es = #es{init=Init,debug=Deb,path=Path,pa=Pa,pz=Pz, path_choice=PathChoice, - prim_load=true,load_mode=LoadMode,par_load=ParLoad, + prim_load=true,load_mode=LoadMode, vars=BootVars}, eval_script(BootList, Es), @@ -857,15 +854,12 @@ eval_script([{kernel_load_completed}|T], #es{load_mode=Mode}=Es0) -> _ -> Es0#es{prim_load=false} end, eval_script(T, Es); -eval_script([{primLoad,Mods}|T], #es{init=Init,prim_load=PrimLoad, - par_load=Par}=Es) +eval_script([{primLoad,Mods}|T], #es{prim_load=PrimLoad}=Es) when is_list(Mods) -> - case {PrimLoad,Par} of - {true,true} -> - par_load_modules(Mods, Init); - {true,false} -> + case PrimLoad of + true -> load_modules(Mods); - {false,_} -> + false -> %% Do not load now, code_server does that dynamically! ok end, @@ -892,41 +886,6 @@ load_modules([Mod|Mods]) -> load_modules([]) -> ok. -%%% An optimization: erl_prim_loader gets the chance of loading many -%%% files in parallel, using threads. This will reduce the seek times, -%%% and loaded code can be processed while other threads are waiting -%%% for the disk. The optimization is not tried unless the loader is -%%% "efile" and there is a non-empty pool of threads. -%%% -%%% Many threads are needed to get a good result, so it would be -%%% beneficial to load several applications in parallel. However, -%%% measurements show that the file system handles one directory at a -%%% time, regardless if parallel threads are created for files on -%%% several directories (a guess: writing the meta information when -%%% the file was last read ('mtime'), forces the file system to sync -%%% between directories). - -par_load_modules(Mods,Init) -> - Ext = objfile_extension(), - ModFiles = [{Mod,concat([Mod,Ext])} || Mod <- Mods, - not erlang:module_loaded(Mod)], - Self = self(), - Fun = fun(Mod, BinCode, FullName) -> - case catch load_mod_code(Mod, BinCode, FullName) of - {ok, _} -> - Init ! {Self,loaded,{Mod,FullName}}, - ok; - _EXIT -> - {error, Mod} - end - end, - case erl_prim_loader:get_files(ModFiles, Fun) of - ok -> - ok; - {error,Mod} -> - exit({'cannot load',Mod,get_files}) - end. - make_path(Pa, Pz, Path, Vars) -> append([Pa,append([fix_path(Path,Vars),Pz])]). -- cgit v1.2.3 From 566a7f4324376428f3f0f6a77bc57679f04ada78 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Gustavsson?= Date: Wed, 16 Dec 2015 15:15:03 +0100 Subject: Clean up start of erl_prim_loader The 'init' module fetches command line parameters and passes them to erl_prim_loader:start/3. The code can be simplified if 'init' calls a new erl_prim_loader:start/0 function that itself fetches the necessary command line parameters. Also remove the documentation for the start() function, since it there is no way that it can be usefully called by a user application. While we are at it, also get rid of '-id' command line parameter, which is fetched and stored but never actually used. --- erts/preloaded/src/erl_prim_loader.erl | 65 ++++++++++++++++------------------ erts/preloaded/src/init.erl | 51 ++++++++++++-------------- 2 files changed, 52 insertions(+), 64 deletions(-) (limited to 'erts/preloaded/src') diff --git a/erts/preloaded/src/erl_prim_loader.erl b/erts/preloaded/src/erl_prim_loader.erl index a8d1e4df76..041b54ee0d 100644 --- a/erts/preloaded/src/erl_prim_loader.erl +++ b/erts/preloaded/src/erl_prim_loader.erl @@ -42,7 +42,7 @@ -include("inet_boot.hrl"). %% Public --export([start/3, set_path/1, get_path/0, get_file/1, +-export([start/0, set_path/1, get_path/0, get_file/1, list_dir/1, read_file_info/1, read_link_info/1, get_cwd/0, get_cwd/1]). %% Used by erl_boot_server @@ -64,9 +64,8 @@ -record(state, {loader :: 'efile' | 'inet', hosts = [] :: [host()], % hosts list (to boot from) - id, % not used any more? data :: 'noport' | port(), % data port etc - timeout :: timeout(), % idle timeout + timeout :: timeout(), % idle timeout %% Number of timeouts before archives are released n_timeouts :: non_neg_integer(), prim_state :: prim_state()}). % state for efile code loader @@ -102,26 +101,13 @@ debug(#prim_state{debug = Deb}, Term) -> %%% Interface Functions. %%% -------------------------------------------------------- --spec start(Id, Loader, Hosts) -> +-spec start() -> {'ok', Pid} | {'error', What} when - Id :: term(), - Loader :: atom() | string(), - Hosts :: Host | [Host], - Host :: host(), Pid :: pid(), What :: term(). -start(Id, Pgm, Hosts) when is_atom(Hosts) -> - start(Id, Pgm, [Hosts]); -start(Id, Pgm0, Hosts) -> - Pgm = if - is_atom(Pgm0) -> - atom_to_list(Pgm0); - true -> - Pgm0 - end, +start() -> Self = self(), - Pid = spawn_link(fun() -> start_it(Pgm, Id, Self, Hosts) end), - register(erl_prim_loader, Pid), + Pid = spawn_link(fun() -> start_it(Self) end), receive {Pid,ok} -> {ok,Pid}; @@ -129,26 +115,40 @@ start(Id, Pgm0, Hosts) -> {error,Reason} end. -%% Hosts must be a list of form ['1.2.3.4' ...] -start_it("inet", Id, Pid, Hosts) -> +start_it(Parent) -> process_flag(trap_exit, true), - ?dbg(inet, {Id,Pid,Hosts}), + register(erl_prim_loader, self()), + Loader = case init:get_argument(loader) of + {ok,[[Loader0]]} -> + Loader0; + error -> + "efile" + end, + case Loader of + "efile" -> start_efile(Parent); + "inet" -> start_inet(Parent) + end. + +%% Hosts must be a list of form ['1.2.3.4' ...] +start_inet(Parent) -> + Hosts = case init:get_argument(hosts) of + {ok,[Hosts0]} -> Hosts0; + _ -> [] + end, AL = ipv4_list(Hosts), ?dbg(addresses, AL), {ok,Tcp} = find_master(AL), - init_ack(Pid), + init_ack(Parent), PS = prim_init(), State = #state {loader = inet, hosts = AL, - id = Id, data = Tcp, timeout = ?IDLE_TIMEOUT, n_timeouts = ?N_TIMEOUTS, prim_state = PS}, - loop(State, Pid, []); + loop(State, Parent, []). -start_it("efile", Id, Pid, _Hosts) -> - process_flag(trap_exit, true), +start_efile(Parent) -> {ok, Port} = prim_file:start(), %% Check that we started in a valid directory. case prim_file:get_cwd(Port) of @@ -159,15 +159,14 @@ start_it("efile", Id, Pid, _Hosts) -> erlang:display(Report), exit({error, invalid_current_directory}); _ -> - init_ack(Pid) + init_ack(Parent) end, PS = prim_init(), State = #state {loader = efile, - id = Id, data = Port, timeout = infinity, prim_state = PS}, - loop(State, Pid, []). + loop(State, Parent, []). init_ack(Pid) -> Pid ! {self(),ok}, @@ -1262,11 +1261,7 @@ string_split2(_, _Ext, _RevBase, _RevTop, SaveFile, SaveExt, SaveTop) -> %% Parse list of ipv4 addresses ipv4_list([H | T]) -> - IPV = if is_atom(H) -> ipv4_address(atom_to_list(H)); - is_list(H) -> ipv4_address(H); - true -> {error,einal} - end, - case IPV of + case ipv4_address(H) of {ok,IP} -> [IP | ipv4_list(T)]; _ -> ipv4_list(T) end; diff --git a/erts/preloaded/src/init.erl b/erts/preloaded/src/init.erl index b5c1d46e60..197bc5fde8 100644 --- a/erts/preloaded/src/init.erl +++ b/erts/preloaded/src/init.erl @@ -23,7 +23,6 @@ %% a local file or distributed from another erlang node. %% %% Flags: -%% -id Identity : identity of the system. %% -boot File : Absolute file name of the boot script. %% -boot_var Var Value %% : $Var in the boot script is expanded to @@ -693,17 +692,15 @@ sleep(T) -> receive after T -> ok end. %%% The loader shall run for ever! %%% ------------------------------------------------- -start_prim_loader(Init,Id,Pgm,Nodes,Path,{Pa,Pz}) -> - case erl_prim_loader:start(Id,Pgm,Nodes) of - {ok,Pid} when Path =:= false -> - InitPath = append(Pa,["."|Pz]), - erl_prim_loader:set_path(InitPath), - add_to_kernel(Init,Pid), - Pid; +start_prim_loader(Init, Path0, {Pa,Pz}) -> + Path = case Path0 of + false -> Pa ++ ["."|Pz]; + _ -> Path0 + end, + case erl_prim_loader:start() of {ok,Pid} -> erl_prim_loader:set_path(Path), - add_to_kernel(Init,Pid), - Pid; + add_to_kernel(Init, Pid); {error,Reason} -> erlang:display({"cannot start loader",Reason}), exit(Reason) @@ -717,13 +714,6 @@ add_to_kernel(Init,Pid) -> ok end. -prim_load_flags(Flags) -> - PortPgm = get_flag(loader, Flags, <<"efile">>), - Hosts = get_flag_list(hosts, Flags, []), - Id = get_flag(id, Flags, none), - Path = get_flag_list(path, Flags, false), - {PortPgm, Hosts, Id, Path}. - %%% ------------------------------------------------- %%% The boot process fetches a boot script and loads %%% all modules specified and starts spec. processes. @@ -736,12 +726,10 @@ do_boot(Flags,Start) -> do_boot(Init,Flags,Start) -> process_flag(trap_exit,true), - {Pgm0,Nodes,Id,Path} = prim_load_flags(Flags), Root = get_root(Flags), + Path = get_flag_list(path, Flags, false), {Pa,Pz} = PathFls = path_flags(Flags), - Pgm = b2s(Pgm0), - _Pid = start_prim_loader(Init,b2a(Id),Pgm,bs2as(Nodes), - bs2ss(Path),PathFls), + start_prim_loader(Init, bs2ss(Path), PathFls), BootFile = bootfile(Flags,Root), BootList = get_boot(BootFile,Root), LoadMode = b2a(get_flag(mode, Flags, false)), @@ -854,11 +842,18 @@ eval_script([{kernel_load_completed}|T], #es{load_mode=Mode}=Es0) -> _ -> Es0#es{prim_load=false} end, eval_script(T, Es); -eval_script([{primLoad,Mods}|T], #es{prim_load=PrimLoad}=Es) +eval_script([{primLoad,[Mod]}|T], #es{prim_load=true}=Es) -> + %% Common special case (loading of error_handler). Nothing + %% to gain by parallel loading. + File = atom_to_list(Mod) ++ objfile_extension(), + {ok,Full} = load_mod(Mod, File), + init ! {self(),loaded,{Mod,Full}}, % Tell init about loaded module + eval_script(T, Es); +eval_script([{primLoad,Mods}|T], #es{init=Init,prim_load=PrimLoad}=Es) when is_list(Mods) -> case PrimLoad of true -> - load_modules(Mods); + load_modules(Mods, Init); false -> %% Do not load now, code_server does that dynamically! ok @@ -878,12 +873,12 @@ eval_script([], #es{}) -> eval_script(What, #es{}) -> exit({'unexpected command in bootfile',What}). -load_modules([Mod|Mods]) -> +load_modules([Mod|Mods], Init) -> File = concat([Mod,objfile_extension()]), {ok,Full} = load_mod(Mod,File), - init ! {self(),loaded,{Mod,Full}}, %% Tell init about loaded module - load_modules(Mods); -load_modules([]) -> + Init ! {self(),loaded,{Mod,Full}}, %Tell init about loaded module + load_modules(Mods, Init); +load_modules([], _) -> ok. make_path(Pa, Pz, Path, Vars) -> @@ -1244,8 +1239,6 @@ concat([S|T]) -> concat([]) -> []. -append(L, Z) -> L ++ Z. - append([E]) -> E; append([H|T]) -> H ++ append(T); -- cgit v1.2.3 From e2e49ee0b0292da4a48d90ed762d7df0b3a64f78 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Gustavsson?= Date: Thu, 26 Nov 2015 11:23:41 +0100 Subject: init: Eliminate the concat/1 function There is no need to use the concat/1 function since all arguments that are passed to it have known types. --- erts/preloaded/src/init.erl | 21 +++++---------------- 1 file changed, 5 insertions(+), 16 deletions(-) (limited to 'erts/preloaded/src') diff --git a/erts/preloaded/src/init.erl b/erts/preloaded/src/init.erl index 197bc5fde8..383c4a1ec6 100644 --- a/erts/preloaded/src/init.erl +++ b/erts/preloaded/src/init.erl @@ -338,7 +338,7 @@ boot_loop(BootPid, State) -> end. ensure_loaded(Module, Loaded) -> - File = concat([Module,objfile_extension()]), + File = atom_to_list(Module) ++ objfile_extension(), case catch load_mod(Module,File) of {ok, FullName} -> {{module, Module}, [{Module, FullName}|Loaded]}; @@ -773,7 +773,7 @@ get_boot_vars_1(Vars, []) -> Vars. bootfile(Flags,Root) -> - b2s(get_flag(boot, Flags, concat([Root,"/bin/start"]))). + b2s(get_flag(boot, Flags, Root++"/bin/start")). path_flags(Flags) -> Pa = append(reverse(get_flag_args(pa, Flags))), @@ -781,12 +781,12 @@ path_flags(Flags) -> {bs2ss(Pa),bs2ss(Pz)}. get_boot(BootFile0,Root) -> - BootFile = concat([BootFile0,".boot"]), + BootFile = BootFile0 ++ ".boot", case get_boot(BootFile) of {ok, CmdList} -> CmdList; not_found -> %% Check for default. - BootF = concat([Root,"/bin/",BootFile]), + BootF = Root ++ "/bin/" ++ BootFile, case get_boot(BootF) of {ok, CmdList} -> CmdList; @@ -874,7 +874,7 @@ eval_script(What, #es{}) -> exit({'unexpected command in bootfile',What}). load_modules([Mod|Mods], Init) -> - File = concat([Mod,objfile_extension()]), + File = atom_to_list(Mod) ++ objfile_extension(), {ok,Full} = load_mod(Mod,File), Init ! {self(),loaded,{Mod,Full}}, %Tell init about loaded module load_modules(Mods, Init); @@ -1228,17 +1228,6 @@ set_argument([Item|Flags],Flag,Value) -> set_argument([],Flag,Value) -> [{Flag,[Value]}]. -concat([A|T]) when is_atom(A) -> - atom_to_list(A) ++ concat(T); -concat([C|T]) when is_integer(C), 0 =< C, C =< 255 -> - [C|concat(T)]; -concat([Bin|T]) when is_binary(Bin) -> - binary_to_list(Bin) ++ concat(T); -concat([S|T]) -> - S ++ concat(T); -concat([]) -> - []. - append([E]) -> E; append([H|T]) -> H ++ append(T); -- cgit v1.2.3 From 07c69ccb45b5d39493cdc830ee78fe3ec0f3d973 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Gustavsson?= Date: Fri, 27 Nov 2015 15:53:23 +0100 Subject: erl_prim_loader: Clean up splitting of filenames --- erts/preloaded/src/erl_prim_loader.erl | 55 +++++++++++++++++----------------- 1 file changed, 27 insertions(+), 28 deletions(-) (limited to 'erts/preloaded/src') diff --git a/erts/preloaded/src/erl_prim_loader.erl b/erts/preloaded/src/erl_prim_loader.erl index 041b54ee0d..dbb658c904 100644 --- a/erts/preloaded/src/erl_prim_loader.erl +++ b/erts/preloaded/src/erl_prim_loader.erl @@ -1205,24 +1205,15 @@ path_join([Path|Paths],Acc) -> name_split(ArchiveFile, File0) -> File = absname(File0), do_name_split(ArchiveFile, File). - + do_name_split(undefined, File) -> %% Ignore primary archive - case string_split(File, init:archive_extension(), []) of + RevExt = reverse(init:archive_extension()), + case archive_split(File, RevExt, []) of no_split -> - %% Plain file {file, File}; - {split, _RevArchiveBase, RevArchiveFile, []} -> - %% Top dir in archive - ArchiveFile = reverse(RevArchiveFile), - {archive, ArchiveFile, []}; - {split, _RevArchiveBase, RevArchiveFile, [$/ | FileInArchive]} -> - %% File in archive - ArchiveFile = reverse(RevArchiveFile), - {archive, ArchiveFile, FileInArchive}; - {split, _RevArchiveBase, _RevArchiveFile, _FileInArchive} -> - %% False match. Assume plain file - {file, File} + Archive -> + Archive end; do_name_split(ArchiveFile, File) -> %% Look first in primary archive @@ -1244,20 +1235,28 @@ string_match([$/ | File], [], RevTop) -> string_match(_File, _Archive, _RevTop) -> no_match. -string_split([Char | File], [Char | Ext] = FullExt, RevTop) -> - RevTop2 = [Char | RevTop], - string_split2(File, Ext, RevTop, RevTop2, File, FullExt, RevTop2); -string_split([Char | File], Ext, RevTop) -> - string_split(File, Ext, [Char | RevTop]); -string_split([], _Ext, _RevTop) -> - no_split. - -string_split2([Char | File], [Char | Ext], RevBase, RevTop, SaveFile, SaveExt, SaveTop) -> - string_split2(File, Ext, RevBase, [Char | RevTop], SaveFile, SaveExt, SaveTop); -string_split2(File, [], RevBase, RevTop, _SaveFile, _SaveExt, _SaveTop) -> - {split, RevBase, RevTop, File}; -string_split2(_, _Ext, _RevBase, _RevTop, SaveFile, SaveExt, SaveTop) -> - string_split(SaveFile, SaveExt, SaveTop). +archive_split("/"++File, RevExt, Acc) -> + case is_prefix(RevExt, Acc) of + false -> + archive_split(File, RevExt, [$/|Acc]); + true -> + ArchiveFile = reverse(Acc), + {archive, ArchiveFile, File} + end; +archive_split([H|T], RevExt, Acc) -> + archive_split(T, RevExt, [H|Acc]); +archive_split([], RevExt, Acc) -> + case is_prefix(RevExt, Acc) of + false -> + no_split; + true -> + ArchiveFile = reverse(Acc), + {archive, ArchiveFile, []} + end. + +is_prefix([H|T1], [H|T2]) -> is_prefix(T1, T2); +is_prefix([_|_], _) -> false; +is_prefix([], _ ) -> true. %% Parse list of ipv4 addresses ipv4_list([H | T]) -> -- cgit v1.2.3 From ea2481f1fdec3ce9f510201130eca51ab553fa71 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Gustavsson?= Date: Fri, 27 Nov 2015 16:06:41 +0100 Subject: erl_prim_loader: Avoid making absolute paths We don't need absolute paths unless we are dealing with archives. Since it is not free to turn a relative path absolute (we will need a call to prim_file to fetch the current directory), it's better to delay the call to absname/1 until we are sure it's needed. --- erts/preloaded/src/erl_prim_loader.erl | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) (limited to 'erts/preloaded/src') diff --git a/erts/preloaded/src/erl_prim_loader.erl b/erts/preloaded/src/erl_prim_loader.erl index dbb658c904..91ef2bd6d0 100644 --- a/erts/preloaded/src/erl_prim_loader.erl +++ b/erts/preloaded/src/erl_prim_loader.erl @@ -1202,11 +1202,7 @@ path_join([Path],Acc) -> path_join([Path|Paths],Acc) -> path_join(Paths,"/" ++ reverse(Path) ++ Acc). -name_split(ArchiveFile, File0) -> - File = absname(File0), - do_name_split(ArchiveFile, File). - -do_name_split(undefined, File) -> +name_split(undefined, File) -> %% Ignore primary archive RevExt = reverse(init:archive_extension()), case archive_split(File, RevExt, []) of @@ -1215,12 +1211,13 @@ do_name_split(undefined, File) -> Archive -> Archive end; -do_name_split(ArchiveFile, File) -> +name_split(ArchiveFile, File0) -> %% Look first in primary archive + File = absname(File0), case string_match(real_path(File), ArchiveFile, []) of no_match -> %% Archive or plain file - do_name_split(undefined, File); + name_split(undefined, File); {match, _RevPrimArchiveFile, FileInArchive} -> %% Primary archive {archive, ArchiveFile, FileInArchive} @@ -1240,7 +1237,7 @@ archive_split("/"++File, RevExt, Acc) -> false -> archive_split(File, RevExt, [$/|Acc]); true -> - ArchiveFile = reverse(Acc), + ArchiveFile = absname(reverse(Acc)), {archive, ArchiveFile, File} end; archive_split([H|T], RevExt, Acc) -> @@ -1250,7 +1247,7 @@ archive_split([], RevExt, Acc) -> false -> no_split; true -> - ArchiveFile = reverse(Acc), + ArchiveFile = absname(reverse(Acc)), {archive, ArchiveFile, []} end. -- cgit v1.2.3 From 8a2c833d1ff02957d2fbd15640e876a5247a1b63 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Gustavsson?= Date: Mon, 14 Dec 2015 13:53:05 +0100 Subject: erl_prim_loader: Clean up string_match() Part of the return value for string_match/3 is not used by its only caller. Eliminate the unused part of the return value and the accumulator argument for string_match(). --- erts/preloaded/src/erl_prim_loader.erl | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) (limited to 'erts/preloaded/src') diff --git a/erts/preloaded/src/erl_prim_loader.erl b/erts/preloaded/src/erl_prim_loader.erl index 91ef2bd6d0..5f88029585 100644 --- a/erts/preloaded/src/erl_prim_loader.erl +++ b/erts/preloaded/src/erl_prim_loader.erl @@ -1214,22 +1214,22 @@ name_split(undefined, File) -> name_split(ArchiveFile, File0) -> %% Look first in primary archive File = absname(File0), - case string_match(real_path(File), ArchiveFile, []) of + case string_match(real_path(File), ArchiveFile) of no_match -> %% Archive or plain file name_split(undefined, File); - {match, _RevPrimArchiveFile, FileInArchive} -> + {match, FileInArchive} -> %% Primary archive {archive, ArchiveFile, FileInArchive} end. -string_match([Char | File], [Char | Archive], RevTop) -> - string_match(File, Archive, [Char | RevTop]); -string_match([] = File, [], RevTop) -> - {match, RevTop, File}; -string_match([$/ | File], [], RevTop) -> - {match, RevTop, File}; -string_match(_File, _Archive, _RevTop) -> +string_match([Char | File], [Char | Archive]) -> + string_match(File, Archive); +string_match([] = File, []) -> + {match, File}; +string_match([$/ | File], []) -> + {match, File}; +string_match(_File, _Archive) -> no_match. archive_split("/"++File, RevExt, Acc) -> -- cgit v1.2.3 From 37f58ad6bff2bf2bac4f3f20c2684e8cee66af03 Mon Sep 17 00:00:00 2001 From: Rickard Green Date: Tue, 15 Dec 2015 09:40:30 +0100 Subject: Light weight statistics of run queue lengths - statistics(total_run_queue_lengths) - statistics(run_queue_lengths) - statistics(total_active_tasks) - statistics(active_tasks) Conflicts: erts/emulator/beam/erl_process.c --- erts/preloaded/src/erlang.erl | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) (limited to 'erts/preloaded/src') diff --git a/erts/preloaded/src/erlang.erl b/erts/preloaded/src/erlang.erl index 7280b43502..5fc6d14938 100644 --- a/erts/preloaded/src/erlang.erl +++ b/erts/preloaded/src/erlang.erl @@ -2205,7 +2205,9 @@ setelement(_Index, _Tuple1, _Value) -> spawn_opt(_Tuple) -> erlang:nif_error(undefined). --spec statistics(context_switches) -> {ContextSwitches,0} when +-spec statistics(active_tasks) -> [ActiveTasks] when + ActiveTasks :: non_neg_integer(); + (context_switches) -> {ContextSwitches,0} when ContextSwitches :: non_neg_integer(); (exact_reductions) -> {Total_Exact_Reductions, Exact_Reductions_Since_Last_Call} when @@ -2222,6 +2224,8 @@ spawn_opt(_Tuple) -> Total_Reductions :: non_neg_integer(), Reductions_Since_Last_Call :: non_neg_integer(); (run_queue) -> non_neg_integer(); + (run_queue_lengths) -> [RunQueueLenght] when + RunQueueLenght :: non_neg_integer(); (runtime) -> {Total_Run_Time, Time_Since_Last_Call} when Total_Run_Time :: non_neg_integer(), Time_Since_Last_Call :: non_neg_integer(); @@ -2229,6 +2233,10 @@ spawn_opt(_Tuple) -> SchedulerId :: pos_integer(), ActiveTime :: non_neg_integer(), TotalTime :: non_neg_integer(); + (total_active_tasks) -> ActiveTasks when + ActiveTasks :: non_neg_integer(); + (total_run_queue_lengths) -> TotalRunQueueLenghts when + TotalRunQueueLenghts :: non_neg_integer(); (wall_clock) -> {Total_Wallclock_Time, Wallclock_Time_Since_Last_Call} when Total_Wallclock_Time :: non_neg_integer(), -- cgit v1.2.3 From e293ad1b08b2f937555a102e6f3b4336574773c8 Mon Sep 17 00:00:00 2001 From: Serge Aleynikov Date: Wed, 30 Dec 2015 13:29:34 -0500 Subject: Assign externally open fd to gen_tcp (UDS support) When a AF_LOCAL file descriptor is created externally (e.g. Unix Domain Socket) and passed to `gen_tcp:listen(0, [{fd, FD}])`, the implementation incorrectly assigned the address family to be equal to `inet`, which in the inet_drv driver translated to AF_INET instead of AF_LOCAL (or AF_UNIX), and an `einval` error code was returned. This patch fixes this problem such that the file descriptors of the `local` address family are supported in the inet:fdopen/5, gen_tcp:connect/3, gen_tcp:listen/2, gen_udp:open/2 calls --- erts/preloaded/src/prim_inet.erl | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) (limited to 'erts/preloaded/src') diff --git a/erts/preloaded/src/prim_inet.erl b/erts/preloaded/src/prim_inet.erl index bd74831bb7..4659448221 100644 --- a/erts/preloaded/src/prim_inet.erl +++ b/erts/preloaded/src/prim_inet.erl @@ -70,6 +70,8 @@ open(Protocol, Family, Type) -> open(Protocol, Family, Type, Opts) -> open(Protocol, Family, Type, Opts, ?INET_REQ_OPEN, []). +%% FDOPEN(tcp|udp|sctp, inet|inet6|local, stream|dgram|seqpacket, integer()) + fdopen(Protocol, Family, Type, Fd) when is_integer(Fd) -> fdopen(Protocol, Family, Type, Fd, true). @@ -104,8 +106,9 @@ open(Protocol, Family, Type, Opts, Req, Data) -> error:system_limit -> {error, system_limit} end. -enc_family(inet) -> ?INET_AF_INET; -enc_family(inet6) -> ?INET_AF_INET6. +enc_family(inet) -> ?INET_AF_INET; +enc_family(inet6) -> ?INET_AF_INET6; +enc_family(local) -> ?INET_AF_LOCAL. enc_type(stream) -> ?INET_TYPE_STREAM; enc_type(dgram) -> ?INET_TYPE_DGRAM; @@ -1619,6 +1622,8 @@ enc_value_2(addr, {IP,Port}) when tuple_size(IP) =:= 4 -> [?INET_AF_INET,?int16(Port)|ip4_to_bytes(IP)]; enc_value_2(addr, {IP,Port}) when tuple_size(IP) =:= 8 -> [?INET_AF_INET6,?int16(Port)|ip6_to_bytes(IP)]; +enc_value_2(addr, {File,0}) when is_list(File) -> + [?INET_AF_LOCAL,0,0,length(File)|File]; enc_value_2(ether, [_,_,_,_,_,_]=Xs) -> Xs; enc_value_2(sockaddr, any) -> [?INET_AF_ANY]; @@ -1628,6 +1633,8 @@ enc_value_2(sockaddr, IP) when tuple_size(IP) =:= 4 -> [?INET_AF_INET|ip4_to_bytes(IP)]; enc_value_2(sockaddr, IP) when tuple_size(IP) =:= 8 -> [?INET_AF_INET6|ip6_to_bytes(IP)]; +enc_value_2(sockaddr, File) when is_list(File) -> + [?INET_AF_LOCAL,0,0,length(File)|File]; enc_value_2(linkaddr, Linkaddr) -> [?int16(length(Linkaddr)),Linkaddr]; enc_value_2(sctp_assoc_id, Val) -> ?int32(Val); @@ -2265,8 +2272,10 @@ get_addrs([F,P1,P0|Addr]) -> {IP,Addrs} = get_ip(F, Addr), [{IP,?u16(P1, P0)}|get_addrs(Addrs)]. -get_ip(?INET_AF_INET, Addr) -> get_ip4(Addr); -get_ip(?INET_AF_INET6, Addr) -> get_ip6(Addr). +get_ip(?INET_AF_INET, Addr) -> get_ip4(Addr); +get_ip(?INET_AF_INET6, Addr) -> get_ip6(Addr); +get_ip(?INET_AF_LOCAL, [0]) -> {[], []}; +get_ip(?INET_AF_LOCAL, [N | Addr]) -> lists:split(N, Addr). get_ip4([A,B,C,D | T]) -> {{A,B,C,D},T}. -- cgit v1.2.3 From ebe42ec76748546f464076d8cf5d1238a56baf91 Mon Sep 17 00:00:00 2001 From: Sverker Eriksson Date: Tue, 15 Dec 2015 16:37:10 +0100 Subject: erts: Introduce erts_code_purger as a system process with preloaded code. --- erts/preloaded/src/Makefile | 1 + erts/preloaded/src/erts.app.src | 1 + erts/preloaded/src/erts_code_purger.erl | 32 ++++++++++++++++++++++++++++++++ 3 files changed, 34 insertions(+) create mode 100644 erts/preloaded/src/erts_code_purger.erl (limited to 'erts/preloaded/src') diff --git a/erts/preloaded/src/Makefile b/erts/preloaded/src/Makefile index 52034a0881..31383dda83 100644 --- a/erts/preloaded/src/Makefile +++ b/erts/preloaded/src/Makefile @@ -41,6 +41,7 @@ PRE_LOADED_ERL_MODULES = \ zlib \ prim_zip \ otp_ring0 \ + erts_code_purger \ erlang \ erts_internal diff --git a/erts/preloaded/src/erts.app.src b/erts/preloaded/src/erts.app.src index 8442aaf7e8..e53b6e5bab 100644 --- a/erts/preloaded/src/erts.app.src +++ b/erts/preloaded/src/erts.app.src @@ -27,6 +27,7 @@ erts_internal, init, otp_ring0, + erts_code_purger, prim_eval, prim_file, prim_inet, diff --git a/erts/preloaded/src/erts_code_purger.erl b/erts/preloaded/src/erts_code_purger.erl new file mode 100644 index 0000000000..1ef4d096b7 --- /dev/null +++ b/erts/preloaded/src/erts_code_purger.erl @@ -0,0 +1,32 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2016. All Rights Reserved. +%% +%% Licensed under the Apache License, Version 2.0 (the "License"); +%% you may not use this file except in compliance with the License. +%% You may obtain a copy of the License at +%% +%% http://www.apache.org/licenses/LICENSE-2.0 +%% +%% Unless required by applicable law or agreed to in writing, software +%% distributed under the License is distributed on an "AS IS" BASIS, +%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +%% See the License for the specific language governing permissions and +%% limitations under the License. +%% +%% %CopyrightEnd% +%% +-module(erts_code_purger). + +%% Purpose : Implement system process erts_code_purger +%% to handle code module purging. + +-export([start/0]). + +-spec start() -> term(). +start() -> + receive M -> + erlang:display({"erts_code_purger got msg", M}) + end, + start(). -- cgit v1.2.3 From c612edf4ada1f00b2bdb8404103e0d8307dc8f4c Mon Sep 17 00:00:00 2001 From: Sverker Eriksson Date: Mon, 11 Jan 2016 19:17:04 +0100 Subject: erts: Refactor code:purge/1 and code:soft_purge/1 by moving code from code_server to erts_code_purger. This is more or less a copy-paste from code_server.erl to erts_code_purger.erl. All the inner mechanics of code:purge/1 and code:soft_purge/1 are unchanged. --- erts/preloaded/src/erts_code_purger.erl | 283 +++++++++++++++++++++++++++++++- 1 file changed, 280 insertions(+), 3 deletions(-) (limited to 'erts/preloaded/src') diff --git a/erts/preloaded/src/erts_code_purger.erl b/erts/preloaded/src/erts_code_purger.erl index 1ef4d096b7..6bb6e4fcdc 100644 --- a/erts/preloaded/src/erts_code_purger.erl +++ b/erts/preloaded/src/erts_code_purger.erl @@ -22,11 +22,288 @@ %% Purpose : Implement system process erts_code_purger %% to handle code module purging. --export([start/0]). +-export([start/0, purge/1, soft_purge/1]). -spec start() -> term(). start() -> - receive M -> + register(erts_code_purger, self()), + process_flag(trap_exit, true), + loop(). + +loop() -> + receive + {purge,Mod,From,Ref} when is_atom(Mod), is_pid(From) -> + Res = do_purge(Mod), + From ! {reply, purge, Res, Ref}; + + {soft_purge,Mod,From,Ref} when is_atom(Mod), is_pid(From) -> + Res = do_soft_purge(Mod), + From ! {reply, soft_purge, Res, Ref}; + + M -> erlang:display({"erts_code_purger got msg", M}) end, - start(). + loop(). + + +%% purge(Module) +%% Kill all processes running code from *old* Module, and then purge the +%% module. Return {WasOld, DidKill}: +%% {false, false} there was no old module to purge +%% {true, false} module purged, no process killed +%% {true, true} module purged, at least one process killed + +purge(Mod) when is_atom(Mod) -> + Ref = make_ref(), + erts_code_purger ! {purge, Mod, self(), Ref}, + receive + {reply, purge, Result, Ref} -> + Result + end. + + +do_purge(Mod) -> + case erlang:check_old_code(Mod) of + false -> + {false, false}; + true -> + true = erlang:copy_literals(Mod, true), + DidKill = check_proc_code(erlang:processes(), Mod, true), + true = erlang:copy_literals(Mod, false), + try + erlang:purge_module(Mod) + catch + _:_ -> ignore + end, + {true, DidKill} + end. + +%% 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) + +soft_purge(Mod) -> + Ref = make_ref(), + erts_code_purger ! {soft_purge, Mod, self(), Ref}, + receive + {reply, soft_purge, Result, Ref} -> + Result + end. + + +do_soft_purge(Mod) -> + case erlang:check_old_code(Mod) of + false -> + true; + true -> + true = erlang:copy_literals(Mod, true), + case check_proc_code(erlang:processes(), Mod, false) of + false -> + true = erlang:copy_literals(Mod, false), + false; + true -> + true = erlang:copy_literals(Mod, false), + 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. -- cgit v1.2.3 From fa44f865c3fc6253cf4691cf94839c303a3ee40f Mon Sep 17 00:00:00 2001 From: Sverker Eriksson Date: Tue, 15 Dec 2015 20:32:39 +0100 Subject: erts: Make erlang:purge_module/1 safe Problem: erlang:purge_module/1 is not safe in the sense that very bad things may happen if the code to be purged is still referred to by live processes. Introduce erts_internal:purge_module which is the same as the old erlang:purge_module BIF (except it returns false if no such old module). Implement erlang:purge_module in Erlang and let it invoke erts_code_purger for safe purging where all clogging processes first are killed. --- erts/preloaded/src/erlang.erl | 12 ++++++++++-- erts/preloaded/src/erts_code_purger.erl | 14 +++----------- erts/preloaded/src/erts_internal.erl | 6 ++++++ erts/preloaded/src/init.erl | 4 ++-- 4 files changed, 21 insertions(+), 15 deletions(-) (limited to 'erts/preloaded/src') diff --git a/erts/preloaded/src/erlang.erl b/erts/preloaded/src/erlang.erl index d9dc9a1976..ab54d716cc 100644 --- a/erts/preloaded/src/erlang.erl +++ b/erts/preloaded/src/erlang.erl @@ -1471,8 +1471,16 @@ processes() -> %% purge_module/1 -spec purge_module(Module) -> true when Module :: atom(). -purge_module(_Module) -> - erlang:nif_error(undefined). +purge_module(Module) when erlang:is_atom(Module) -> + case erts_code_purger:purge(Module) of + {false, _} -> + erlang:error(badarg, [Module]); + {true, _} -> + true + end; +purge_module(Arg) -> + erlang:error(badarg, [Arg]). + %% put/2 -spec put(Key, Val) -> term() when diff --git a/erts/preloaded/src/erts_code_purger.erl b/erts/preloaded/src/erts_code_purger.erl index 6bb6e4fcdc..880c86aad1 100644 --- a/erts/preloaded/src/erts_code_purger.erl +++ b/erts/preloaded/src/erts_code_purger.erl @@ -70,12 +70,8 @@ do_purge(Mod) -> true = erlang:copy_literals(Mod, true), DidKill = check_proc_code(erlang:processes(), Mod, true), true = erlang:copy_literals(Mod, false), - try - erlang:purge_module(Mod) - catch - _:_ -> ignore - end, - {true, DidKill} + WasPurged = erts_internal:purge_module(Mod), + {WasPurged, DidKill} end. %% soft_purge(Module) @@ -104,11 +100,7 @@ do_soft_purge(Mod) -> false; true -> true = erlang:copy_literals(Mod, false), - try - erlang:purge_module(Mod) - catch - _:_ -> ignore - end, + erts_internal:purge_module(Mod), true end end. diff --git a/erts/preloaded/src/erts_internal.erl b/erts/preloaded/src/erts_internal.erl index 426749264f..6e649e8395 100644 --- a/erts/preloaded/src/erts_internal.erl +++ b/erts/preloaded/src/erts_internal.erl @@ -38,6 +38,7 @@ -export([request_system_task/3]). -export([check_process_code/2]). +-export([purge_module/1]). -export([flush_monitor_messages/3]). @@ -204,6 +205,11 @@ request_system_task(_Pid, _Prio, _Request) -> check_process_code(_Module, _OptionList) -> erlang:nif_error(undefined). +-spec purge_module(Module) -> boolean() when + Module :: module(). +purge_module(_Module) -> + erlang:nif_error(undefined). + %% term compare where integer() < float() = true -spec cmp_term(A,B) -> Result when diff --git a/erts/preloaded/src/init.erl b/erts/preloaded/src/init.erl index 383c4a1ec6..ed65c57c0d 100644 --- a/erts/preloaded/src/init.erl +++ b/erts/preloaded/src/init.erl @@ -636,9 +636,9 @@ unload(_) -> do_unload(sub([heart|erlang:pre_loaded()],erlang:loaded())). do_unload([M|Mods]) -> - catch erlang:purge_module(M), + catch erts_internal:purge_module(M), catch erlang:delete_module(M), - catch erlang:purge_module(M), + catch erts_internal:purge_module(M), do_unload(Mods); do_unload([]) -> purge_all_hipe_refs(), -- cgit v1.2.3 From dc54c2a27c41930a18e0c7f2b97eda6cd4a0b1c1 Mon Sep 17 00:00:00 2001 From: Sverker Eriksson Date: Wed, 16 Dec 2015 19:11:48 +0100 Subject: erts: Move copy_literals/2 from erlang to erts_internal as it's not a public interface. --- erts/preloaded/src/erlang.erl | 9 +-------- erts/preloaded/src/erts_code_purger.erl | 10 +++++----- erts/preloaded/src/erts_internal.erl | 7 +++++++ 3 files changed, 13 insertions(+), 13 deletions(-) (limited to 'erts/preloaded/src') diff --git a/erts/preloaded/src/erlang.erl b/erts/preloaded/src/erlang.erl index ab54d716cc..0a41951900 100644 --- a/erts/preloaded/src/erlang.erl +++ b/erts/preloaded/src/erlang.erl @@ -91,7 +91,7 @@ -export([bit_size/1, bitsize/1, bitstring_to_list/1]). -export([bump_reductions/1, byte_size/1, call_on_load_function/1]). -export([cancel_timer/1, cancel_timer/2, check_old_code/1, check_process_code/2, - check_process_code/3, copy_literals/2, crc32/1]). + check_process_code/3, crc32/1]). -export([crc32/2, crc32_combine/3, date/0, decode_packet/3]). -export([delete_element/2]). -export([delete_module/1, demonitor/1, demonitor/2, display/1]). @@ -520,13 +520,6 @@ get_cpc_opts([{allow_gc, AllowGC} | Options], Async, _OldAllowGC) -> get_cpc_opts([], Async, AllowGC) -> {Async, AllowGC}. -%% copy_literals/2 --spec erlang:copy_literals(Module,Bool) -> 'true' | 'false' | 'aborted' when - Module :: module(), - Bool :: boolean(). -copy_literals(_Mod, _Bool) -> - erlang:nif_error(undefined). - %% crc32/1 -spec erlang:crc32(Data) -> non_neg_integer() when Data :: iodata(). diff --git a/erts/preloaded/src/erts_code_purger.erl b/erts/preloaded/src/erts_code_purger.erl index 880c86aad1..c7fe3ce22f 100644 --- a/erts/preloaded/src/erts_code_purger.erl +++ b/erts/preloaded/src/erts_code_purger.erl @@ -67,9 +67,9 @@ do_purge(Mod) -> false -> {false, false}; true -> - true = erlang:copy_literals(Mod, true), + true = erts_internal:copy_literals(Mod, true), DidKill = check_proc_code(erlang:processes(), Mod, true), - true = erlang:copy_literals(Mod, false), + true = erts_internal:copy_literals(Mod, false), WasPurged = erts_internal:purge_module(Mod), {WasPurged, DidKill} end. @@ -93,13 +93,13 @@ do_soft_purge(Mod) -> false -> true; true -> - true = erlang:copy_literals(Mod, true), + true = erts_internal:copy_literals(Mod, true), case check_proc_code(erlang:processes(), Mod, false) of false -> - true = erlang:copy_literals(Mod, false), + true = erts_internal:copy_literals(Mod, false), false; true -> - true = erlang:copy_literals(Mod, false), + true = erts_internal:copy_literals(Mod, false), erts_internal:purge_module(Mod), true end diff --git a/erts/preloaded/src/erts_internal.erl b/erts/preloaded/src/erts_internal.erl index 6e649e8395..30e9ba304c 100644 --- a/erts/preloaded/src/erts_internal.erl +++ b/erts/preloaded/src/erts_internal.erl @@ -38,6 +38,7 @@ -export([request_system_task/3]). -export([check_process_code/2]). +-export([copy_literals/2]). -export([purge_module/1]). -export([flush_monitor_messages/3]). @@ -205,6 +206,12 @@ request_system_task(_Pid, _Prio, _Request) -> check_process_code(_Module, _OptionList) -> erlang:nif_error(undefined). +-spec copy_literals(Module,Bool) -> 'true' | 'false' | 'aborted' when + Module :: module(), + Bool :: boolean(). +copy_literals(_Mod, _Bool) -> + erlang:nif_error(undefined). + -spec purge_module(Module) -> boolean() when Module :: module(). purge_module(_Module) -> -- cgit v1.2.3 From 79efde2d8503e5055ef9e8afa5d8d63208710b1f Mon Sep 17 00:00:00 2001 From: Sverker Eriksson Date: Wed, 16 Dec 2015 20:03:32 +0100 Subject: erts: Make copy_literals more fail safe * Same process must do enable-disable. * System process will force it and never get 'aborted' --- erts/preloaded/src/erts_code_purger.erl | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) (limited to 'erts/preloaded/src') diff --git a/erts/preloaded/src/erts_code_purger.erl b/erts/preloaded/src/erts_code_purger.erl index c7fe3ce22f..791ef72f13 100644 --- a/erts/preloaded/src/erts_code_purger.erl +++ b/erts/preloaded/src/erts_code_purger.erl @@ -63,11 +63,10 @@ purge(Mod) when is_atom(Mod) -> do_purge(Mod) -> - case erlang:check_old_code(Mod) of + case erts_internal:copy_literals(Mod, true) of false -> {false, false}; true -> - true = erts_internal:copy_literals(Mod, true), DidKill = check_proc_code(erlang:processes(), Mod, true), true = erts_internal:copy_literals(Mod, false), WasPurged = erts_internal:purge_module(Mod), @@ -89,17 +88,16 @@ soft_purge(Mod) -> do_soft_purge(Mod) -> - case erlang:check_old_code(Mod) of + case erts_internal:copy_literals(Mod, true) of false -> true; true -> - true = erts_internal:copy_literals(Mod, true), - case check_proc_code(erlang:processes(), Mod, false) of + DoPurge = check_proc_code(erlang:processes(), Mod, false), + true = erts_internal:copy_literals(Mod, false), + case DoPurge of false -> - true = erts_internal:copy_literals(Mod, false), false; true -> - true = erts_internal:copy_literals(Mod, false), erts_internal:purge_module(Mod), true end -- cgit v1.2.3 From a4920dc4045f394f6f4ab1cc89d54d55722a66d6 Mon Sep 17 00:00:00 2001 From: Sverker Eriksson Date: Tue, 12 Jan 2016 17:02:06 +0100 Subject: erts: Refactor check_process_code/3 Move impl from erlang to erts_internal. Cut and paste. --- erts/preloaded/src/erlang.erl | 44 ++--------------------------- erts/preloaded/src/erts_internal.erl | 55 +++++++++++++++++++++++++++++++++++- 2 files changed, 56 insertions(+), 43 deletions(-) (limited to 'erts/preloaded/src') diff --git a/erts/preloaded/src/erlang.erl b/erts/preloaded/src/erlang.erl index 0a41951900..40d5aedd24 100644 --- a/erts/preloaded/src/erlang.erl +++ b/erts/preloaded/src/erlang.erl @@ -460,7 +460,7 @@ check_old_code(_Module) -> CheckResult :: boolean(). check_process_code(Pid, Module) -> try - erlang:check_process_code(Pid, Module, [{allow_gc, true}]) + erts_internal:check_process_code(Pid, Module, [{allow_gc, true}]) catch error:Error -> erlang:error(Error, [Pid, Module]) end. @@ -475,51 +475,11 @@ check_process_code(Pid, Module) -> CheckResult :: boolean() | aborted. check_process_code(Pid, Module, OptionList) -> try - {Async, AllowGC} = get_cpc_opts(OptionList, sync, true), - case Async of - {async, ReqId} -> - {priority, Prio} = erlang:process_info(erlang:self(), - priority), - erts_internal:request_system_task(Pid, - Prio, - {check_process_code, - ReqId, - Module, - AllowGC}), - async; - sync -> - case Pid == erlang:self() of - true -> - erts_internal:check_process_code(Module, - [{allow_gc, AllowGC}]); - false -> - {priority, Prio} = erlang:process_info(erlang:self(), - priority), - ReqId = erlang:make_ref(), - erts_internal:request_system_task(Pid, - Prio, - {check_process_code, - ReqId, - Module, - AllowGC}), - receive - {check_process_code, ReqId, CheckResult} -> - CheckResult - end - end - end + erts_internal:check_process_code(Pid, Module, OptionList) catch error:Error -> erlang:error(Error, [Pid, Module, OptionList]) end. -% gets async and allow_gc opts and verify valid option list -get_cpc_opts([{async, _ReqId} = AsyncTuple | Options], _OldAsync, AllowGC) -> - get_cpc_opts(Options, AsyncTuple, AllowGC); -get_cpc_opts([{allow_gc, AllowGC} | Options], Async, _OldAllowGC) -> - get_cpc_opts(Options, Async, AllowGC); -get_cpc_opts([], Async, AllowGC) -> - {Async, AllowGC}. - %% crc32/1 -spec erlang:crc32(Data) -> non_neg_integer() when Data :: iodata(). diff --git a/erts/preloaded/src/erts_internal.erl b/erts/preloaded/src/erts_internal.erl index 30e9ba304c..e32d65ff59 100644 --- a/erts/preloaded/src/erts_internal.erl +++ b/erts/preloaded/src/erts_internal.erl @@ -37,7 +37,7 @@ -export([request_system_task/3]). --export([check_process_code/2]). +-export([check_process_code/3]). -export([copy_literals/2]). -export([purge_module/1]). @@ -49,6 +49,9 @@ -export([is_system_process/1]). +%% Auto import name clash +-export([check_process_code/2]). + %% %% Await result of send to port %% @@ -206,6 +209,56 @@ request_system_task(_Pid, _Prio, _Request) -> check_process_code(_Module, _OptionList) -> erlang:nif_error(undefined). +-spec check_process_code(Pid, Module, OptionList) -> CheckResult | async when + Pid :: pid(), + Module :: module(), + RequestId :: term(), + Option :: {async, RequestId} | {allow_gc, boolean()}, + OptionList :: [Option], + CheckResult :: boolean() | aborted. +check_process_code(Pid, Module, OptionList) -> + {Async, AllowGC} = get_cpc_opts(OptionList, sync, true), + case Async of + {async, ReqId} -> + {priority, Prio} = erlang:process_info(erlang:self(), + priority), + erts_internal:request_system_task(Pid, + Prio, + {check_process_code, + ReqId, + Module, + AllowGC}), + async; + sync -> + case Pid == erlang:self() of + true -> + erts_internal:check_process_code(Module, + [{allow_gc, AllowGC}]); + false -> + {priority, Prio} = erlang:process_info(erlang:self(), + priority), + ReqId = erlang:make_ref(), + erts_internal:request_system_task(Pid, + Prio, + {check_process_code, + ReqId, + Module, + AllowGC}), + receive + {check_process_code, ReqId, CheckResult} -> + CheckResult + end + end + end. + +% gets async and allow_gc opts and verify valid option list +get_cpc_opts([{async, _ReqId} = AsyncTuple | Options], _OldAsync, AllowGC) -> + get_cpc_opts(Options, AsyncTuple, AllowGC); +get_cpc_opts([{allow_gc, AllowGC} | Options], Async, _OldAllowGC) -> + get_cpc_opts(Options, Async, AllowGC); +get_cpc_opts([], Async, AllowGC) -> + {Async, AllowGC}. + -spec copy_literals(Module,Bool) -> 'true' | 'false' | 'aborted' when Module :: module(), Bool :: boolean(). -- cgit v1.2.3 From 4c763443365591e170308a1c5f11a4586734ca4e Mon Sep 17 00:00:00 2001 From: Sverker Eriksson Date: Tue, 12 Jan 2016 16:57:59 +0100 Subject: erts: Optimize erlang:check_process_code by ignoring literals. erts_internal:check_process_code will be called again anyway (with option {copy_literals, true}) before the module is actually purged. No need to check literals twice. --- erts/preloaded/src/erts_code_purger.erl | 5 ++-- erts/preloaded/src/erts_internal.erl | 42 ++++++++++++++++++++------------- 2 files changed, 28 insertions(+), 19 deletions(-) (limited to 'erts/preloaded/src') diff --git a/erts/preloaded/src/erts_code_purger.erl b/erts/preloaded/src/erts_code_purger.erl index 791ef72f13..e492ba1812 100644 --- a/erts/preloaded/src/erts_code_purger.erl +++ b/erts/preloaded/src/erts_code_purger.erl @@ -283,8 +283,9 @@ cpc_sched_kill(Pid, 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}]). + erts_internal:check_process_code(Pid, Mod, [{async, {Tag, Pid, AllowGc}}, + {allow_gc, AllowGc}, + {copy_literals, true}]). cpc_request_gc(CpcS, [Pid|Pids]) -> cpc_request(CpcS, Pid, true), diff --git a/erts/preloaded/src/erts_internal.erl b/erts/preloaded/src/erts_internal.erl index e32d65ff59..84dedab930 100644 --- a/erts/preloaded/src/erts_internal.erl +++ b/erts/preloaded/src/erts_internal.erl @@ -202,22 +202,24 @@ port_info(_Result, _Item) -> request_system_task(_Pid, _Prio, _Request) -> erlang:nif_error(undefined). --spec check_process_code(Module, OptionList) -> boolean() when +-define(ERTS_CPC_ALLOW_GC, (1 bsl 0)). +-define(ERTS_CPC_COPY_LITERALS, (1 bsl 1)). + +-spec check_process_code(Module, Flags) -> boolean() when Module :: module(), - Option :: {allow_gc, boolean()}, - OptionList :: [Option]. -check_process_code(_Module, _OptionList) -> + Flags :: non_neg_integer(). +check_process_code(_Module, _Flags) -> erlang:nif_error(undefined). -spec check_process_code(Pid, Module, OptionList) -> CheckResult | async when Pid :: pid(), Module :: module(), RequestId :: term(), - Option :: {async, RequestId} | {allow_gc, boolean()}, + Option :: {async, RequestId} | {allow_gc, boolean()} | {copy_literals, boolean()}, OptionList :: [Option], CheckResult :: boolean() | aborted. check_process_code(Pid, Module, OptionList) -> - {Async, AllowGC} = get_cpc_opts(OptionList, sync, true), + {Async, Flags} = get_cpc_opts(OptionList, sync, ?ERTS_CPC_ALLOW_GC), case Async of {async, ReqId} -> {priority, Prio} = erlang:process_info(erlang:self(), @@ -227,13 +229,12 @@ check_process_code(Pid, Module, OptionList) -> {check_process_code, ReqId, Module, - AllowGC}), + Flags}), async; sync -> case Pid == erlang:self() of true -> - erts_internal:check_process_code(Module, - [{allow_gc, AllowGC}]); + erts_internal:check_process_code(Module, Flags); false -> {priority, Prio} = erlang:process_info(erlang:self(), priority), @@ -243,7 +244,7 @@ check_process_code(Pid, Module, OptionList) -> {check_process_code, ReqId, Module, - AllowGC}), + Flags}), receive {check_process_code, ReqId, CheckResult} -> CheckResult @@ -251,13 +252,20 @@ check_process_code(Pid, Module, OptionList) -> end end. -% gets async and allow_gc opts and verify valid option list -get_cpc_opts([{async, _ReqId} = AsyncTuple | Options], _OldAsync, AllowGC) -> - get_cpc_opts(Options, AsyncTuple, AllowGC); -get_cpc_opts([{allow_gc, AllowGC} | Options], Async, _OldAllowGC) -> - get_cpc_opts(Options, Async, AllowGC); -get_cpc_opts([], Async, AllowGC) -> - {Async, AllowGC}. +% gets async and flag opts and verify valid option list +get_cpc_opts([{async, _ReqId} = AsyncTuple | Options], _OldAsync, Flags) -> + get_cpc_opts(Options, AsyncTuple, Flags); +get_cpc_opts([{allow_gc, AllowGC} | Options], Async, Flags) -> + get_cpc_opts(Options, Async, cpc_flags(Flags, ?ERTS_CPC_ALLOW_GC, AllowGC)); +get_cpc_opts([{copy_literals, CopyLit} | Options], Async, Flags) -> + get_cpc_opts(Options, Async, cpc_flags(Flags, ?ERTS_CPC_COPY_LITERALS, CopyLit)); +get_cpc_opts([], Async, Flags) -> + {Async, Flags}. + +cpc_flags(OldFlags, Bit, true) -> + OldFlags bor Bit; +cpc_flags(OldFlags, Bit, false) -> + OldFlags band (bnot Bit). -spec copy_literals(Module,Bool) -> 'true' | 'false' | 'aborted' when Module :: module(), -- cgit v1.2.3 From f6c266765cfd48416000e49f0043827d42e0e83f Mon Sep 17 00:00:00 2001 From: Sverker Eriksson Date: Tue, 19 Jan 2016 16:22:44 +0100 Subject: erts: Ignore unexpected messages to erts_code_purger --- erts/preloaded/src/erts_code_purger.erl | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'erts/preloaded/src') diff --git a/erts/preloaded/src/erts_code_purger.erl b/erts/preloaded/src/erts_code_purger.erl index e492ba1812..a64860bec8 100644 --- a/erts/preloaded/src/erts_code_purger.erl +++ b/erts/preloaded/src/erts_code_purger.erl @@ -40,8 +40,7 @@ loop() -> Res = do_soft_purge(Mod), From ! {reply, soft_purge, Res, Ref}; - M -> - erlang:display({"erts_code_purger got msg", M}) + _Other -> ignore end, loop(). -- cgit v1.2.3 From 858c6f7fa44f7b2dc363b359198d6522dd60e914 Mon Sep 17 00:00:00 2001 From: Rickard Green Date: Tue, 5 Jan 2016 16:55:04 +0100 Subject: Introduce time warp safe trace timestamp formats New timestamp options for trace, sequential trace, and system profile: - monotonic_timestamp - strict_monotonic_timestamp --- erts/preloaded/src/erlang.erl | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) (limited to 'erts/preloaded/src') diff --git a/erts/preloaded/src/erlang.erl b/erts/preloaded/src/erlang.erl index 5fc6d14938..063b9a1f26 100644 --- a/erts/preloaded/src/erlang.erl +++ b/erts/preloaded/src/erlang.erl @@ -185,6 +185,8 @@ 'receive' | 'print' | 'timestamp' | + 'monotonic_timestamp' | + 'strict_monotonic_timestamp' | 'label' | 'serial'. @@ -198,7 +200,10 @@ 'exclusive' | 'runnable_ports' | 'runnable_procs' | - 'scheduler'. + 'scheduler' | + 'timestamp' | + 'monotonic_timestamp' | + 'strict_monotonic_timestamp'. -type system_monitor_option() :: 'busy_port' | @@ -230,6 +235,8 @@ garbage_collection | timestamp | cpu_timestamp | + monotonic_timestamp | + strict_monotonic_timestamp | arity | set_on_spawn | set_on_first_spawn | @@ -258,6 +265,8 @@ running | garbage_collection | timestamp | + monotonic_timestamp | + strict_monotonic_timestamp | arity. -type trace_info_return() :: @@ -2178,6 +2187,8 @@ send(_Dest,_Msg,_Options) -> ('receive') -> {'receive', boolean()}; (print) -> {print, boolean()}; (timestamp) -> {timestamp, boolean()}; + (monotonic_timestamp) -> {timestamp, boolean()}; + (strict_monotonic_timestamp) -> {strict_monotonic_timestamp, boolean()}; (label) -> [] | {label, non_neg_integer()}; (serial) -> [] | {serial, {non_neg_integer(), non_neg_integer()}}. seq_trace_info(_What) -> -- cgit v1.2.3 From 7189317ef89dfedaa35a804dfedd4fc27bf28d14 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Gustavsson?= Date: Wed, 13 Jan 2016 12:59:15 +0100 Subject: erl_prim_loader: Remove unused 'cache' field The #prim_state.cache' field is unused. The actual cache is kept in the process dictionary. --- erts/preloaded/src/erl_prim_loader.erl | 1 - 1 file changed, 1 deletion(-) (limited to 'erts/preloaded/src') diff --git a/erts/preloaded/src/erl_prim_loader.erl b/erts/preloaded/src/erl_prim_loader.erl index 5f88029585..3ef48ad61e 100644 --- a/erts/preloaded/src/erl_prim_loader.erl +++ b/erts/preloaded/src/erl_prim_loader.erl @@ -57,7 +57,6 @@ -type host() :: atom(). -record(prim_state, {debug :: boolean(), - cache, primary_archive}). -type prim_state() :: #prim_state{}. -- cgit v1.2.3 From ca1964e765595dfe9089759adb5ef5eded4f2bf1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Gustavsson?= Date: Wed, 13 Jan 2016 13:35:53 +0100 Subject: erl_prim_loader: Correct purging of the archive cache prim_do_release_archives/3 can't make up its mind whether the primary archive should be released or not. The key in the process dictionary is kept, while #prim_state.primary_archive is cleared. It seems that intent was the primary archive should be preserved, because the function was intended to be called by a timeout routine every sixth minute (it is not because of a bug in setting up the timeout). Therefore, rewrite the code to preserve the primary archive and simplify it while at it. Also, rename prim_release_archives/1 to prim_purge_cache/0 to make it clearer what it is doing. --- erts/preloaded/src/erl_prim_loader.erl | 47 +++++++++++----------------------- 1 file changed, 15 insertions(+), 32 deletions(-) (limited to 'erts/preloaded/src') diff --git a/erts/preloaded/src/erl_prim_loader.erl b/erts/preloaded/src/erl_prim_loader.erl index 3ef48ad61e..ac461bc6c7 100644 --- a/erts/preloaded/src/erl_prim_loader.erl +++ b/erts/preloaded/src/erl_prim_loader.erl @@ -435,10 +435,6 @@ efile_set_primary_archive(#state{prim_state = PS} = State, File, FileInfo, ParserFun), {Res,State#state{prim_state = PS2}}. -efile_release_archives(#state{prim_state = PS} = State) -> - {Res, PS2} = prim_release_archives(PS), - {Res,State#state{prim_state = PS2}}. - efile_list_dir(#state{prim_state = PS} = State, Dir) -> {Res, PS2} = prim_list_dir(PS, Dir), {Res, State#state{prim_state = PS2}}. @@ -463,8 +459,8 @@ efile_exit_port(State, _Port, _Reason) -> efile_timeout_handler(#state{n_timeouts = N} = State, _Parent) -> if N =< 0 -> - {_Res, State2} = efile_release_archives(State), - State2#state{n_timeouts = ?N_TIMEOUTS}; + prim_purge_cache(), + State#state{n_timeouts = ?N_TIMEOUTS}; true -> State#state{n_timeouts = N - 1} end. @@ -733,32 +729,19 @@ prim_init() -> end, cache_new(#prim_state{debug = Deb}). -prim_release_archives(PS) -> - debug(PS, release_archives), - {Res, PS2} = prim_do_release_archives(PS, get(), []), - debug(PS2, {return, Res}), - {Res, PS2}. - -prim_do_release_archives(PS, [{ArchiveFile, DictVal} | KeyVals], Acc) -> - Res = - case DictVal of - {primary, _PrimZip, _FI, _ParserFun} -> - ok; % Keep primary archive - {Cache, _FI} -> - debug(PS, {release, cache, ArchiveFile}), - erase(ArchiveFile), - clear_cache(ArchiveFile, Cache) - end, - case Res of - ok -> - prim_do_release_archives(PS, KeyVals, Acc); - {error, Reason} -> - prim_do_release_archives(PS, KeyVals, [{ArchiveFile, Reason} | Acc]) - end; -prim_do_release_archives(PS, [], []) -> - {ok, PS#prim_state{primary_archive = undefined}}; -prim_do_release_archives(PS, [], Errors) -> - {{error, Errors}, PS#prim_state{primary_archive = undefined}}. +prim_purge_cache() -> + do_prim_purge_cache(get()). + +do_prim_purge_cache([{Key,Val}|T]) -> + case Val of + {Cache,_FI} -> + catch clear_cache(Key, Cache); + _ -> + ok + end, + do_prim_purge_cache(T); +do_prim_purge_cache([]) -> + ok. prim_set_primary_archive(PS, undefined, undefined, undefined, _ParserFun) -> debug(PS, {set_primary_archive, clean}), -- cgit v1.2.3 From b662e8abbdf63390af5173752ea87d7c952f5185 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Gustavsson?= Date: Wed, 13 Jan 2016 13:41:53 +0100 Subject: erl_prim_loader: Correct timeout handling for efile The timeout routine for efile was never called. While at it, eliminate the n_timeouts field and simplify the logic. --- erts/preloaded/src/erl_prim_loader.erl | 24 ++++++++---------------- 1 file changed, 8 insertions(+), 16 deletions(-) (limited to 'erts/preloaded/src') diff --git a/erts/preloaded/src/erl_prim_loader.erl b/erts/preloaded/src/erl_prim_loader.erl index ac461bc6c7..e1c014fee6 100644 --- a/erts/preloaded/src/erl_prim_loader.erl +++ b/erts/preloaded/src/erl_prim_loader.erl @@ -65,12 +65,10 @@ hosts = [] :: [host()], % hosts list (to boot from) data :: 'noport' | port(), % data port etc timeout :: timeout(), % idle timeout - %% Number of timeouts before archives are released - n_timeouts :: non_neg_integer(), prim_state :: prim_state()}). % state for efile code loader --define(IDLE_TIMEOUT, 60000). %% tear inet connection after 1 minutes --define(N_TIMEOUTS, 6). %% release efile archive after 6 minutes +-define(EFILE_IDLE_TIMEOUT, (6*60*1000)). %purge archives +-define(INET_IDLE_TIMEOUT, (60*1000)). %tear down connection timeout %% Defines for inet as prim_loader -define(INET_FAMILY, inet). @@ -142,8 +140,7 @@ start_inet(Parent) -> State = #state {loader = inet, hosts = AL, data = Tcp, - timeout = ?IDLE_TIMEOUT, - n_timeouts = ?N_TIMEOUTS, + timeout = ?INET_IDLE_TIMEOUT, prim_state = PS}, loop(State, Parent, []). @@ -163,7 +160,7 @@ start_efile(Parent) -> PS = prim_init(), State = #state {loader = efile, data = Port, - timeout = infinity, + timeout = ?EFILE_IDLE_TIMEOUT, prim_state = PS}, loop(State, Parent, []). @@ -456,14 +453,9 @@ efile_exit_port(State, Port, Reason) when State#state.data =:= Port -> efile_exit_port(State, _Port, _Reason) -> State. -efile_timeout_handler(#state{n_timeouts = N} = State, _Parent) -> - if - N =< 0 -> - prim_purge_cache(), - State#state{n_timeouts = ?N_TIMEOUTS}; - true -> - State#state{n_timeouts = N - 1} - end. +efile_timeout_handler(State, _Parent) -> + prim_purge_cache(), + State. %%% -------------------------------------------------------- %%% Functions which handle inet prim_loader @@ -604,7 +596,7 @@ inet_get_file_from_port1(_File, [], State) -> inet_send_and_rcv(Msg, Tag, State) when State#state.data =:= noport -> {ok,Tcp} = find_master(State#state.hosts), %% reconnect inet_send_and_rcv(Msg, Tag, State#state{data = Tcp, - timeout = ?IDLE_TIMEOUT}); + timeout = ?INET_IDLE_TIMEOUT}); inet_send_and_rcv(Msg, Tag, #state{data = Tcp, timeout = Timeout} = State) -> prim_inet:send(Tcp, term_to_binary(Msg)), receive -- cgit v1.2.3 From 56eded8ac675bf0e6f955c291be845f668d2b795 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Gustavsson?= Date: Wed, 13 Jan 2016 15:11:43 +0100 Subject: erl_prim_loader: Rename release_archives/0 Rename release_archives/0 to purge_archive_cache/0 to make it clearer what it does and what it doesn't do. Also add a comment about its intended purpose. Note that release_archives/0 is not documented and is part of the experimental archive feature. Furthermore, the only uses I could find were in the test suite. I did not find any uses in the external applications relx and rebar3 applications that are known to use archives. Therefore, I think that the increased clarity is worth the small risk of breaking code. --- erts/preloaded/src/erl_prim_loader.erl | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) (limited to 'erts/preloaded/src') diff --git a/erts/preloaded/src/erl_prim_loader.erl b/erts/preloaded/src/erl_prim_loader.erl index e1c014fee6..824ed3435d 100644 --- a/erts/preloaded/src/erl_prim_loader.erl +++ b/erts/preloaded/src/erl_prim_loader.erl @@ -50,7 +50,10 @@ prim_read_file_info/3, prim_get_cwd/2]). %% Used by escript and code --export([set_primary_archive/4, release_archives/0]). +-export([set_primary_archive/4]). + +%% Used by test suites +-export([purge_archive_cache/0]). -include_lib("kernel/include/file.hrl"). @@ -225,10 +228,13 @@ set_primary_archive(File, ArchiveBin, FileInfo, ParserFun) when is_list(File), is_binary(ArchiveBin), is_record(FileInfo, file_info) -> request({set_primary_archive, File, ArchiveBin, FileInfo, ParserFun}). --spec release_archives() -> 'ok' | {'error', _}. +%% NOTE: Does not close the primary archive. Only closes all +%% open zip files kept in the cache. Should be called before an archive +%% file is to be removed (for example in the test suites). -release_archives() -> - request(release_archives). +-spec purge_archive_cache() -> 'ok' | {'error', _}. +purge_archive_cache() -> + request(purge_archive_cache). request(Req) -> Loader = whereis(erl_prim_loader), @@ -332,8 +338,8 @@ handle_request(Req, Paths, St0) -> {set_primary_archive,File,ArchiveBin,FileInfo,ParserFun} -> handle_set_primary_archive(St0, File, ArchiveBin, FileInfo, ParserFun); - release_archives -> - handle_release_archives(St0); + purge_archive_cache -> + handle_purge_archive_cache(St0); _ -> ignore end. @@ -346,8 +352,9 @@ handle_get_file(State = #state{loader = inet}, Paths, File) -> handle_set_primary_archive(State= #state{loader = efile}, File, ArchiveBin, FileInfo, ParserFun) -> ?SAFE2(efile_set_primary_archive(State, File, ArchiveBin, FileInfo, ParserFun), State). -handle_release_archives(State= #state{loader = efile}) -> - ?SAFE2(efile_release_archives(State), State). +handle_purge_archive_cache(#state{loader = efile}=State) -> + prim_purge_cache(), + {ok,State}. handle_list_dir(State = #state{loader = efile}, Dir) -> ?SAFE2(efile_list_dir(State, Dir), State); -- cgit v1.2.3 From 70e92b321feb10b5976c9a9f571a273155ebcf79 Mon Sep 17 00:00:00 2001 From: Sverker Eriksson Date: Mon, 25 Jan 2016 15:45:13 +0100 Subject: erts: Fix harmless dialyzer warnings --- erts/preloaded/src/erts_code_purger.erl | 2 +- erts/preloaded/src/erts_internal.erl | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'erts/preloaded/src') diff --git a/erts/preloaded/src/erts_code_purger.erl b/erts/preloaded/src/erts_code_purger.erl index a64860bec8..d1e64342e0 100644 --- a/erts/preloaded/src/erts_code_purger.erl +++ b/erts/preloaded/src/erts_code_purger.erl @@ -31,7 +31,7 @@ start() -> loop(). loop() -> - receive + _ = receive {purge,Mod,From,Ref} when is_atom(Mod), is_pid(From) -> Res = do_purge(Mod), From ! {reply, purge, Res, Ref}; diff --git a/erts/preloaded/src/erts_internal.erl b/erts/preloaded/src/erts_internal.erl index 84dedab930..2b15abe0fb 100644 --- a/erts/preloaded/src/erts_internal.erl +++ b/erts/preloaded/src/erts_internal.erl @@ -49,7 +49,7 @@ -export([is_system_process/1]). -%% Auto import name clash +%% Auto-import name clash -export([check_process_code/2]). %% @@ -196,7 +196,7 @@ port_info(_Result, _Item) -> -spec request_system_task(Pid, Prio, Request) -> 'ok' when Prio :: 'max' | 'high' | 'normal' | 'low', Request :: {'garbage_collect', term()} - | {'check_process_code', term(), module(), boolean()}, + | {'check_process_code', term(), module(), non_neg_integer()}, Pid :: pid(). request_system_task(_Pid, _Prio, _Request) -> -- cgit v1.2.3 From eea5f896780e07f7ca76685061d01e7be5a7abaa Mon Sep 17 00:00:00 2001 From: Lukas Larsson Date: Thu, 11 Sep 2014 18:26:26 +0200 Subject: erts, kernel: Add os:perf_counter function The perf_counter is a very very cheap and high resolution timer that can be used to timestamp system events. It does not have monoticity guarantees, but should on most OS's expose a monotonous time. A special instruction has been created for this counter to further speed up fetching it. OTP-12908 --- erts/preloaded/src/erlang.erl | 5 ++++- erts/preloaded/src/erts_internal.erl | 7 ++++++- 2 files changed, 10 insertions(+), 2 deletions(-) (limited to 'erts/preloaded/src') diff --git a/erts/preloaded/src/erlang.erl b/erts/preloaded/src/erlang.erl index bca366681d..6f56a81eec 100644 --- a/erts/preloaded/src/erlang.erl +++ b/erts/preloaded/src/erlang.erl @@ -71,7 +71,8 @@ | 'milli_seconds' | 'micro_seconds' | 'nano_seconds' - | 'native'. + | 'native' + | 'perf_counter'. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% Native code BIF stubs and their types @@ -1347,6 +1348,7 @@ convert_time_unit(Time, FromUnit, ToUnit) -> try FU = case FromUnit of native -> erts_internal:time_unit(); + perf_counter -> erts_internal:perf_counter_unit(); nano_seconds -> 1000*1000*1000; micro_seconds -> 1000*1000; milli_seconds -> 1000; @@ -1355,6 +1357,7 @@ convert_time_unit(Time, FromUnit, ToUnit) -> end, TU = case ToUnit of native -> erts_internal:time_unit(); + perf_counter -> erts_internal:perf_counter_unit(); nano_seconds -> 1000*1000*1000; micro_seconds -> 1000*1000; milli_seconds -> 1000; diff --git a/erts/preloaded/src/erts_internal.erl b/erts/preloaded/src/erts_internal.erl index 84dedab930..c3a14d272d 100644 --- a/erts/preloaded/src/erts_internal.erl +++ b/erts/preloaded/src/erts_internal.erl @@ -45,7 +45,7 @@ -export([await_result/1, gather_io_bytes/2]). --export([time_unit/0]). +-export([time_unit/0, perf_counter_unit/0]). -export([is_system_process/1]). @@ -345,6 +345,11 @@ flush_monitor_messages(Ref, Multi, Res) when is_reference(Ref) -> time_unit() -> erlang:nif_error(undefined). +-spec erts_internal:perf_counter_unit() -> pos_integer(). + +perf_counter_unit() -> + erlang:nif_error(undefined). + -spec erts_internal:is_system_process(Pid) -> boolean() when Pid :: pid(). -- cgit v1.2.3 From 664ed2a6fd2b324bb6b56db3d3eca853cfda8f61 Mon Sep 17 00:00:00 2001 From: Lukas Larsson Date: Fri, 12 Sep 2014 16:38:00 +0200 Subject: erts: Add microstate accounting Microstate accounting is a way to track which state the different threads within ERTS are in. The main usage area is to pin point performance bottlenecks by checking which states the threads are in and then from there figuring out why and where to optimize. Since checking whether microstate accounting is on or off is relatively expensive if done in a short loop only a few of the states are enabled by default and more states can be enabled through configure. I've done some benchmarking and the overhead with it turned off is not noticible and with it on it is a fraction of a percent. If you enable the extra states, depending on the benchmark, the ovehead when turned off is about 1% and when turned on somewhere inbetween 5-15%. OTP-12345 --- erts/preloaded/src/erlang.erl | 13 +++++++++++++ erts/preloaded/src/erts_internal.erl | 28 ++++++++++++++++++++++++++++ 2 files changed, 41 insertions(+) (limited to 'erts/preloaded/src') diff --git a/erts/preloaded/src/erlang.erl b/erts/preloaded/src/erlang.erl index 6f56a81eec..ab51cf385c 100644 --- a/erts/preloaded/src/erlang.erl +++ b/erts/preloaded/src/erlang.erl @@ -2217,6 +2217,16 @@ spawn_opt(_Tuple) -> (io) -> {{input, Input}, {output, Output}} when Input :: non_neg_integer(), Output :: non_neg_integer(); + (microstate_accounting) -> [MSAcc_Thread] | undefined when + MSAcc_Thread :: #{ type => MSAcc_Thread_Type, + id => MSAcc_Thread_Id, + counters => MSAcc_Counters}, + MSAcc_Thread_Type :: scheduler | async | aux, + MSAcc_Thread_Id :: non_neg_integer(), + MSAcc_Counters :: #{ MSAcc_Thread_State => non_neg_integer() }, + MSAcc_Thread_State :: alloc | aux | bif | busy_wait | check_io | + emulator | ets | gc | gc_fullsweep | nif | + other | port | send | sleep | timers; (reductions) -> {Total_Reductions, Reductions_Since_Last_Call} when Total_Reductions :: non_neg_integer(), @@ -2271,6 +2281,9 @@ subtract(_,_) -> (fullsweep_after, Number) -> OldNumber when Number :: non_neg_integer(), OldNumber :: non_neg_integer(); + (microstate_accounting, Action) -> OldState when + Action :: true | false | reset, + OldState :: true | false; (min_heap_size, MinHeapSize) -> OldMinHeapSize when MinHeapSize :: non_neg_integer(), OldMinHeapSize :: non_neg_integer(); diff --git a/erts/preloaded/src/erts_internal.erl b/erts/preloaded/src/erts_internal.erl index c3a14d272d..a15355bb10 100644 --- a/erts/preloaded/src/erts_internal.erl +++ b/erts/preloaded/src/erts_internal.erl @@ -49,6 +49,9 @@ -export([is_system_process/1]). +-export([await_microstate_accounting_modifications/3, + gather_microstate_accounting_result/2]). + %% Auto import name clash -export([check_process_code/2]). @@ -355,3 +358,28 @@ perf_counter_unit() -> is_system_process(_Pid) -> erlang:nif_error(undefined). + +-spec await_microstate_accounting_modifications(Ref, Result, Threads) -> boolean() when + Ref :: reference(), + Result :: boolean(), + Threads :: pos_integer(). + +await_microstate_accounting_modifications(Ref, Result, Threads) -> + _ = microstate_accounting(Ref,Threads), + Result. + +-spec gather_microstate_accounting_result(Ref, Threads) -> [#{}] when + Ref :: reference(), + Threads :: pos_integer(). + +gather_microstate_accounting_result(Ref, Threads) -> + microstate_accounting(Ref, Threads). + +microstate_accounting(_Ref, 0) -> + []; +microstate_accounting(Ref, Threads) -> + receive + Ref -> microstate_accounting(Ref, Threads - 1); + {Ref, Res} -> + [Res | microstate_accounting(Ref, Threads - 1)] + end. -- cgit v1.2.3 From 4ea67ffdac2629255b1b0ed4e9423823f62c0947 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn-Egil=20Dahlberg?= Date: Mon, 15 Feb 2016 18:12:48 +0100 Subject: erts: Add BIF erts_internal:system_check/1 This commit implements erts_internal:system_check(schedulers) with the intent of a basic responsiveness test check of the schedulers. --- erts/preloaded/src/erts_internal.erl | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) (limited to 'erts/preloaded/src') diff --git a/erts/preloaded/src/erts_internal.erl b/erts/preloaded/src/erts_internal.erl index 7ed4efea4b..6db77a8482 100644 --- a/erts/preloaded/src/erts_internal.erl +++ b/erts/preloaded/src/erts_internal.erl @@ -35,6 +35,9 @@ -export([port_command/3, port_connect/2, port_close/1, port_control/3, port_call/3, port_info/1, port_info/2]). +-export([system_check/1, + gather_system_check_result/1]). + -export([request_system_task/3]). -export([check_process_code/2]). @@ -197,6 +200,23 @@ request_system_task(_Pid, _Prio, _Request) -> check_process_code(_Module, _OptionList) -> erlang:nif_error(undefined). +-spec system_check(Type) -> 'ok' when + Type :: 'schedulers'. + +system_check(_Type) -> + erlang:nif_error(undefined). + +gather_system_check_result(Ref) when is_reference(Ref) -> + gather_system_check_result(Ref, erlang:system_info(schedulers)). + +gather_system_check_result(_Ref, 0) -> + ok; +gather_system_check_result(Ref, N) -> + receive + Ref -> + gather_system_check_result(Ref, N - 1) + end. + %% term compare where integer() < float() = true -spec cmp_term(A,B) -> Result when -- cgit v1.2.3 From f10621e0cd4321834d072d2c495fc84066f04cd3 Mon Sep 17 00:00:00 2001 From: Hans Bolinder Date: Thu, 18 Feb 2016 15:01:15 +0100 Subject: Fix a few dialyzer warnings --- erts/preloaded/src/prim_file.erl | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'erts/preloaded/src') diff --git a/erts/preloaded/src/prim_file.erl b/erts/preloaded/src/prim_file.erl index c87b2645ec..ab5359ebbc 100644 --- a/erts/preloaded/src/prim_file.erl +++ b/erts/preloaded/src/prim_file.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2000-2013. All Rights Reserved. +%% Copyright Ericsson AB 2000-2016. All Rights Reserved. %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. @@ -1276,6 +1276,7 @@ lseek_position(_) -> %% Translates the response from the driver into %% {ok, Result} or {error, Reason}. +-dialyzer({no_improper_lists, translate_response/2}). translate_response(?FILE_RESP_OK, []) -> ok; translate_response(?FILE_RESP_ERROR, List) when is_list(List) -> -- cgit v1.2.3 From 272985d3d1b36833ebd586e5f051ac3a4ab0cd91 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Gustavsson?= Date: Thu, 3 Dec 2015 15:42:02 +0100 Subject: Add has_prepared_code_on_load/1 BIF --- erts/preloaded/src/erlang.erl | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) (limited to 'erts/preloaded/src') diff --git a/erts/preloaded/src/erlang.erl b/erts/preloaded/src/erlang.erl index ab51cf385c..9bf8d13fde 100644 --- a/erts/preloaded/src/erlang.erl +++ b/erts/preloaded/src/erlang.erl @@ -105,7 +105,9 @@ -export([garbage_collect/0, garbage_collect/1, garbage_collect/2]). -export([garbage_collect_message_area/0, get/0, get/1, get_keys/0, get_keys/1]). -export([get_module_info/1, get_stacktrace/0, group_leader/0]). --export([group_leader/2, halt/0, halt/1, halt/2, hash/2, hibernate/3]). +-export([group_leader/2]). +-export([halt/0, halt/1, halt/2, hash/2, + has_prepared_code_on_load/1, hibernate/3]). -export([insert_element/3]). -export([integer_to_binary/1, integer_to_list/1]). -export([iolist_size/1, iolist_to_binary/1]). @@ -997,6 +999,12 @@ halt(_Status, _Options) -> hash(_Term, _Range) -> erlang:nif_error(undefined). +%% has_prepared_code_on_load/1 +-spec erlang:has_prepared_code_on_load(PreparedCode) -> boolean() when + PreparedCode :: binary(). +has_prepared_code_on_load(_PreparedCode) -> + erlang:nif_error(undefined). + %% hibernate/3 -spec erlang:hibernate(Module, Function, Args) -> no_return() when Module :: module(), -- cgit v1.2.3 From cd283583f8898b88bbcccc622c733fba82bd3e5b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Gustavsson?= Date: Tue, 15 Dec 2015 12:20:26 +0100 Subject: Add erl_prim_loader:get_modules/3 When we are going to implement functions that can load many modules at once, we don't the erl_prim_loader server to become a bottleneck. Therefore, we need erl_prim_loader:get_modules/3 that can read many BEAM files in parallel. Note that we will not bother making reading from archive files or using the inet loader efficient. That can be done later if it turns out to be important. --- erts/preloaded/src/erl_prim_loader.erl | 133 +++++++++++++++++++++++++++++++++ 1 file changed, 133 insertions(+) (limited to 'erts/preloaded/src') diff --git a/erts/preloaded/src/erl_prim_loader.erl b/erts/preloaded/src/erl_prim_loader.erl index 824ed3435d..cbcced5512 100644 --- a/erts/preloaded/src/erl_prim_loader.erl +++ b/erts/preloaded/src/erl_prim_loader.erl @@ -55,6 +55,9 @@ %% Used by test suites -export([purge_archive_cache/0]). +%% Used by init and the code server. +-export([get_modules/3]). + -include_lib("kernel/include/file.hrl"). -type host() :: atom(). @@ -236,6 +239,16 @@ set_primary_archive(File, ArchiveBin, FileInfo, ParserFun) purge_archive_cache() -> request(purge_archive_cache). + +-spec get_modules([module()], + fun((atom(), string(), binary()) -> + {'ok',any()} | {'error',any()}), + [string()]) -> + {'ok',{[any()],[any()]}}. + +get_modules(Modules, Fun, Path) -> + request({get_modules,{Modules,Fun,Path}}). + request(Req) -> Loader = whereis(erl_prim_loader), Loader ! {self(),Req}, @@ -325,6 +338,8 @@ handle_request(Req, Paths, St0) -> {{ok,Paths},St0}; {get_file,File} -> handle_get_file(St0, Paths, File); + {get_modules,{Modules,Fun,ModPaths}} -> + handle_get_modules(St0, Modules, Fun, ModPaths); {list_dir,Dir} -> handle_list_dir(St0, Dir); {read_file_info,File} -> @@ -464,6 +479,124 @@ efile_timeout_handler(State, _Parent) -> prim_purge_cache(), State. +%%% -------------------------------------------------------- +%%% Read and process severals modules in parallel. +%%% -------------------------------------------------------- + +handle_get_modules(#state{loader=efile}=St, Ms, Process, Paths) -> + Primary = (St#state.prim_state)#prim_state.primary_archive, + Res = case efile_any_archives(Paths, Primary) of + false -> + efile_get_mods_par(Ms, Process, Paths); + true -> + Get = fun efile_get_file_from_port/3, + gm_get_mods(St, Get, Ms, Process, Paths) + end, + {Res,St}; +handle_get_modules(#state{loader=inet}=St, Ms, Process, Paths) -> + Get = fun inet_get_file_from_port/3, + {gm_get_mods(St, Get, Ms, Process, Paths),St}. + +efile_get_mods_par(Ms, Process, Paths) -> + Self = self(), + Ref = make_ref(), + GmSpawn = fun() -> + efile_gm_spawn({Self,Ref}, Ms, Process, Paths) + end, + _ = spawn_link(GmSpawn), + N = length(Ms), + efile_gm_recv(N, Ref, [], []). + +efile_any_archives([H|T], Primary) -> + case name_split(Primary, H) of + {file,_} -> efile_any_archives(T, Primary); + {archive,_,_} -> true + end; +efile_any_archives([], _) -> + false. + +efile_gm_recv(0, _Ref, Succ, Fail) -> + {ok,{Succ,Fail}}; +efile_gm_recv(N, Ref, Succ, Fail) -> + receive + {Ref,Mod,{ok,Res}} -> + efile_gm_recv(N-1, Ref, [{Mod,Res}|Succ], Fail); + {Ref,Mod,{error,Res}} -> + efile_gm_recv(N-1, Ref, Succ, [{Mod,Res}|Fail]) + end. + +efile_gm_spawn(ParentRef, Ms, Process, Paths) -> + efile_gm_spawn_1(0, Ms, ParentRef, Process, Paths). + +efile_gm_spawn_1(N, Ms, ParentRef, Process, Paths) when N >= 32 -> + receive + {'DOWN',_,process,_,_} -> + efile_gm_spawn_1(N-1, Ms, ParentRef, Process, Paths) + end; +efile_gm_spawn_1(N, [M|Ms], ParentRef, Process, Paths) -> + Get = fun() -> efile_gm_get(Paths, M, ParentRef, Process) end, + _ = spawn_monitor(Get), + efile_gm_spawn_1(N+1, Ms, ParentRef, Process, Paths); +efile_gm_spawn_1(_, [], _, _, _) -> + ok. + +efile_gm_get(Paths, Mod, ParentRef, Process) -> + File = atom_to_list(Mod) ++ init:objfile_extension(), + efile_gm_get_1(Paths, File, Mod, ParentRef, Process). + +efile_gm_get_1([P|Ps], File0, Mod, {Parent,Ref}=PR, Process) -> + File = join(P, File0), + Res = try prim_file:read_file(File) of + {ok,Bin} -> + gm_process(Mod, File, Bin, Process); + {error,enoent} -> + efile_gm_get_1(Ps, File0, Mod, PR, Process); + Error -> + check_file_result(get_modules, File, Error), + Error + catch + _:Reason -> + {error,{crash,Reason}} + end, + Parent ! {Ref,Mod,Res}; +efile_gm_get_1([], _, Mod, {Parent,Ref}, _Process) -> + Parent ! {Ref,Mod,{error,enoent}}. + +gm_get_mods(St, Get, Ms, Process, Paths) -> + gm_get_mods(St, Get, Ms, Process, Paths, [], []). + +gm_get_mods(St, Get, [M|Ms], Process, Paths, Succ, Fail) -> + File = atom_to_list(M) ++ init:objfile_extension(), + case gm_arch_get(St, Get, M, File, Paths, Process) of + {ok,Res} -> + gm_get_mods(St, Get, Ms, Process, Paths, + [{M,Res}|Succ], Fail); + {error,Res} -> + gm_get_mods(St, Get, Ms, Process, Paths, + Succ, [{M,Res}|Fail]) + end; +gm_get_mods(_St, _Get, [], _, _, Succ, Fail) -> + {ok,{Succ,Fail}}. + +gm_arch_get(St, Get, Mod, File, Paths, Process) -> + case Get(St, File, Paths) of + {{error,_}=E,_} -> + E; + {{ok,Bin,Full},_} -> + gm_process(Mod, Full, Bin, Process) + end. + +gm_process(Mod, File, Bin, Process) -> + try Process(Mod, File, Bin) of + {ok,_}=Res -> Res; + {error,_}=Res -> Res; + Other -> {error,{bad_return,Other}} + catch + _:Error -> + {error,{crash,Error}} + end. + + %%% -------------------------------------------------------- %%% Functions which handle inet prim_loader %%% -------------------------------------------------------- -- cgit v1.2.3 From 207a569d4caf80b10a54eec2220ac672a3377f00 Mon Sep 17 00:00:00 2001 From: Rickard Green Date: Fri, 22 Jan 2016 17:48:49 +0100 Subject: Improved scheduler suspend functionality - The calling process is now suspended while synchronizing scheduler suspends via erlang:system_flag(schedulers_online, _) and erlang:system_flag(multi_scheduling, _), instead of blocking the scheduler thread in the BIF call waiting for the operation to synchronize. Besides releasing the scheduler for other work (or immediate suspend) it also makes it possible to abort the operation by killing the process. - erlang:system_flag(schedulers_online, _) now only wait for normal schedulers to complete before it returns. This since it may take a very long time before all dirty schedulers suspends. - erlang:system_flag(multi_scheduling, block_normal|unblock_normal) which only operate on normal schedulers has been introduced. This since there are use cases where suspend of dirty schedulers are not of interest (hipe loader). - erlang:system_flag(multi_scheduling, block) still blocks all dirty schedulers as well as all normal schedulers except one since it is hard to redefine what multi scheduling block means. - The three operations: - changing amount of schedulers online - blocking/unblocking normal multi scheduling - blocking/unblocking full multi scheduling can now be done in parallel. This is important since otherwise a full multi scheduling block would potentially delay the other operations for a very long time. --- erts/preloaded/src/erlang.erl | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'erts/preloaded/src') diff --git a/erts/preloaded/src/erlang.erl b/erts/preloaded/src/erlang.erl index 9bf8d13fde..dfbd116d6e 100644 --- a/erts/preloaded/src/erlang.erl +++ b/erts/preloaded/src/erlang.erl @@ -2300,8 +2300,8 @@ subtract(_,_) -> MinBinVHeapSize :: non_neg_integer(), OldMinBinVHeapSize :: non_neg_integer(); (multi_scheduling, BlockState) -> OldBlockState when - BlockState :: block | unblock, - OldBlockState :: block | unblock | enabled; + BlockState :: block | unblock | block_normal | unblock_normal, + OldBlockState :: blocked | disabled | enabled; (scheduler_bind_type, How) -> OldBindType when How :: scheduler_bind_type() | default_bind, OldBindType :: scheduler_bind_type(); @@ -2446,14 +2446,15 @@ tuple_to_list(_Tuple) -> logical_processors_available | logical_processors_online) -> unknown | pos_integer(); (machine) -> string(); + (message_queue_data) -> message_queue_data(); (min_heap_size) -> {min_heap_size, MinHeapSize :: pos_integer()}; (min_bin_vheap_size) -> {min_bin_vheap_size, MinBinVHeapSize :: pos_integer()}; (modified_timing_level) -> integer() | undefined; - (multi_scheduling) -> disabled | blocked | enabled; + (multi_scheduling) -> disabled | blocked | blocked_normal | enabled; (multi_scheduling_blockers) -> [Pid :: pid()]; (nif_version) -> string(); - (message_queue_data) -> message_queue_data(); + (normal_multi_scheduling_blockers) -> [Pid :: pid()]; (otp_release) -> string(); (os_monotonic_time_source) -> [{atom(),term()}]; (os_system_time_source) -> [{atom(),term()}]; -- cgit v1.2.3 From 6664eed554974336909d3ffe03f20349cc4c38fd Mon Sep 17 00:00:00 2001 From: Henrik Nord Date: Tue, 15 Mar 2016 15:19:56 +0100 Subject: update copyright-year --- erts/preloaded/src/Makefile | 2 +- erts/preloaded/src/add_abstract_code | 2 +- erts/preloaded/src/erl_prim_loader.erl | 2 +- erts/preloaded/src/erlang.erl | 2 +- erts/preloaded/src/erts.app.src | 2 +- erts/preloaded/src/erts_internal.erl | 2 +- erts/preloaded/src/init.erl | 2 +- erts/preloaded/src/otp_ring0.erl | 2 +- erts/preloaded/src/prim_eval.S | 2 +- erts/preloaded/src/prim_eval.erl | 2 +- erts/preloaded/src/prim_inet.erl | 2 +- erts/preloaded/src/prim_zip.erl | 2 +- erts/preloaded/src/zip_internal.hrl | 2 +- erts/preloaded/src/zlib.erl | 2 +- 14 files changed, 14 insertions(+), 14 deletions(-) (limited to 'erts/preloaded/src') diff --git a/erts/preloaded/src/Makefile b/erts/preloaded/src/Makefile index 31383dda83..1e3de9f1d7 100644 --- a/erts/preloaded/src/Makefile +++ b/erts/preloaded/src/Makefile @@ -1,7 +1,7 @@ # # %CopyrightBegin% # -# Copyright Ericsson AB 2008-2013. All Rights Reserved. +# Copyright Ericsson AB 2008-2016. All Rights Reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/erts/preloaded/src/add_abstract_code b/erts/preloaded/src/add_abstract_code index 4f479db2e8..943987872e 100644 --- a/erts/preloaded/src/add_abstract_code +++ b/erts/preloaded/src/add_abstract_code @@ -4,7 +4,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2013. All Rights Reserved. +%% Copyright Ericsson AB 2013-2016. All Rights Reserved. %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. diff --git a/erts/preloaded/src/erl_prim_loader.erl b/erts/preloaded/src/erl_prim_loader.erl index cbcced5512..86ab4b30ef 100644 --- a/erts/preloaded/src/erl_prim_loader.erl +++ b/erts/preloaded/src/erl_prim_loader.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2013. All Rights Reserved. +%% Copyright Ericsson AB 1996-2016. All Rights Reserved. %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. diff --git a/erts/preloaded/src/erlang.erl b/erts/preloaded/src/erlang.erl index dfbd116d6e..484b00413d 100644 --- a/erts/preloaded/src/erlang.erl +++ b/erts/preloaded/src/erlang.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2013. All Rights Reserved. +%% Copyright Ericsson AB 1996-2016. All Rights Reserved. %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. diff --git a/erts/preloaded/src/erts.app.src b/erts/preloaded/src/erts.app.src index e53b6e5bab..98e0224a5f 100644 --- a/erts/preloaded/src/erts.app.src +++ b/erts/preloaded/src/erts.app.src @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2013. All Rights Reserved. +%% Copyright Ericsson AB 2013-2016. All Rights Reserved. %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. diff --git a/erts/preloaded/src/erts_internal.erl b/erts/preloaded/src/erts_internal.erl index 330fcc4a9c..769757ba75 100644 --- a/erts/preloaded/src/erts_internal.erl +++ b/erts/preloaded/src/erts_internal.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2012-2013. All Rights Reserved. +%% Copyright Ericsson AB 2012-2016. All Rights Reserved. %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. diff --git a/erts/preloaded/src/init.erl b/erts/preloaded/src/init.erl index ed65c57c0d..f8345ef219 100644 --- a/erts/preloaded/src/init.erl +++ b/erts/preloaded/src/init.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2013. All Rights Reserved. +%% Copyright Ericsson AB 1996-2016. All Rights Reserved. %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. diff --git a/erts/preloaded/src/otp_ring0.erl b/erts/preloaded/src/otp_ring0.erl index 3158fc7d21..62a60fffe2 100644 --- a/erts/preloaded/src/otp_ring0.erl +++ b/erts/preloaded/src/otp_ring0.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2000-2010. All Rights Reserved. +%% Copyright Ericsson AB 2000-2016. All Rights Reserved. %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. diff --git a/erts/preloaded/src/prim_eval.S b/erts/preloaded/src/prim_eval.S index 1b7b00a7c9..e7f09a870c 100644 --- a/erts/preloaded/src/prim_eval.S +++ b/erts/preloaded/src/prim_eval.S @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2013. All Rights Reserved. +%% Copyright Ericsson AB 2013-2016. All Rights Reserved. %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. diff --git a/erts/preloaded/src/prim_eval.erl b/erts/preloaded/src/prim_eval.erl index 732e22468e..22e924f9e9 100644 --- a/erts/preloaded/src/prim_eval.erl +++ b/erts/preloaded/src/prim_eval.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2013. All Rights Reserved. +%% Copyright Ericsson AB 2013-2016. All Rights Reserved. %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. diff --git a/erts/preloaded/src/prim_inet.erl b/erts/preloaded/src/prim_inet.erl index bd74831bb7..4872ffd00c 100644 --- a/erts/preloaded/src/prim_inet.erl +++ b/erts/preloaded/src/prim_inet.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2000-2013. All Rights Reserved. +%% Copyright Ericsson AB 2000-2016. All Rights Reserved. %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. diff --git a/erts/preloaded/src/prim_zip.erl b/erts/preloaded/src/prim_zip.erl index c4b949afcb..b1ddbbe173 100644 --- a/erts/preloaded/src/prim_zip.erl +++ b/erts/preloaded/src/prim_zip.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2013. All Rights Reserved. +%% Copyright Ericsson AB 2008-2016. All Rights Reserved. %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. diff --git a/erts/preloaded/src/zip_internal.hrl b/erts/preloaded/src/zip_internal.hrl index d5cf52fae4..2769ca152d 100644 --- a/erts/preloaded/src/zip_internal.hrl +++ b/erts/preloaded/src/zip_internal.hrl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2009. All Rights Reserved. +%% Copyright Ericsson AB 2008-2016. All Rights Reserved. %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. diff --git a/erts/preloaded/src/zlib.erl b/erts/preloaded/src/zlib.erl index 473ad649c7..fa0f28c5c3 100644 --- a/erts/preloaded/src/zlib.erl +++ b/erts/preloaded/src/zlib.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2003-2013. All Rights Reserved. +%% Copyright Ericsson AB 2003-2016. All Rights Reserved. %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. -- cgit v1.2.3 From aae682cebfbb747565b5a6536f646e6c8d9e3b26 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Gustavsson?= Date: Wed, 16 Mar 2016 10:09:04 +0100 Subject: init: Correct spec for fetch_loaded/1 fetch_loaded/1 returns a list of tuples, not a list of atoms. --- erts/preloaded/src/init.erl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'erts/preloaded/src') diff --git a/erts/preloaded/src/init.erl b/erts/preloaded/src/init.erl index ed65c57c0d..5de3732c20 100644 --- a/erts/preloaded/src/init.erl +++ b/erts/preloaded/src/init.erl @@ -129,7 +129,7 @@ bs2ss(L) -> get_status() -> request(get_status). --spec fetch_loaded() -> [atom()]. +-spec fetch_loaded() -> [{module(),file:filename()}]. fetch_loaded() -> request(fetch_loaded). -- cgit v1.2.3 From c54c6243423b55602dd7c204f2351852132d4a98 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Gustavsson?= Date: Thu, 10 Mar 2016 15:42:33 +0100 Subject: init: Load modules in parallel using the new loader BIFs Use erlang:prepare_loading/1 and erlang:finish_loading/1 to load modules in parallel to potentially decrease start-up times. --- erts/preloaded/src/erl_prim_loader.erl | 11 +++- erts/preloaded/src/init.erl | 116 +++++++++++++++++++-------------- 2 files changed, 77 insertions(+), 50 deletions(-) (limited to 'erts/preloaded/src') diff --git a/erts/preloaded/src/erl_prim_loader.erl b/erts/preloaded/src/erl_prim_loader.erl index cbcced5512..641abae7b1 100644 --- a/erts/preloaded/src/erl_prim_loader.erl +++ b/erts/preloaded/src/erl_prim_loader.erl @@ -56,7 +56,7 @@ -export([purge_archive_cache/0]). %% Used by init and the code server. --export([get_modules/3]). +-export([get_modules/2,get_modules/3]). -include_lib("kernel/include/file.hrl"). @@ -239,6 +239,13 @@ set_primary_archive(File, ArchiveBin, FileInfo, ParserFun) purge_archive_cache() -> request(purge_archive_cache). +-spec get_modules([module()], + fun((atom(), string(), binary()) -> + {'ok',any()} | {'error',any()})) -> + {'ok',{[any()],[any()]}}. + +get_modules(Modules, Fun) -> + request({get_modules,{Modules,Fun}}). -spec get_modules([module()], fun((atom(), string(), binary()) -> @@ -338,6 +345,8 @@ handle_request(Req, Paths, St0) -> {{ok,Paths},St0}; {get_file,File} -> handle_get_file(St0, Paths, File); + {get_modules,{Modules,Fun}} -> + handle_get_modules(St0, Modules, Fun, Paths); {get_modules,{Modules,Fun,ModPaths}} -> handle_get_modules(St0, Modules, Fun, ModPaths); {list_dir,Dir} -> diff --git a/erts/preloaded/src/init.erl b/erts/preloaded/src/init.erl index 5de3732c20..915f1183d6 100644 --- a/erts/preloaded/src/init.erl +++ b/erts/preloaded/src/init.erl @@ -297,9 +297,9 @@ crash(String, List) -> -spec boot_loop(pid(), state()) -> no_return(). boot_loop(BootPid, State) -> receive - {BootPid,loaded,ModLoaded} -> - Loaded = State#state.loaded, - boot_loop(BootPid,State#state{loaded = [ModLoaded|Loaded]}); + {BootPid,loaded,NewlyLoaded} -> + Loaded = NewlyLoaded ++ State#state.loaded, + boot_loop(BootPid, State#state{loaded = Loaded}); {BootPid,started,KernelPid} -> boot_loop(BootPid, new_kernelpid(KernelPid, BootPid, State)); {BootPid,progress,started} -> @@ -338,12 +338,25 @@ boot_loop(BootPid, State) -> end. ensure_loaded(Module, Loaded) -> + case erlang:module_loaded(Module) of + true -> + {{module, Module}, Loaded}; + false -> + do_ensure_loaded(Module, Loaded) + end. + +do_ensure_loaded(Module, Loaded) -> File = atom_to_list(Module) ++ objfile_extension(), - case catch load_mod(Module,File) of - {ok, FullName} -> - {{module, Module}, [{Module, FullName}|Loaded]}; - Res -> - {Res, Loaded} + case erl_prim_loader:get_file(File) of + {ok,BinCode,FullName} -> + case do_load_module(Module, BinCode) of + ok -> + {{module, Module}, [{Module, FullName}|Loaded]}; + error -> + {error, [{Module, FullName}|Loaded]} + end; + Error -> + {Error, Loaded} end. %% Tell subscribed processes the system has started. @@ -842,13 +855,6 @@ eval_script([{kernel_load_completed}|T], #es{load_mode=Mode}=Es0) -> _ -> Es0#es{prim_load=false} end, eval_script(T, Es); -eval_script([{primLoad,[Mod]}|T], #es{prim_load=true}=Es) -> - %% Common special case (loading of error_handler). Nothing - %% to gain by parallel loading. - File = atom_to_list(Mod) ++ objfile_extension(), - {ok,Full} = load_mod(Mod, File), - init ! {self(),loaded,{Mod,Full}}, % Tell init about loaded module - eval_script(T, Es); eval_script([{primLoad,Mods}|T], #es{init=Init,prim_load=PrimLoad}=Es) when is_list(Mods) -> case PrimLoad of @@ -873,14 +879,44 @@ eval_script([], #es{}) -> eval_script(What, #es{}) -> exit({'unexpected command in bootfile',What}). -load_modules([Mod|Mods], Init) -> - File = atom_to_list(Mod) ++ objfile_extension(), - {ok,Full} = load_mod(Mod,File), - Init ! {self(),loaded,{Mod,Full}}, %Tell init about loaded module - load_modules(Mods, Init); -load_modules([], _) -> +load_modules(Mods0, Init) -> + Mods = [M || M <- Mods0, not erlang:module_loaded(M)], + F = prepare_loading_fun(), + case erl_prim_loader:get_modules(Mods, F) of + {ok,{Prep0,[]}} -> + Prep = [Code || {_,{prepared,Code,_}} <- Prep0], + ok = erlang:finish_loading(Prep), + Loaded = [{Mod,Full} || {Mod,{_,_,Full}} <- Prep0], + Init ! {self(),loaded,Loaded}, + Beams = [{M,Beam,Full} || {M,{on_load,Beam,Full}} <- Prep0], + load_rest(Beams, Init); + {ok,{_,[_|_]=Errors}} -> + Ms = [M || {M,_} <- Errors], + exit({load_failed,Ms}) + end. + +load_rest([{Mod,Beam,Full}|T], Init) -> + do_load_module(Mod, Beam), + Init ! {self(),loaded,[{Mod,Full}]}, + load_rest(T, Init); +load_rest([], _) -> ok. +prepare_loading_fun() -> + fun(Mod, FullName, Beam) -> + case erlang:prepare_loading(Mod, Beam) of + Prepared when is_binary(Prepared) -> + case erlang:has_prepared_code_on_load(Prepared) of + true -> + {ok,{on_load,Beam,FullName}}; + false -> + {ok,{prepared,Prepared,FullName}} + end; + {error,_}=Error -> + Error + end + end. + make_path(Pa, Pz, Path, Vars) -> append([Pa,append([fix_path(Path,Vars),Pz])]). @@ -1033,35 +1069,17 @@ start_it([_|_]=MFA) -> [M,F|Args] -> M:F(Args) % Args is a list end. -%% -%% Fetch a module and load it into the system. -%% -load_mod(Mod, File) -> - case erlang:module_loaded(Mod) of - false -> - case erl_prim_loader:get_file(File) of - {ok,BinCode,FullName} -> - load_mod_code(Mod, BinCode, FullName); - _ -> - exit({'cannot load',Mod,get_file}) - end; - _ -> % Already loaded. - {ok,File} - end. +%% Load a module. -load_mod_code(Mod, BinCode, FullName) -> - case erlang:module_loaded(Mod) of - false -> - case erlang:load_module(Mod, BinCode) of - {module,Mod} -> {ok,FullName}; - {error,on_load} -> - ?ON_LOAD_HANDLER ! {loaded,Mod}, - {ok,FullName}; - Other -> - exit({'cannot load',Mod,Other}) - end; - _ -> % Already loaded. - {ok,FullName} +do_load_module(Mod, BinCode) -> + case erlang:load_module(Mod, BinCode) of + {module,Mod} -> + ok; + {error,on_load} -> + ?ON_LOAD_HANDLER ! {loaded,Mod}, + ok; + _ -> + error end. %% -------------------------------------------------------- -- cgit v1.2.3 From 0914884d534dab195f0ff4752e8ea4feda56dbb6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn-Egil=20Dahlberg?= Date: Thu, 7 Apr 2016 16:52:05 +0200 Subject: erts: Fix process_info/2 result spec --- erts/preloaded/src/erlang.erl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'erts/preloaded/src') diff --git a/erts/preloaded/src/erlang.erl b/erts/preloaded/src/erlang.erl index dfbd116d6e..50b01703ac 100644 --- a/erts/preloaded/src/erlang.erl +++ b/erts/preloaded/src/erlang.erl @@ -2130,7 +2130,7 @@ process_flag(_Flag, _Value) -> {message_queue_data, MQD :: message_queue_data()} | {priority, Level :: priority_level()} | {reductions, Number :: non_neg_integer()} | - {registered_name, Atom :: atom()} | + {registered_name, [] | (Atom :: atom())} | {sequential_trace_token, [] | (SequentialTraceToken :: term())} | {stack_size, Size :: non_neg_integer()} | {status, Status :: exiting | garbage_collecting | waiting | running | runnable | suspended} | -- cgit v1.2.3 From 37092dab15448ef6a078800e3ff0cc41880ea765 Mon Sep 17 00:00:00 2001 From: Lukas Larsson Date: Thu, 10 Dec 2015 11:10:46 +0100 Subject: erts: Implement tracer modules Add the possibility to use modules as trace data receivers. The functions in the module have to be nifs as otherwise complex trace probes will be very hard to handle (complex means trace probes for ports for example). This commit changes the way that the ptab->tracer field works from always being an immediate, to now be NIL if no tracer is present or else be the tuple {TracerModule, TracerState} where TracerModule is an atom that is later used to lookup the appropriate tracer callbacks to call and TracerState is just passed to the tracer callback. The default process and port tracers have been rewritten to use the new API. This commit also changes the order which trace messages are delivered to the potential tracer process. Any enif_send done in a tracer module may be delayed indefinitely because of lock order issues. If a message is delayed any other trace message send from that process is also delayed so that order is preserved for each traced entity. This means that for some trace events (i.e. send/receive) the events may come in an unintuitive order (receive before send) to the trace receiver. Timestamps are taken when the trace message is generated so trace messages from differented processes may arrive with the timestamp out of order. Both the erlang:trace and seq_trace:set_system_tracer accept the new tracer module tracers and also the backwards compatible arguments. OTP-10267 --- erts/preloaded/src/Makefile | 3 +- erts/preloaded/src/erl_tracer.erl | 41 ++++++++++++++++++++++ erts/preloaded/src/erlang.erl | 67 +++++++++++++++++++++++++++++++----- erts/preloaded/src/erts_internal.erl | 29 +++++++++++++++- erts/preloaded/src/init.erl | 4 +++ 5 files changed, 134 insertions(+), 10 deletions(-) create mode 100644 erts/preloaded/src/erl_tracer.erl (limited to 'erts/preloaded/src') diff --git a/erts/preloaded/src/Makefile b/erts/preloaded/src/Makefile index 1e3de9f1d7..4a447d3a09 100644 --- a/erts/preloaded/src/Makefile +++ b/erts/preloaded/src/Makefile @@ -43,7 +43,8 @@ PRE_LOADED_ERL_MODULES = \ otp_ring0 \ erts_code_purger \ erlang \ - erts_internal + erts_internal \ + erl_tracer PRE_LOADED_BEAM_MODULES = \ prim_eval diff --git a/erts/preloaded/src/erl_tracer.erl b/erts/preloaded/src/erl_tracer.erl new file mode 100644 index 0000000000..3415ff3135 --- /dev/null +++ b/erts/preloaded/src/erl_tracer.erl @@ -0,0 +1,41 @@ +-module(erl_tracer). + +-export([enabled/3, trace/6, on_load/0]). + +-type tracee() :: port() | pid() | undefined. +-type trace_tag() :: send | send_to_non_existing_process | 'receive' | + call | return_to | return_from | exception_from | + spawn | exit | link | unlink | getting_linked | + getting_unlinked | register | unregister | in | out | + gc_start | gc_end. +-type trace_opts() :: #{ match_spec_result => true | term(), + scheduler_id => undefined | non_neg_integer(), + timestamp => undefined | timestamp | cpu_timestamp | + monotonic | strict_monotonic }. +-type tracer_state() :: term(). + +on_load() -> + case erlang:load_nif(atom_to_list(?MODULE), 0) of + ok -> ok + end. + +%%% +%%% NIF placeholders +%%% + +-spec enabled(Tag :: trace_tag() | seq_trace | trace_status, + TracerState :: tracer_state(), + Tracee :: tracee()) -> + trace | discard | remove. +enabled(_, _, _) -> + erlang:nif_error(nif_not_loaded). + +-spec trace(Tag :: trace_tag() | seq_trace, + TracerState :: tracer_state(), + Tracee :: tracee(), + Msg :: term(), + Extra :: term(), + Opts :: trace_opts()) -> any(). + +trace(_, _, _, _, _, _) -> + erlang:nif_error(nif_not_loaded). diff --git a/erts/preloaded/src/erlang.erl b/erts/preloaded/src/erlang.erl index 4374bdcd89..8d6d17b043 100644 --- a/erts/preloaded/src/erlang.erl +++ b/erts/preloaded/src/erlang.erl @@ -245,12 +245,14 @@ set_on_first_spawn | set_on_link | set_on_first_link | - {tracer, pid() | port()}. + {tracer, pid() | port()} | + {tracer, module(), term()}. -type trace_info_item_result() :: {traced, global | local | false | undefined} | {match_spec, trace_match_spec() | false | undefined} | {meta, pid() | port() | false | undefined | []} | + {meta, module(), term() } | {meta_match_spec, trace_match_spec() | false | undefined} | {call_count, non_neg_integer() | boolean() | undefined} | {call_time, [{pid(), non_neg_integer(), @@ -276,6 +278,7 @@ undefined | {flags, [trace_info_flag()]} | {tracer, pid() | port() | []} | + {tracer, module(), term()} | trace_info_item_result() | {all, [ trace_info_item_result() ] | false | undefined}. @@ -1709,8 +1712,28 @@ time() -> PidSpec :: pid() | existing | new | all, How :: boolean(), FlagList :: [trace_flag()]. -trace(_PidSpec, _How, _FlagList) -> - erlang:nif_error(undefined). +trace(PidSpec, How, FlagList) -> + %% Make sure that we have loaded the tracer module + case lists:keyfind(tracer, 1, FlagList) of + {tracer, Module, State} when erlang:is_atom(Module) -> + case erlang:module_loaded(Module) of + false -> + Module:enabled(trace_status, erlang:self(), State); + true -> + ok + end; + _ -> + ignore + end, + + try erts_internal:trace(PidSpec, How, FlagList) of + Res -> Res + catch E:R -> + {_, [_ | CST]} = erlang:process_info( + erlang:self(), current_stacktrace), + erlang:raise( + E, R, [{?MODULE, trace, [PidSpec, How, FlagList], []} | CST]) + end. %% trace_delivered/1 -spec erlang:trace_delivered(Tracee) -> Ref when @@ -2319,7 +2342,7 @@ subtract(_,_) -> OldState :: preliminary | final | volatile; %% These are deliberately not documented (internal_cpu_topology, term()) -> term(); - (sequential_tracer, pid() | port() | false) -> pid() | port() | false; + (sequential_tracer, pid() | port() | {module(), term()} | false) -> pid() | port() | false; (1,0) -> true. system_flag(_Flag, _Value) -> @@ -2355,12 +2378,20 @@ tl(_List) -> | boolean() | restart | pause. -trace_pattern(_MFA, _MatchSpec) -> - erlang:nif_error(undefined). +trace_pattern(MFA, MatchSpec) -> + try erts_internal:trace_pattern(MFA, MatchSpec, []) of + Res -> Res + catch E:R -> + {_, [_ | CST]} = erlang:process_info( + erlang:self(), current_stacktrace), + erlang:raise( + E, R, [{?MODULE, trace_pattern, [MFA, MatchSpec], []} | CST]) + end. -type trace_pattern_flag() :: global | local | meta | {meta, Pid :: pid()} | + {meta, TracerModule :: module(), TracerState :: term()} | call_count | call_time. @@ -2371,8 +2402,28 @@ trace_pattern(_MFA, _MatchSpec) -> | restart | pause, FlagList :: [ trace_pattern_flag() ]. -trace_pattern(_MFA, _MatchSpec, _FlagList) -> - erlang:nif_error(undefined). +trace_pattern(MFA, MatchSpec, FlagList) -> + %% Make sure that we have loaded the tracer module + case lists:keyfind(meta, 1, FlagList) of + {meta, Module, State} when erlang:is_atom(Module) -> + case erlang:module_loaded(Module) of + false -> + Module:enabled(trace_status, erlang:self(), State); + true -> + ok + end; + _ -> + ignore + end, + + try erts_internal:trace_pattern(MFA, MatchSpec, FlagList) of + Res -> Res + catch E:R -> + {_, [_ | CST]} = erlang:process_info( + erlang:self(), current_stacktrace), + erlang:raise( + E, R, [{?MODULE, trace_pattern, [MFA, MatchSpec, FlagList], []} | CST]) + end. %% Shadowed by erl_bif_types: erlang:tuple_to_list/1 -spec tuple_to_list(Tuple) -> [term()] when diff --git a/erts/preloaded/src/erts_internal.erl b/erts/preloaded/src/erts_internal.erl index 769757ba75..2459ea2a2c 100644 --- a/erts/preloaded/src/erts_internal.erl +++ b/erts/preloaded/src/erts_internal.erl @@ -55,7 +55,9 @@ -export([await_microstate_accounting_modifications/3, gather_microstate_accounting_result/2]). -%% Auto-import name clash +-export([trace/3, trace_pattern/3]). + +%% Auto import name clash -export([check_process_code/2]). %% @@ -403,3 +405,28 @@ microstate_accounting(Ref, Threads) -> {Ref, Res} -> [Res | microstate_accounting(Ref, Threads - 1)] end. + +-spec trace(PidPortSpec, How, FlagList) -> integer() when + PidPortSpec :: pid() | port() + | all | processes | ports + | existing | existing_processes | existing_ports + | new | new_processes | new_ports, + How :: boolean(), + FlagList :: []. +trace(_PidSpec, _How, _FlagList) -> + erlang:nif_error(undefined). + +-type trace_pattern_mfa() :: + {atom(),atom(),arity() | '_'} | on_load. +-type trace_match_spec() :: + [{[term()] | '_' ,[term()],[term()]}]. + +-spec trace_pattern(MFA, MatchSpec, FlagList) -> non_neg_integer() when + MFA :: trace_pattern_mfa(), + MatchSpec :: (MatchSpecList :: trace_match_spec()) + | boolean() + | restart + | pause, + FlagList :: [ ]. +trace_pattern(_MFA, _MatchSpec, _FlagList) -> + erlang:nif_error(undefined). diff --git a/erts/preloaded/src/init.erl b/erts/preloaded/src/init.erl index 5d5d2f8012..77684751c8 100644 --- a/erts/preloaded/src/init.erl +++ b/erts/preloaded/src/init.erl @@ -179,6 +179,10 @@ stop(Status) -> init ! {stop,{stop,Status}}, ok. boot(BootArgs) -> register(init, self()), process_flag(trap_exit, true), + + %% Load the tracer nif + erl_tracer:on_load(), + {Start0,Flags,Args} = parse_boot_args(BootArgs), Start = map(fun prepare_run_args/1, Start0), boot(Start, Flags, Args). -- cgit v1.2.3 From 6cb6b59cd4cd5bd4383053e12ae8ab192711c827 Mon Sep 17 00:00:00 2001 From: Lukas Larsson Date: Mon, 8 Feb 2016 18:31:43 +0100 Subject: erts: Extend process and port tracing This commit completes the tracing for processes so that all messages sent by a process (via nifs or otherwise) will be traced. The commit also adds tracing of all types of events from ports. When enabling tracing using erlang:trace, the 'all' flag now also enables tracing on all ports. OTP-13496 --- erts/preloaded/src/erl_tracer.erl | 3 ++- erts/preloaded/src/erlang.erl | 30 +++++++++++++++++++----------- 2 files changed, 21 insertions(+), 12 deletions(-) (limited to 'erts/preloaded/src') diff --git a/erts/preloaded/src/erl_tracer.erl b/erts/preloaded/src/erl_tracer.erl index 3415ff3135..a8da2b4c14 100644 --- a/erts/preloaded/src/erl_tracer.erl +++ b/erts/preloaded/src/erl_tracer.erl @@ -7,7 +7,8 @@ call | return_to | return_from | exception_from | spawn | exit | link | unlink | getting_linked | getting_unlinked | register | unregister | in | out | - gc_start | gc_end. + in_exiting | out_exiting | out_exited | + open | closed | gc_start | gc_end. -type trace_opts() :: #{ match_spec_result => true | term(), scheduler_id => undefined | non_neg_integer(), timestamp => undefined | timestamp | cpu_timestamp | diff --git a/erts/preloaded/src/erlang.erl b/erts/preloaded/src/erlang.erl index 8d6d17b043..40d0abd321 100644 --- a/erts/preloaded/src/erlang.erl +++ b/erts/preloaded/src/erlang.erl @@ -230,17 +230,20 @@ send | 'receive' | procs | + ports | call | - silent | + arity | return_to | + silent | running | exiting | + running_procs | + running_ports | garbage_collection | timestamp | cpu_timestamp | monotonic_timestamp | strict_monotonic_timestamp | - arity | set_on_spawn | set_on_first_spawn | set_on_link | @@ -1708,11 +1711,14 @@ time() -> erlang:nif_error(undefined). %% trace/3 --spec erlang:trace(PidSpec, How, FlagList) -> integer() when - PidSpec :: pid() | existing | new | all, +-spec erlang:trace(PidPortSpec, How, FlagList) -> integer() when + PidPortSpec :: pid() | port() + | all | processes | ports + | existing | existing_processes | existing_ports + | new | new_processes | new_ports, How :: boolean(), FlagList :: [trace_flag()]. -trace(PidSpec, How, FlagList) -> +trace(PidPortSpec, How, FlagList) -> %% Make sure that we have loaded the tracer module case lists:keyfind(tracer, 1, FlagList) of {tracer, Module, State} when erlang:is_atom(Module) -> @@ -1726,13 +1732,13 @@ trace(PidSpec, How, FlagList) -> ignore end, - try erts_internal:trace(PidSpec, How, FlagList) of + try erts_internal:trace(PidPortSpec, How, FlagList) of Res -> Res catch E:R -> {_, [_ | CST]} = erlang:process_info( erlang:self(), current_stacktrace), erlang:raise( - E, R, [{?MODULE, trace, [PidSpec, How, FlagList], []} | CST]) + E, R, [{?MODULE, trace, [PidPortSpec, How, FlagList], []} | CST]) end. %% trace_delivered/1 @@ -1743,14 +1749,16 @@ trace_delivered(_Tracee) -> erlang:nif_error(undefined). %% trace_info/2 --spec erlang:trace_info(PidOrFunc, Item) -> Res when - PidOrFunc :: pid() | new | {Module, Function, Arity} | on_load, +-spec erlang:trace_info(PidPortOrFunc, Item) -> Res when + PidPortOrFunc :: pid() | port() | new | new_processes | new_ports + | {Module, Function, Arity} | on_load, Module :: module(), Function :: atom(), Arity :: arity(), - Item :: flags | tracer | traced | match_spec | meta | meta_match_spec | call_count | call_time | all, + Item :: flags | tracer | traced | match_spec + | meta | meta_match_spec | call_count | call_time | all, Res :: trace_info_return(). -trace_info(_PidOrFunc, _Item) -> +trace_info(_PidPortOrFunc, _Item) -> erlang:nif_error(undefined). %% trunc/1 -- cgit v1.2.3 From 3738103d0b1195e570a7525c4370cd490a5368aa Mon Sep 17 00:00:00 2001 From: Lukas Larsson Date: Mon, 29 Feb 2016 15:09:26 +0100 Subject: erts: Add 'spawned' trace event to 'procs' trace flag OTP-13497 This trace event is triggered when a process is created from the process that is created. --- erts/preloaded/src/erl_tracer.erl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'erts/preloaded/src') diff --git a/erts/preloaded/src/erl_tracer.erl b/erts/preloaded/src/erl_tracer.erl index a8da2b4c14..2177e48f60 100644 --- a/erts/preloaded/src/erl_tracer.erl +++ b/erts/preloaded/src/erl_tracer.erl @@ -5,7 +5,7 @@ -type tracee() :: port() | pid() | undefined. -type trace_tag() :: send | send_to_non_existing_process | 'receive' | call | return_to | return_from | exception_from | - spawn | exit | link | unlink | getting_linked | + spawn | spawned | exit | link | unlink | getting_linked | getting_unlinked | register | unregister | in | out | in_exiting | out_exiting | out_exited | open | closed | gc_start | gc_end. -- cgit v1.2.3 From 8e2ec999394c77741241ef1a12728b11195961c8 Mon Sep 17 00:00:00 2001 From: Lukas Larsson Date: Mon, 21 Mar 2016 17:53:26 +0100 Subject: erts: Document erlang:match_spec_test/3 OTP-13501 --- erts/preloaded/src/erlang.erl | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'erts/preloaded/src') diff --git a/erts/preloaded/src/erlang.erl b/erts/preloaded/src/erlang.erl index 40d0abd321..3cc17014ff 100644 --- a/erts/preloaded/src/erlang.erl +++ b/erts/preloaded/src/erlang.erl @@ -1163,10 +1163,10 @@ map_size(_Map) -> erlang:nif_error(undefined). %% match_spec_test/3 --spec erlang:match_spec_test(P1, P2, P3) -> TestResult when - P1 :: [term()] | tuple(), - P2 :: term(), - P3 :: table | trace, +-spec erlang:match_spec_test(MatchAgainst, MatchSpec, Type) -> TestResult when + MatchAgainst :: [term()] | tuple(), + MatchSpec :: term(), + Type :: table | trace, TestResult :: {ok, term(), [return_trace], [ {error | warning, string()} ]} | {error, [ {error | warning, string()} ]}. match_spec_test(_P1, _P2, _P3) -> erlang:nif_error(undefined). -- cgit v1.2.3 From 4acfd18a0e934789f752fd48d3031e48cdd3fbde Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn-Egil=20Dahlberg?= Date: Tue, 26 Apr 2016 15:28:48 +0200 Subject: erts: Add profiling of startup Usage: erl -profile_boot ... --- erts/preloaded/src/init.erl | 76 ++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 75 insertions(+), 1 deletion(-) (limited to 'erts/preloaded/src') diff --git a/erts/preloaded/src/init.erl b/erts/preloaded/src/init.erl index 77684751c8..618b53f6bb 100644 --- a/erts/preloaded/src/init.erl +++ b/erts/preloaded/src/init.erl @@ -41,6 +41,7 @@ %% -s : Start own processes. %% %% Experimental flags: +%% -profile_boot : Use an 'eprof light' to profile boot sequence %% -init_debug : Activate debug printouts in init %% -loader_debug : Activate debug printouts in erl_prim_loader %% -code_path_choice : strict | relaxed @@ -184,6 +185,11 @@ boot(BootArgs) -> erl_tracer:on_load(), {Start0,Flags,Args} = parse_boot_args(BootArgs), + %% We don't get to profile parsing of BootArgs + case get_flag(profile_boot, Flags, false) of + false -> ok; + true -> debug_profile_start() + end, Start = map(fun prepare_run_args/1, Start0), boot(Start, Flags, Args). @@ -765,7 +771,14 @@ do_boot(Init,Flags,Start) -> %% print the node name into the Purify log. (catch erlang:system_info({purify, "Node: " ++ atom_to_list(node())})), - start_em(Start). + start_em(Start), + case get_flag(profile_boot,Flags,false) of + false -> ok; + true -> + debug_profile_format_mfas(debug_profile_mfas()), + debug_profile_stop() + end, + ok. get_root(Flags) -> case get_argument(root, Flags) of @@ -1339,3 +1352,64 @@ run_on_load_handlers([M|Ms], Debug) -> end end; run_on_load_handlers([], _) -> ok. + + +%% debug profile (light variant of eprof) +debug_profile_start() -> + _ = erlang:trace_pattern({'_','_','_'},true,[call_time]), + _ = erlang:trace_pattern(on_load,true,[call_time]), + _ = erlang:trace(all,true,[call]), + ok. + +debug_profile_stop() -> + _ = erlang:trace_pattern({'_','_','_'},false,[call_time]), + _ = erlang:trace_pattern(on_load,false,[call_time]), + _ = erlang:trace(all,false,[call]), + ok. + +debug_profile_mfas() -> + _ = erlang:trace_pattern({'_','_','_'},pause,[call_time]), + _ = erlang:trace_pattern(on_load,pause,[call_time]), + MFAs = collect_loaded_mfas() ++ erlang:system_info(snifs), + collect_mfas(MFAs,[]). + +%% debug_profile_format_mfas should be called at the end of the boot phase +%% so all pertinent modules should be loaded at that point. +debug_profile_format_mfas(MFAs0) -> + MFAs = lists:sort(MFAs0), + lists:foreach(fun({{Us,C},{M,F,A}}) -> + Str = io_lib:format("~w:~w/~w", [M,F,A]), + io:format(standard_error,"~55s - ~6w : ~w us~n", [Str,C,Us]) + end, MFAs), + ok. + +collect_loaded_mfas() -> + Ms = [M || M <- [element(1, Mi) || Mi <- code:all_loaded()]], + collect_loaded_mfas(Ms,[]). + +collect_loaded_mfas([],MFAs) -> MFAs; +collect_loaded_mfas([M|Ms],MFAs0) -> + MFAs = [{M,F,A} || {F,A} <- M:module_info(functions)], + collect_loaded_mfas(Ms,MFAs ++ MFAs0). + + +collect_mfas([], Info) -> Info; +collect_mfas([MFA|MFAs],Info) -> + case erlang:trace_info(MFA,call_time) of + {call_time, []} -> + collect_mfas(MFAs,Info); + {call_time, false} -> + collect_mfas(MFAs,Info); + {call_time, Data} -> + case collect_mfa(MFA,Data,0,0) of + {{0,_},_} -> + %% ignore mfas with zero time + collect_mfas(MFAs,Info); + MfaData -> + collect_mfas(MFAs,[MfaData|Info]) + end + end. + +collect_mfa(Mfa,[],Count,Time) -> {{Time,Count},Mfa}; +collect_mfa(Mfa,[{_Pid,C,S,Us}|Data],Count,Time) -> + collect_mfa(Mfa,Data,Count + C,Time + S * 1000000 + Us). -- cgit v1.2.3 From a13d4a750dfdf9a2a96d1e7ec0054644187afa59 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Magnus=20L=C3=A5ng?= Date: Sat, 27 Feb 2016 19:23:48 +0100 Subject: Enhance map specs in erts, stdlib, runtime_tools Using the new type syntax, we can specify which keys are required, and which are optional in a way Dialyzer could use. --- erts/preloaded/src/erlang.erl | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'erts/preloaded/src') diff --git a/erts/preloaded/src/erlang.erl b/erts/preloaded/src/erlang.erl index 3cc17014ff..20a64e81b4 100644 --- a/erts/preloaded/src/erlang.erl +++ b/erts/preloaded/src/erlang.erl @@ -2257,9 +2257,9 @@ spawn_opt(_Tuple) -> Input :: non_neg_integer(), Output :: non_neg_integer(); (microstate_accounting) -> [MSAcc_Thread] | undefined when - MSAcc_Thread :: #{ type => MSAcc_Thread_Type, - id => MSAcc_Thread_Id, - counters => MSAcc_Counters}, + MSAcc_Thread :: #{ type := MSAcc_Thread_Type, + id := MSAcc_Thread_Id, + counters := MSAcc_Counters}, MSAcc_Thread_Type :: scheduler | async | aux, MSAcc_Thread_Id :: non_neg_integer(), MSAcc_Counters :: #{ MSAcc_Thread_State => non_neg_integer() }, -- cgit v1.2.3 From 4a3d9ea99f54278640f9c958af5f8389bf7ddde5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn-Egil=20Dahlberg?= Date: Wed, 20 Apr 2016 16:18:36 +0200 Subject: erts: Update erl_tracer type specs --- erts/preloaded/src/erl_tracer.erl | 29 +++++++++++++++++++++++------ 1 file changed, 23 insertions(+), 6 deletions(-) (limited to 'erts/preloaded/src') diff --git a/erts/preloaded/src/erl_tracer.erl b/erts/preloaded/src/erl_tracer.erl index 2177e48f60..de1e9ca01e 100644 --- a/erts/preloaded/src/erl_tracer.erl +++ b/erts/preloaded/src/erl_tracer.erl @@ -3,12 +3,29 @@ -export([enabled/3, trace/6, on_load/0]). -type tracee() :: port() | pid() | undefined. --type trace_tag() :: send | send_to_non_existing_process | 'receive' | - call | return_to | return_from | exception_from | - spawn | spawned | exit | link | unlink | getting_linked | - getting_unlinked | register | unregister | in | out | - in_exiting | out_exiting | out_exited | - open | closed | gc_start | gc_end. + +-type trace_tag_running_ports() :: in | out | in_exiting | out_exiting | out_exited. +-type trace_tag_running_procs() :: in | out | in_exiting | out_exiting | out_exited. +-type trace_tag_send() :: send | send_to_non_existing_process. +-type trace_tag_receive() :: 'receive'. +-type trace_tag_call() :: call | return_to | return_from | exception_from. +-type trace_tag_procs() :: spawn | spawned | exit | link | unlink + | getting_linked | getting_unlinked + | register | unregister. +-type trace_tag_ports() :: open | closed | link | unlink + | getting_linked | getting_unlinked. +-type trace_tag_gc() :: gc_minor_start | gc_minor_end + | gc_major_start | gc_major_end. + +-type trace_tag() :: trace_tag_send() + | trace_tag_receive() + | trace_tag_call() + | trace_tag_procs() + | trace_tag_ports() + | trace_tag_running_procs() + | trace_tag_running_ports() + | trace_tag_gc(). + -type trace_opts() :: #{ match_spec_result => true | term(), scheduler_id => undefined | non_neg_integer(), timestamp => undefined | timestamp | cpu_timestamp | -- cgit v1.2.3 From 36e9d73aa08930ddf3e3587addfb9a647a41b3e7 Mon Sep 17 00:00:00 2001 From: Sverker Eriksson Date: Wed, 6 Apr 2016 15:05:10 +0200 Subject: erts: Add docs for trace_pattern with 'send' and 'receive' --- erts/preloaded/src/erlang.erl | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) (limited to 'erts/preloaded/src') diff --git a/erts/preloaded/src/erlang.erl b/erts/preloaded/src/erlang.erl index 20a64e81b4..d09958032b 100644 --- a/erts/preloaded/src/erlang.erl +++ b/erts/preloaded/src/erlang.erl @@ -2381,7 +2381,7 @@ tl(_List) -> [{[term()] | '_' ,[term()],[term()]}]. -spec erlang:trace_pattern(MFA, MatchSpec) -> non_neg_integer() when - MFA :: trace_pattern_mfa(), + MFA :: trace_pattern_mfa() | send | 'receive', MatchSpec :: (MatchSpecList :: trace_match_spec()) | boolean() | restart @@ -2403,7 +2403,13 @@ trace_pattern(MFA, MatchSpec) -> call_count | call_time. --spec erlang:trace_pattern(MFA, MatchSpec, FlagList) -> non_neg_integer() when +-spec erlang:trace_pattern(send, MatchSpec, []) -> non_neg_integer() when + MatchSpec :: (MatchSpecList :: trace_match_spec()) + | boolean(); + ('receive', MatchSpec, []) -> non_neg_integer() when + MatchSpec :: (MatchSpecList :: trace_match_spec()) + | boolean(); + (MFA, MatchSpec, FlagList) -> non_neg_integer() when MFA :: trace_pattern_mfa(), MatchSpec :: (MatchSpecList :: trace_match_spec()) | boolean() -- cgit v1.2.3 From 54172674e71caf7da7a0b069c9bd92543e4f705d Mon Sep 17 00:00:00 2001 From: Sverker Eriksson Date: Wed, 4 May 2016 14:45:05 +0200 Subject: erts: Add send and 'receive' to trace_info/2 to obtain match specs --- erts/preloaded/src/erlang.erl | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'erts/preloaded/src') diff --git a/erts/preloaded/src/erlang.erl b/erts/preloaded/src/erlang.erl index d09958032b..90fd536b15 100644 --- a/erts/preloaded/src/erlang.erl +++ b/erts/preloaded/src/erlang.erl @@ -1749,16 +1749,16 @@ trace_delivered(_Tracee) -> erlang:nif_error(undefined). %% trace_info/2 --spec erlang:trace_info(PidPortOrFunc, Item) -> Res when - PidPortOrFunc :: pid() | port() | new | new_processes | new_ports - | {Module, Function, Arity} | on_load, +-spec erlang:trace_info(PidPortFuncEvent, Item) -> Res when + PidPortFuncEvent :: pid() | port() | new | new_processes | new_ports + | {Module, Function, Arity} | on_load | send | 'receive', Module :: module(), Function :: atom(), Arity :: arity(), Item :: flags | tracer | traced | match_spec | meta | meta_match_spec | call_count | call_time | all, Res :: trace_info_return(). -trace_info(_PidPortOrFunc, _Item) -> +trace_info(_PidPortFuncEvent, _Item) -> erlang:nif_error(undefined). %% trunc/1 -- cgit v1.2.3 From e146a3eec5a2d384260aa8829777c89eaab09cbd Mon Sep 17 00:00:00 2001 From: Lukas Larsson Date: Thu, 21 Apr 2016 18:36:45 +0200 Subject: erts: Implement max_heap_size process flag The max_heap_size process flag can be used to limit the growth of a process heap by killing it before it becomes too large to handle. It is possible to set the maximum using the `erl +hmax` option, `system_flag(max_heap_size, ...)`, `spawn_opt(Fun, [{max_heap_size, ...}])` and `process_flag(max_heap_size, ...)`. It is possible to configure the behaviour of the process when the maximum heap size is reached. The process may be sent an untrappable exit signal with reason kill and/or send an error_logger message with details on the process state. A new trace event called gc_max_heap_size is also triggered for the garbage_collection trace flag when the heap grows larger than the configured size. If kill and error_logger are disabled, it is still possible to see that the maximum has been reached by doing garbage collection tracing on the process. The heap size is defined as the sum of the heap memory that the process is currently using. This includes all generational heaps, the stack, any messages that are considered to be part of the heap and any extra memory the garbage collector may need during collection. In the current implementation this means that when a process is set using on_heap message queue data mode, the messages that are in the internal message queue are counted towards this value. For off_heap, only matched messages count towards the size of the heap. For mixed, it depends on race conditions within the VM whether a message is part of the heap or not. Below is an example run of the new behaviour: Eshell V8.0 (abort with ^G) 1> f(P),P = spawn_opt(fun() -> receive ok -> ok end end, [{max_heap_size, 512}]). <0.60.0> 2> erlang:trace(P, true, [garbage_collection, procs]). 1 3> [P ! lists:duplicate(M,M) || M <- lists:seq(1,15)],ok. ok 4> =ERROR REPORT==== 26-Apr-2016::16:25:10 === Process: <0.60.0> Context: maximum heap size reached Max heap size: 512 Total heap size: 723 Kill: true Error Logger: true GC Info: [{old_heap_block_size,0}, {heap_block_size,609}, {mbuf_size,145}, {recent_size,0}, {stack_size,9}, {old_heap_size,0}, {heap_size,211}, {bin_vheap_size,0}, {bin_vheap_block_size,46422}, {bin_old_vheap_size,0}, {bin_old_vheap_block_size,46422}] flush(). Shell got {trace,<0.60.0>,gc_start, [{old_heap_block_size,0}, {heap_block_size,233}, {mbuf_size,145}, {recent_size,0}, {stack_size,9}, {old_heap_size,0}, {heap_size,211}, {bin_vheap_size,0}, {bin_vheap_block_size,46422}, {bin_old_vheap_size,0}, {bin_old_vheap_block_size,46422}]} Shell got {trace,<0.60.0>,gc_max_heap_size, [{old_heap_block_size,0}, {heap_block_size,609}, {mbuf_size,145}, {recent_size,0}, {stack_size,9}, {old_heap_size,0}, {heap_size,211}, {bin_vheap_size,0}, {bin_vheap_block_size,46422}, {bin_old_vheap_size,0}, {bin_old_vheap_block_size,46422}]} Shell got {trace,<0.60.0>,exit,killed} --- erts/preloaded/src/erlang.erl | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) (limited to 'erts/preloaded/src') diff --git a/erts/preloaded/src/erlang.erl b/erts/preloaded/src/erlang.erl index 90fd536b15..3d152c4e92 100644 --- a/erts/preloaded/src/erlang.erl +++ b/erts/preloaded/src/erlang.erl @@ -2073,6 +2073,9 @@ open_port(PortName, PortSettings) -> (min_bin_vheap_size, MinBinVHeapSize) -> OldMinBinVHeapSize when MinBinVHeapSize :: non_neg_integer(), OldMinBinVHeapSize :: non_neg_integer(); + (max_heap_size, MaxHeapSize) -> OldMaxHeapSize when + MaxHeapSize :: max_heap_size(), + OldMaxHeapSize :: max_heap_size(); (message_queue_data, MQD) -> OldMQD when MQD :: message_queue_data(), OldMQD :: message_queue_data(); @@ -2154,6 +2157,7 @@ process_flag(_Flag, _Value) -> {messages, MessageQueue :: [term()]} | {min_heap_size, MinHeapSize :: non_neg_integer()} | {min_bin_vheap_size, MinBinVHeapSize :: non_neg_integer()} | + {max_heap_size, MaxHeapSize :: max_heap_size()} | {monitored_by, Pids :: [pid()]} | {monitors, Monitors :: [{process, Pid :: pid() | @@ -2238,6 +2242,7 @@ setelement(_Index, _Tuple1, _Value) -> | {priority, Level :: priority_level()} | {fullsweep_after, Number :: non_neg_integer()} | {min_heap_size, Size :: non_neg_integer()} + | {max_heap_size, Size :: max_heap_size()} | {min_bin_vheap_size, VSize :: non_neg_integer()}. spawn_opt(_Tuple) -> erlang:nif_error(undefined). @@ -2330,6 +2335,9 @@ subtract(_,_) -> OldMinBinVHeapSize when MinBinVHeapSize :: non_neg_integer(), OldMinBinVHeapSize :: non_neg_integer(); + (max_heap_size, MaxHeapSize) -> OldMaxHeapSize when + MaxHeapSize :: max_heap_size(), + OldMaxHeapSize :: max_heap_size(); (multi_scheduling, BlockState) -> OldBlockState when BlockState :: block | unblock | block_normal | unblock_normal, OldBlockState :: blocked | disabled | enabled; @@ -2511,6 +2519,7 @@ tuple_to_list(_Tuple) -> logical_processors_available | logical_processors_online) -> unknown | pos_integer(); (machine) -> string(); + (max_heap_size) -> {max_heap_size, MaxHeapSize :: max_heap_size()}; (message_queue_data) -> message_queue_data(); (min_heap_size) -> {min_heap_size, MinHeapSize :: pos_integer()}; (min_bin_vheap_size) -> {min_bin_vheap_size, @@ -2648,6 +2657,13 @@ spawn_monitor(M, F, A) -> erlang:error(badarg, [M,F,A]). +-type max_heap_size() :: + Size :: non_neg_integer() + %% TODO change size => to := when -type maps support is finalized + | #{ size => non_neg_integer(), + kill => boolean(), + error_logger => boolean() }. + -type spawn_opt_option() :: link | monitor @@ -2655,6 +2671,7 @@ spawn_monitor(M, F, A) -> | {fullsweep_after, Number :: non_neg_integer()} | {min_heap_size, Size :: non_neg_integer()} | {min_bin_vheap_size, VSize :: non_neg_integer()} + | {max_heap_size, Size :: max_heap_size()} | {message_queue_data, MQD :: message_queue_data()}. -spec spawn_opt(Fun, Options) -> pid() | {pid(), reference()} when -- cgit v1.2.3 From 3471d44a6a5ed5ab038c4cdc76b350119fe745e2 Mon Sep 17 00:00:00 2001 From: Lukas Larsson Date: Wed, 11 May 2016 11:16:16 +0200 Subject: erts: Only allow remove from trace_status callback Make it so that it is only possible to remove a tracer via returning remove from an erl_tracer. This limition is put in place in order to avoid a lot of lock checking and taking in various places, especially in regards to trace events happening on dirty schedulers. --- erts/preloaded/src/erl_tracer.erl | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'erts/preloaded/src') diff --git a/erts/preloaded/src/erl_tracer.erl b/erts/preloaded/src/erl_tracer.erl index de1e9ca01e..fe15812535 100644 --- a/erts/preloaded/src/erl_tracer.erl +++ b/erts/preloaded/src/erl_tracer.erl @@ -41,10 +41,14 @@ on_load() -> %%% NIF placeholders %%% --spec enabled(Tag :: trace_tag() | seq_trace | trace_status, +-spec enabled(Tag :: trace_status, TracerState :: tracer_state(), Tracee :: tracee()) -> - trace | discard | remove. + trace | remove; + (Tag :: trace_tag() | seq_trace, + TracerState :: tracer_state(), + Tracee :: tracee()) -> + trace | discard. enabled(_, _, _) -> erlang:nif_error(nif_not_loaded). -- cgit v1.2.3 From cc59f962511733c5dfcb1be27a274f9298736006 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Gustavsson?= Date: Mon, 16 May 2016 14:56:03 +0200 Subject: Tolerate bad directories in the code path A bad directory in the path would prevent the run-time system from starting: $ echo >foobar $ erl -pa foobar {"init terminating in do_boot",{load_failed,[supervisor,kernel,gen_server,file_io_server,filename,file,erl_parse,error_logger,code_server,erl_lint,proc_lib,code,application_controller,application_master,gen_event,application,error_handler,lists,heart,gen,file_server,ets,erl_eval]}} Crash dump is being written to: erl_crash.dump...done init terminating in do_boot () The reason is that when attempting to read each of the BEAM files, there would be an 'enotdir' error which erl_prim_load:get_modules/2,3 assumed was a fatal error. Update erl_prim_load:get_modules/2,3 to ignore any error and try the next directory in the path. Reported-by: http://bugs.erlang.org/browse/ERL-142 Reported-by: Michael Truog --- erts/preloaded/src/erl_prim_loader.erl | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'erts/preloaded/src') diff --git a/erts/preloaded/src/erl_prim_loader.erl b/erts/preloaded/src/erl_prim_loader.erl index e18e187cb7..b3ec73a60e 100644 --- a/erts/preloaded/src/erl_prim_loader.erl +++ b/erts/preloaded/src/erl_prim_loader.erl @@ -558,11 +558,9 @@ efile_gm_get_1([P|Ps], File0, Mod, {Parent,Ref}=PR, Process) -> Res = try prim_file:read_file(File) of {ok,Bin} -> gm_process(Mod, File, Bin, Process); - {error,enoent} -> - efile_gm_get_1(Ps, File0, Mod, PR, Process); Error -> - check_file_result(get_modules, File, Error), - Error + _ = check_file_result(get_modules, File, Error), + efile_gm_get_1(Ps, File0, Mod, PR, Process) catch _:Reason -> {error,{crash,Reason}} -- cgit v1.2.3 From be353901879b3cccda7cd01947936cf1550dea04 Mon Sep 17 00:00:00 2001 From: Richard Carlsson Date: Tue, 1 Dec 2015 11:25:12 +0100 Subject: Check exit status in init:stop/1 and simplify documentation --- erts/preloaded/src/init.erl | 36 ++++++++++++++++++++++++++---------- 1 file changed, 26 insertions(+), 10 deletions(-) (limited to 'erts/preloaded/src') diff --git a/erts/preloaded/src/init.erl b/erts/preloaded/src/init.erl index 618b53f6bb..04c5210aa3 100644 --- a/erts/preloaded/src/init.erl +++ b/erts/preloaded/src/init.erl @@ -90,6 +90,8 @@ -define(ON_LOAD_HANDLER, init__boot__on_load_handler). +-define(MAX_HALT_STRING_SIZE, 199). + debug(false, _) -> ok; debug(_, T) -> erlang:display(T). @@ -173,7 +175,25 @@ stop() -> init ! {stop,stop}, ok. -spec stop(Status) -> 'ok' when Status :: non_neg_integer() | string(). -stop(Status) -> init ! {stop,{stop,Status}}, ok. +stop(Status) when is_integer(Status), Status >= 0 -> + stop_1(Status); +stop(Status) when is_list(Status) -> + case is_bytelist(Status) of + true -> + stop_1(limit_halt_string(Status)); + false -> + erlang:error(badarg) + end; +stop(_) -> + erlang:error(badarg). + +is_bytelist([B|Bs]) when is_integer(B), B >= 0, B < 256 -> is_bytelist(Bs); +is_bytelist([]) -> true; +is_bytelist(_) -> false. + +%% Note that we check the type of Status beforehand to ensure that +%% the call to halt(Status) by the init process cannot fail +stop_1(Status) -> init ! {stop,{stop,Status}}, ok. -spec boot(BootArgs) -> no_return() when BootArgs :: [binary()]. @@ -285,16 +305,12 @@ things_to_string([]) -> "". halt_string(String, List) -> - HaltString = String ++ things_to_string(List), - if - length(HaltString)<199 -> HaltString; - true -> first198(HaltString, 198) - end. + limit_halt_string(String ++ things_to_string(List)). -first198([H|T], N) when N>0 -> - [H|first198(T, N-1)]; -first198(_, 0) -> - []. +limit_halt_string(String) when length(String) < ?MAX_HALT_STRING_SIZE -> + String; +limit_halt_string(String) -> + lists:sublist(String, ?MAX_HALT_STRING_SIZE-1). %% String = string() %% List = [string() | atom() | pid() | number()] -- cgit v1.2.3 From 115f0ba77ad7d01ab95fd9f9bbeca53f04f12284 Mon Sep 17 00:00:00 2001 From: Lukas Larsson Date: Thu, 19 May 2016 10:54:43 +0200 Subject: erts: Move tracer SecondTraceTerm to Opts map The extra trace data has been moved to the opts map in order for the tracer to be able to distinguish inbetween extra trace data 'undefined' and no extra trace data. In the same commit all opts associations have been changed so that if the tracer should not use them, the key is left unassicated instead of being sent to undefined. This should be give a small performance gain and also makes the API easier to work with. --- erts/preloaded/src/erl_tracer.erl | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) (limited to 'erts/preloaded/src') diff --git a/erts/preloaded/src/erl_tracer.erl b/erts/preloaded/src/erl_tracer.erl index fe15812535..c810069d17 100644 --- a/erts/preloaded/src/erl_tracer.erl +++ b/erts/preloaded/src/erl_tracer.erl @@ -1,6 +1,6 @@ -module(erl_tracer). --export([enabled/3, trace/6, on_load/0]). +-export([enabled/3, trace/5, on_load/0]). -type tracee() :: port() | pid() | undefined. @@ -26,9 +26,9 @@ | trace_tag_running_ports() | trace_tag_gc(). --type trace_opts() :: #{ match_spec_result => true | term(), - scheduler_id => undefined | non_neg_integer(), - timestamp => undefined | timestamp | cpu_timestamp | +-type trace_opts() :: #{ extra => term(), match_spec_result => term(), + scheduler_id => non_neg_integer(), + timestamp => timestamp | cpu_timestamp | monotonic | strict_monotonic }. -type tracer_state() :: term(). @@ -41,6 +41,9 @@ on_load() -> %%% NIF placeholders %%% +%% This suppression is needed as trace_tag gets collapsed to atom() +-dialyzer({no_contracts, enabled/3}). + -spec enabled(Tag :: trace_status, TracerState :: tracer_state(), Tracee :: tracee()) -> @@ -56,8 +59,7 @@ enabled(_, _, _) -> TracerState :: tracer_state(), Tracee :: tracee(), Msg :: term(), - Extra :: term(), Opts :: trace_opts()) -> any(). -trace(_, _, _, _, _, _) -> +trace(_, _, _, _, _) -> erlang:nif_error(nif_not_loaded). -- cgit v1.2.3 From f9cb80861f169743a96099a06d68149a91f18dfa Mon Sep 17 00:00:00 2001 From: Sverker Eriksson Date: Fri, 20 May 2016 15:58:04 +0200 Subject: erts: Implement halt/0 and halt/1 in Erlang just to make things simpler. --- erts/preloaded/src/erlang.erl | 8 +++----- erts/preloaded/src/init.erl | 1 + 2 files changed, 4 insertions(+), 5 deletions(-) (limited to 'erts/preloaded/src') diff --git a/erts/preloaded/src/erlang.erl b/erts/preloaded/src/erlang.erl index 3d152c4e92..4c456bbed4 100644 --- a/erts/preloaded/src/erlang.erl +++ b/erts/preloaded/src/erlang.erl @@ -977,17 +977,15 @@ group_leader(_GroupLeader, _Pid) -> erlang:nif_error(undefined). %% halt/0 -%% Shadowed by erl_bif_types: erlang:halt/0 -spec halt() -> no_return(). halt() -> - erlang:nif_error(undefined). + erlang:halt(0, []). %% halt/1 -%% Shadowed by erl_bif_types: erlang:halt/1 -spec halt(Status) -> no_return() when Status :: non_neg_integer() | 'abort' | string(). -halt(_Status) -> - erlang:nif_error(undefined). +halt(Status) -> + erlang:halt(Status, []). %% halt/2 %% Shadowed by erl_bif_types: erlang:halt/2 diff --git a/erts/preloaded/src/init.erl b/erts/preloaded/src/init.erl index 04c5210aa3..e8f02f5056 100644 --- a/erts/preloaded/src/init.erl +++ b/erts/preloaded/src/init.erl @@ -316,6 +316,7 @@ limit_halt_string(String) -> %% List = [string() | atom() | pid() | number()] %% Any other items in List, such as tuples, are ignored when creating %% the string used as argument to erlang:halt/1. +-spec crash(_, _) -> no_return(). crash(String, List) -> halt(halt_string(String, List)). -- cgit v1.2.3 From e5b7f259be44efa45ec8ee3355577e691754cc63 Mon Sep 17 00:00:00 2001 From: Sverker Eriksson Date: Fri, 20 May 2016 18:10:25 +0200 Subject: erts: Remove unnecessary halt string truncation as erlang:halt does it for us now --- erts/preloaded/src/init.erl | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) (limited to 'erts/preloaded/src') diff --git a/erts/preloaded/src/init.erl b/erts/preloaded/src/init.erl index e8f02f5056..45468b3b9c 100644 --- a/erts/preloaded/src/init.erl +++ b/erts/preloaded/src/init.erl @@ -90,7 +90,6 @@ -define(ON_LOAD_HANDLER, init__boot__on_load_handler). --define(MAX_HALT_STRING_SIZE, 199). debug(false, _) -> ok; debug(_, T) -> erlang:display(T). @@ -180,7 +179,7 @@ stop(Status) when is_integer(Status), Status >= 0 -> stop(Status) when is_list(Status) -> case is_bytelist(Status) of true -> - stop_1(limit_halt_string(Status)); + stop_1(Status); false -> erlang:error(badarg) end; @@ -305,12 +304,7 @@ things_to_string([]) -> "". halt_string(String, List) -> - limit_halt_string(String ++ things_to_string(List)). - -limit_halt_string(String) when length(String) < ?MAX_HALT_STRING_SIZE -> - String; -limit_halt_string(String) -> - lists:sublist(String, ?MAX_HALT_STRING_SIZE-1). + String ++ things_to_string(List). %% String = string() %% List = [string() | atom() | pid() | number()] -- cgit v1.2.3 From 36f98375d57daaba3fec42bb91482cdac9ef4cc9 Mon Sep 17 00:00:00 2001 From: Rickard Green Date: Wed, 25 May 2016 16:15:36 +0200 Subject: Remove the 'message_queue_data' option 'mixed' --- erts/preloaded/src/erlang.erl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'erts/preloaded/src') diff --git a/erts/preloaded/src/erlang.erl b/erts/preloaded/src/erlang.erl index 3d152c4e92..f3f8696f32 100644 --- a/erts/preloaded/src/erlang.erl +++ b/erts/preloaded/src/erlang.erl @@ -2059,7 +2059,7 @@ open_port(PortName, PortSettings) -> low | normal | high | max. -type message_queue_data() :: - off_heap | on_heap | mixed. + off_heap | on_heap. -spec process_flag(trap_exit, Boolean) -> OldBoolean when Boolean :: boolean(), -- cgit v1.2.3 From d83ecf6b20d0e1d804f343a837e5e4fe676bf077 Mon Sep 17 00:00:00 2001 From: Rickard Green Date: Fri, 27 May 2016 10:52:50 +0200 Subject: Bumped runtime dependencies between erts, kernel, stdlib, sasl --- erts/preloaded/src/erts.app.src | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'erts/preloaded/src') diff --git a/erts/preloaded/src/erts.app.src b/erts/preloaded/src/erts.app.src index 98e0224a5f..e18da28905 100644 --- a/erts/preloaded/src/erts.app.src +++ b/erts/preloaded/src/erts.app.src @@ -37,7 +37,7 @@ {registered, []}, {applications, []}, {env, []}, - {runtime_dependencies, ["stdlib-2.5", "kernel-4.0", "sasl-2.4"]} + {runtime_dependencies, ["stdlib-3.0", "kernel-5.0", "sasl-3.0"]} ]}. %% vim: ft=erlang -- cgit v1.2.3 From d319179eee6a523812c81c7ca49afb670de0b277 Mon Sep 17 00:00:00 2001 From: Sverker Eriksson Date: Mon, 30 May 2016 17:20:54 +0200 Subject: Reintroduce erlang:halt/0/1 in erl_bif_types.erl Removed in f9cb80861f169743 when changed impl from C to Erlang. But seems they are needed to keep dialyzer tests happy. Also improved bif_SUITE:shadow_comments to include all exported in module erlang, not just the "snifs". ...which detected that apply/2 was missing Shadowed comment as well. --- erts/preloaded/src/erlang.erl | 3 +++ 1 file changed, 3 insertions(+) (limited to 'erts/preloaded/src') diff --git a/erts/preloaded/src/erlang.erl b/erts/preloaded/src/erlang.erl index 5283519c0a..94f3078173 100644 --- a/erts/preloaded/src/erlang.erl +++ b/erts/preloaded/src/erlang.erl @@ -977,11 +977,13 @@ group_leader(_GroupLeader, _Pid) -> erlang:nif_error(undefined). %% halt/0 +%% Shadowed by erl_bif_types: erlang:halt/0 -spec halt() -> no_return(). halt() -> erlang:halt(0, []). %% halt/1 +%% Shadowed by erl_bif_types: erlang:halt/1 -spec halt(Status) -> no_return() when Status :: non_neg_integer() | 'abort' | string(). halt(Status) -> @@ -2576,6 +2578,7 @@ universaltime_to_localtime(_Universaltime) -> %%-------------------------------------------------------------------------- +%% Shadowed by erl_bif_types: erlang:apply/2 -spec apply(Fun, Args) -> term() when Fun :: function(), Args :: [term()]. -- cgit v1.2.3 From 011954e851d421b882b0b4eaeda04cfc2895d70a Mon Sep 17 00:00:00 2001 From: Raimo Niskanen Date: Wed, 4 May 2016 14:09:04 +0200 Subject: Rewrite inet_drv for AF_LOCAL --- erts/preloaded/src/prim_inet.erl | 341 +++++++++++++++++++++++++++------------ 1 file changed, 241 insertions(+), 100 deletions(-) (limited to 'erts/preloaded/src') diff --git a/erts/preloaded/src/prim_inet.erl b/erts/preloaded/src/prim_inet.erl index 4659448221..c6434fd83b 100644 --- a/erts/preloaded/src/prim_inet.erl +++ b/erts/preloaded/src/prim_inet.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2000-2013. All Rights Reserved. +%% Copyright Ericsson AB 2000-2016. All Rights Reserved. %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. @@ -76,7 +76,7 @@ fdopen(Protocol, Family, Type, Fd) when is_integer(Fd) -> fdopen(Protocol, Family, Type, Fd, true). fdopen(Protocol, Family, Type, Fd, Bound) - when is_integer(Fd), Bound == true orelse Bound == false -> + when is_integer(Fd), is_boolean(Bound) -> open(Protocol, Family, Type, [], ?INET_REQ_FDOPEN, [?int32(Fd), enc_value_2(bool, Bound)]). @@ -192,41 +192,52 @@ close_port(S) -> %% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -bind(S,IP,Port) when is_port(S), is_integer(Port), Port >= 0, Port =< 65535 -> - case ctl_cmd(S,?INET_REQ_BIND,enc_value(set, addr, {IP,Port})) of - {ok, [P1,P0]} -> {ok, ?u16(P1, P0)}; - {error,_}=Error -> Error - end; - %% Multi-homed "bind": sctp_bindx(). The Op is 'add' or 'remove'. %% If no addrs are specified, it just does nothing. %% Function returns {ok, S} on success, unlike TCP/UDP "bind": -bind(S, Op, Addrs) when is_port(S), is_list(Addrs) -> - case Op of - add -> - bindx(S, 1, Addrs); - remove -> - bindx(S, 0, Addrs); - _ -> {error, einval} +bind(S, add, Addrs) when is_port(S), is_list(Addrs) -> + bindx(S, 1, Addrs); +bind(S, remove, Addrs) when is_port(S), is_list(Addrs) -> + bindx(S, 0, Addrs); +bind(S, Addr, _) when is_port(S), tuple_size(Addr) =:= 2 -> + case type_value(set, addr, Addr) of + true -> + case ctl_cmd(S,?INET_REQ_BIND,enc_value(set, addr, Addr)) of + {ok, [P1,P0]} -> {ok, ?u16(P1, P0)}; + {error, _} = Error -> Error + end; + false -> + {error, einval} end; -bind(_, _, _) -> {error, einval}. +bind(S, IP, Port) -> + bind(S, {IP, Port}, 0). bindx(S, AddFlag, Addrs) -> case getprotocol(S) of sctp -> - %% Really multi-homed "bindx". Stringified args: - %% [AddFlag, (AddrBytes see enc_value_2(addr,X))+]: - Args = - [?int8(AddFlag)| - [enc_value(set, addr, {IP,Port}) || - {IP, Port} <- Addrs]], - case ctl_cmd(S, ?SCTP_REQ_BINDX, Args) of - {ok,_} -> {ok, S}; - {error,_}=Error -> Error + case bindx_check_addrs(Addrs) of + true -> + %% Really multi-homed "bindx". Stringified args: + %% [AddFlag, (AddrBytes see enc_value_2(addr,X))+]: + Args = + [?int8(AddFlag)| + [enc_value(set, addr, Addr) || Addr <- Addrs]], + case ctl_cmd(S, ?SCTP_REQ_BINDX, Args) of + {ok, _} -> {ok, S}; + {error, _}=Error -> Error + end; + false -> + {error, einval} end; - _ -> {error, einval} + _ -> + {error, einval} end. +bindx_check_addrs([Addr|Addrs]) -> + type_value(set, addr, Addr) andalso bindx_check_addrs(Addrs); +bindx_check_addrs([]) -> + true. + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% %% CONNECT(insock(), IP, Port [,Timeout]) -> ok | {error, Reason} @@ -245,14 +256,24 @@ bindx(S, AddFlag, Addrs) -> %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% For TCP, UDP or SCTP sockets. %% -connect(S, IP, Port) -> connect0(S, IP, Port, -1). -connect(S, IP, Port, infinity) -> connect0(S, IP, Port, -1); -connect(S, IP, Port, Time) -> connect0(S, IP, Port, Time). +connect(S, IP, Port) -> + connect(S, IP, Port, infinity). +%% +connect(S, Addr, _, Time) when is_port(S), tuple_size(Addr) =:= 2 -> + case type_value(set, addr, Addr) of + true when Time =:= infinity -> + connect0(S, Addr, -1); + true when is_integer(Time) -> + connect0(S, Addr, Time); + false -> + {error, einval} + end; +connect(S, IP, Port, Time) -> + connect(S, {IP, Port}, 0, Time). -connect0(S, IP, Port, Time) when is_port(S), Port > 0, Port =< 65535, - is_integer(Time) -> - case async_connect(S, IP, Port, Time) of +connect0(S, Addr, Time) -> + case async_connect0(S, Addr, Time) of {ok, S, Ref} -> receive {inet_async, S, Ref, Status} -> @@ -261,11 +282,27 @@ connect0(S, IP, Port, Time) when is_port(S), Port > 0, Port =< 65535, Error -> Error end. + +async_connect(S, Addr, _, Time) when is_port(S), tuple_size(Addr) =:= 2 -> + case type_value(set, addr, Addr) of + true when Time =:= infinity -> + async_connect0(S, Addr, -1); + true when is_integer(Time) -> + async_connect0(S, Addr, Time); + false -> + {error, einval} + end; +%% async_connect(S, IP, Port, Time) -> - case ctl_cmd(S, ?INET_REQ_CONNECT, - [enc_time(Time),?int16(Port),ip_to_bytes(IP)]) of + async_connect(S, {IP, Port}, 0, Time). + +async_connect0(S, Addr, Time) -> + case ctl_cmd( + S, ?INET_REQ_CONNECT, + [enc_time(Time),enc_value(set, addr, Addr)]) + of {ok, [R1,R0]} -> {ok, S, ?u16(R1,R0)}; - {error,_}=Error -> Error + {error, _}=Error -> Error end. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -403,20 +440,34 @@ send(S, Data) -> %% "sendto" is for UDP. IP and Port are set by the caller to 0 if the socket %% is known to be connected. -sendto(S, IP, Port, Data) when is_port(S), Port >= 0, Port =< 65535 -> - ?DBG_FORMAT("prim_inet:sendto(~p, ~p, ~p, ~p)~n", [S,IP,Port,Data]), - try erlang:port_command(S, [?int16(Port),ip_to_bytes(IP),Data]) of - true -> - receive - {inet_reply,S,Reply} -> - ?DBG_FORMAT("prim_inet:sendto() -> ~p~n", [Reply]), - Reply - end - catch - error:_ -> - ?DBG_FORMAT("prim_inet:sendto() -> {error,einval}~n", []), - {error,einval} - end. +sendto(S, Addr, _, Data) when is_port(S), tuple_size(Addr) =:= 2 -> + case type_value(set, addr, Addr) of + true -> + ?DBG_FORMAT("prim_inet:sendto(~p, ~p, ~p)~n", [S,Addr,Data]), + try + erlang:port_command(S, [enc_value(set, addr, Addr),Data]) + of + true -> + receive + {inet_reply,S,Reply} -> + ?DBG_FORMAT( + "prim_inet:sendto() -> ~p~n", [Reply]), + Reply + end + catch + error:_ -> + ?DBG_FORMAT( + "prim_inet:sendto() -> {error,einval}~n", []), + {error,einval} + end; + false -> + ?DBG_FORMAT( + "prim_inet:sendto() -> {error,einval}~n", []), + {error,einval} + end; +sendto(S, IP, Port, Data) -> + sendto(S, {IP, Port}, 0, Data). + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% @@ -487,29 +538,37 @@ async_recv(S, Length, Time) -> %% oriented: preserved here only for API compatibility. %% recvfrom(S, Length) -> - recvfrom0(S, Length, -1). + recvfrom(S, Length, infinity). -recvfrom(S, Length, infinity) -> +recvfrom(S, Length, infinity) when is_port(S) -> recvfrom0(S, Length, -1); -recvfrom(S, Length, Time) when is_integer(Time), Time < 16#ffffffff -> - recvfrom0(S, Length, Time); -recvfrom(_, _, _) -> {error,einval}. +recvfrom(S, Length, Time) when is_port(S) -> + if + is_integer(Time), 0 =< Time, Time < 16#ffffffff -> + recvfrom0(S, Length, Time); + true -> + {error, einval} + end. recvfrom0(S, Length, Time) - when is_port(S), is_integer(Length), Length >= 0, Length =< 16#ffffffff -> + when is_integer(Length), 0 =< Length, Length =< 16#ffffffff -> case ctl_cmd(S, ?PACKET_REQ_RECV,[enc_time(Time),?int32(Length)]) of {ok,[R1,R0]} -> Ref = ?u16(R1,R0), receive % Success, UDP: - {inet_async, S, Ref, {ok, [F,P1,P0 | AddrData]}} -> - {IP,Data} = get_ip(F, AddrData), - {ok, {IP, ?u16(P1,P0), Data}}; + {inet_async, S, Ref, {ok, [F | AddrData]}} -> + case get_addr(F, AddrData) of + {{Family, _} = Addr, Data} when is_atom(Family) -> + {ok, {Addr, 0, Data}}; + {{IP, Port}, Data} -> + {ok, {IP, Port, Data}} + end; % Success, SCTP: {inet_async, S, Ref, {ok, {[F,P1,P0 | Addr], AncData, DE}}} -> - {IP, _} = get_ip(F, Addr), - {ok, {IP, ?u16(P1,P0), AncData, DE}}; + {IP, _} = get_ip(F, Addr), + {ok, {IP, ?u16(P1, P0), AncData, DE}}; % Back-end error: {inet_async, S, Ref, Error={error, _}} -> @@ -528,21 +587,26 @@ recvfrom0(_, _, _) -> {error,einval}. peername(S) when is_port(S) -> case ctl_cmd(S, ?INET_REQ_PEER, []) of - {ok, [F, P1,P0 | Addr]} -> - {IP, _} = get_ip(F, Addr), - {ok, { IP, ?u16(P1, P0) }}; - {error,_}=Error -> Error + {ok, [F | Addr]} -> + {A, _} = get_addr(F, Addr), + {ok, A}; + {error, _} = Error -> Error end. -setpeername(S, {IP,Port}) when is_port(S) -> - case ctl_cmd(S, ?INET_REQ_SETPEER, [?int16(Port),ip_to_bytes(IP)]) of - {ok,[]} -> ok; - {error,_}=Error -> Error - end; setpeername(S, undefined) when is_port(S) -> case ctl_cmd(S, ?INET_REQ_SETPEER, []) of - {ok,[]} -> ok; - {error,_}=Error -> Error + {ok, []} -> ok; + {error, _} = Error -> Error + end; +setpeername(S, Addr) when is_port(S) -> + case type_value(set, addr, Addr) of + true -> + case ctl_cmd(S, ?INET_REQ_SETPEER, enc_value(set, addr, Addr)) of + {ok, []} -> ok; + {error, _} = Error -> Error + end; + false -> + {error, einval} end. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -583,21 +647,28 @@ peernames(S, AssocId) sockname(S) when is_port(S) -> case ctl_cmd(S, ?INET_REQ_NAME, []) of - {ok, [F, P1, P0 | Addr]} -> - {IP, _} = get_ip(F, Addr), - {ok, { IP, ?u16(P1, P0) }}; - {error,_}=Error -> Error + {ok, [F | Addr]} -> + {A, _} = get_addr(F, Addr), + {ok, A}; + {error, _} = Error -> Error end. -setsockname(S, {IP,Port}) when is_port(S) -> - case ctl_cmd(S, ?INET_REQ_SETNAME, [?int16(Port),ip_to_bytes(IP)]) of - {ok,[]} -> ok; - {error,_}=Error -> Error - end; setsockname(S, undefined) when is_port(S) -> case ctl_cmd(S, ?INET_REQ_SETNAME, []) of - {ok,[]} -> ok; - {error,_}=Error -> Error + {ok, []} -> ok; + {error, _} = Error -> Error + end; +setsockname(S, Addr) when is_port(S) -> + case type_value(set, addr, Addr) of + true -> + case + ctl_cmd(S, ?INET_REQ_SETNAME, enc_value(set, addr, Addr)) + of + {ok, []} -> ok; + {error, _} = Error -> Error + end; + false -> + {error, einval} end. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -1499,14 +1570,49 @@ type_value_2(uint8, X) when X band 16#ff =:= X -> true; type_value_2(time, infinity) -> true; type_value_2(time, X) when is_integer(X), X >= 0 -> true; type_value_2(ip,{A,B,C,D}) when ?ip(A,B,C,D) -> true; +%% type_value_2(addr, {any,Port}) -> type_value_2(uint16, Port); type_value_2(addr, {loopback,Port}) -> type_value_2(uint16, Port); -type_value_2(addr, {{A,B,C,D},Port}) when ?ip(A,B,C,D) -> +type_value_2(addr, {IP,_} = Addr) when tuple_size(IP) =:= 4 -> + type_value_2(addr, {inet,Addr}); +type_value_2(addr, {IP,_} = Addr) when tuple_size(IP) =:= 8 -> + type_value_2(addr, {inet6,Addr}); +type_value_2(addr, {Local,_}) when is_list(Local); is_binary(Local) -> + type_value_2(addr, {local,Local}); +%% +type_value_2(addr, {Family,{Tag,Port}}) + when (Family =:= inet orelse Family =:= inet6) andalso + (Tag =:= any orelse Tag =:= loopback) -> + type_value_2(uint16, Port); +type_value_2(addr, {inet,{{A,B,C,D},Port}}) + when ?ip(A,B,C,D) -> type_value_2(uint16, Port); -type_value_2(addr, {{A,B,C,D,E,F,G,H},Port}) when ?ip6(A,B,C,D,E,F,G,H) -> +type_value_2(addr, {inet6,{{A,B,C,D,E,F,G,H},Port}}) + when ?ip6(A,B,C,D,E,F,G,H) -> type_value_2(uint16, Port); +type_value_2(addr, {local,Addr}) -> + if + is_binary(Addr) -> + byte_size(Addr) =< 255; + true -> + try + %% We either get a badarg from byte_size + %% or from characters_to_binary + byte_size( + unicode:characters_to_binary( + Addr, file:native_name_encoding())) + of + N when N =< 255 -> + true; + _ -> + false + catch error:badarg -> + false + end + end; +%% type_value_2(ether,[X1,X2,X3,X4,X5,X6]) when ?ether(X1,X2,X3,X4,X5,X6) -> true; type_value_2({enum,List}, Enum) -> @@ -1614,6 +1720,7 @@ enc_value_2(time, Val) -> ?int32(Val); enc_value_2(ip,{A,B,C,D}) -> [A,B,C,D]; enc_value_2(ip, any) -> [0,0,0,0]; enc_value_2(ip, loopback) -> [127,0,0,1]; +%% enc_value_2(addr, {any,Port}) -> [?INET_AF_ANY|?int16(Port)]; enc_value_2(addr, {loopback,Port}) -> @@ -1622,8 +1729,35 @@ enc_value_2(addr, {IP,Port}) when tuple_size(IP) =:= 4 -> [?INET_AF_INET,?int16(Port)|ip4_to_bytes(IP)]; enc_value_2(addr, {IP,Port}) when tuple_size(IP) =:= 8 -> [?INET_AF_INET6,?int16(Port)|ip6_to_bytes(IP)]; -enc_value_2(addr, {File,0}) when is_list(File) -> - [?INET_AF_LOCAL,0,0,length(File)|File]; +enc_value_2(addr, {File,_}) when is_list(File); is_binary(File) -> + [?INET_AF_LOCAL,iolist_size(File)|File]; +%% +enc_value_2(addr, {inet,{any,Port}}) -> + [?INET_AF_INET,?int16(Port),0,0,0,0]; +enc_value_2(addr, {inet,{loopback,Port}}) -> + [?INET_AF_INET,?int16(Port),127,0,0,1]; +enc_value_2(addr, {inet,{IP,Port}}) -> + [?INET_AF_INET,?int16(Port)|ip4_to_bytes(IP)]; +enc_value_2(addr, {inet6,{any,Port}}) -> + [?INET_AF_INET6,?int16(Port),0,0,0,0,0,0,0,0]; +enc_value_2(addr, {inet6,{loopback,Port}}) -> + [?INET_AF_INET6,?int16(Port),0,0,0,0,0,0,0,1]; +enc_value_2(addr, {inet6,{IP,Port}}) -> + [?INET_AF_INET6,?int16(Port)|ip6_to_bytes(IP)]; +enc_value_2(addr, {local,Addr}) -> + %% A binary is passed as is, but anything else will be + %% regarded as a filename and therefore UTF-8 encoded + %% if the system filename encoding flag so dictates. + Bin = + if + is_binary(Addr) -> + Addr; + true -> + unicode:characters_to_binary( + Addr, file:native_name_encoding()) + end, + [?INET_AF_LOCAL,byte_size(Bin)|Bin]; +%% enc_value_2(ether, [_,_,_,_,_,_]=Xs) -> Xs; enc_value_2(sockaddr, any) -> [?INET_AF_ANY]; @@ -1633,8 +1767,6 @@ enc_value_2(sockaddr, IP) when tuple_size(IP) =:= 4 -> [?INET_AF_INET|ip4_to_bytes(IP)]; enc_value_2(sockaddr, IP) when tuple_size(IP) =:= 8 -> [?INET_AF_INET6|ip6_to_bytes(IP)]; -enc_value_2(sockaddr, File) when is_list(File) -> - [?INET_AF_LOCAL,0,0,length(File)|File]; enc_value_2(linkaddr, Linkaddr) -> [?int16(length(Linkaddr)),Linkaddr]; enc_value_2(sctp_assoc_id, Val) -> ?int32(Val); @@ -2256,9 +2388,6 @@ utf8_to_characters(Bs, U, 0) -> utf8_to_characters([B|Bs], U, N) when ((B band 16#3F) bor 16#80) =:= B -> utf8_to_characters(Bs, (U bsl 6) bor (B band 16#3F), N-1). -ip_to_bytes(IP) when tuple_size(IP) =:= 4 -> ip4_to_bytes(IP); -ip_to_bytes(IP) when tuple_size(IP) =:= 8 -> ip6_to_bytes(IP). - ip4_to_bytes({A,B,C,D}) -> [A band 16#ff, B band 16#ff, C band 16#ff, D band 16#ff]. @@ -2268,20 +2397,32 @@ ip6_to_bytes({A,B,C,D,E,F,G,H}) -> get_addrs([]) -> []; -get_addrs([F,P1,P0|Addr]) -> - {IP,Addrs} = get_ip(F, Addr), - [{IP,?u16(P1, P0)}|get_addrs(Addrs)]. - -get_ip(?INET_AF_INET, Addr) -> get_ip4(Addr); -get_ip(?INET_AF_INET6, Addr) -> get_ip6(Addr); -get_ip(?INET_AF_LOCAL, [0]) -> {[], []}; -get_ip(?INET_AF_LOCAL, [N | Addr]) -> lists:split(N, Addr). +get_addrs([F|Addrs]) -> + {Addr,Rest} = get_addr(F, Addrs), + [Addr|get_addrs(Rest)]. + +get_addr(?INET_AF_LOCAL, [0]) -> + {{local,<<>>},[]}; +get_addr(?INET_AF_LOCAL, [N|Addr]) -> + {A,Rest} = lists:split(N, Addr), + {{local,iolist_to_binary(A)},Rest}; +get_addr(?INET_AF_UNDEFINED, Rest) -> + {{undefined,0},Rest}; +get_addr(Family, [P1,P0|Addr]) -> + {IP,Rest} = get_ip(Family, Addr), + {{IP,?u16(P1, P0)},Rest}. + +get_ip(?INET_AF_INET, Addr) -> + get_ip4(Addr); +get_ip(?INET_AF_INET6, Addr) -> + get_ip6(Addr). get_ip4([A,B,C,D | T]) -> {{A,B,C,D},T}. get_ip6([X1,X2,X3,X4,X5,X6,X7,X8,X9,X10,X11,X12,X13,X14,X15,X16 | T]) -> { { ?u16(X1,X2),?u16(X3,X4),?u16(X5,X6),?u16(X7,X8), - ?u16(X9,X10),?u16(X11,X12),?u16(X13,X14),?u16(X15,X16)}, T}. + ?u16(X9,X10),?u16(X11,X12),?u16(X13,X14),?u16(X15,X16)}, + T }. %% Control command -- cgit v1.2.3 From 03e6d8e02a187633a6a09c77e36670f0892d063d Mon Sep 17 00:00:00 2001 From: Raimo Niskanen Date: Thu, 2 Jun 2016 08:44:59 +0200 Subject: AF_UNIX is more portable Fix dialyzer warning for improper list in prim_inet by not using an improper list. --- erts/preloaded/src/prim_inet.erl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'erts/preloaded/src') diff --git a/erts/preloaded/src/prim_inet.erl b/erts/preloaded/src/prim_inet.erl index c6434fd83b..71dbfbd0a7 100644 --- a/erts/preloaded/src/prim_inet.erl +++ b/erts/preloaded/src/prim_inet.erl @@ -1756,7 +1756,7 @@ enc_value_2(addr, {local,Addr}) -> unicode:characters_to_binary( Addr, file:native_name_encoding()) end, - [?INET_AF_LOCAL,byte_size(Bin)|Bin]; + [?INET_AF_LOCAL,byte_size(Bin),Bin]; %% enc_value_2(ether, [_,_,_,_,_,_]=Xs) -> Xs; enc_value_2(sockaddr, any) -> -- cgit v1.2.3 From f429adba7e7a862b9949821b40aa3cba12455b3e Mon Sep 17 00:00:00 2001 From: Raimo Niskanen Date: Wed, 8 Jun 2016 09:56:04 +0200 Subject: Remove internal state BOUND from inet_drv --- erts/preloaded/src/prim_inet.erl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'erts/preloaded/src') diff --git a/erts/preloaded/src/prim_inet.erl b/erts/preloaded/src/prim_inet.erl index 71dbfbd0a7..7f8097e17e 100644 --- a/erts/preloaded/src/prim_inet.erl +++ b/erts/preloaded/src/prim_inet.erl @@ -1746,8 +1746,8 @@ enc_value_2(addr, {inet6,{IP,Port}}) -> [?INET_AF_INET6,?int16(Port)|ip6_to_bytes(IP)]; enc_value_2(addr, {local,Addr}) -> %% A binary is passed as is, but anything else will be - %% regarded as a filename and therefore UTF-8 encoded - %% if the system filename encoding flag so dictates. + %% regarded as a filename and therefore encoded according to + %% the current system filename encoding. Bin = if is_binary(Addr) -> -- cgit v1.2.3 From 16e895198a541ccbbbe6c970bd9572cf347a9c77 Mon Sep 17 00:00:00 2001 From: Raimo Niskanen Date: Wed, 8 Jun 2016 14:46:44 +0200 Subject: Document the local (unix) address family --- erts/preloaded/src/prim_inet.erl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'erts/preloaded/src') diff --git a/erts/preloaded/src/prim_inet.erl b/erts/preloaded/src/prim_inet.erl index 7f8097e17e..560810d222 100644 --- a/erts/preloaded/src/prim_inet.erl +++ b/erts/preloaded/src/prim_inet.erl @@ -1747,7 +1747,7 @@ enc_value_2(addr, {inet6,{IP,Port}}) -> enc_value_2(addr, {local,Addr}) -> %% A binary is passed as is, but anything else will be %% regarded as a filename and therefore encoded according to - %% the current system filename encoding. + %% the current system filename encoding mode. Bin = if is_binary(Addr) -> -- cgit v1.2.3 From 3ee5343415d6ae0ce1ff1c2a2555051431a9315e Mon Sep 17 00:00:00 2001 From: Dmytro Lytovchenko Date: Wed, 25 May 2016 14:37:03 +0200 Subject: erts: Add port monitors * erlang:monitor/2 with port argument is added, erlang:demonitor, using port task API and avoiding locking; * port_info and process_info support for monitored ports (with named port monitors support); * Exit signals contain type 'process' or 'port'; * Propagation of port exit signals; * Self-cleaning when origin process dies with monitor on; * 8 test cases + testcase for port driver crashing; * Documentation for all of the above (monitor, demonitor, port_info and process_info) updated --- erts/preloaded/src/erlang.erl | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) (limited to 'erts/preloaded/src') diff --git a/erts/preloaded/src/erlang.erl b/erts/preloaded/src/erlang.erl index 94f3078173..edf79b8f75 100644 --- a/erts/preloaded/src/erlang.erl +++ b/erts/preloaded/src/erlang.erl @@ -1206,16 +1206,18 @@ module_loaded(_Module) -> erlang:nif_error(undefined). -type registered_name() :: atom(). - -type registered_process_identifier() :: registered_name() | {registered_name(), node()}. - -type monitor_process_identifier() :: pid() | registered_process_identifier(). +-type monitor_port_identifier() :: port() | registered_name(). %% monitor/2 --spec monitor(process, monitor_process_identifier()) -> MonitorRef when - MonitorRef :: reference(); - (time_offset, clock_service) -> MonitorRef when - MonitorRef :: reference(). +-spec monitor + (process, monitor_process_identifier()) -> MonitorRef + when MonitorRef :: reference(); + (port, monitor_port_identifier()) -> MonitorRef + when MonitorRef :: reference(); + (time_offset, clock_service) -> MonitorRef + when MonitorRef :: reference(). monitor(_Type, _Item) -> erlang:nif_error(undefined). @@ -2160,7 +2162,7 @@ process_flag(_Flag, _Value) -> {max_heap_size, MaxHeapSize :: max_heap_size()} | {monitored_by, Pids :: [pid()]} | {monitors, - Monitors :: [{process, Pid :: pid() | + Monitors :: [{process | port, Pid :: pid() | port() | {RegName :: atom(), Node :: node()}}]} | {message_queue_data, MQD :: message_queue_data()} | {priority, Level :: priority_level()} | @@ -3087,6 +3089,9 @@ port_info(Port) -> (Port, monitors) -> {monitors, Monitors} | 'undefined' when Port :: port() | atom(), Monitors :: [{process, pid()}]; + (Port, monitored_by) -> {monitored_by, MonitoredBy} | 'undefined' when + Port :: port() | atom(), + MonitoredBy :: [pid()]; (Port, name) -> {name, Name} | 'undefined' when Port :: port() | atom(), Name :: string(); -- cgit v1.2.3