aboutsummaryrefslogtreecommitdiffstats
path: root/lib/stdlib/src/gen_server.erl
diff options
context:
space:
mode:
authorAnton N Ryabkov <[email protected]>2017-04-12 15:06:39 +0700
committerAnton N Ryabkov <[email protected]>2017-05-02 08:21:13 +0700
commit42faed747858483506c12e722573e48d0f5f7996 (patch)
tree8e439ddf9178ce50fb6914130ffe54c5cec3fc60 /lib/stdlib/src/gen_server.erl
parentffa80a41370025ed2fb95967e731f13cc7e45e4f (diff)
downloadotp-42faed747858483506c12e722573e48d0f5f7996.tar.gz
otp-42faed747858483506c12e722573e48d0f5f7996.tar.bz2
otp-42faed747858483506c12e722573e48d0f5f7996.zip
Added support of auto_hibernate_timeout option for gen_server, gen_fsm, gen_event process's.
There is realized gen_server, gen_fsm, gen_event automatic hibernation functionality. Added unit tests for realized functionality. Added documentation for auto_hibernate_timeout option.
Diffstat (limited to 'lib/stdlib/src/gen_server.erl')
-rw-r--r--lib/stdlib/src/gen_server.erl106
1 files changed, 58 insertions, 48 deletions
diff --git a/lib/stdlib/src/gen_server.erl b/lib/stdlib/src/gen_server.erl
index 8504af86f8..a538e80211 100644
--- a/lib/stdlib/src/gen_server.erl
+++ b/lib/stdlib/src/gen_server.erl
@@ -94,7 +94,7 @@
cast/2, reply/2,
abcast/2, abcast/3,
multi_call/2, multi_call/3, multi_call/4,
- enter_loop/3, enter_loop/4, enter_loop/5, wake_hib/5]).
+ enter_loop/3, enter_loop/4, enter_loop/5, wake_hib/6]).
%% System exports
-export([system_continue/3,
@@ -307,7 +307,8 @@ enter_loop(Mod, Options, State, ServerName, Timeout) ->
Name = gen:get_proc_name(ServerName),
Parent = gen:get_parent(),
Debug = gen:debug_options(Name, Options),
- loop(Parent, Name, State, Mod, Timeout, Debug).
+ AutoHibernateTimeout = gen:auto_hibernate_timeout(Options),
+ loop(Parent, Name, State, Mod, Timeout, AutoHibernateTimeout, Debug).
%%%========================================================================
%%% Gen-callback functions
@@ -325,13 +326,14 @@ init_it(Starter, self, Name, Mod, Args, Options) ->
init_it(Starter, Parent, Name0, Mod, Args, Options) ->
Name = gen:name(Name0),
Debug = gen:debug_options(Name, Options),
+ AutoHibernateTimeout = gen:auto_hibernate_timeout(Options),
case catch Mod:init(Args) of
{ok, State} ->
proc_lib:init_ack(Starter, {ok, self()}),
- loop(Parent, Name, State, Mod, infinity, Debug);
+ loop(Parent, Name, State, Mod, infinity, AutoHibernateTimeout, Debug);
{ok, State, Timeout} ->
proc_lib:init_ack(Starter, {ok, self()}),
- loop(Parent, Name, State, Mod, Timeout, Debug);
+ loop(Parent, Name, State, Mod, Timeout, AutoHibernateTimeout, Debug);
{stop, Reason} ->
%% For consistency, we must make sure that the
%% registered name (if any) is unregistered before
@@ -362,37 +364,46 @@ init_it(Starter, Parent, Name0, Mod, Args, Options) ->
%%% ---------------------------------------------------
%%% The MAIN loop.
%%% ---------------------------------------------------
-loop(Parent, Name, State, Mod, hibernate, Debug) ->
- proc_lib:hibernate(?MODULE,wake_hib,[Parent, Name, State, Mod, Debug]);
-loop(Parent, Name, State, Mod, Time, Debug) ->
+loop(Parent, Name, State, Mod, hibernate, AutoHibernateTimeout, Debug) ->
+ proc_lib:hibernate(?MODULE,wake_hib,[Parent, Name, State, Mod, AutoHibernateTimeout, Debug]);
+
+loop(Parent, Name, State, Mod, infinity, AutoHibernateTimeout, Debug) ->
+ receive
+ Msg ->
+ decode_msg(Msg, Parent, Name, State, Mod, infinity, AutoHibernateTimeout, Debug, false)
+ after AutoHibernateTimeout ->
+ proc_lib:hibernate(?MODULE,wake_hib,[Parent, Name, State, Mod, AutoHibernateTimeout, Debug])
+ end;
+
+loop(Parent, Name, State, Mod, Time, AutoHibernateTimeout, Debug) ->
Msg = receive
Input ->
Input
after Time ->
timeout
end,
- decode_msg(Msg, Parent, Name, State, Mod, Time, Debug, false).
+ decode_msg(Msg, Parent, Name, State, Mod, Time, AutoHibernateTimeout, Debug, false).
-wake_hib(Parent, Name, State, Mod, Debug) ->
+wake_hib(Parent, Name, State, Mod, AutoHibernateTimeout, Debug) ->
Msg = receive
Input ->
Input
end,
- decode_msg(Msg, Parent, Name, State, Mod, hibernate, Debug, true).
+ decode_msg(Msg, Parent, Name, State, Mod, hibernate, AutoHibernateTimeout, Debug, true).
-decode_msg(Msg, Parent, Name, State, Mod, Time, Debug, Hib) ->
+decode_msg(Msg, Parent, Name, State, Mod, Time, AutoHibernateTimeout, Debug, Hib) ->
case Msg of
{system, From, Req} ->
sys:handle_system_msg(Req, From, Parent, ?MODULE, Debug,
- [Name, State, Mod, Time], Hib);
+ [Name, State, Mod, Time, AutoHibernateTimeout], Hib);
{'EXIT', Parent, Reason} ->
terminate(Reason, Name, undefined, Msg, Mod, State, Debug);
_Msg when Debug =:= [] ->
- handle_msg(Msg, Parent, Name, State, Mod);
+ handle_msg(Msg, Parent, Name, State, Mod, AutoHibernateTimeout);
_Msg ->
Debug1 = sys:handle_debug(Debug, fun print_event/3,
Name, {in, Msg}),
- handle_msg(Msg, Parent, Name, State, Mod, Debug1)
+ handle_msg(Msg, Parent, Name, State, Mod, AutoHibernateTimeout, Debug1)
end.
%%% ---------------------------------------------------
@@ -659,65 +670,65 @@ try_terminate(Mod, Reason, State) ->
%%% Message handling functions
%%% ---------------------------------------------------
-handle_msg({'$gen_call', From, Msg}, Parent, Name, State, Mod) ->
+handle_msg({'$gen_call', From, Msg}, Parent, Name, State, Mod, AutoHibernateTimeout) ->
Result = try_handle_call(Mod, Msg, From, State),
case Result of
{ok, {reply, Reply, NState}} ->
reply(From, Reply),
- loop(Parent, Name, NState, Mod, infinity, []);
+ loop(Parent, Name, NState, Mod, infinity, AutoHibernateTimeout, []);
{ok, {reply, Reply, NState, Time1}} ->
reply(From, Reply),
- loop(Parent, Name, NState, Mod, Time1, []);
+ loop(Parent, Name, NState, Mod, Time1, AutoHibernateTimeout, []);
{ok, {noreply, NState}} ->
- loop(Parent, Name, NState, Mod, infinity, []);
+ loop(Parent, Name, NState, Mod, infinity, AutoHibernateTimeout, []);
{ok, {noreply, NState, Time1}} ->
- loop(Parent, Name, NState, Mod, Time1, []);
+ loop(Parent, Name, NState, Mod, Time1, AutoHibernateTimeout, []);
{ok, {stop, Reason, Reply, NState}} ->
{'EXIT', R} =
(catch terminate(Reason, Name, From, Msg, Mod, NState, [])),
reply(From, Reply),
exit(R);
- Other -> handle_common_reply(Other, Parent, Name, From, Msg, Mod, State)
+ Other -> handle_common_reply(Other, Parent, Name, From, Msg, Mod, AutoHibernateTimeout, State)
end;
-handle_msg(Msg, Parent, Name, State, Mod) ->
+handle_msg(Msg, Parent, Name, State, Mod, AutoHibernateTimeout) ->
Reply = try_dispatch(Msg, Mod, State),
- handle_common_reply(Reply, Parent, Name, undefined, Msg, Mod, State).
+ handle_common_reply(Reply, Parent, Name, undefined, Msg, Mod, AutoHibernateTimeout, State).
-handle_msg({'$gen_call', From, Msg}, Parent, Name, State, Mod, Debug) ->
+handle_msg({'$gen_call', From, Msg}, Parent, Name, State, Mod, AutoHibernateTimeout, Debug) ->
Result = try_handle_call(Mod, Msg, From, State),
case Result of
{ok, {reply, Reply, NState}} ->
Debug1 = reply(Name, From, Reply, NState, Debug),
- loop(Parent, Name, NState, Mod, infinity, Debug1);
+ loop(Parent, Name, NState, Mod, infinity, AutoHibernateTimeout, Debug1);
{ok, {reply, Reply, NState, Time1}} ->
Debug1 = reply(Name, From, Reply, NState, Debug),
- loop(Parent, Name, NState, Mod, Time1, Debug1);
+ loop(Parent, Name, NState, Mod, Time1, AutoHibernateTimeout, Debug1);
{ok, {noreply, NState}} ->
Debug1 = sys:handle_debug(Debug, fun print_event/3, Name,
{noreply, NState}),
- loop(Parent, Name, NState, Mod, infinity, Debug1);
+ loop(Parent, Name, NState, Mod, infinity, AutoHibernateTimeout, Debug1);
{ok, {noreply, NState, Time1}} ->
Debug1 = sys:handle_debug(Debug, fun print_event/3, Name,
{noreply, NState}),
- loop(Parent, Name, NState, Mod, Time1, Debug1);
+ loop(Parent, Name, NState, Mod, Time1, AutoHibernateTimeout, Debug1);
{ok, {stop, Reason, Reply, NState}} ->
{'EXIT', R} =
(catch terminate(Reason, Name, From, Msg, Mod, NState, Debug)),
_ = reply(Name, From, Reply, NState, Debug),
exit(R);
Other ->
- handle_common_reply(Other, Parent, Name, From, Msg, Mod, State, Debug)
+ handle_common_reply(Other, Parent, Name, From, Msg, Mod, AutoHibernateTimeout, State, Debug)
end;
-handle_msg(Msg, Parent, Name, State, Mod, Debug) ->
+handle_msg(Msg, Parent, Name, State, Mod, AutoHibernateTimeout, Debug) ->
Reply = try_dispatch(Msg, Mod, State),
- handle_common_reply(Reply, Parent, Name, undefined, Msg, Mod, State, Debug).
+ handle_common_reply(Reply, Parent, Name, undefined, Msg, Mod, AutoHibernateTimeout, State, Debug).
-handle_common_reply(Reply, Parent, Name, From, Msg, Mod, State) ->
+handle_common_reply(Reply, Parent, Name, From, Msg, Mod, AutoHibernateTimeout, State) ->
case Reply of
{ok, {noreply, NState}} ->
- loop(Parent, Name, NState, Mod, infinity, []);
+ loop(Parent, Name, NState, Mod, infinity, AutoHibernateTimeout, []);
{ok, {noreply, NState, Time1}} ->
- loop(Parent, Name, NState, Mod, Time1, []);
+ loop(Parent, Name, NState, Mod, Time1, AutoHibernateTimeout, []);
{ok, {stop, Reason, NState}} ->
terminate(Reason, Name, From, Msg, Mod, NState, []);
{'EXIT', ExitReason, ReportReason} ->
@@ -726,16 +737,16 @@ handle_common_reply(Reply, Parent, Name, From, Msg, Mod, State) ->
terminate({bad_return_value, BadReply}, Name, From, Msg, Mod, State, [])
end.
-handle_common_reply(Reply, Parent, Name, From, Msg, Mod, State, Debug) ->
+handle_common_reply(Reply, Parent, Name, From, Msg, Mod, AutoHibernateTimeout, State, Debug) ->
case Reply of
{ok, {noreply, NState}} ->
Debug1 = sys:handle_debug(Debug, fun print_event/3, Name,
{noreply, NState}),
- loop(Parent, Name, NState, Mod, infinity, Debug1);
+ loop(Parent, Name, NState, Mod, infinity, AutoHibernateTimeout, Debug1);
{ok, {noreply, NState, Time1}} ->
Debug1 = sys:handle_debug(Debug, fun print_event/3, Name,
{noreply, NState}),
- loop(Parent, Name, NState, Mod, Time1, Debug1);
+ loop(Parent, Name, NState, Mod, Time1, AutoHibernateTimeout, Debug1);
{ok, {stop, Reason, NState}} ->
terminate(Reason, Name, From, Msg, Mod, NState, Debug);
{'EXIT', ExitReason, ReportReason} ->
@@ -753,26 +764,26 @@ reply(Name, {To, Tag}, Reply, State, Debug) ->
%%-----------------------------------------------------------------
%% Callback functions for system messages handling.
%%-----------------------------------------------------------------
-system_continue(Parent, Debug, [Name, State, Mod, Time]) ->
- loop(Parent, Name, State, Mod, Time, Debug).
+system_continue(Parent, Debug, [Name, State, Mod, Time, AutoHibernateTimeout]) ->
+ loop(Parent, Name, State, Mod, Time, AutoHibernateTimeout, Debug).
-spec system_terminate(_, _, _, [_]) -> no_return().
-system_terminate(Reason, _Parent, Debug, [Name, State, Mod, _Time]) ->
+system_terminate(Reason, _Parent, Debug, [Name, State, Mod, _Time, _AutoHibernateTimeout]) ->
terminate(Reason, Name, undefined, [], Mod, State, Debug).
-system_code_change([Name, State, Mod, Time], _Module, OldVsn, Extra) ->
+system_code_change([Name, State, Mod, Time, AutoHibernateTimeout], _Module, OldVsn, Extra) ->
case catch Mod:code_change(OldVsn, State, Extra) of
- {ok, NewState} -> {ok, [Name, NewState, Mod, Time]};
+ {ok, NewState} -> {ok, [Name, NewState, Mod, Time, AutoHibernateTimeout]};
Else -> Else
end.
-system_get_state([_Name, State, _Mod, _Time]) ->
+system_get_state([_Name, State, _Mod, _Time, _AutoHibernateTimeout]) ->
{ok, State}.
-system_replace_state(StateFun, [Name, State, Mod, Time]) ->
+system_replace_state(StateFun, [Name, State, Mod, Time, AutoHibernateTimeout]) ->
NState = StateFun(State),
- {ok, NState, [Name, NState, Mod, Time]}.
+ {ok, NState, [Name, NState, Mod, Time, AutoHibernateTimeout]}.
%%-----------------------------------------------------------------
%% Format debug messages. Print them as the call-back module sees
@@ -802,10 +813,10 @@ print_event(Dev, Event, Name) ->
%%% Terminate the server.
%%% ---------------------------------------------------
+
-spec terminate(_, _, _, _, _, _, _) -> no_return().
terminate(Reason, Name, From, Msg, Mod, State, Debug) ->
terminate(Reason, Reason, Name, From, Msg, Mod, State, Debug).
-
-spec terminate(_, _, _, _, _, _, _, _) -> no_return().
terminate(ExitReason, ReportReason, Name, From, Msg, Mod, State, Debug) ->
Reply = try_terminate(Mod, ExitReason, State),
@@ -851,7 +862,7 @@ error_info(Reason, Name, From, Msg, State, Debug) ->
end;
_ ->
Reason
- end,
+ end,
{ClientFmt, ClientArgs} = client_stacktrace(From),
format("** Generic server ~p terminating \n"
"** Last message in was ~p~n"
@@ -860,7 +871,6 @@ error_info(Reason, Name, From, Msg, State, Debug) ->
[Name, Msg, State, Reason1] ++ ClientArgs),
sys:print_log(Debug),
ok.
-
client_stacktrace(undefined) ->
{"", []};
client_stacktrace({From, _Tag}) ->
@@ -885,7 +895,7 @@ client_stacktrace(From) when is_pid(From) ->
%% Status information
%%-----------------------------------------------------------------
format_status(Opt, StatusData) ->
- [PDict, SysState, Parent, Debug, [Name, State, Mod, _Time]] = StatusData,
+ [PDict, SysState, Parent, Debug, [Name, State, Mod, _Time, _AutoHibernateTimeout]] = StatusData,
Header = gen:format_status_header("Status for generic server", Name),
Log = sys:get_debug(log, Debug, []),
Specfic = case format_status(Opt, Mod, PDict, State) of