File 1581-Add-ability-to-always-spawn-for-erpc-call-and-multic.patch of Package erlang

From aa79cb57b4f90b8a702f96290e96e0e92456fafa Mon Sep 17 00:00:00 2001
From: Jan Uhlig <juhlig@hnc-agency.org>
Date: Mon, 26 Aug 2024 09:59:53 +0200
Subject: [PATCH 1/3] Add ability to always spawn for erpc:call and multicall

Co-authored-by: Maria Scott <maria-12648430@hnc-agency.org>
---
 lib/kernel/src/erpc.erl | 99 ++++++++++++++++++++++++-----------------
 1 file changed, 59 insertions(+), 40 deletions(-)

diff --git a/lib/kernel/src/erpc.erl b/lib/kernel/src/erpc.erl
index db28e54bb2..c674a08d67 100644
--- a/lib/kernel/src/erpc.erl
+++ b/lib/kernel/src/erpc.erl
@@ -126,11 +126,14 @@ The value can be:
 """.
 -type timeout_time() :: 0..?MAX_INT_TIMEOUT | 'infinity' | {abs, integer()}.
 
+-type call_options() :: #{'timeout' => timeout_time(),
+			  'always_spawn' => boolean()}.
+
 %%------------------------------------------------------------------------
 %% Exported API
 %%------------------------------------------------------------------------
 
--doc(#{equiv => call(Node, Fun, infinity)}).
+-doc(#{equiv => call(Node, Fun, #{timeout => infinity})}).
 -doc(#{since => <<"OTP 23.0">>}).
 -spec call(Node, Fun) -> Result when
       Node :: node(),
@@ -138,28 +141,28 @@ The value can be:
       Result :: term().
 
 call(N, Fun) ->
-    call(N, Fun, infinity).
+    call(N, Fun, #{timeout => infinity}).
 
 -doc """
 Equivalent to
-[`erpc:call(Node, erlang, apply, [Fun,[]], Timeout)`](`call/5`).
+[`erpc:call(Node, erlang, apply, [Fun,[]], #{timeout => Timeout})`](`call/5`).
 
 May raise all the same exceptions as [`call/5`](`call/5`) plus an `{erpc, badarg}`
 `error` exception if `Fun` is not a fun of zero arity.
 """.
 -doc(#{since => <<"OTP 23.0">>}).
--spec call(Node, Fun, Timeout) -> Result when
+-spec call(Node, Fun, TimeoutOrOptions) -> Result when
       Node :: node(),
       Fun :: function(),
-      Timeout :: timeout_time(),
+      TimeoutOrOptions :: timeout_time() | call_options(),
       Result :: term().
 
-call(N, Fun, Timeout) when is_function(Fun, 0) ->
-    call(N, erlang, apply, [Fun, []], Timeout);
+call(N, Fun, TimeoutOrOptions) when is_function(Fun, 0) ->
+    call(N, erlang, apply, [Fun, []], TimeoutOrOptions);
 call(_N, _Fun, _Timeout) ->
     error({?MODULE, badarg}).
 
--doc(#{equiv => call(Node, Module, Function, Args, infinity)}).
+-doc(#{equiv => call(Node, Module, Function, Args, #{timeout => infinity})}).
 -doc(#{since => <<"OTP 23.0">>}).
 -spec call(Node, Module, Function, Args) -> Result when
       Node :: node(),
@@ -169,7 +172,7 @@ call(_N, _Fun, _Timeout) ->
       Result :: term().
 
 call(N, M, F, A) ->
-    call(N, M, F, A, infinity).
+    call(N, M, F, A, #{timeout => infinity}).
 
 -dialyzer([{nowarn_function, call/5}, no_return]).
 
@@ -244,18 +247,19 @@ communication may, of course, reach the calling process.
 > spawned process.
 """.
 -doc(#{since => <<"OTP 23.0">>}).
--spec call(Node, Module, Function, Args, Timeout) -> Result when
+-spec call(Node, Module, Function, Args, TimeoutOrOptions) -> Result when
       Node :: node(),
       Module :: atom(),
       Function :: atom(),
       Args :: [term()],
-      Timeout :: timeout_time(),
+      TimeoutOrOptions :: timeout_time() | call_options(),
       Result :: term().
 
-call(N, M, F, A, infinity) when node() =:= N,  %% Optimize local call
-                                is_atom(M),
-                                is_atom(F),
-                                is_list(A) ->
+call(N, M, F, A, #{timeout := infinity,
+		   always_spawn := false}) when node() =:= N,  %% Optimize local call
+                                                is_atom(M),
+                                                is_atom(F),
+                                                is_list(A) ->
     try
         {return, Return} = execute_call(M,F,A),
         Return
@@ -271,10 +275,12 @@ call(N, M, F, A, infinity) when node() =:= N,  %% Optimize local call
                     error({exception, Reason, ErpcStack})
             end
     end;
-call(N, M, F, A, T) when is_atom(N),
-                         is_atom(M),
-                         is_atom(F),
-                         is_list(A) ->
+call(N, M, F, A, #{timeout := T,
+		   always_spawn := AlwaysSpawn}) when is_atom(N),
+                                                      is_atom(M),
+                                                      is_atom(F),
+                                                      is_list(A),
+                                                      is_boolean(AlwaysSpawn) ->
     Timeout = timeout_value(T),
     Res = make_ref(),
     ReqId = spawn_request(N, ?MODULE, execute_call, [Res, M, F, A],
@@ -287,8 +293,15 @@ call(N, M, F, A, T) when is_atom(N),
     after Timeout ->
             result(timeout, ReqId, Res, undefined)
     end;
-call(_N, _M, _F, _A, _T) ->
-    error({?MODULE, badarg}).
+call(_N, _M, _F, _A, #{timeout := _T,
+		       always_spawn := _AlwaysSpawn} = _Opts) ->
+    error({?MODULE, badarg});
+call(N, M, F, A, #{} = Opts) ->
+    call(N, M, F, A, maps:merge(#{timeout => infinity,
+				  always_spawn => false}, Opts));
+call(N, M, F, A, T) ->
+    call(N, M, F, A, #{timeout => T,
+		       always_spawn => false}).
 
 %% Asynchronous call
 
@@ -992,7 +1005,7 @@ reqids_to_list(_) ->
       | {error, {?MODULE, Reason :: term()}}.
 
 
--doc(#{equiv => multicall(Nodes, Fun, infinity)}).
+-doc(#{equiv => multicall(Nodes, Fun, #{timeout => infinity})}).
 -doc(#{since => <<"OTP 23.0">>}).
 -spec multicall(Nodes, Fun) -> Result when
       Nodes :: [atom()],
@@ -1000,28 +1013,28 @@ reqids_to_list(_) ->
       Result :: term().
 
 multicall(Ns, Fun) ->
-    multicall(Ns, Fun, infinity).
+    multicall(Ns, Fun, #{timeout => infinity}).
 
 -doc """
 Equivalent to
-[`erpc:multicall(Nodes, erlang, apply, [Fun,[]], Timeout)`](`multicall/5`).
+[`erpc:multicall(Nodes, erlang, apply, [Fun,[]], #{timeout => Timeout})`](`multicall/5`).
 
 May raise all the same exceptions as [`multicall/5`](`multicall/5`) plus an
 `{erpc, badarg}` `error` exception if `Fun` is not a fun of zero arity.
 """.
 -doc(#{since => <<"OTP 23.0">>}).
--spec multicall(Nodes, Fun, Timeout) -> Result when
+-spec multicall(Nodes, Fun, TimeoutOrOptions) -> Result when
       Nodes :: [atom()],
       Fun :: function(),
-      Timeout :: timeout_time(),
+      TimeoutOrOptions :: timeout_time() | call_options(),
       Result :: term().
 
-multicall(Ns, Fun, Timeout) when is_function(Fun, 0) ->
-    multicall(Ns, erlang, apply, [Fun, []], Timeout);
-multicall(_Ns, _Fun, _Timeout) ->
+multicall(Ns, Fun, TimeoutOrOptions) when is_function(Fun, 0) ->
+    multicall(Ns, erlang, apply, [Fun, []], TimeoutOrOptions);
+multicall(_Ns, _Fun, _TimeoutOrOptions) ->
     error({?MODULE, badarg}).
 
--doc(#{equiv => multicall(Nodes, Module, Function, Args, infinity)}).
+-doc(#{equiv => multicall(Nodes, Module, Function, Args, #{timeout => infinity})}).
 -doc(#{since => <<"OTP 23.0">>}).
 -spec multicall(Nodes, Module, Function, Args) -> Result when
       Nodes :: [atom()],
@@ -1031,7 +1044,7 @@ multicall(_Ns, _Fun, _Timeout) ->
       Result :: [{ok, ReturnValue :: term()} | caught_call_exception()].
 
 multicall(Ns, M, F, A) ->
-    multicall(Ns, M, F, A, infinity).
+    multicall(Ns, M, F, A, #{timeout => infinity}).
 
 -doc """
 Performs multiple `call` operations in parallel on multiple nodes.
@@ -1099,27 +1112,33 @@ calling process, such communication may, of course, reach the calling process.
 > spawned process.
 """.
 -doc(#{since => <<"OTP 23.0">>}).
--spec multicall(Nodes, Module, Function, Args, Timeout) -> Result when
+-spec multicall(Nodes, Module, Function, Args, TimeoutOrOptions) -> Result when
       Nodes :: [atom()],
       Module :: atom(),
       Function :: atom(),
       Args :: [term()],
-      Timeout :: timeout_time(),
+      TimeoutOrOptions :: timeout_time() | call_options(),
       Result :: [{ok, ReturnValue :: term()} | caught_call_exception()].
 
-multicall(Ns, M, F, A, T) ->
+multicall(Ns, M, F, A, #{} = Opts) ->
     try
         true = is_atom(M),
         true = is_atom(F),
         true = is_list(A),
         Tag = make_ref(),
-        Timeout = timeout_value(T),
-        SendState = mcall_send_requests(Tag, Ns, M, F, A, Timeout),
+        Timeout = timeout_value(maps:get(timeout, Opts, infinity)),
+	LocalCall = case maps:get(always_spawn, Opts, false) of
+			true -> always_spawn;
+			false -> allow_local_call
+		    end,
+        SendState = mcall_send_requests(Tag, Ns, M, F, A, LocalCall, Timeout),
         mcall_receive_replies(Tag, SendState)
     catch
         error:NotIErr when NotIErr /= internal_error ->
             error({?MODULE, badarg})
-    end.
+    end;
+multicall(Ns, M, F, A, T) ->
+    multicall(Ns, M, F, A, #{timeout => T}).
 
 -doc """
 Equivalent to
@@ -1515,9 +1534,9 @@ mcall_send_request(T, N, M, F, A) when is_reference(T),
                    {reply_tag, T},
                    {monitor, [{tag, T}]}]).
 
-mcall_send_requests(Tag, Ns, M, F, A, Tmo) ->
+mcall_send_requests(Tag, Ns, M, F, A, LC, Tmo) ->
     DL = deadline(Tmo),
-    mcall_send_requests(Tag, Ns, M, F, A, [], DL, undefined, 0).
+    mcall_send_requests(Tag, Ns, M, F, A, [], DL, LC, 0).
 
 mcall_send_requests(_Tag, [], M, F, A, RIDs, DL, local_call, NRs) ->
     %% Timeout infinity and call on local node wanted;
@@ -1527,7 +1546,7 @@ mcall_send_requests(_Tag, [], M, F, A, RIDs, DL, local_call, NRs) ->
 mcall_send_requests(_Tag, [], _M, _F, _A, RIDs, DL, _LC, NRs) ->
     {ok, RIDs, #{}, NRs, DL};
 mcall_send_requests(Tag, [N|Ns], M, F, A, RIDs,
-                    infinity, undefined, NRs) when N == node() ->
+                    infinity, allow_local_call, NRs) when N == node() ->
     mcall_send_requests(Tag, Ns, M, F, A, [local_call|RIDs],
                         infinity, local_call, NRs);
 mcall_send_requests(Tag, [N|Ns], M, F, A, RIDs, DL, LC, NRs) ->
-- 
2.43.0

openSUSE Build Service is sponsored by