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/doc') 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 From cbcac6f0d55907dda2e0c385eba44eac2e7923d2 Mon Sep 17 00:00:00 2001 From: Steve Vinoski Date: Wed, 19 Mar 2014 11:49:12 -0400 Subject: remove tuple funs from special process documentation Support for tuple funs was removed in R16B but the documentation for special processes, sys, and proc_lib in the OTP Design Principles still showed examples using them, and those examples no longer worked. Fix the examples to use regular functions instead and fix the documentation to reflect the changes. --- system/doc/design_principles/spec_proc.xml | 37 +++++++++++------------------- 1 file changed, 14 insertions(+), 23 deletions(-) (limited to 'system/doc') diff --git a/system/doc/design_principles/spec_proc.xml b/system/doc/design_principles/spec_proc.xml index d55427aa10..69bf2e0448 100644 --- a/system/doc/design_principles/spec_proc.xml +++ b/system/doc/design_principles/spec_proc.xml @@ -157,15 +157,15 @@ init(Parent) -> loop(Chs, Parent, Deb) -> receive {From, alloc} -> - Deb2 = sys:handle_debug(Deb, {ch4, write_debug}, + Deb2 = sys:handle_debug(Deb, fun ch4:write_debug/3, ch4, {in, alloc, From}), {Ch, Chs2} = alloc(Chs), From ! {ch4, Ch}, - Deb3 = sys:handle_debug(Deb2, {ch4, write_debug}, + Deb3 = sys:handle_debug(Deb2, fun ch4:write_debug/3, ch4, {out, {ch4, Ch}, From}), loop(Chs2, Parent, Deb3); {free, Ch} -> - Deb2 = sys:handle_debug(Deb, {ch4, write_debug}, + Deb2 = sys:handle_debug(Deb, fun ch4:write_debug/3, ch4, {in, {free, Ch}}), Chs2 = free(Ch, Chs), loop(Chs2, Parent, Deb2); @@ -185,13 +185,8 @@ system_get_state(Chs) -> {ok, Chs}. system_replace_state(StateFun, Chs) -> - try - NChs = StateFun(Chs), - {ok, NChs, NChs} - catch - _:_ -> - {ok, Chs, Chs} - end. + NChs = StateFun(Chs), + {ok, NChs, NChs}. write_debug(Dev, Event, Name) -> io:format(Dev, "~p event = ~p~n", [Name, Event]). @@ -294,10 +289,10 @@ sys:handle_debug(Deb, Func, Info, Event) => Deb1

Deb is the debug structure.

-

Func is a tuple {Module, Name} (or a fun) and - should specify a (user defined) function used to format +

Func is a fun specifying + a (user defined) function used to format trace output. For each system event, the format function is - called as Module:Name(Dev, Event, Info), where:

+ called as Func(Dev, Event, Info), where:

Dev is the IO device to which the output should @@ -332,15 +327,15 @@ sys:handle_debug(Deb, Func, Info, Event) => Deb1 loop(Chs, Parent, Deb) -> receive {From, alloc} -> - Deb2 = sys:handle_debug(Deb, {ch4, write_debug}, + Deb2 = sys:handle_debug(Deb, fun ch4:write_debug/3, ch4, {in, alloc, From}), {Ch, Chs2} = alloc(Chs), From ! {ch4, Ch}, - Deb3 = sys:handle_debug(Deb2, {ch4, write_debug}, + Deb3 = sys:handle_debug(Deb2, fun ch4:write_debug/3, ch4, {out, {ch4, Ch}, From}), loop(Chs2, Parent, Deb3); {free, Ch} -> - Deb2 = sys:handle_debug(Deb, {ch4, write_debug}, + Deb2 = sys:handle_debug(Deb, fun ch4:write_debug/3, ch4, {in, {free, Ch}}), Chs2 = free(Ch, Chs), loop(Chs2, Parent, Deb2); @@ -409,13 +404,9 @@ system_get_state(Chs) -> {ok, Chs, Chs}. system_replace_state(StateFun, Chs) -> - try - NChs = StateFun(Chs), - {ok, NChs, NChs} - catch - _:_ -> - {ok, Chs, Chs} - end. + NChs = StateFun(Chs), + {ok, NChs, NChs}. +

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