summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRaimo Niskanen <raimo@erlang.org>2020-02-21 15:30:03 +0100
committerRaimo Niskanen <raimo@erlang.org>2020-02-21 15:30:03 +0100
commit28f9bd0dac889a532fde4a8b1d534fbdb0593703 (patch)
tree7d50f609d16b6add2ae249e60aa4bc2139fcc5ee
parentcbe4d292faa540db9a07f6f8659a84d608f05845 (diff)
downloaderlang-28f9bd0dac889a532fde4a8b1d534fbdb0593703.tar.gz
Document change|push|pop _callback_module
-rw-r--r--lib/stdlib/doc/src/gen_statem.xml81
-rw-r--r--system/doc/design_principles/statem.xml45
2 files changed, 113 insertions, 13 deletions
diff --git a/lib/stdlib/doc/src/gen_statem.xml b/lib/stdlib/doc/src/gen_statem.xml
index 39fc565ff8..c12ad2deef 100644
--- a/lib/stdlib/doc/src/gen_statem.xml
+++ b/lib/stdlib/doc/src/gen_statem.xml
@@ -101,10 +101,10 @@
</item>
<item>
In OTP 22.3 the possibility to change the callback module
- with action
- <seealso marker="#type-action">
- <c>change_callback_module</c>
- </seealso>
+ with actions
+ <seealso marker="#type-action"><c>change_callback_module</c></seealso>,
+ <seealso marker="#type-action"><c>push_callback_module</c></seealso> and
+ <seealso marker="#type-action"><c>pop_callback_module</c></seealso>,
was added.
</item>
</list>
@@ -750,8 +750,10 @@ handle_event(_, _, State, Data) ->
<seealso marker="#Module:callback_mode/0"><c>Module:callback_mode/0</c></seealso>
is called when starting the <c>gen_statem</c>,
after code change
- and after changing the callback module with action
- <seealso marker="#type-action"><c>change_callback_module</c></seealso>.
+ and after changing the callback module with any of the actions
+ <seealso marker="#type-action"><c>change_callback_module</c></seealso>,
+ <seealso marker="#type-action"><c>push_callback_module</c></seealso> or
+ <seealso marker="#type-action"><c>pop_callback_module</c></seealso>.
The result is cached for subsequent calls to
<seealso marker="#state callback">state callbacks</seealso>.
</p>
@@ -1191,7 +1193,9 @@ handle_event(_, _, State, Data) ->
an event inserted this way from any external event.
</p>
</item>
- <tag><c>change_callback_module</c></tag>
+ <tag>
+ <c>change_callback_module</c>
+ </tag>
<item>
<p>
Changes the callback module to
@@ -1231,6 +1235,32 @@ handle_event(_, _, State, Data) ->
from the old module.
</p>
</item>
+ <tag>
+ <c>push_callback_module</c><br />
+ </tag>
+ <item>
+ <p>
+ Pushes the current callback module
+ to the top of an internal stack of callback modules
+ and changes the callback module to
+ <c><anno>NewModule</anno></c>.
+ Otherwise like
+ <c>{change_callback_module, NewModule}</c>
+ above.
+ </p>
+ </item>
+ <tag>
+ <c>pop_callback_module</c>
+ </tag>
+ <item>
+ Pops the top module from the internal stack of
+ callback modules and changes the callback module
+ to be the popped module.
+ If the stack is empty the server fails.
+ Otherwise like
+ <c>{change_callback_module, NewModule}</c>
+ above.
+ </item>
</taglist>
</desc>
</datatype>
@@ -2017,8 +2047,10 @@ handle_event(_, _, State, Data) ->
returns.
A change of the callback module happens when a
<seealso marker="#state callback"><em>state callback</em></seealso>
- returns the action
- <seealso marker="#type-action"><c>change_callback_module</c></seealso>.
+ returns any of the actions
+ <seealso marker="#type-action"><c>change_callback_module</c></seealso>,
+ <seealso marker="#type-action"><c>push_callback_module</c></seealso> or
+ <seealso marker="#type-action"><c>pop_callback_module</c></seealso>.
</p>
<p>
The <c>CallbackMode</c> is either just
@@ -2125,6 +2157,37 @@ handle_event(_, _, State, Data) ->
will not be honoured,
most probably causing a server crash.
</p>
+ <p>
+ If the server changes callback module using any of the actions
+ <seealso marker="#type-action"><c>change_callback_module</c></seealso>,
+ <seealso marker="#type-action"><c>push_callback_module</c></seealso> or
+ <seealso marker="#type-action"><c>pop_callback_module</c></seealso>,
+ be aware that it is always the current callback module that
+ will get this callback call. That the current callback module
+ handles the current state and data update should be no surprise,
+ but it must be able to handle even parts of
+ the state and data that it is not familiar with,
+ somehow.
+ </p>
+ <p>
+ In the supervisor
+ <seealso marker="doc/design_principles:sup_princ#child-specification">child specification</seealso>
+ there is a list of modules which is recommended to contain
+ only the callback module.
+ For a <c>gen_statem</c> with multiple callback modules
+ there is no real need to list all of them,
+ it may not even be possible since the list could change
+ after code upgrade.
+ If this list would contain only the start callback module,
+ as recommended, what is important is to upgrade <em>that</em> module
+ whenever a <em>synchronized code replacement</em> is done.
+ Then the release handler concludes that an upgrade
+ that upgrades <em>that</em> module needs to suspend,
+ code change, and resume any server whose child specification
+ declares that it is using <em>that</em> module.
+ And again; the <em>current</em> callback module will get the
+ <c>Module:code_change/4</c> call.
+ </p>
</desc>
</func>
diff --git a/system/doc/design_principles/statem.xml b/system/doc/design_principles/statem.xml
index f657e8cb00..d6d907de45 100644
--- a/system/doc/design_principles/statem.xml
+++ b/system/doc/design_principles/statem.xml
@@ -185,15 +185,17 @@ State(S) x Event(E) -> Actions(A), State(S')</pre>
</p>
<p>
The <em>callback module</em> can be changed for a running server
- using the
- <seealso marker="#Transition Actions">transition action</seealso>
- <seealso marker="stdlib:gen_statem#type-action"><c>{change_callback_module, NewModule}</c></seealso>.
+ using any of the
+ <seealso marker="#Transition Actions">transition actions</seealso>
+ <seealso marker="stdlib:gen_statem#type-action"><c>{change_callback_module, NewModule}</c></seealso>,
+ <seealso marker="stdlib:gen_statem#type-action"><c>{push_callback_module, NewModule}</c></seealso> or
+ <seealso marker="stdlib:gen_statem#type-action"><c>pop_callback_module</c></seealso>.
Note that this is a pretty esotheric thing to do...
The origin for this feature is a protocol that after
version negotiation branches off into quite different
state machines depending on the protocol version.
There <i>might</i> be other use cases.
- <i>Beware</i> that the <c>NewModule</c>
+ <i>Beware</i> that the new callback module
completely replaces the previous behaviour module,
so all relevant callback functions has to handle
the state and data from the previous callback module.
@@ -664,6 +666,41 @@ State(S) x Event(E) -> Actions(A), State(S')</pre>
but it can <i>not</i> be done from a
<seealso marker="#State Enter Calls"><em>state enter call</em></seealso>.
</item>
+ <tag>
+ <seealso marker="stdlib:gen_statem#type-action">
+ <c>{push_callback_module, NewModule}</c>
+ </seealso>
+ </tag>
+ <item>
+ Push the current <em>callback module</em>
+ to the top of an internal stack of callback modules
+ and set the new
+ <seealso marker="#Callback Module">
+ <em>callback module</em>
+ </seealso>
+ for the running server.
+ Otherwise like
+ <c>{change_callback_module, NewModule}</c>
+ above.
+ </item>
+ <tag>
+ <seealso marker="stdlib:gen_statem#type-action">
+ <c>pop_callback_module</c>
+ </seealso>
+ </tag>
+ <item>
+ Pop the top module from
+ the internal stack of callback modules
+ and set it to be the new
+ <seealso marker="#Callback Module">
+ <em>callback module</em>
+ </seealso>
+ for the running server.
+ If the stack is empty the server fails.
+ Otherwise like
+ <c>{change_callback_module, NewModule}</c>
+ above.
+ </item>
</taglist>
<p>
For details, see the <c>gen_statem(3)</c>