Sign Up
Log In
Log In
or
Sign Up
Places
All Projects
Status Monitor
Collapse sidebar
home:Ledest:erlang:23
erlang
8241-kernel-Fix-AC-to-respond-to-calls-while-te...
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
File 8241-kernel-Fix-AC-to-respond-to-calls-while-terminating.patch of Package erlang
From ec8e4402bf896eb73d3501487e5036a597dba68c Mon Sep 17 00:00:00 2001 From: Lukas Larsson <lukas@erlang.org> Date: Tue, 23 Apr 2024 21:12:28 +0200 Subject: [PATCH 1/2] kernel: Fix AC to respond to calls while terminating --- lib/kernel/src/application_controller.erl | 89 +++++++++++-------- lib/kernel/src/kernel.app.src | 3 +- lib/kernel/test/application_SUITE.erl | 60 ++++++++++++- .../deadlock/deadlock.erl | 4 +- lib/sasl/test/release_handler_SUITE.erl | 7 +- 5 files changed, 119 insertions(+), 44 deletions(-) diff --git a/lib/kernel/src/application_controller.erl b/lib/kernel/src/application_controller.erl index 60080c155e..838176d48d 100644 --- a/lib/kernel/src/application_controller.erl +++ b/lib/kernel/src/application_controller.erl @@ -209,10 +209,10 @@ start(KernelApp) -> %% Returns: ok | {error, Reason} %%----------------------------------------------------------------- load_application(Application) -> - gen_server:call(?AC, {load_application, Application}, infinity). + call({load_application, Application}, infinity). unload_application(AppName) -> - gen_server:call(?AC, {unload_application, AppName}, infinity). + call({unload_application, AppName}, infinity). %%----------------------------------------------------------------- %% Func: start_application/2 @@ -236,7 +236,7 @@ unload_application(AppName) -> %% Returns: ok | {error, Reason} %%----------------------------------------------------------------- start_application(AppName, RestartType) -> - gen_server:call(?AC, {start_application, AppName, RestartType}, infinity). + call({start_application, AppName, RestartType}, infinity). %%----------------------------------------------------------------- %% Func: is_running/1 @@ -250,7 +250,7 @@ start_application_request(AppName, RestartType) -> %% Returns: boolean %%----------------------------------------------------------------- is_running(AppName) when is_atom(AppName) -> - gen_server:call(?AC, {is_running, AppName}, infinity). + call({is_running, AppName}, infinity). %%----------------------------------------------------------------- %% Func: start_boot_application/2 @@ -263,9 +263,9 @@ start_boot_application(Application, RestartType) -> case {application:load(Application), RestartType} of {ok, _} -> AppName = get_appl_name(Application), - gen_server:call(?AC, {start_application, AppName, RestartType}, infinity); + call({start_application, AppName, RestartType}, infinity); {{error, {already_loaded, AppName}}, _} -> - gen_server:call(?AC, {start_application, AppName, RestartType}, infinity); + call({start_application, AppName, RestartType}, infinity); {{error,{bad_environment_value,Env}}, permanent} -> Txt = io_lib:format("Bad environment variable: ~tp Application: ~p", [Env, Application]), @@ -275,15 +275,15 @@ start_boot_application(Application, RestartType) -> end. stop_application(AppName) -> - gen_server:call(?AC, {stop_application, AppName}, infinity). + call({stop_application, AppName}, infinity). %%----------------------------------------------------------------- %% Returns: [{Name, Descr, Vsn}] %%----------------------------------------------------------------- which_applications() -> - gen_server:call(?AC, which_applications). + call(which_applications). which_applications(Timeout) -> - gen_server:call(?AC, which_applications, Timeout). + call(which_applications, Timeout). loaded_applications() -> ets:select(ac_tab, @@ -295,10 +295,10 @@ loaded_applications() -> %% Returns some debug info info() -> - gen_server:call(?AC, info). + call(info). control_application(AppName) -> - gen_server:call(?AC, {control_application, AppName}, infinity). + call({control_application, AppName}, infinity). %%----------------------------------------------------------------- %% Func: change_application_data/2 @@ -323,21 +323,14 @@ control_application(AppName) -> %% some applicatation may have got new config data. %%----------------------------------------------------------------- change_application_data(Applications, Config) -> - gen_server:call(?AC, - {change_application_data, Applications, Config}, - infinity). + call({change_application_data, Applications, Config},infinity). prep_config_change() -> - gen_server:call(?AC, - prep_config_change, - infinity). + call(prep_config_change, infinity). config_change(EnvPrev) -> - gen_server:call(?AC, - {config_change, EnvPrev}, - infinity). - + call({config_change, EnvPrev},infinity). get_pid_env(Master, Key) -> @@ -439,7 +432,7 @@ get_all_key(AppName) -> start_type(Master) -> case ets:match(ac_tab, {{application_master, '$1'}, Master}) of [[AppName]] -> - gen_server:call(?AC, {start_type, AppName}, infinity); + call({start_type, AppName}, infinity); _X -> undefined end. @@ -475,31 +468,44 @@ get_application_module(_Module, []) -> undefined. permit_application(ApplName, Flag) -> - gen_server:call(?AC, - {permit_application, ApplName, Flag}, - infinity). + call({permit_application, ApplName, Flag},infinity). set_env(Config, Opts) -> case check_conf_data(Config) of ok -> Timeout = proplists:get_value(timeout, Opts, 5000), - gen_server:call(?AC, {set_env, Config, Opts}, Timeout); + call({set_env, Config, Opts}, Timeout); {error, _} = Error -> Error end. set_env(AppName, Key, Val) -> - gen_server:call(?AC, {set_env, AppName, Key, Val, []}). + call({set_env, AppName, Key, Val, []}). set_env(AppName, Key, Val, Opts) -> Timeout = proplists:get_value(timeout, Opts, 5000), - gen_server:call(?AC, {set_env, AppName, Key, Val, Opts}, Timeout). + call({set_env, AppName, Key, Val, Opts}, Timeout). unset_env(AppName, Key) -> - gen_server:call(?AC, {unset_env, AppName, Key, []}). + call({unset_env, AppName, Key, []}). unset_env(AppName, Key, Opts) -> Timeout = proplists:get_value(timeout, Opts, 5000), - gen_server:call(?AC, {unset_env, AppName, Key, Opts}, Timeout). + call({unset_env, AppName, Key, Opts}, Timeout). + +call(Cmd) -> + case gen_server:call(?AC, Cmd) of + {error, terminating} -> + exit(terminating); + Res -> + Res + end. +call(Cmd, Timeout) -> + case gen_server:call(?AC, Cmd, Timeout) of + {error, terminating} -> + exit(terminating); + Res -> + Res + end. %%%----------------------------------------------------------------- %%% call-back functions from gen_server @@ -1233,14 +1239,21 @@ terminate(Reason, S) -> %% Proc died before link {'EXIT', Id, _} -> ok after 0 -> - receive - {'DOWN', Ref, process, Id, _} -> ok - after ShutdownTimeout -> - exit(Id, kill), - receive - {'DOWN', Ref, process, Id, _} -> ok - end - end + (fun F() -> + receive + {'DOWN', Ref, process, Id, _} -> ok; + %% We need to handle any gen_server:call here + %% and reply to them so that they don't deadlock + {'$gen_call', From, _Msg} -> + gen_server:reply(From, {error, terminating}), + F() + after ShutdownTimeout -> + exit(Id, kill), + receive + {'DOWN', Ref, process, Id, _} -> ok + end + end + end)() end; (_) -> ok end, diff --git a/lib/kernel/src/kernel.app.src b/lib/kernel/src/kernel.app.src index 10705d9d76..c7fa92e73f 100644 --- a/lib/kernel/src/kernel.app.src +++ b/lib/kernel/src/kernel.app.src @@ -157,7 +157,8 @@ {net_tickintensity, 4}, {net_ticktime, 60}, {prevent_overlapping_partitions, false}, - {shell_docs_ansi,auto} + {shell_docs_ansi,auto}, + {shell_history_drop,[]} ]}, {mod, {kernel, []}}, {runtime_dependencies, ["erts-11.2.2.11", "stdlib-3.13", "sasl-3.0"]} diff --git a/lib/kernel/test/application_SUITE.erl b/lib/kernel/test/application_SUITE.erl index 83f1bfada9..5b7f3e9d16 100644 --- a/lib/kernel/test/application_SUITE.erl +++ b/lib/kernel/test/application_SUITE.erl @@ -20,6 +20,7 @@ -module(application_SUITE). -include_lib("common_test/include/ct.hrl"). +-include_lib("stdlib/include/assert.hrl"). -export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1, init_per_group/2,end_per_group/2 @@ -38,7 +39,8 @@ -export([config_change/1, persistent_env/1, invalid_app_file/1, distr_changed_tc1/1, distr_changed_tc2/1, ensure_started/1, ensure_all_started/1, - shutdown_func/1, do_shutdown/1, shutdown_timeout/1, shutdown_deadlock/1, + shutdown_func/1, do_shutdown/1, shutdown_timeout/1, + shutdown_application_call/1,shutdown_deadlock/1, config_relative_paths/1, handle_many_config_files/1, format_log_1/1, format_log_2/1]). @@ -60,7 +62,7 @@ all() -> permit_false_start_dist, get_key, get_env, ensure_all_started, set_env, set_env_persistent, set_env_errors, get_supervisor, {group, distr_changed}, config_change, shutdown_func, shutdown_timeout, - shutdown_deadlock, config_relative_paths, optional_applications, + shutdown_application_call, shutdown_deadlock, config_relative_paths, optional_applications, persistent_env, handle_many_config_files, format_log_1, format_log_2, invalid_app_file]. @@ -2576,6 +2578,60 @@ shutdown_timeout(Config) when is_list(Config) -> end, ok. +%%%----------------------------------------------------------------- +%%% Test that we do not cause a deadlock if we call +%%% application:set_env or application:ensure_started +%%% when terminating +%%%----------------------------------------------------------------- +shutdown_application_call(Config) when is_list(Config) -> + Tester = self(), + shutdown_application_call( + fun() -> + Tester ! {Tester, + catch application:set_env( + deadlock, a, b, [{timeout, infinity}, + {persistent, true}])} + end, Config), + receive + {Tester, M} -> + ?assertMatch({'EXIT',terminating}, M) + after 1000 -> + ct:fail("timeout 1 sec: no crash message found") + end, + + shutdown_application_call( + fun() -> + Tester ! {Tester, catch application:ensure_started(runtime_tools)} + end, Config), + receive + {Tester, M2} -> + ?assertMatch({'EXIT',terminating}, M2) + after 1000 -> + ct:fail("timeout 1 sec: no crash message found") + end. + +shutdown_application_call(Fun, Config) -> + + DataDir = proplists:get_value(data_dir,Config), + {ok,Cp1} = start_node(?MODULE_STRING++"_"++atom_to_list(?FUNCTION_NAME)), + wait_for_ready_net(), + rpc:call(Cp1, code, add_path, [filename:join([DataDir,deadlock])]), + rpc:call(Cp1, code, add_path, [filename:dirname(code:which(?MODULE))]), + ok = rpc:call(Cp1, application, start, [sasl]), + + ok = rpc:call(Cp1, application, start, [deadlock]), + rpc:call(Cp1, application, set_env, [deadlock, fail_stop, Fun]), + + ok = net_kernel:monitor_nodes(true), + _ = rpc:call(Cp1, init, stop, []), + receive + {nodedown,Cp1} -> + ok + after 10000 -> + ct:fail("timeout 10 sec: node termination hangs") + end, + ok. + %%%----------------------------------------------------------------- %%% Provokes a (previous) application shutdown deadlock %%%----------------------------------------------------------------- diff --git a/lib/kernel/test/application_SUITE_data/deadlock/deadlock.erl b/lib/kernel/test/application_SUITE_data/deadlock/deadlock.erl index 3ef6105371..d8ade0c7c7 100644 --- a/lib/kernel/test/application_SUITE_data/deadlock/deadlock.erl +++ b/lib/kernel/test/application_SUITE_data/deadlock/deadlock.erl @@ -54,7 +54,9 @@ handle_info(_Msg, State) -> terminate(_Reason, _State) -> case application:get_env(deadlock, fail_stop) of {ok, false} -> ok; - {ok, Tester} -> + {ok, Fun} when is_function(Fun, 0) -> + Fun(); + {ok, Tester} when is_pid(Tester) -> Tester ! {deadlock, self()}, io:format("~p: Waiting in terminate (~p)~n",[?MODULE,Tester]), receive continue -> ok end diff --git a/lib/sasl/test/release_handler_SUITE.erl b/lib/sasl/test/release_handler_SUITE.erl index 7e4c9df56f..f5924d1af9 100644 --- a/lib/sasl/test/release_handler_SUITE.erl +++ b/lib/sasl/test/release_handler_SUITE.erl @@ -2388,7 +2388,10 @@ wait_nodes_up(Nodes, Tag, Apps, N) -> fun(NodeInfo={Node,OldInitPid}, A) -> case rpc:call(Node, application, which_applications, []) of {badrpc, nodedown} -> - ?t:format( " ~p = {badarg, nodedown}",[Node]), + ?t:format( " ~p = {badrpc, nodedown}",[Node]), + [NodeInfo | A]; + {badrpc, {'EXIT',terminating}} -> + ?t:format( " ~p = {badrpc, {'EXIT',terminating}}",[Node]), [NodeInfo | A]; List when is_list(List)-> ?t:format( " ~p = [~p]",[Node, List]), @@ -2406,7 +2409,7 @@ wait_nodes_up(Nodes, Tag, Apps, N) -> false -> [NodeInfo | A] end - end + end end, Pang = lists:foldl(Fun,[],Nodes), case Pang of -- 2.35.3
Locations
Projects
Search
Status Monitor
Help
OpenBuildService.org
Documentation
API Documentation
Code of Conduct
Contact
Support
@OBShq
Terms
openSUSE Build Service is sponsored by
The Open Build Service is an
openSUSE project
.
Sign Up
Log In
Places
Places
All Projects
Status Monitor