File 2331-Check-for-embedded-mode-in-the-client.patch of Package erlang

From e0ea6f5fd2b0a92e4ff8516c2a6f2680b31684fc Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jos=C3=A9=20Valim?= <jose.valim@dashbit.co>
Date: Tue, 9 Jan 2024 11:44:52 +0100
Subject: [PATCH] Check for embedded mode in the client

This ensures that checking for code:ensure_loaded/1
in embedded mode (and other operations) do not send
additional messages to the code server.

This pull request fully closes #7889. While previous
work has fixed the slow path in the code server, this
pull request makes it so the code server is avoided
altogether.
---
 lib/kernel/doc/src/code.xml    | 11 +++++++---
 lib/kernel/src/code.erl        | 29 ++++++++++++++-----------
 lib/kernel/src/code_server.erl | 39 +++++++++++++---------------------
 3 files changed, 40 insertions(+), 39 deletions(-)

diff --git a/lib/kernel/doc/src/code.xml b/lib/kernel/doc/src/code.xml
index 66090cc6fd..7d5f2c10c9 100644
--- a/lib/kernel/doc/src/code.xml
+++ b/lib/kernel/doc/src/code.xml
@@ -602,8 +602,11 @@ ok = code:finish_loading(Prepared),
       <desc>
         <p>Tries to load a module in the same way as
           <seemfa marker="#load_file/1"><c>load_file/1</c></seemfa>,
-	  unless the module is already loaded.
-          However, in embedded mode it does not load a module that is not
+	  unless the module is already loaded. If called concurrently,
+          this function ensures only one process attempts to load said
+          module at a given time.</p>
+
+        <p>In embedded mode, it does not load a module that is not
           already loaded, but returns <c>{error, embedded}</c> instead.
 	  See <seeerl marker="#error_reasons">Error Reasons for Code-Loading Functions</seeerl> for a description of other possible error reasons.</p>
       </desc>
@@ -614,7 +617,9 @@ ok = code:finish_loading(Prepared),
       <desc>
         <p>Tries to load any modules not already loaded in the list
 	<c><anno>Modules</anno></c> in the same way as
-          <seemfa marker="#load_file/1">load_file/1</seemfa>.</p>
+          <seemfa marker="#load_file/1">load_file/1</seemfa>.
+          Unlike <seemfa marker="#ensure_loaded/1">ensure_loaded/1</seemfa>,
+          modules are loaded even in <c>embedded</c> mode.</p>
 	  <p>Returns <c>ok</c> if successful, or
 	  <c>{error,[{Module,Reason}]}</c> if loading of some modules fails.
 	  See <seeerl marker="#error_reasons">Error Reasons for Code-Loading Functions</seeerl> for a description of other possible error reasons.</p>
diff --git a/lib/kernel/src/code.erl b/lib/kernel/src/code.erl
index 7b82b6be9a..32555971dc 100644
--- a/lib/kernel/src/code.erl
+++ b/lib/kernel/src/code.erl
@@ -196,16 +196,21 @@ ensure_loaded(Mod) when is_atom(Mod) ->
     case erlang:module_loaded(Mod) of
         true -> {module, Mod};
         false ->
-            case call({get_object_code_for_loading, Mod}) of
-                {module, Mod} -> {module, Mod};
-                {error, What} -> {error, What};
-                {Binary,File,Ref} ->
-                    case ensure_prepare_loading(Mod, Binary, File) of
-                        {error,_}=Error ->
-                            call({load_error, Ref, Mod, Error});
-                        Prepared ->
-                            call({load_module, Prepared, Mod, File, false, Ref})
-                    end
+            case get_mode() of
+                interactive ->
+                    case call({get_object_code_for_loading, Mod}) of
+                        {module, Mod} -> {module, Mod};
+                        {error, What} -> {error, What};
+                        {Binary,File,Ref} ->
+                            case ensure_prepare_loading(Mod, Binary, File) of
+                                {error,_}=Error ->
+                                    call({load_error, Ref, Mod, Error});
+                                Prepared ->
+                                    call({load_module, Prepared, Mod, File, false, Ref})
+                            end
+                    end;
+                embedded ->
+                    {error, embedded}
             end
     end.
 
@@ -313,7 +318,7 @@ all_loaded() -> call(all_loaded).
       Filename :: loaded_filename(),
       Loaded :: boolean().
 all_available() ->
-    case code:get_mode() of
+    case get_mode() of
         interactive ->
             all_available(get_path(), #{});
         embedded ->
@@ -520,7 +525,7 @@ replace_path(Name, Dir, Cache) when (is_atom(Name) orelse is_list(Name)),
     call({replace_path,Name,Dir,Cache}).
 
 -spec get_mode() -> 'embedded' | 'interactive'.
-get_mode() -> call(get_mode).
+get_mode() -> code_server:get_mode().
 
 -spec clear_cache() -> ok.
 clear_cache() -> call(clear_cache).
diff --git a/lib/kernel/src/code_server.erl b/lib/kernel/src/code_server.erl
index 5315fa1e1a..78e635a1a9 100644
--- a/lib/kernel/src/code_server.erl
+++ b/lib/kernel/src/code_server.erl
@@ -22,7 +22,7 @@
 %% This file holds the server part of the code_server.
 
 -export([start_link/1,
-	 call/1, absname/1,
+	 call/1, absname/1, get_mode/0,
 	 is_loaded/1, is_sticky/1,
 	 system_code_change/4,
 	 error_msg/2, info_msg/2
@@ -46,7 +46,6 @@
 		path :: [{file:name_all(), cache | nocache}],
 		moddb :: ets:table(),
 		namedb :: ets:table(),
-		mode = interactive :: 'interactive' | 'embedded',
 		on_load = [] :: [on_load_item()],
                 loading = #{} :: #{module() => [pid()]}}).
 -type state() :: #state{}.
@@ -70,6 +69,9 @@ is_loaded(Mod) ->
 is_sticky(Mod) ->
     is_sticky(Mod, ?moddb).
 
+get_mode() ->
+    persistent_term:get(?MODULE).
+
 %% -----------------------------------------------------------
 %% Init the code_server process.
 %% -----------------------------------------------------------
@@ -104,9 +106,9 @@ init(Ref, Parent, [Root,Mode]) ->
 		   root = Root,
 		   path = Path,
 		   moddb = Db,
-		   namedb = create_namedb(Path, Root),
-		   mode = Mode},
+		   namedb = create_namedb(Path, Root)},
 
+    persistent_term:put(?MODULE, Mode),
     Parent ! {Ref,{ok,self()}},
     loop(State).
 
@@ -342,7 +344,7 @@ handle_call({get_object_code,Mod}, _From, St0) when is_atom(Mod) ->
 handle_call({get_object_code_for_loading,Mod}, From, St0) when is_atom(Mod) ->
     case erlang:module_loaded(Mod) of
         true -> {reply, {module, Mod}, St0};
-        false when St0#state.mode =:= interactive ->
+        false ->
             %% Handles pending on_load events first. If the code is being
             %% loaded, finish before adding more entries to the queue.
             Action = fun(_, St1) ->
@@ -351,16 +353,12 @@ handle_call({get_object_code_for_loading,Mod}, From, St0) when is_atom(Mod) ->
                     false -> get_object_code_for_loading(St1, Mod, From)
                 end
             end,
-            handle_pending_on_load(Action, Mod, From, St0);
-        false -> {reply, {error,embedded}, St0}
+            handle_pending_on_load(Action, Mod, From, St0)
     end;
 
 handle_call(stop,_From, S) ->
     {stop,normal,stopped,S};
 
-handle_call(get_mode, _From, S=#state{mode=Mode}) ->
-    {reply, Mode, S};
-
 handle_call({finish_loading,Prepared,EnsureLoaded}, _From, S) ->
     {reply,finish_loading(Prepared, EnsureLoaded, S),S};
 
@@ -1087,20 +1085,13 @@ del_paths(_,Path,_) ->
     {ok,Path}.
 
 try_finish_module(File, Mod, PC, EnsureLoaded, From, St) ->
-    Action = case EnsureLoaded of
-        false ->
-            fun(_, S) -> try_finish_module_1(File, Mod, PC, From, false, S) end;
-        _ ->
-            fun(_, S0) ->
-                case erlang:module_loaded(Mod) of
-                    true ->
-                        reply_loading(EnsureLoaded, Mod, {module, Mod}, S0);
-                    false when S0#state.mode =:= interactive ->
-                        try_finish_module_1(File, Mod, PC, From, EnsureLoaded, S0);
-                    false ->
-                        reply_loading(EnsureLoaded, Mod, {error, embedded}, S0)
-                end
-            end
+    Action =  fun(_, S) ->
+        case (EnsureLoaded =/= false) andalso erlang:module_loaded(Mod) of
+            true ->
+                reply_loading(EnsureLoaded, Mod, {module, Mod}, S);
+            false ->
+                try_finish_module_1(File, Mod, PC, From, EnsureLoaded, S)
+        end
     end,
     handle_pending_on_load(Action, Mod, From, St).
 
-- 
2.35.3

openSUSE Build Service is sponsored by