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') 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') 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') 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 285b4fa13914dc4748c1020213a9c65cad3d2738 Mon Sep 17 00:00:00 2001 From: Serge Aleynikov Date: Tue, 2 Jun 2015 08:44:23 -0400 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/ebin/prim_inet.beam | Bin 72748 -> 36456 bytes erts/preloaded/src/prim_inet.erl | 3 +++ 2 files changed, 3 insertions(+) (limited to 'erts/preloaded') diff --git a/erts/preloaded/ebin/prim_inet.beam b/erts/preloaded/ebin/prim_inet.beam index 5a188be3ba..6cf8d30cb2 100644 Binary files a/erts/preloaded/ebin/prim_inet.beam and b/erts/preloaded/ebin/prim_inet.beam differ 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 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/ebin/prim_inet.beam | Bin 72748 -> 72712 bytes erts/preloaded/src/prim_inet.erl | 3 +++ 2 files changed, 3 insertions(+) (limited to 'erts/preloaded') diff --git a/erts/preloaded/ebin/prim_inet.beam b/erts/preloaded/ebin/prim_inet.beam index 5a188be3ba..8b87d1ae26 100644 Binary files a/erts/preloaded/ebin/prim_inet.beam and b/erts/preloaded/ebin/prim_inet.beam differ 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/ebin/init.beam | Bin 48768 -> 48812 bytes erts/preloaded/src/init.erl | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) (limited to 'erts/preloaded') diff --git a/erts/preloaded/ebin/init.beam b/erts/preloaded/ebin/init.beam index 851513b2e9..73dfb3d351 100644 Binary files a/erts/preloaded/ebin/init.beam and b/erts/preloaded/ebin/init.beam differ 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/ebin/erlang.beam | Bin 101840 -> 101544 bytes erts/preloaded/src/erlang.erl | 44 ++++++++++++++++++---------------------- 2 files changed, 20 insertions(+), 24 deletions(-) (limited to 'erts/preloaded') diff --git a/erts/preloaded/ebin/erlang.beam b/erts/preloaded/ebin/erlang.beam index 863a5e61ef..641fac2d26 100644 Binary files a/erts/preloaded/ebin/erlang.beam and b/erts/preloaded/ebin/erlang.beam differ 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 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') 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 da8220501710184f3ee80337bac57d215560ea64 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn-Egil=20Dahlberg?= Date: Tue, 29 Sep 2015 15:35:54 +0200 Subject: Update preloaded module erlang.beam --- erts/preloaded/ebin/erlang.beam | Bin 101544 -> 101816 bytes 1 file changed, 0 insertions(+), 0 deletions(-) (limited to 'erts/preloaded') diff --git a/erts/preloaded/ebin/erlang.beam b/erts/preloaded/ebin/erlang.beam index 641fac2d26..4f35928db2 100644 Binary files a/erts/preloaded/ebin/erlang.beam and b/erts/preloaded/ebin/erlang.beam differ -- 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/ebin/erts_internal.beam | Bin 5964 -> 5988 bytes erts/preloaded/src/erts_internal.erl | 12 ++++++------ 2 files changed, 6 insertions(+), 6 deletions(-) (limited to 'erts/preloaded') diff --git a/erts/preloaded/ebin/erts_internal.beam b/erts/preloaded/ebin/erts_internal.beam index dc8c711e1a..d63f79c327 100644 Binary files a/erts/preloaded/ebin/erts_internal.beam and b/erts/preloaded/ebin/erts_internal.beam differ 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') 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') 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 cfecb31a2f6795dafb8858e39a3844bd301b84db Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn-Egil=20Dahlberg?= Date: Tue, 8 Dec 2015 15:16:17 +0100 Subject: Update preloaded modules --- erts/preloaded/ebin/erl_prim_loader.beam | Bin 56328 -> 56060 bytes erts/preloaded/ebin/erlang.beam | Bin 101816 -> 101752 bytes erts/preloaded/ebin/erts_internal.beam | Bin 5988 -> 6076 bytes erts/preloaded/ebin/init.beam | Bin 48812 -> 48600 bytes erts/preloaded/ebin/otp_ring0.beam | Bin 1468 -> 1460 bytes erts/preloaded/ebin/prim_eval.beam | Bin 1340 -> 1332 bytes erts/preloaded/ebin/prim_file.beam | Bin 44904 -> 44788 bytes erts/preloaded/ebin/prim_inet.beam | Bin 72628 -> 72624 bytes erts/preloaded/ebin/prim_zip.beam | Bin 23416 -> 23296 bytes erts/preloaded/ebin/zlib.beam | Bin 14176 -> 14168 bytes 10 files changed, 0 insertions(+), 0 deletions(-) (limited to 'erts/preloaded') diff --git a/erts/preloaded/ebin/erl_prim_loader.beam b/erts/preloaded/ebin/erl_prim_loader.beam index df12c6f8e0..e94a1ba796 100644 Binary files a/erts/preloaded/ebin/erl_prim_loader.beam and b/erts/preloaded/ebin/erl_prim_loader.beam differ diff --git a/erts/preloaded/ebin/erlang.beam b/erts/preloaded/ebin/erlang.beam index 4f35928db2..632defdb46 100644 Binary files a/erts/preloaded/ebin/erlang.beam and b/erts/preloaded/ebin/erlang.beam differ diff --git a/erts/preloaded/ebin/erts_internal.beam b/erts/preloaded/ebin/erts_internal.beam index d63f79c327..fd0a502d2c 100644 Binary files a/erts/preloaded/ebin/erts_internal.beam and b/erts/preloaded/ebin/erts_internal.beam differ diff --git a/erts/preloaded/ebin/init.beam b/erts/preloaded/ebin/init.beam index 73dfb3d351..60c08819eb 100644 Binary files a/erts/preloaded/ebin/init.beam and b/erts/preloaded/ebin/init.beam differ diff --git a/erts/preloaded/ebin/otp_ring0.beam b/erts/preloaded/ebin/otp_ring0.beam index 33c112f4de..04814c091b 100644 Binary files a/erts/preloaded/ebin/otp_ring0.beam and b/erts/preloaded/ebin/otp_ring0.beam differ diff --git a/erts/preloaded/ebin/prim_eval.beam b/erts/preloaded/ebin/prim_eval.beam index ebca6e7eea..7779c8374d 100644 Binary files a/erts/preloaded/ebin/prim_eval.beam and b/erts/preloaded/ebin/prim_eval.beam differ diff --git a/erts/preloaded/ebin/prim_file.beam b/erts/preloaded/ebin/prim_file.beam index e8817d183e..254b0e5b90 100644 Binary files a/erts/preloaded/ebin/prim_file.beam and b/erts/preloaded/ebin/prim_file.beam differ diff --git a/erts/preloaded/ebin/prim_inet.beam b/erts/preloaded/ebin/prim_inet.beam index 357bcd3d9a..b7cfe26462 100644 Binary files a/erts/preloaded/ebin/prim_inet.beam and b/erts/preloaded/ebin/prim_inet.beam differ diff --git a/erts/preloaded/ebin/prim_zip.beam b/erts/preloaded/ebin/prim_zip.beam index 969239be98..6b5c6195c8 100644 Binary files a/erts/preloaded/ebin/prim_zip.beam and b/erts/preloaded/ebin/prim_zip.beam differ diff --git a/erts/preloaded/ebin/zlib.beam b/erts/preloaded/ebin/zlib.beam index 281f668f8c..43d7b436be 100644 Binary files a/erts/preloaded/ebin/zlib.beam and b/erts/preloaded/ebin/zlib.beam differ -- cgit v1.2.3 From 83b9161cb4f96b5ee1fddb1c4f69b63b91c5b6e2 Mon Sep 17 00:00:00 2001 From: Henrik Nord Date: Mon, 14 Dec 2015 11:12:03 +0100 Subject: Update preloaded modules --- erts/preloaded/ebin/erl_prim_loader.beam | Bin 56328 -> 56336 bytes erts/preloaded/ebin/erlang.beam | Bin 101840 -> 101796 bytes erts/preloaded/ebin/erts_internal.beam | Bin 5964 -> 5960 bytes erts/preloaded/ebin/init.beam | Bin 48812 -> 48764 bytes erts/preloaded/ebin/otp_ring0.beam | Bin 1468 -> 1468 bytes erts/preloaded/ebin/prim_eval.beam | Bin 1340 -> 1340 bytes erts/preloaded/ebin/prim_file.beam | Bin 44904 -> 44892 bytes erts/preloaded/ebin/prim_inet.beam | Bin 72712 -> 72716 bytes erts/preloaded/ebin/prim_zip.beam | Bin 23416 -> 23424 bytes erts/preloaded/ebin/zlib.beam | Bin 14176 -> 14176 bytes 10 files changed, 0 insertions(+), 0 deletions(-) (limited to 'erts/preloaded') diff --git a/erts/preloaded/ebin/erl_prim_loader.beam b/erts/preloaded/ebin/erl_prim_loader.beam index df12c6f8e0..4a6fb6109f 100644 Binary files a/erts/preloaded/ebin/erl_prim_loader.beam and b/erts/preloaded/ebin/erl_prim_loader.beam differ diff --git a/erts/preloaded/ebin/erlang.beam b/erts/preloaded/ebin/erlang.beam index 863a5e61ef..cd2e7f18a2 100644 Binary files a/erts/preloaded/ebin/erlang.beam and b/erts/preloaded/ebin/erlang.beam differ diff --git a/erts/preloaded/ebin/erts_internal.beam b/erts/preloaded/ebin/erts_internal.beam index dc8c711e1a..32d5d70122 100644 Binary files a/erts/preloaded/ebin/erts_internal.beam and b/erts/preloaded/ebin/erts_internal.beam differ diff --git a/erts/preloaded/ebin/init.beam b/erts/preloaded/ebin/init.beam index 73dfb3d351..9b0fc82bed 100644 Binary files a/erts/preloaded/ebin/init.beam and b/erts/preloaded/ebin/init.beam differ diff --git a/erts/preloaded/ebin/otp_ring0.beam b/erts/preloaded/ebin/otp_ring0.beam index 33c112f4de..c8166d5ed7 100644 Binary files a/erts/preloaded/ebin/otp_ring0.beam and b/erts/preloaded/ebin/otp_ring0.beam differ diff --git a/erts/preloaded/ebin/prim_eval.beam b/erts/preloaded/ebin/prim_eval.beam index ebca6e7eea..ddcc3886a4 100644 Binary files a/erts/preloaded/ebin/prim_eval.beam and b/erts/preloaded/ebin/prim_eval.beam differ diff --git a/erts/preloaded/ebin/prim_file.beam b/erts/preloaded/ebin/prim_file.beam index e8817d183e..97170551bf 100644 Binary files a/erts/preloaded/ebin/prim_file.beam and b/erts/preloaded/ebin/prim_file.beam differ diff --git a/erts/preloaded/ebin/prim_inet.beam b/erts/preloaded/ebin/prim_inet.beam index 8b87d1ae26..72065661c5 100644 Binary files a/erts/preloaded/ebin/prim_inet.beam and b/erts/preloaded/ebin/prim_inet.beam differ diff --git a/erts/preloaded/ebin/prim_zip.beam b/erts/preloaded/ebin/prim_zip.beam index 969239be98..2a0b33279d 100644 Binary files a/erts/preloaded/ebin/prim_zip.beam and b/erts/preloaded/ebin/prim_zip.beam differ diff --git a/erts/preloaded/ebin/zlib.beam b/erts/preloaded/ebin/zlib.beam index 281f668f8c..0d3d1d9343 100644 Binary files a/erts/preloaded/ebin/zlib.beam and b/erts/preloaded/ebin/zlib.beam differ -- 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') 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 1cf9bed55624fefabcb8c517f9e496a92883117a Mon Sep 17 00:00:00 2001 From: Lukas Larsson Date: Tue, 15 Dec 2015 10:22:25 +0100 Subject: Update preloaded modules --- erts/preloaded/ebin/erlang.beam | Bin 101752 -> 34396 bytes erts/preloaded/ebin/erts_internal.beam | Bin 6076 -> 2032 bytes 2 files changed, 0 insertions(+), 0 deletions(-) (limited to 'erts/preloaded') diff --git a/erts/preloaded/ebin/erlang.beam b/erts/preloaded/ebin/erlang.beam index 632defdb46..6610800458 100644 Binary files a/erts/preloaded/ebin/erlang.beam and b/erts/preloaded/ebin/erlang.beam differ diff --git a/erts/preloaded/ebin/erts_internal.beam b/erts/preloaded/ebin/erts_internal.beam index fd0a502d2c..fcc8c85e52 100644 Binary files a/erts/preloaded/ebin/erts_internal.beam and b/erts/preloaded/ebin/erts_internal.beam differ -- cgit v1.2.3 From 568cd49812ff0b59b0b8f1ebfc2da588f78d55a4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Gustavsson?= Date: Wed, 16 Dec 2015 12:45:05 +0100 Subject: Update preloaded modules --- erts/preloaded/ebin/erl_prim_loader.beam | Bin 56060 -> 56052 bytes erts/preloaded/ebin/erlang.beam | Bin 34396 -> 102012 bytes erts/preloaded/ebin/erts_internal.beam | Bin 2032 -> 6260 bytes erts/preloaded/ebin/init.beam | Bin 48600 -> 48592 bytes erts/preloaded/ebin/otp_ring0.beam | Bin 1460 -> 1452 bytes erts/preloaded/ebin/prim_eval.beam | Bin 1332 -> 1324 bytes erts/preloaded/ebin/prim_file.beam | Bin 44788 -> 44780 bytes erts/preloaded/ebin/prim_inet.beam | Bin 72624 -> 72612 bytes erts/preloaded/ebin/prim_zip.beam | Bin 23296 -> 23284 bytes erts/preloaded/ebin/zlib.beam | Bin 14168 -> 14160 bytes 10 files changed, 0 insertions(+), 0 deletions(-) (limited to 'erts/preloaded') diff --git a/erts/preloaded/ebin/erl_prim_loader.beam b/erts/preloaded/ebin/erl_prim_loader.beam index e94a1ba796..8ccbd1e36b 100644 Binary files a/erts/preloaded/ebin/erl_prim_loader.beam and b/erts/preloaded/ebin/erl_prim_loader.beam differ diff --git a/erts/preloaded/ebin/erlang.beam b/erts/preloaded/ebin/erlang.beam index 6610800458..87a48525bb 100644 Binary files a/erts/preloaded/ebin/erlang.beam and b/erts/preloaded/ebin/erlang.beam differ diff --git a/erts/preloaded/ebin/erts_internal.beam b/erts/preloaded/ebin/erts_internal.beam index fcc8c85e52..191dd332e2 100644 Binary files a/erts/preloaded/ebin/erts_internal.beam and b/erts/preloaded/ebin/erts_internal.beam differ diff --git a/erts/preloaded/ebin/init.beam b/erts/preloaded/ebin/init.beam index 60c08819eb..a78d9abc20 100644 Binary files a/erts/preloaded/ebin/init.beam and b/erts/preloaded/ebin/init.beam differ diff --git a/erts/preloaded/ebin/otp_ring0.beam b/erts/preloaded/ebin/otp_ring0.beam index 04814c091b..9cc91be343 100644 Binary files a/erts/preloaded/ebin/otp_ring0.beam and b/erts/preloaded/ebin/otp_ring0.beam differ diff --git a/erts/preloaded/ebin/prim_eval.beam b/erts/preloaded/ebin/prim_eval.beam index 7779c8374d..e84c8ffd2d 100644 Binary files a/erts/preloaded/ebin/prim_eval.beam and b/erts/preloaded/ebin/prim_eval.beam differ diff --git a/erts/preloaded/ebin/prim_file.beam b/erts/preloaded/ebin/prim_file.beam index 254b0e5b90..e1b2a1c8eb 100644 Binary files a/erts/preloaded/ebin/prim_file.beam and b/erts/preloaded/ebin/prim_file.beam differ diff --git a/erts/preloaded/ebin/prim_inet.beam b/erts/preloaded/ebin/prim_inet.beam index b7cfe26462..8853ae8bda 100644 Binary files a/erts/preloaded/ebin/prim_inet.beam and b/erts/preloaded/ebin/prim_inet.beam differ diff --git a/erts/preloaded/ebin/prim_zip.beam b/erts/preloaded/ebin/prim_zip.beam index 6b5c6195c8..563e604a1d 100644 Binary files a/erts/preloaded/ebin/prim_zip.beam and b/erts/preloaded/ebin/prim_zip.beam differ diff --git a/erts/preloaded/ebin/zlib.beam b/erts/preloaded/ebin/zlib.beam index 43d7b436be..304783ae37 100644 Binary files a/erts/preloaded/ebin/zlib.beam and b/erts/preloaded/ebin/zlib.beam differ -- 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') 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') 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') 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') 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') 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') 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') 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') 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') 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') 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') 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') 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') 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') 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 ef8a03c6dc3965ed56a746df524036b6b205feb9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Gustavsson?= Date: Wed, 16 Dec 2015 15:52:56 +0100 Subject: Update preloaded modules --- erts/preloaded/ebin/erl_prim_loader.beam | Bin 56052 -> 51424 bytes erts/preloaded/ebin/erlang.beam | Bin 102012 -> 102012 bytes erts/preloaded/ebin/erts_internal.beam | Bin 6260 -> 6260 bytes erts/preloaded/ebin/init.beam | Bin 48592 -> 44700 bytes erts/preloaded/ebin/otp_ring0.beam | Bin 1452 -> 1452 bytes erts/preloaded/ebin/prim_eval.beam | Bin 1324 -> 1324 bytes erts/preloaded/ebin/prim_file.beam | Bin 44780 -> 44892 bytes erts/preloaded/ebin/prim_inet.beam | Bin 72612 -> 72612 bytes erts/preloaded/ebin/prim_zip.beam | Bin 23284 -> 23284 bytes erts/preloaded/ebin/zlib.beam | Bin 14160 -> 14160 bytes 10 files changed, 0 insertions(+), 0 deletions(-) (limited to 'erts/preloaded') diff --git a/erts/preloaded/ebin/erl_prim_loader.beam b/erts/preloaded/ebin/erl_prim_loader.beam index 8ccbd1e36b..6ee26b7575 100644 Binary files a/erts/preloaded/ebin/erl_prim_loader.beam and b/erts/preloaded/ebin/erl_prim_loader.beam differ diff --git a/erts/preloaded/ebin/erlang.beam b/erts/preloaded/ebin/erlang.beam index 87a48525bb..77f25653a3 100644 Binary files a/erts/preloaded/ebin/erlang.beam and b/erts/preloaded/ebin/erlang.beam differ diff --git a/erts/preloaded/ebin/erts_internal.beam b/erts/preloaded/ebin/erts_internal.beam index 191dd332e2..4e1cb7f8a0 100644 Binary files a/erts/preloaded/ebin/erts_internal.beam and b/erts/preloaded/ebin/erts_internal.beam differ diff --git a/erts/preloaded/ebin/init.beam b/erts/preloaded/ebin/init.beam index a78d9abc20..a44b022931 100644 Binary files a/erts/preloaded/ebin/init.beam and b/erts/preloaded/ebin/init.beam differ diff --git a/erts/preloaded/ebin/otp_ring0.beam b/erts/preloaded/ebin/otp_ring0.beam index 9cc91be343..328520844d 100644 Binary files a/erts/preloaded/ebin/otp_ring0.beam and b/erts/preloaded/ebin/otp_ring0.beam differ diff --git a/erts/preloaded/ebin/prim_eval.beam b/erts/preloaded/ebin/prim_eval.beam index e84c8ffd2d..8d6c1927fd 100644 Binary files a/erts/preloaded/ebin/prim_eval.beam and b/erts/preloaded/ebin/prim_eval.beam differ diff --git a/erts/preloaded/ebin/prim_file.beam b/erts/preloaded/ebin/prim_file.beam index e1b2a1c8eb..1221c513db 100644 Binary files a/erts/preloaded/ebin/prim_file.beam and b/erts/preloaded/ebin/prim_file.beam differ diff --git a/erts/preloaded/ebin/prim_inet.beam b/erts/preloaded/ebin/prim_inet.beam index 8853ae8bda..fa617f1f51 100644 Binary files a/erts/preloaded/ebin/prim_inet.beam and b/erts/preloaded/ebin/prim_inet.beam differ diff --git a/erts/preloaded/ebin/prim_zip.beam b/erts/preloaded/ebin/prim_zip.beam index 563e604a1d..83e1e49974 100644 Binary files a/erts/preloaded/ebin/prim_zip.beam and b/erts/preloaded/ebin/prim_zip.beam differ diff --git a/erts/preloaded/ebin/zlib.beam b/erts/preloaded/ebin/zlib.beam index 304783ae37..8f654e3abf 100644 Binary files a/erts/preloaded/ebin/zlib.beam and b/erts/preloaded/ebin/zlib.beam differ -- 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/ebin/erlang.beam | Bin 101796 -> 102000 bytes erts/preloaded/src/erlang.erl | 10 +++++++++- 2 files changed, 9 insertions(+), 1 deletion(-) (limited to 'erts/preloaded') diff --git a/erts/preloaded/ebin/erlang.beam b/erts/preloaded/ebin/erlang.beam index cd2e7f18a2..58516c0ff3 100644 Binary files a/erts/preloaded/ebin/erlang.beam and b/erts/preloaded/ebin/erlang.beam differ 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 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/ebin/erts_code_purger.beam | Bin 0 -> 1132 bytes erts/preloaded/src/Makefile | 1 + erts/preloaded/src/erts.app.src | 1 + erts/preloaded/src/erts_code_purger.erl | 32 ++++++++++++++++++++++++++++++ 4 files changed, 34 insertions(+) create mode 100644 erts/preloaded/ebin/erts_code_purger.beam create mode 100644 erts/preloaded/src/erts_code_purger.erl (limited to 'erts/preloaded') diff --git a/erts/preloaded/ebin/erts_code_purger.beam b/erts/preloaded/ebin/erts_code_purger.beam new file mode 100644 index 0000000000..176497b052 Binary files /dev/null and b/erts/preloaded/ebin/erts_code_purger.beam differ 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/ebin/erts_code_purger.beam | Bin 1132 -> 9020 bytes erts/preloaded/src/erts_code_purger.erl | 283 +++++++++++++++++++++++++++++- 2 files changed, 280 insertions(+), 3 deletions(-) (limited to 'erts/preloaded') diff --git a/erts/preloaded/ebin/erts_code_purger.beam b/erts/preloaded/ebin/erts_code_purger.beam index 176497b052..adfe298a44 100644 Binary files a/erts/preloaded/ebin/erts_code_purger.beam and b/erts/preloaded/ebin/erts_code_purger.beam differ 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/ebin/erlang.beam | Bin 102216 -> 102556 bytes erts/preloaded/ebin/erts_code_purger.beam | Bin 9020 -> 8992 bytes erts/preloaded/ebin/erts_internal.beam | Bin 6260 -> 6432 bytes erts/preloaded/ebin/init.beam | Bin 44700 -> 44728 bytes 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 ++-- 8 files changed, 21 insertions(+), 15 deletions(-) (limited to 'erts/preloaded') diff --git a/erts/preloaded/ebin/erlang.beam b/erts/preloaded/ebin/erlang.beam index 68578c3a49..4353e115ca 100644 Binary files a/erts/preloaded/ebin/erlang.beam and b/erts/preloaded/ebin/erlang.beam differ diff --git a/erts/preloaded/ebin/erts_code_purger.beam b/erts/preloaded/ebin/erts_code_purger.beam index adfe298a44..553b34b105 100644 Binary files a/erts/preloaded/ebin/erts_code_purger.beam and b/erts/preloaded/ebin/erts_code_purger.beam differ diff --git a/erts/preloaded/ebin/erts_internal.beam b/erts/preloaded/ebin/erts_internal.beam index 4e1cb7f8a0..150e76505d 100644 Binary files a/erts/preloaded/ebin/erts_internal.beam and b/erts/preloaded/ebin/erts_internal.beam differ diff --git a/erts/preloaded/ebin/init.beam b/erts/preloaded/ebin/init.beam index a44b022931..b6d1df7bbc 100644 Binary files a/erts/preloaded/ebin/init.beam and b/erts/preloaded/ebin/init.beam differ 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/ebin/erlang.beam | Bin 102556 -> 102332 bytes erts/preloaded/ebin/erts_code_purger.beam | Bin 8992 -> 8996 bytes erts/preloaded/ebin/erts_internal.beam | Bin 6432 -> 6632 bytes erts/preloaded/src/erlang.erl | 9 +-------- erts/preloaded/src/erts_code_purger.erl | 10 +++++----- erts/preloaded/src/erts_internal.erl | 7 +++++++ 6 files changed, 13 insertions(+), 13 deletions(-) (limited to 'erts/preloaded') diff --git a/erts/preloaded/ebin/erlang.beam b/erts/preloaded/ebin/erlang.beam index 4353e115ca..d58d9c909e 100644 Binary files a/erts/preloaded/ebin/erlang.beam and b/erts/preloaded/ebin/erlang.beam differ diff --git a/erts/preloaded/ebin/erts_code_purger.beam b/erts/preloaded/ebin/erts_code_purger.beam index 553b34b105..74001fc799 100644 Binary files a/erts/preloaded/ebin/erts_code_purger.beam and b/erts/preloaded/ebin/erts_code_purger.beam differ diff --git a/erts/preloaded/ebin/erts_internal.beam b/erts/preloaded/ebin/erts_internal.beam index 150e76505d..7577522151 100644 Binary files a/erts/preloaded/ebin/erts_internal.beam and b/erts/preloaded/ebin/erts_internal.beam differ 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/ebin/erts_code_purger.beam | Bin 8996 -> 8832 bytes erts/preloaded/src/erts_code_purger.erl | 12 +++++------- 2 files changed, 5 insertions(+), 7 deletions(-) (limited to 'erts/preloaded') diff --git a/erts/preloaded/ebin/erts_code_purger.beam b/erts/preloaded/ebin/erts_code_purger.beam index 74001fc799..c5aec6bb25 100644 Binary files a/erts/preloaded/ebin/erts_code_purger.beam and b/erts/preloaded/ebin/erts_code_purger.beam differ 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/ebin/erlang.beam | Bin 102332 -> 101268 bytes erts/preloaded/ebin/erts_internal.beam | Bin 6632 -> 8168 bytes erts/preloaded/src/erlang.erl | 44 ++------------------------ erts/preloaded/src/erts_internal.erl | 55 ++++++++++++++++++++++++++++++++- 4 files changed, 56 insertions(+), 43 deletions(-) (limited to 'erts/preloaded') diff --git a/erts/preloaded/ebin/erlang.beam b/erts/preloaded/ebin/erlang.beam index d58d9c909e..b6e38e4b5b 100644 Binary files a/erts/preloaded/ebin/erlang.beam and b/erts/preloaded/ebin/erlang.beam differ diff --git a/erts/preloaded/ebin/erts_internal.beam b/erts/preloaded/ebin/erts_internal.beam index 7577522151..4c66171965 100644 Binary files a/erts/preloaded/ebin/erts_internal.beam and b/erts/preloaded/ebin/erts_internal.beam differ 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/ebin/erts_code_purger.beam | Bin 8832 -> 8884 bytes erts/preloaded/ebin/erts_internal.beam | Bin 8168 -> 8536 bytes erts/preloaded/src/erts_code_purger.erl | 5 ++-- erts/preloaded/src/erts_internal.erl | 42 ++++++++++++++++++------------ 4 files changed, 28 insertions(+), 19 deletions(-) (limited to 'erts/preloaded') diff --git a/erts/preloaded/ebin/erts_code_purger.beam b/erts/preloaded/ebin/erts_code_purger.beam index c5aec6bb25..ca6c8570ed 100644 Binary files a/erts/preloaded/ebin/erts_code_purger.beam and b/erts/preloaded/ebin/erts_code_purger.beam differ diff --git a/erts/preloaded/ebin/erts_internal.beam b/erts/preloaded/ebin/erts_internal.beam index 4c66171965..d3d990519d 100644 Binary files a/erts/preloaded/ebin/erts_internal.beam and b/erts/preloaded/ebin/erts_internal.beam differ 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/ebin/erts_code_purger.beam | Bin 8884 -> 8768 bytes erts/preloaded/src/erts_code_purger.erl | 3 +-- 2 files changed, 1 insertion(+), 2 deletions(-) (limited to 'erts/preloaded') diff --git a/erts/preloaded/ebin/erts_code_purger.beam b/erts/preloaded/ebin/erts_code_purger.beam index ca6c8570ed..227d96d4c8 100644 Binary files a/erts/preloaded/ebin/erts_code_purger.beam and b/erts/preloaded/ebin/erts_code_purger.beam differ 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 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') 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') 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') 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') 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 613a8d74d1641ee67d3d9e7333c9711ff8a1f446 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Gustavsson?= Date: Wed, 20 Jan 2016 12:36:49 +0100 Subject: Update preloaded modules --- erts/preloaded/ebin/erl_prim_loader.beam | Bin 51424 -> 49964 bytes 1 file changed, 0 insertions(+), 0 deletions(-) (limited to 'erts/preloaded') diff --git a/erts/preloaded/ebin/erl_prim_loader.beam b/erts/preloaded/ebin/erl_prim_loader.beam index 6ee26b7575..f6057b45d4 100644 Binary files a/erts/preloaded/ebin/erl_prim_loader.beam and b/erts/preloaded/ebin/erl_prim_loader.beam differ -- cgit v1.2.3