From 4bc282d812cc2c49aa3e2d073e96c720f16aa270 Mon Sep 17 00:00:00 2001 From: Rickard Green Date: Wed, 7 Mar 2018 01:17:21 +0100 Subject: Implementation of true asynchronous signaling between processes Communication between Erlang processes has conceptually always been performed through asynchronous signaling. The runtime system implementation has however previously preformed most operation synchronously. In a system with only one true thread of execution, this is not problematic (often the opposite). In a system with multiple threads of execution (as current runtime system implementation with SMP support) it becomes problematic. This since it often involves locking of structures when updating them which in turn cause resource contention. Utilizing true asynchronous communication often avoids these resource contention issues. The case that triggered this change was contention on the link lock due to frequent updates of the monitor trees during communication with a frequently used server. The signal order delivery guarantees of the language makes it hard to change the implementation of only some signals to use true asynchronous signaling. Therefore the implementations of (almost) all signals have been changed. Currently the following signals have been implemented as true asynchronous signals: - Message signals - Exit signals - Monitor signals - Demonitor signals - Monitor triggered signals (DOWN, CHANGE, etc) - Link signals - Unlink signals - Group leader signals All of the above already defined as asynchronous signals in the language. The implementation of messages signals was quite asynchronous to begin with, but had quite strict delivery constraints due to the ordering guarantees of signals between a pair of processes. The previously used message queue partitioned into two halves has been replaced by a more general signal queue partitioned into three parts that service all kinds of signals. More details regarding the signal queue can be found in comments in the erl_proc_sig_queue.h file. The monitor and link implementations have also been completely replaced in order to fit the new asynchronous signaling implementation as good as possible. More details regarding the new monitor and link implementations can be found in the erl_monitor_link.h file. --- erts/preloaded/ebin/erlang.beam | Bin 102992 -> 103248 bytes .../ebin/erts_dirty_process_code_checker.beam | Bin 2100 -> 0 bytes .../ebin/erts_dirty_process_signal_handler.beam | Bin 0 -> 2740 bytes erts/preloaded/ebin/erts_internal.beam | Bin 14104 -> 14712 bytes erts/preloaded/src/Makefile | 4 +- erts/preloaded/src/erlang.erl | 36 +++++--- .../src/erts_dirty_process_code_checker.erl | 81 ----------------- .../src/erts_dirty_process_signal_handler.erl | 97 +++++++++++++++++++++ erts/preloaded/src/erts_internal.erl | 28 +++++- 9 files changed, 150 insertions(+), 96 deletions(-) delete mode 100644 erts/preloaded/ebin/erts_dirty_process_code_checker.beam create mode 100644 erts/preloaded/ebin/erts_dirty_process_signal_handler.beam delete mode 100644 erts/preloaded/src/erts_dirty_process_code_checker.erl create mode 100644 erts/preloaded/src/erts_dirty_process_signal_handler.erl (limited to 'erts/preloaded') diff --git a/erts/preloaded/ebin/erlang.beam b/erts/preloaded/ebin/erlang.beam index cf4b5c56ea..4d1691d71a 100644 Binary files a/erts/preloaded/ebin/erlang.beam and b/erts/preloaded/ebin/erlang.beam differ diff --git a/erts/preloaded/ebin/erts_dirty_process_code_checker.beam b/erts/preloaded/ebin/erts_dirty_process_code_checker.beam deleted file mode 100644 index 2a4cb53d3e..0000000000 Binary files a/erts/preloaded/ebin/erts_dirty_process_code_checker.beam and /dev/null differ diff --git a/erts/preloaded/ebin/erts_dirty_process_signal_handler.beam b/erts/preloaded/ebin/erts_dirty_process_signal_handler.beam new file mode 100644 index 0000000000..2df6da7415 Binary files /dev/null and b/erts/preloaded/ebin/erts_dirty_process_signal_handler.beam differ diff --git a/erts/preloaded/ebin/erts_internal.beam b/erts/preloaded/ebin/erts_internal.beam index b79f734a6d..799c3e17fb 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/Makefile b/erts/preloaded/src/Makefile index a2872082f2..4333f6643a 100644 --- a/erts/preloaded/src/Makefile +++ b/erts/preloaded/src/Makefile @@ -1,7 +1,7 @@ # # %CopyrightBegin% # -# Copyright Ericsson AB 2008-2016. All Rights Reserved. +# Copyright Ericsson AB 2008-2018. 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. @@ -47,7 +47,7 @@ PRE_LOADED_ERL_MODULES = \ erts_internal \ erl_tracer \ erts_literal_area_collector \ - erts_dirty_process_code_checker + erts_dirty_process_signal_handler PRE_LOADED_BEAM_MODULES = \ prim_eval diff --git a/erts/preloaded/src/erlang.erl b/erts/preloaded/src/erlang.erl index 370ecdc3f6..6cfca68a56 100644 --- a/erts/preloaded/src/erlang.erl +++ b/erts/preloaded/src/erlang.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2017. All Rights Reserved. +%% Copyright Ericsson AB 1996-2018. 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. @@ -31,7 +31,7 @@ -export([localtime_to_universaltime/1]). -export([suspend_process/1]). -export([min/2, max/2]). --export([dmonitor_node/3, dmonitor_p/2]). +-export([dmonitor_node/3]). -export([delay_trap/2]). -export([set_cookie/2, get_cookie/0]). -export([nodes/0]). @@ -122,7 +122,7 @@ -export([delete_element/2]). -export([delete_module/1, demonitor/1, demonitor/2, display/1]). -export([display_nl/0, display_string/1, erase/0, erase/1]). --export([error/1, error/2, exit/1, exit/2, external_size/1]). +-export([error/1, error/2, exit/1, exit/2, exit_signal/2, external_size/1]). -export([external_size/2, finish_after_on_load/2, finish_loading/1, float/1]). -export([float_to_binary/1, float_to_binary/2, float_to_list/1, float_to_list/2, floor/1]). @@ -786,6 +786,13 @@ exit(_Reason) -> exit(_Pid, _Reason) -> erlang:nif_error(undefined). +%% exit_signal/2 +-spec erlang:exit_signal(Pid, Reason) -> true when + Pid :: pid() | port(), + Reason :: term(). +exit_signal(_Pid, _Reason) -> + erlang:nif_error(undefined). + %% external_size/1 -spec erlang:external_size(Term) -> non_neg_integer() when Term :: term(). @@ -1012,8 +1019,20 @@ group_leader() -> -spec group_leader(GroupLeader, Pid) -> true when GroupLeader :: pid(), Pid :: pid(). -group_leader(_GroupLeader, _Pid) -> - erlang:nif_error(undefined). +group_leader(GroupLeader, Pid) -> + case case erts_internal:group_leader(GroupLeader, Pid) of + false -> + Ref = erlang:make_ref(), + erts_internal:group_leader(GroupLeader, + Pid, + Ref), + receive {Ref, MsgRes} -> MsgRes end; + Res -> + Res + end of + true -> true; + Error -> erlang:error(Error, [GroupLeader, Pid]) + end. %% halt/0 %% Shadowed by erl_bif_types: erlang:halt/0 @@ -3279,13 +3298,6 @@ dmonitor_node(Node, Flag, Opts) -> dmonitor_node(Node,Flag,[]) end. --spec erlang:dmonitor_p('process', pid() | {atom(),atom()}) -> reference(). -dmonitor_p(process, ProcSpec) -> - %% Only called when auto-connect attempt failed early in VM - Ref = erlang:make_ref(), - erlang:self() ! {'DOWN', Ref, process, ProcSpec, noconnection}, - Ref. - %% %% Trap function used when modified timing has been enabled. %% diff --git a/erts/preloaded/src/erts_dirty_process_code_checker.erl b/erts/preloaded/src/erts_dirty_process_code_checker.erl deleted file mode 100644 index 7d3fa264be..0000000000 --- a/erts/preloaded/src/erts_dirty_process_code_checker.erl +++ /dev/null @@ -1,81 +0,0 @@ -%% -%% %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_dirty_process_code_checker). - --export([start/0]). - -%% -%% The erts_dirty_process_code_checker is started at -%% VM boot by the VM. It is a spawned as a system -%% process, i.e, the whole VM will terminate if -%% this process terminates. -%% -start() -> - process_flag(trap_exit, true), - msg_loop(). - -msg_loop() -> - _ = receive - Request -> - handle_request(Request) - end, - msg_loop(). - -check_process(Requester, Target, ReqId, Module) -> - Result = erts_internal:check_dirty_process_code(Target, Module), - Requester ! {check_process_code, ReqId, Result}. - -handle_request({Requester, - Target, - Prio, - {check_process_code, - ReqId, - Module} = Op}) -> - %% - %% Target may have stopped executing dirty since the - %% initial request was made. Check its current state - %% and try to send the request if possible; otherwise, - %% check the dirty executing process and send the result... - %% - try - case erts_internal:is_process_executing_dirty(Target) of - true -> - check_process(Requester, Target, ReqId, Module); - false -> - case erts_internal:request_system_task(Requester, - Target, - Prio, - Op) of - ok -> - ok; - dirty_execution -> - check_process(Requester, Target, ReqId, Module) - end - end - catch - _ : _ -> - ok %% Ignore all failures; someone passed us garbage... - end; -handle_request(_Garbage) -> - ignore. - - - diff --git a/erts/preloaded/src/erts_dirty_process_signal_handler.erl b/erts/preloaded/src/erts_dirty_process_signal_handler.erl new file mode 100644 index 0000000000..ab71790b9d --- /dev/null +++ b/erts/preloaded/src/erts_dirty_process_signal_handler.erl @@ -0,0 +1,97 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2018. 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_dirty_process_signal_handler). + +-export([start/0]). + +%% +%% The erts_dirty_process_signal_handler is started at +%% VM boot by the VM. It is a spawned as a system +%% process, i.e, the whole VM will terminate if +%% this process terminates. +%% +start() -> + process_flag(trap_exit, true), + msg_loop(). + +msg_loop() -> + _ = receive + Request -> + try + handle_request(Request) + catch + _ : _ -> + %% Ignore all failures; + %% someone passed us garbage... + ok + end + end, + msg_loop(). + +handle_request(Pid) when is_pid(Pid) -> + handle_incoming_signals(Pid, 0); +handle_request({Requester, Target, Prio, + {SysTaskOp, ReqId, Arg} = Op} = Request) -> + case handle_sys_task(Requester, Target, SysTaskOp, ReqId, Arg) of + true -> + ok; + false -> + %% Target has stopped executing dirty since the + %% initial request was made. Dispatch the + %% request to target and let it handle it itself... + case erts_internal:request_system_task(Requester, + Target, + Prio, + Op) of + ok -> + ok; + dirty_execution -> + %% Ahh... It began executing dirty again... + handle_request(Request) + end + end; +handle_request(_Garbage) -> + ignore. + +%% +%% ---------------------------------------------------------------------------- +%% + +handle_incoming_signals(Pid, 5) -> + self() ! Pid; %% Work with other requests for a while... +handle_incoming_signals(Pid, N) -> + case erts_internal:dirty_process_handle_signals(Pid) of + more -> handle_incoming_signals(Pid, N+1); + _Res -> ok + end. + +handle_sys_task(Requester, Target, check_process_code, ReqId, Module) -> + case erts_internal:is_process_executing_dirty(Target) of + false -> + false; + true -> + _ = check_process(Requester, Target, ReqId, Module), + true + end. + +check_process(Requester, Target, ReqId, Module) -> + Result = erts_internal:check_dirty_process_code(Target, Module), + Requester ! {check_process_code, ReqId, Result}. diff --git a/erts/preloaded/src/erts_internal.erl b/erts/preloaded/src/erts_internal.erl index a51c0c4c0e..21f228395e 100644 --- a/erts/preloaded/src/erts_internal.erl +++ b/erts/preloaded/src/erts_internal.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2012-2017. All Rights Reserved. +%% Copyright Ericsson AB 2012-2018. 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. @@ -45,6 +45,8 @@ -export([check_process_code/3]). -export([check_dirty_process_code/2]). -export([is_process_executing_dirty/1]). +-export([dirty_process_handle_signals/1]). + -export([release_literal_area_switch/0]). -export([purge_module/2]). @@ -71,6 +73,8 @@ gather_sched_wall_time_result/1, await_sched_wall_time_modifications/2]). +-export([group_leader/2, group_leader/3]). + %% Auto import name clash -export([check_process_code/1]). @@ -306,6 +310,13 @@ check_dirty_process_code(_Pid,_Module) -> is_process_executing_dirty(_Pid) -> erlang:nif_error(undefined). +-spec dirty_process_handle_signals(Pid) -> Res when + Pid :: pid(), + Res :: 'false' | 'true' | 'noproc' | 'normal' | 'more' | 'ok'. + +dirty_process_handle_signals(_Pid) -> + erlang:nif_error(undefined). + -spec release_literal_area_switch() -> 'true' | 'false'. release_literal_area_switch() -> @@ -574,3 +585,18 @@ sched_wall_time(Ref, N, Acc) -> {Ref, SWTL} when erlang:is_list(SWTL) -> sched_wall_time(Ref, N-1, Acc ++ SWTL); {Ref, SWT} -> sched_wall_time(Ref, N-1, [SWT|Acc]) end. + +-spec erts_internal:group_leader(GL, Pid) -> true | false | badarg when + GL :: pid(), + Pid :: pid(). + +group_leader(_GL, _Pid) -> + erlang:nif_error(undefined). + +-spec erts_internal:group_leader(GL, Pid, Ref) -> ok when + GL :: pid(), + Pid :: pid(), + Ref :: reference(). + +group_leader(_GL, _Pid, _Ref) -> + erlang:nif_error(undefined). -- cgit v1.2.3