From 6c298a7bfa332e5b7d153648d741740abc3bcdf8 Mon Sep 17 00:00:00 2001 From: Steve Vinoski Date: Wed, 19 Mar 2014 11:45:11 -0400 Subject: fix sys:get_state/1,2 and sys:replace_state/2,3 when sys suspended Add two new system callbacks Module:system_get_state/1 and Module:system_replace_state/2 to allow sys:get_state/1,2 and sys:replace_state/2,3 to operate correctly even if a process is sys suspended. Modify gen_server, gen_fsm, and gen_event to support the new callbacks. If a callback module does not export these functions, then by default the Misc value (the same as that passed as the final argument to sys:handle_system_msg/6, and returned as part of the return value of sys:get_status/1,2) is treated as the callback module's state. The previous behaviour of intercepting the system message and passing a tuple of size 2 as the last argument to sys:handle_system_msg/6 is no longer supported. Add tests to verify the correctness of sys:get_state/1,2 and sys:replace_state/2,3 when processes are sys suspended. Add two tests for modules that implement special processes, one that exports system_get_state/1 and system_replace_state/2 and one that doesn't. Much of the credit for this patch goes to James Fish, who reported the initial problem and implemented much of the fix. --- system/doc/design_principles/spec_proc.xml | 40 +++++++++++++++++++++++++++--- 1 file changed, 36 insertions(+), 4 deletions(-) (limited to 'system') diff --git a/system/doc/design_principles/spec_proc.xml b/system/doc/design_principles/spec_proc.xml index 8de7a5fe03..d55427aa10 100644 --- a/system/doc/design_principles/spec_proc.xml +++ b/system/doc/design_principles/spec_proc.xml @@ -130,7 +130,8 @@ ok -export([alloc/0, free/1]). -export([init/1]). -export([system_continue/3, system_terminate/4, - write_debug/3]). + write_debug/3, + system_get_state/1, system_replace_state/2]). start_link() -> proc_lib:start_link(ch4, init, [self()]). @@ -177,9 +178,21 @@ loop(Chs, Parent, Deb) -> system_continue(Parent, Deb, Chs) -> loop(Chs, Parent, Deb). -system_terminate(Reason, Parent, Deb, Chs) -> +system_terminate(Reason, _Parent, _Deb, _Chs) -> exit(Reason). +system_get_state(Chs) -> + {ok, Chs}. + +system_replace_state(StateFun, Chs) -> + try + NChs = StateFun(Chs), + {ok, NChs, NChs} + catch + _:_ -> + {ok, Chs, Chs} + end. + write_debug(Dev, Event, Name) -> io:format(Dev, "~p event = ~p~n", [Name, Event]).

Example on how the simple debugging functions in sys can @@ -366,8 +379,15 @@ Module:system_terminate(Reason, Parent, Deb, State) Module is the name of the module. Deb is the debug structure. State is a term describing the internal state and - is passed to system_continue/system_terminate. + is passed to system_continue/system_terminate/ + system_get_state/system_replace_state. +

If the process should return its state handle_system_msg will call:

+ +Module:system_get_state(State) +

or if the process should replace its state using the fun StateFun:

+ +Module:system_replace_state(StateFun, State)

In the example:

loop(Chs, Parent, Deb) -> @@ -383,7 +403,19 @@ system_continue(Parent, Deb, Chs) -> loop(Chs, Parent, Deb). system_terminate(Reason, Parent, Deb, Chs) -> - exit(Reason). + exit(Reason). + +system_get_state(Chs) -> + {ok, Chs, Chs}. + +system_replace_state(StateFun, Chs) -> + try + NChs = StateFun(Chs), + {ok, NChs, NChs} + catch + _:_ -> + {ok, Chs, Chs} + end.

If the special process is set to trap exits, note that if the parent process terminates, the expected behavior is to terminate with the same reason:

-- cgit v1.2.3