aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLukas Larsson <[email protected]>2016-07-04 11:56:20 +0200
committerLukas Larsson <[email protected]>2016-08-12 11:35:09 +0200
commit53a487cd5019e7f7e3abee6b4a5e2d0b05aa34c6 (patch)
tree84d36c55f2b30345dd553f38f4bad1de75c3384d
parent30e1d890e37ffd57bfbcf043b3b982c781139418 (diff)
downloadotp-53a487cd5019e7f7e3abee6b4a5e2d0b05aa34c6.tar.gz
otp-53a487cd5019e7f7e3abee6b4a5e2d0b05aa34c6.tar.bz2
otp-53a487cd5019e7f7e3abee6b4a5e2d0b05aa34c6.zip
erts/kernel: Fix code loading deadlock during init:stop
When init:stop is called it walks the application hierarchy and terminates each process. Some of these processes may do something while terminating and sometimes that something needs to load some new code in order to work. When this happens the code_server could just be in the process of terminating or the erl_prim_loader could be active. In both these cases the request to load the new code would cause a deadlock in the termination of the system. This commit fixes this by init rejecting attempts to load new code when init:stop has been called and fixing a termination race in the code_server. This however means that the process that tried to do something when told to terminate (for instance logging that it is terminating) will crash instead of loading the code.
-rw-r--r--erts/preloaded/ebin/init.beambin50048 -> 50036 bytes
-rw-r--r--erts/preloaded/src/init.erl5
-rw-r--r--lib/kernel/src/code_server.erl6
3 files changed, 7 insertions, 4 deletions
diff --git a/erts/preloaded/ebin/init.beam b/erts/preloaded/ebin/init.beam
index b856bff4fe..f0344fd6ba 100644
--- a/erts/preloaded/ebin/init.beam
+++ b/erts/preloaded/ebin/init.beam
Binary files differ
diff --git a/erts/preloaded/src/init.erl b/erts/preloaded/src/init.erl
index 45468b3b9c..67929c53c2 100644
--- a/erts/preloaded/src/init.erl
+++ b/erts/preloaded/src/init.erl
@@ -423,9 +423,6 @@ loop(State) ->
Loaded = State#state.loaded, %% boot_loop but is handled here
From ! {init,Loaded}, %% anyway.
loop(State);
- {From, {ensure_loaded, _}} ->
- From ! {init, not_allowed},
- loop(State);
Msg ->
loop(handle_msg(Msg,State))
end.
@@ -465,6 +462,8 @@ do_handle_msg(Msg,State) ->
From ! {init,ok},
{new_state,State#state{subscribed = [Pid|Subscribed]}}
end;
+ {From, {ensure_loaded, _}} ->
+ From ! {init, not_allowed};
X ->
case whereis(user) of
undefined ->
diff --git a/lib/kernel/src/code_server.erl b/lib/kernel/src/code_server.erl
index 6174136507..c7d0c3299a 100644
--- a/lib/kernel/src/code_server.erl
+++ b/lib/kernel/src/code_server.erl
@@ -135,10 +135,14 @@ split_paths([], _S, Path, Paths) ->
-spec call(term()) -> term().
call(Req) ->
+ Ref = erlang:monitor(process, ?MODULE),
?MODULE ! {code_call, self(), Req},
receive
{?MODULE, Reply} ->
- Reply
+ erlang:demonitor(Ref,[flush]),
+ Reply;
+ {'DOWN',Ref,process,_,_} ->
+ exit({'DOWN',code_server,Req})
end.
reply(Pid, Res) ->