From cdb452bf9ac48e3b5602ced5222391964fa13fd9 Mon Sep 17 00:00:00 2001 From: Vlad Dumitrescu Date: Mon, 4 Jul 2016 15:19:12 +0200 Subject: use top-level README in packaged release Previously, system/README was not being updated and had become confusing. --- system/doc/top/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'system/doc') diff --git a/system/doc/top/Makefile b/system/doc/top/Makefile index 7f9cec540b..116ec688fa 100644 --- a/system/doc/top/Makefile +++ b/system/doc/top/Makefile @@ -35,7 +35,7 @@ RELSYSDIR = "$(RELEASE_PATH)/doc" GIF_FILES = -INFO_FILES = ../../README ../../COPYRIGHT PR.template +INFO_FILES = ../../../README.md ../../COPYRIGHT PR.template TOPDOCDIR=. -- cgit v1.2.3 From 66cc419fd993204a66cf57a674a2c62bbd14d9fe Mon Sep 17 00:00:00 2001 From: Brujo Benavides Date: Tue, 12 Jul 2016 14:27:13 +0200 Subject: Add clarification on LC semantics (#1) It addresses the special case of generator-less LCs. As a bonus, I fixed a typo :) --- system/doc/reference_manual/expressions.xml | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) (limited to 'system/doc') diff --git a/system/doc/reference_manual/expressions.xml b/system/doc/reference_manual/expressions.xml index 355fd3cfef..1a3d19aed1 100644 --- a/system/doc/reference_manual/expressions.xml +++ b/system/doc/reference_manual/expressions.xml @@ -1541,7 +1541,16 @@ end
 1> [X*2 || X <- [1,2,3]].
 [2,4,6]
-

More examples are provoded in +

When there are no generators or bit string generators, a list comprehension + returns either a list with one element (the result of evaluating Expr) + if all filters are true or an empty list otherwise.

+

Example:

+
+1> [2 || is_integer(2)].
+[2]
+2> [x || is_integer(x)].
+[]
+

More examples are provided in Programming Examples.

-- cgit v1.2.3 From d81d4ce2aa69e62067cb81707ef0e971945e00c3 Mon Sep 17 00:00:00 2001 From: Bernhard Schwarz Date: Wed, 13 Jul 2016 11:20:26 +0200 Subject: Fix verb conjugation in statem docs 'We' wait. --- system/doc/design_principles/statem.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'system/doc') diff --git a/system/doc/design_principles/statem.xml b/system/doc/design_principles/statem.xml index b63327291d..aea623851a 100644 --- a/system/doc/design_principles/statem.xml +++ b/system/doc/design_principles/statem.xml @@ -755,7 +755,7 @@ stop() -> Suppose that we do not want a button to lock the door, instead we want to ignore button events in the open state. Then we start a timer when entering the open state - and waits for it to expire while ignoring button events: + and wait for it to expire while ignoring button events:

Date: Wed, 27 Jul 2016 14:41:45 +0200 Subject: Rewrite gen_statem docs for M:callback_mode/0 --- system/doc/design_principles/statem.xml | 79 +++++++++++++++++++-------------- 1 file changed, 45 insertions(+), 34 deletions(-) (limited to 'system/doc') diff --git a/system/doc/design_principles/statem.xml b/system/doc/design_principles/statem.xml index aea623851a..1351997bc1 100644 --- a/system/doc/design_principles/statem.xml +++ b/system/doc/design_principles/statem.xml @@ -52,7 +52,7 @@
Event-Driven State Machines

- Established Automata theory does not deal much with + Established Automata Theory does not deal much with how a state transition is triggered, but assumes that the output is a function of the input (and the state) and that they are @@ -226,11 +226,10 @@ handle_event(EventType, EventContent, State, Data) -> -module(code_lock). -behaviour(gen_statem). -define(NAME, code_lock). --define(CALLBACK_MODE, state_functions). -export([start_link/1]). -export([button/1]). --export([init/1,terminate/3,code_change/4]). +-export([init/1,callback_mode/0,terminate/3,code_change/4]). -export([locked/3,open/3]). start_link(Code) -> @@ -242,7 +241,10 @@ button(Digit) -> init(Code) -> do_lock(), Data = #{code => Code, remaining => Code}, - {?CALLBACK_MODE,locked,Data}. + {ok,locked,Data}. + +callback_mode() -> + state_functions. locked( cast, {button,Digit}, @@ -273,7 +275,7 @@ terminate(_Reason, State, _Data) -> State =/= locked andalso do_lock(), ok. code_change(_Vsn, State, Data, _Extra) -> - {?CALLBACK_MODE,State,Data}. + {ok,State,Data}. ]]>

The code is explained in the next sections.

@@ -343,14 +345,8 @@ start_link(Code) ->

If name registration succeeds, the new gen_statem process calls callback function code_lock:init(Code). - This function is expected to return {CallbackMode,State,Data}, - where - CallbackMode - selects callback module state function mode, in this case - state_functions - through macro ?CALLBACK_MODE. That is, each state - has got its own handler function. - State is the initial state of the gen_statem, + This function is expected to return {ok,State,Data}, + where State is the initial state of the gen_statem, in this case locked; assuming that the door is locked to begin with. Data is the internal server data of the gen_statem. Here the server data is a map @@ -359,11 +355,12 @@ start_link(Code) -> that stores the remaining correct button sequence (the same as the code to begin with).

+ do_lock(), Data = #{code => Code, remaining => Code}, - {?CALLBACK_MODE,locked,Data}. + {ok,locked,Data}. ]]>

Function gen_statem:start_link @@ -380,6 +377,21 @@ init(Code) -> can be used to start a standalone gen_statem, that is, a gen_statem that is not part of a supervision tree.

+ + + state_functions. + ]]> +

+ Function + Module:callback_mode/0 + selects the + CallbackMode + for the callback module, in this case + state_functions. + That is, each state has got its own handler function. +

+ @@ -532,13 +544,12 @@ handle_event({call,From}, code_length, #{code := Code} = Data) -> and then depending on state:

+ handle_event_function. handle_event(cast, {button,Digit}, State, #{code := Code} = Data) -> case State of @@ -962,16 +973,13 @@ do_unlock() ->

process_flag(trap_exit, true), Data = #{code => Code}, - enter(?CALLBACK_MODE, locked, Data). + enter(ok, locked, Data). -... +callback_mode() -> + state_functions. locked(internal, enter, _Data) -> do_lock(), @@ -1027,11 +1035,10 @@ enter(Tag, State, Data) -> -module(code_lock). -behaviour(gen_statem). -define(NAME, code_lock_2). --define(CALLBACK_MODE, state_functions). -export([start_link/1,stop/0]). -export([button/1,code_length/0]). --export([init/1,terminate/3,code_change/4]). +-export([init/1,callback_mode/0,terminate/3,code_change/4]). -export([locked/3,open/3]). start_link(Code) -> @@ -1047,7 +1054,10 @@ code_length() -> init(Code) -> process_flag(trap_exit, true), Data = #{code => Code}, - enter(?CALLBACK_MODE, locked, Data). + enter(ok, locked, Data). + +callback_mode() -> + state_functions. locked(internal, enter, #{code := Code} = Data) -> do_lock(), @@ -1091,7 +1101,7 @@ terminate(_Reason, State, _Data) -> State =/= locked andalso do_lock(), ok. code_change(_Vsn, State, Data, _Extra) -> - {?CALLBACK_MODE,State,Data}. + {ok,State,Data}. ]]> @@ -1105,13 +1115,12 @@ code_change(_Vsn, State, Data, _Extra) -> entry actions, so this example first branches depending on state:

+ handle_event_function. %% State: locked handle_event(internal, enter, locked, #{code := Code} = Data) -> @@ -1273,11 +1282,10 @@ format_status(Opt, [_PDict,State,Data]) -> -module(code_lock). -behaviour(gen_statem). -define(NAME, code_lock_3). --define(CALLBACK_MODE, handle_event_function). -export([start_link/2,stop/0]). -export([button/1,code_length/0,set_lock_button/1]). --export([init/1,terminate/3,code_change/4,format_status/2]). +-export([init/1,callback_mode/0,terminate/3,code_change/4,format_status/2]). -export([handle_event/4]). start_link(Code, LockButton) -> @@ -1296,7 +1304,10 @@ set_lock_button(LockButton) -> init({Code,LockButton}) -> process_flag(trap_exit, true), Data = #{code => Code, remaining => undefined, timer => undefined}, - enter(?CALLBACK_MODE, {locked,LockButton}, Data, []). + enter(ok, {locked,LockButton}, Data, []). + +callback_mode() -> + handle_event_function. handle_event( {call,From}, {set_lock_button,NewLockButton}, @@ -1366,7 +1377,7 @@ terminate(_Reason, State, _Data) -> State =/= locked andalso do_lock(), ok. code_change(_Vsn, State, Data, _Extra) -> - {?CALLBACK_MODE,State,Data}. + {ok,State,Data}. format_status(Opt, [_PDict,State,Data]) -> StateData = {State, -- cgit v1.2.3 From 3a60545091d3075e23c4a7af8c18b3641bb084e2 Mon Sep 17 00:00:00 2001 From: Raimo Niskanen Date: Tue, 9 Aug 2016 08:59:51 +0200 Subject: Doc fixes --- system/doc/design_principles/statem.xml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'system/doc') diff --git a/system/doc/design_principles/statem.xml b/system/doc/design_principles/statem.xml index 1351997bc1..f785ca9650 100644 --- a/system/doc/design_principles/statem.xml +++ b/system/doc/design_principles/statem.xml @@ -608,7 +608,7 @@ init(Args) -> callback function terminate(shutdown, State, Data).

- In the following example, function terminate/3 + In this example, function terminate/3 locks the door if it is open, so we do not accidentally leave the door open when the supervision tree terminates:

@@ -1217,7 +1217,8 @@ format_status(Opt, [_PDict,State,Data]) -> Module:format_status/2 function. If you do not, a default implementation is used that does the same as this example function without filtering - the Data term, that is, StateData = {State,Data}. + the Data term, that is, StateData = {State,Data}, + in this example containing sensitive information.

-- cgit v1.2.3 From ad6e765bcd4f35a282ef00e38ed9129f3a5c1d83 Mon Sep 17 00:00:00 2001 From: Hans Bolinder Date: Thu, 1 Sep 2016 14:32:27 +0200 Subject: doc: Correct errors introduced by Editorial changes Fix some older errors as well. --- system/doc/design_principles/statem.xml | 4 ++-- system/doc/efficiency_guide/advanced.xml | 4 ++-- system/doc/efficiency_guide/profiling.xml | 8 ++++---- system/doc/embedded/embedded_nt.xml | 4 ++-- system/doc/embedded/embedded_solaris.xml | 14 +++++++------- system/doc/embedded/starting.xml | 8 ++++---- system/doc/oam/oam_intro.xml | 10 +++++----- system/doc/programming_examples/records.xml | 2 +- system/doc/reference_manual/typespec.xml | 2 +- 9 files changed, 28 insertions(+), 28 deletions(-) (limited to 'system/doc') diff --git a/system/doc/design_principles/statem.xml b/system/doc/design_principles/statem.xml index f785ca9650..57e47431b8 100644 --- a/system/doc/design_principles/statem.xml +++ b/system/doc/design_principles/statem.xml @@ -33,7 +33,7 @@

This section is to be read with the gen_statem(3) - manual page in STDLIB, where all interface functions and callback + manual page in STDLIB, where all interface functions and callback functions are described in detail.

@@ -310,7 +310,7 @@ start_link(Code) -> as {global,Name}, then the gen_statem is registered using global:register_name/2 - in Kernel. + in Kernel.

diff --git a/system/doc/efficiency_guide/advanced.xml b/system/doc/efficiency_guide/advanced.xml index 016302fe50..eee2648f34 100644 --- a/system/doc/efficiency_guide/advanced.xml +++ b/system/doc/efficiency_guide/advanced.xml @@ -156,7 +156,7 @@ +P command-line flag in the erl(1) - manual page in erts. + manual page in ERTS. Known nodes @@ -236,7 +236,7 @@ +Q command-line flag in the erl(1) manual page - in erts. + in ERTS. Open files and diff --git a/system/doc/efficiency_guide/profiling.xml b/system/doc/efficiency_guide/profiling.xml index 1f3d503170..bf50a03fa6 100644 --- a/system/doc/efficiency_guide/profiling.xml +++ b/system/doc/efficiency_guide/profiling.xml @@ -128,7 +128,7 @@ performance impact. Using fprof is just a matter of calling a few library functions, see the fprof manual page in - tools .fprof was introduced in R8.

+ Tools .fprof was introduced in R8.

@@ -138,7 +138,7 @@ and in which function calls this time has been spent. Time is shown as percentage of total time and absolute time. For more information, see the eprof - manual page in tools.

+ manual page in Tools.

@@ -152,7 +152,7 @@ optimization. Using cover is just a matter of calling a few library functions, see the cover manual page in - tools.

+ Tools.

@@ -165,7 +165,7 @@ any modules to profile (compared with cover). For more information, see the cprof manual page in - tools.

+ Tools.

diff --git a/system/doc/embedded/embedded_nt.xml b/system/doc/embedded/embedded_nt.xml index a1a4b90f3c..8e05100585 100644 --- a/system/doc/embedded/embedded_nt.xml +++ b/system/doc/embedded/embedded_nt.xml @@ -62,7 +62,7 @@

For Windows NT running on standard PCs with ISA and/or PCI bus, an extension card with a hardware watchdog can be installed.

For more information, see the heart(3) manual page in - kernel.

+ Kernel.

@@ -72,7 +72,7 @@ to install the Erlang process as a Windows system service. This service can start after Windows NT has booted.

For more information, see the erlsrv manual page - in erts.

+ in ERTS.

diff --git a/system/doc/embedded/embedded_solaris.xml b/system/doc/embedded/embedded_solaris.xml index f8febcc546..eaa334fb39 100644 --- a/system/doc/embedded/embedded_solaris.xml +++ b/system/doc/embedded/embedded_solaris.xml @@ -190,7 +190,7 @@ esac the onboard hardware watchdog can be activated, provided a VME bus driver is added to the operating system (see also Installation Problems).

-

See also the heart(3) manual page in kernel.

+

See also the heart(3) manual page in Kernel.

@@ -206,7 +206,7 @@ esac
         chown 0 /usr/sbin/reboot
         chmod 4755 /usr/sbin/reboot
-

See also the heart(3) manual page in kernel.

+

See also the heart(3) manual page in Kernel.

@@ -413,8 +413,8 @@ chown root mod_syslog]]>
Related Documents

See the os_mon(3) application, - the application(3) manual page in kernel, - and the erl(1) manual page in erts.

+ the application(3) manual page in Kernel, + and the erl(1) manual page in ERTS.

@@ -474,7 +474,7 @@ chown root mod_syslog]]>
default, it must be called start and reside in /bin]]>. Another start program can be used, by using configuration parameter - start_prg in application sasl.

+ start_prg in application SASL.

The start program must call run_erl as shown below. It must also take an optional parameter, which defaults to /releases/start_erl.data]]>.

@@ -484,7 +484,7 @@ chown root mod_syslog]]>

The ]]> directory is where new release packets are installed, and where the release handler keeps information about releases. For more information, see the - release_handler(3) manual page in sasl.

+ release_handler(3) manual page in SASL.

The following script illustrates the default behaviour of the program:

If a diskless and/or read-only client node with the - sasl configuration parameter static_emulator set + SASL configuration parameter static_emulator set to true is about to start, the -boot and -config flags must be changed.

As such a client cannot diff --git a/system/doc/embedded/starting.xml b/system/doc/embedded/starting.xml index 720383e8ac..11bf9b412a 100644 --- a/system/doc/embedded/starting.xml +++ b/system/doc/embedded/starting.xml @@ -69,7 +69,7 @@ default, it must be called start and reside in /bin]]>. Another start program can be used, by using the configuration parameter start_prg in - the application sasl.

+ application SASL.

The start program must call run_erl as shown below. It must also take an optional parameter which defaults to /bin/start_erl.data]]>. @@ -80,8 +80,8 @@

The ]]> directory is where new release packets are installed, and where the release handler keeps information - about releases. See release_handler(3) in the - application sasl for further information. + about releases. See release_handler(3) in + application SASL for further information.

The following script illustrates the default behaviour of the program. @@ -228,7 +228,7 @@ export PROGNAME export RELDIR exec $BINDIR/erlexec -boot $RELDIR/$VSN/start -config $RELDIR/$VSN/sys $* -

If a diskless and/or read-only client node with the sasl +

If a diskless and/or read-only client node with the SASL configuration parameter static_emulator set to true is about to start the -boot and -config flags must be changed. As such a client can not read a new start_erl.data diff --git a/system/doc/oam/oam_intro.xml b/system/doc/oam/oam_intro.xml index cdcb6e3111..8b8d69e638 100644 --- a/system/doc/oam/oam_intro.xml +++ b/system/doc/oam/oam_intro.xml @@ -178,7 +178,7 @@

MIB Structure

The top-level OTP MIB is called OTP-REG and it is - included in the sasl application. All other OTP MIBs + included in the SASL application. All other OTP MIBs import some objects from this MIB.

Each MIB is contained in one application. The MIB text @@ -188,7 +188,7 @@ .hrl]]>, and the compiled MIBs are stored under .bin]]>. For example, the OTP-MIB is included in the - sasl application:

+ SASL application:

sasl-1.3/mibs/OTP-MIB.mib @@ -211,11 +211,11 @@ snmp:c("MY-MIB", [{il, ["sasl/priv/mibs"]}]).

The following MIBs are defined in the OTP system:

-

OTP-REG) (in sasl) contains the top-level +

OTP-REG) (in SASL) contains the top-level OTP registration objects, used by all other MIBs.

-

OTP-TC (in sasl) contains the general +

OTP-TC (in SASL) contains the general Textual Conventions, which can be used by any other MIB.

-

OTP-MIB (in sasl) contains objects for +

OTP-MIB (in SASL) contains objects for instrumentation of the Erlang nodes, the Erlang machines, and the applications in the system.

OTP-OS-MON-MIB (in oc_mon) contains diff --git a/system/doc/programming_examples/records.xml b/system/doc/programming_examples/records.xml index da346dd0b3..074aa636b4 100644 --- a/system/doc/programming_examples/records.xml +++ b/system/doc/programming_examples/records.xml @@ -93,7 +93,7 @@ person at compile time, not at runtime. For details on records in the shell, see the shell(3) - manual page in stdlib.

+ manual page in STDLIB.

diff --git a/system/doc/reference_manual/typespec.xml b/system/doc/reference_manual/typespec.xml index f17e5df277..1899efd5f3 100644 --- a/system/doc/reference_manual/typespec.xml +++ b/system/doc/reference_manual/typespec.xml @@ -47,7 +47,7 @@ To document function interfaces To provide more information for bug detection tools, - such as Dialyzer + such as Dialyzer To be exploited by documentation tools, such as EDoc, for generating program documentation of various forms -- cgit v1.2.3 From 90345d3fe0daaf094bca2951ed45aaa278a2e447 Mon Sep 17 00:00:00 2001 From: Tony Han Date: Tue, 13 Sep 2016 10:53:54 +0800 Subject: doc: Fix code format in tutorial/c_port --- system/doc/tutorial/c_port.xmlsrc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'system/doc') diff --git a/system/doc/tutorial/c_port.xmlsrc b/system/doc/tutorial/c_port.xmlsrc index 695f16515d..3c3bc48044 100644 --- a/system/doc/tutorial/c_port.xmlsrc +++ b/system/doc/tutorial/c_port.xmlsrc @@ -98,11 +98,11 @@ loop(Port) -> {call, Caller, Msg} -> Port ! {self(), {command, encode(Msg)}}, receive - {Port, {data, Data}} -> + {Port, {data, Data}} -> Caller ! {complex, decode(Data)} end, loop(Port) - end. + end.

Assuming that both the arguments and the results from the C functions are less than 256, a simple encoding/decoding scheme is employed. In this scheme, foo is represented by byte -- cgit v1.2.3 From 6ee0aefd8a0ea9c165211c42d5244182b5aa9210 Mon Sep 17 00:00:00 2001 From: Raimo Niskanen Date: Tue, 13 Sep 2016 14:00:04 +0200 Subject: Implement state entry events --- system/doc/design_principles/statem.xml | 152 ++++++++++++++++++++++++-------- 1 file changed, 113 insertions(+), 39 deletions(-) (limited to 'system/doc') diff --git a/system/doc/design_principles/statem.xml b/system/doc/design_principles/statem.xml index 57e47431b8..8090016b54 100644 --- a/system/doc/design_principles/statem.xml +++ b/system/doc/design_principles/statem.xml @@ -109,7 +109,7 @@ State(S) x Event(E) -> Actions(A), State(S')

 StateName(EventType, EventContent, Data) ->
-    .. code for actions here ...
+    ... code for actions here ...
     {next_state, NewStateName, NewData}.
@@ -120,7 +120,7 @@ StateName(EventType, EventContent, Data) ->

 handle_event(EventType, EventContent, State, Data) ->
-    .. code for actions here ...
+    ... code for actions here ...
     {next_state, NewState, NewData}
@@ -192,13 +192,42 @@ handle_event(EventType, EventContent, State, Data) ->
+ + +
+ + State Entry Events +

+ The gen_statem behavior can regardless of callback mode + automatically generate an + + event whenever the state changes + + so you can write state entry code + near the rest of the state transition rules. + It typically looks like this: +

+
+StateName(enter, _OldState, Data) ->
+    ... code for state entry here ...
+    {keep_state, NewData};
+StateName(EventType, EventContent, Data) ->
+    ... code for actions here ...
+    {next_state, NewStateName, NewData}.
+

+ Depending on how your state machine is specified, + this can be a very useful feature, but if you use it + you will have to handle the state entry events in all states. +

+
+
Example

This example starts off as equivalent to the example in section - gen_fsm Behavior. + gen_fsm-Behavior. In later sections, additions and tweaks are made using features in gen_statem that gen_fsm does not have. The end of this chapter provides the example again @@ -722,6 +751,12 @@ stop() -> Generated by any regular process message sent to the gen_statem process. + enter + + Generated by a state transition with + OldState =/= NewState when running with + state entry events. + timeout Generated by state transition action @@ -981,7 +1016,7 @@ init(Code) -> callback_mode() -> state_functions. -locked(internal, enter, _Data) -> +locked(internal, enter, Data) -> do_lock(), {keep_state,Data#{remaining => Code}}; locked( @@ -992,7 +1027,7 @@ locked( enter(next_state, open, Data); ... -open(internal, enter, _Data) -> +open(internal, enter, Data) -> Tref = erlang:start_timer(10000, self(), lock), do_unlock(), {keep_state,Data#{timer => Tref}}; @@ -1005,6 +1040,49 @@ enter(Tag, State, Data) -> ]]>

+ + +
+ Using State Entry Events +

+ Here is the same example as the previous but instead using + the built in + state entry events. + You will have to handle the state entry events in every state. + If you want state entry code in just a few states the previous + example may be more suitable. +

+ + process_flag(trap_exit, true), + Data = #{code => Code}, + {ok, locked, Data}. + +callback_mode() -> + [state_functions,state_entry_events]. + +locked(enter, _OldState, Data) -> + do_lock(), + {keep_state,Data#{remaining => Code}}; +locked( + cast, {button,Digit}, + #{code := Code, remaining := Remaining} = Data) -> + case Remaining of + [Digit] -> + {next_state, open, Data}; +... + +open(enter, _OldState, Data) -> + Tref = erlang:start_timer(10000, self(), lock), + do_unlock(), + {keep_state,Data#{timer => Tref}}; +open(info, {timeout,Tref,lock}, #{timer := Tref} = Data) -> + {next_state, locked, Data}; +... + ]]> +
+
@@ -1054,12 +1132,12 @@ code_length() -> init(Code) -> process_flag(trap_exit, true), Data = #{code => Code}, - enter(ok, locked, Data). + {ok, locked, Data}. callback_mode() -> - state_functions. + [state_functions,state_entry_events]. -locked(internal, enter, #{code := Code} = Data) -> +locked(enter, _OldState, #{code := Code} = Data) -> do_lock(), {keep_state,Data#{remaining => Code}}; locked( @@ -1067,7 +1145,7 @@ locked( #{code := Code, remaining := Remaining} = Data) -> case Remaining of [Digit] -> % Complete - enter(next_state, open, Data); + {next_state, open, Data}; [Digit|Rest] -> % Incomplete {keep_state,Data#{remaining := Rest}}; [_|_] -> % Wrong @@ -1076,12 +1154,12 @@ locked( locked(EventType, EventContent, Data) -> handle_event(EventType, EventContent, Data). -open(internal, enter, Data) -> +open(enter, _OldState, Data) -> Tref = erlang:start_timer(10000, self(), lock), do_unlock(), {keep_state,Data#{timer => Tref}}; open(info, {timeout,Tref,lock}, #{timer := Tref} = Data) -> - enter(next_state, locked, Data); + {next_state, locked, Data}; open(cast, {button,_}, _) -> {keep_state_and_data,[postpone]}; open(EventType, EventContent, Data) -> @@ -1089,8 +1167,6 @@ open(EventType, EventContent, Data) -> handle_event({call,From}, code_length, #{code := Code}) -> {keep_state_and_data,[{reply,From,length(Code)}]}. -enter(Tag, State, Data) -> - {Tag,State,Data,[{next_event,internal,enter}]}. do_lock() -> io:format("Locked~n", []). @@ -1111,8 +1187,9 @@ code_change(_Vsn, State, Data, _Extra) -> This section describes what to change in the example to use one handle_event/4 function. The previously used approach to first branch depending on event - does not work that well here because of the generated - entry actions, so this example first branches depending on state: + does not work that well here because of + the state entry events, + so this example first branches depending on state:

... callback_mode() -> - handle_event_function. + [handle_event_function,state_entry_events]. %% State: locked -handle_event(internal, enter, locked, #{code := Code} = Data) -> +handle_event(enter, _OldState, locked, #{code := Code} = Data) -> do_lock(), {keep_state,Data#{remaining => Code}}; handle_event( @@ -1131,7 +1208,7 @@ handle_event( #{code := Code, remaining := Remaining} = Data) -> case Remaining of [Digit] -> % Complete - enter(next_state, open, Data); + {next_state, open, Data}; [Digit|Rest] -> % Incomplete {keep_state,Data#{remaining := Rest}}; [_|_] -> % Wrong @@ -1139,12 +1216,12 @@ handle_event( end; %% %% State: open -handle_event(internal, enter, open, Data) -> +handle_event(enter, _OldState, open, Data) -> Tref = erlang:start_timer(10000, self(), lock), do_unlock(), {keep_state,Data#{timer => Tref}}; handle_event(info, {timeout,Tref,lock}, open, #{timer := Tref} = Data) -> - enter(next_state, locked, Data); + {next_state, locked, Data}; handle_event(cast, {button,_}, open, _) -> {keep_state_and_data,[postpone]}; %% @@ -1305,10 +1382,10 @@ set_lock_button(LockButton) -> init({Code,LockButton}) -> process_flag(trap_exit, true), Data = #{code => Code, remaining => undefined, timer => undefined}, - enter(ok, {locked,LockButton}, Data, []). + {ok, {locked,LockButton}, Data}. callback_mode() -> - handle_event_function. + [handle_event_function,state_entry_events]. handle_event( {call,From}, {set_lock_button,NewLockButton}, @@ -1320,55 +1397,52 @@ handle_event( {_StateName,_LockButton}, #{code := Code}) -> {keep_state_and_data, [{reply,From,length(Code)}]}; +%% +%% State: locked handle_event( EventType, EventContent, {locked,LockButton}, #{code := Code, remaining := Remaining} = Data) -> case {EventType,EventContent} of - {internal,enter} -> + {enter,_OldState} -> do_lock(), {keep_state,Data#{remaining := Code}}; {{call,From},{button,Digit}} -> case Remaining of [Digit] -> % Complete - next_state( - {open,LockButton}, Data, - [{reply,From,ok}]); + {next_state, {open,LockButton}, Data, + [{reply,From,ok}]}; [Digit|Rest] -> % Incomplete - {keep_state,Data#{remaining := Rest}, + {keep_state, Data#{remaining := Rest}, [{reply,From,ok}]}; [_|_] -> % Wrong - {keep_state,Data#{remaining := Code}, + {keep_state, Data#{remaining := Code}, [{reply,From,ok}]} end end; +%% +%% State: open handle_event( EventType, EventContent, {open,LockButton}, #{timer := Timer} = Data) -> case {EventType,EventContent} of - {internal,enter} -> + {enter,_OldState} -> Tref = erlang:start_timer(10000, self(), lock), do_unlock(), {keep_state,Data#{timer := Tref}}; {info,{timeout,Timer,lock}} -> - next_state({locked,LockButton}, Data, []); + {next_state, {locked,LockButton}, Data}; {{call,From},{button,Digit}} -> if Digit =:= LockButton -> erlang:cancel_timer(Timer), - next_state( - {locked,LockButton}, Data, - [{reply,From,locked}]); + {next_state, {locked,LockButton}, Data, + [{reply,From,locked}]); true -> {keep_state_and_data, [postpone]} end end. -next_state(State, Data, Actions) -> - enter(next_state, State, Data, Actions). -enter(Tag, State, Data, Actions) -> - {Tag,State,Data,[{next_event,internal,enter}|Actions]}. - do_lock() -> io:format("Locked~n", []). do_unlock() -> @@ -1434,7 +1508,7 @@ handle_event( EventType, EventContent, {open,LockButton}, #{timer := Timer} = Data) -> case {EventType,EventContent} of - {internal,enter} -> + {enter,_OldState} -> Tref = erlang:start_timer(10000, self(), lock), do_unlock(), {keep_state,Data#{timer := Tref},[hibernate]}; -- cgit v1.2.3 From 4ebdabdca2c964887115f21405993f3916843d10 Mon Sep 17 00:00:00 2001 From: Raimo Niskanen Date: Fri, 16 Sep 2016 10:15:22 +0200 Subject: Improve docs --- system/doc/design_principles/statem.xml | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) (limited to 'system/doc') diff --git a/system/doc/design_principles/statem.xml b/system/doc/design_principles/statem.xml index 8090016b54..43359829b2 100644 --- a/system/doc/design_principles/statem.xml +++ b/system/doc/design_principles/statem.xml @@ -989,7 +989,17 @@ do_unlock() -> from your state machine to itself.

- One example of using self-generated events can be when you have + One example for this is to pre-process incoming data, for example + decrypting chunks or collecting characters up to a line break. + This could be modelled with a separate state machine that sends + the pre-processed events to the main state machine, or to decrease + overhead the small pre-processing state machine can be implemented + in the common state event handling of the main state machine + using a few state data variables and then send the pre-processed + events as internal events to the main state machine. +

+

+ Another example of using self-generated events can be when you have a state machine specification that uses state entry actions. You can code that using a dedicated function to do the state transition. But if you want that code to be @@ -1050,7 +1060,15 @@ enter(Tag, State, Data) -> state entry events. You will have to handle the state entry events in every state. If you want state entry code in just a few states the previous - example may be more suitable. + example may be more suitable, especially to only send internal + events when entering just those few states. +

+

+ You can also in the previous example choose to generate + events looking just like the events you get from using + state entry events. + This may be confusing, or practical, + depending on your point of view.

Date: Sun, 18 Sep 2016 12:33:08 +0200 Subject: Use more correct delimiters for erl_nif.h include Anywhere but the beam sources we shouldn't #include "erl_nif.h", because what "erl_nif.h" does is: (1) fail to find it outside of -I dirs, (2) then treat it as if it was written like . Using skips (1). More information can be found in 6.10.2 of the C standard. Because the examples use "erl_nif.h", NIF projects in the Erlang ecosystem copy this verbatim and make the same mistake. --- system/doc/tutorial/complex6_nif.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'system/doc') diff --git a/system/doc/tutorial/complex6_nif.c b/system/doc/tutorial/complex6_nif.c index b656ed43ce..f6c06e94f4 100644 --- a/system/doc/tutorial/complex6_nif.c +++ b/system/doc/tutorial/complex6_nif.c @@ -1,4 +1,4 @@ -#include "erl_nif.h" +#include extern int foo(int x); extern int bar(int y); -- cgit v1.2.3 From 1778a9e0c677134a6b71975168812bcfdc70c7aa Mon Sep 17 00:00:00 2001 From: Raimo Niskanen Date: Tue, 20 Sep 2016 17:03:24 +0200 Subject: Improve docs --- system/doc/design_principles/statem.xml | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) (limited to 'system/doc') diff --git a/system/doc/design_principles/statem.xml b/system/doc/design_principles/statem.xml index 43359829b2..565b0e5274 100644 --- a/system/doc/design_principles/statem.xml +++ b/system/doc/design_principles/statem.xml @@ -1010,6 +1010,8 @@ do_unlock() -> the state, you must explicitly insert the internal event or use a state transition function. + This is something that can be forgotten, and if you find that + annoying please look at the next chapter.

The following is an implementation of entry actions @@ -1058,10 +1060,18 @@ enter(Tag, State, Data) -> Here is the same example as the previous but instead using the built in state entry events. - You will have to handle the state entry events in every state. +

+

+ Since the state entry events are unconditionally inserted by + the gen_statem engine you can not forget to insert them + yourself and you will have to handle the state entry events + in every state. +

+

If you want state entry code in just a few states the previous example may be more suitable, especially to only send internal events when entering just those few states. + Note: additional discipline will be required.

You can also in the previous example choose to generate -- cgit v1.2.3 From 04d40c5cd18aca449606c19608e8044f593ee99e Mon Sep 17 00:00:00 2001 From: Raimo Niskanen Date: Thu, 22 Sep 2016 17:40:47 +0200 Subject: Change state entry events into state enter calls --- system/doc/design_principles/statem.xml | 194 ++++++++++++++------------------ 1 file changed, 86 insertions(+), 108 deletions(-) (limited to 'system/doc') diff --git a/system/doc/design_principles/statem.xml b/system/doc/design_principles/statem.xml index 565b0e5274..d2a9b23570 100644 --- a/system/doc/design_principles/statem.xml +++ b/system/doc/design_principles/statem.xml @@ -195,21 +195,19 @@ handle_event(EventType, EventContent, State, Data) ->

- - State Entry Events + + State Enter Calls

The gen_statem behavior can regardless of callback mode - automatically generate an - - event whenever the state changes - - so you can write state entry code + automatically call the state function + with special arguments whenever the state changes + so you can write state entry actions near the rest of the state transition rules. It typically looks like this:

 StateName(enter, _OldState, Data) ->
-    ... code for state entry here ...
+    ... code for state entry actions here ...
     {keep_state, NewData};
 StateName(EventType, EventContent, Data) ->
     ... code for actions here ...
@@ -217,7 +215,7 @@ StateName(EventType, EventContent, Data) ->
     

Depending on how your state machine is specified, this can be a very useful feature, but if you use it - you will have to handle the state entry events in all states. + you will have to handle the state enter call in all states.

@@ -751,12 +749,6 @@ stop() -> Generated by any regular process message sent to the gen_statem process. - enter - - Generated by a state transition with - OldState =/= NewState when running with - state entry events. - timeout Generated by state transition action @@ -972,63 +964,35 @@ do_unlock() ->
- Self-Generated Events -

- It can sometimes be beneficial to be able to generate events - to your own state machine. - This can be done with the state transition - action - {next_event,EventType,EventContent}. -

+ State Entry Actions

- You can generate events of any existing - type, - but the internal type can only be generated through action - next_event. Hence, it cannot come from an external source, - so you can be certain that an internal event is an event - from your state machine to itself. + Say you have a state machine specification + that uses state entry actions. + Allthough you can code this using self-generated events + (described in the next section), especially if just + one or a few states has got state entry actions, + this is a perfect use case for the built in + state enter calls.

- One example for this is to pre-process incoming data, for example - decrypting chunks or collecting characters up to a line break. - This could be modelled with a separate state machine that sends - the pre-processed events to the main state machine, or to decrease - overhead the small pre-processing state machine can be implemented - in the common state event handling of the main state machine - using a few state data variables and then send the pre-processed - events as internal events to the main state machine. -

-

- Another example of using self-generated events can be when you have - a state machine specification that uses state entry actions. - You can code that using a dedicated function - to do the state transition. But if you want that code to be - visible besides the other state logic, you can insert - an internal event that does the entry actions. - This has the same unfortunate consequence as using - state transition functions: everywhere you go to - the state, you must explicitly - insert the internal event - or use a state transition function. - This is something that can be forgotten, and if you find that - annoying please look at the next chapter. -

-

- The following is an implementation of entry actions - using internal events with content enter - using a helper function enter/3 for state entry: + You return a list containing state_enter from your + callback_mode/0 + function and the gen_statem engine will call your + state function once with the arguments + (enter, OldState, ...) whenever the state changes. + Then you just need to handle these event-like calls in all states.

process_flag(trap_exit, true), Data = #{code => Code}, - enter(ok, locked, Data). + {ok, locked, Data}. callback_mode() -> - state_functions. + [state_functions,state_enter]. -locked(internal, enter, Data) -> +locked(enter, _OldState, Data) -> do_lock(), {keep_state,Data#{remaining => Code}}; locked( @@ -1036,79 +1000,94 @@ locked( #{code := Code, remaining := Remaining} = Data) -> case Remaining of [Digit] -> - enter(next_state, open, Data); + {next_state, open, Data}; ... -open(internal, enter, Data) -> +open(enter, _OldState, Data) -> Tref = erlang:start_timer(10000, self(), lock), do_unlock(), {keep_state,Data#{timer => Tref}}; open(info, {timeout,Tref,lock}, #{timer := Tref} = Data) -> - enter(next_state, locked, Data); + {next_state, locked, Data}; ... - -enter(Tag, State, Data) -> - {Tag,State,Data,[{next_event,internal,enter}]}. ]]>
- Using State Entry Events + Self-Generated Events

- Here is the same example as the previous but instead using - the built in - state entry events. + It can sometimes be beneficial to be able to generate events + to your own state machine. + This can be done with the state transition + action + {next_event,EventType,EventContent}.

- Since the state entry events are unconditionally inserted by - the gen_statem engine you can not forget to insert them - yourself and you will have to handle the state entry events - in every state. + You can generate events of any existing + type, + but the internal type can only be generated through action + next_event. Hence, it cannot come from an external source, + so you can be certain that an internal event is an event + from your state machine to itself.

- If you want state entry code in just a few states the previous - example may be more suitable, especially to only send internal - events when entering just those few states. - Note: additional discipline will be required. + One example for this is to pre-process incoming data, for example + decrypting chunks or collecting characters up to a line break. + Purists may argue that this should be modelled with a separate + state machine that sends pre-processed events + to the main state machine. + But to decrease overhead the small pre-processing state machine + can be implemented in the common state event handling + of the main state machine using a few state data variables + that then sends the pre-processed events as internal events + to the main state machine.

- You can also in the previous example choose to generate - events looking just like the events you get from using - state entry events. - This may be confusing, or practical, - depending on your point of view. + The following example use an input model where you give the lock + characters with put_chars(Chars) and then call + enter() to finish the input.

- process_flag(trap_exit, true), - Data = #{code => Code}, - {ok, locked, Data}. +-export(put_chars/1, enter/0). +... +put_chars(Chars) when is_binary(Chars) -> + gen_statem:call(?NAME, {chars,Chars}). -callback_mode() -> - [state_functions,state_entry_events]. +enter() -> + gen_statem:call(?NAME, enter). + +... locked(enter, _OldState, Data) -> do_lock(), - {keep_state,Data#{remaining => Code}}; -locked( - cast, {button,Digit}, - #{code := Code, remaining := Remaining} = Data) -> - case Remaining of - [Digit] -> - {next_state, open, Data}; + {keep_state,Data#{remaining => Code, buf => []}}; ... -open(enter, _OldState, Data) -> - Tref = erlang:start_timer(10000, self(), lock), - do_unlock(), - {keep_state,Data#{timer => Tref}}; -open(info, {timeout,Tref,lock}, #{timer := Tref} = Data) -> - {next_state, locked, Data}; +handle_event({call,From}, {chars,Chars}, #{buf := Buf} = Data) -> + {keep_state, Data#{buf := [Chars|Buf], + [{reply,From,ok}]}; +handle_event({call,From}, enter, #{buf := Buf} = Data) -> + Chars = unicode:characters_to_binary(lists:reverse(Buf)), + try binary_to_integer(Chars) of + Digit -> + {keep_state, Data#{buf := []}, + [{reply,From,ok}, + {next_event,internal,{button,Chars}}]} + catch + error:badarg -> + {keep_state, Data#{buf := []}, + [{reply,From,{error,not_an_integer}}]} + end; ... ]]> +

+ If you start this program with code_lock:start([17]) + you can unlock with code_lock:put_chars(<<"001">>), + code_lock:put_chars(<<"7">>), code_lock:enter(). +

@@ -1117,7 +1096,7 @@ open(info, {timeout,Tref,lock}, #{timer := Tref} = Data) -> Example Revisited

This section includes the example after all mentioned modifications - and some more using the entry actions, + and some more using state enter calls, which deserves a new state diagram:

@@ -1163,7 +1142,7 @@ init(Code) -> {ok, locked, Data}. callback_mode() -> - [state_functions,state_entry_events]. + [state_functions,state_enter]. locked(enter, _OldState, #{code := Code} = Data) -> do_lock(), @@ -1215,8 +1194,7 @@ code_change(_Vsn, State, Data, _Extra) -> This section describes what to change in the example to use one handle_event/4 function. The previously used approach to first branch depending on event - does not work that well here because of - the state entry events, + does not work that well here because of the state enter calls, so this example first branches depending on state:

... callback_mode() -> - [handle_event_function,state_entry_events]. + [handle_event_function,state_enter]. %% State: locked handle_event(enter, _OldState, locked, #{code := Code} = Data) -> @@ -1413,7 +1391,7 @@ init({Code,LockButton}) -> {ok, {locked,LockButton}, Data}. callback_mode() -> - [handle_event_function,state_entry_events]. + [handle_event_function,state_enter]. handle_event( {call,From}, {set_lock_button,NewLockButton}, -- cgit v1.2.3 From 800265f49f912dcf66846b13aa8032bf2f380caf Mon Sep 17 00:00:00 2001 From: Raimo Niskanen Date: Fri, 30 Sep 2016 11:17:22 +0200 Subject: Improve docs and types --- system/doc/design_principles/statem.xml | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) (limited to 'system/doc') diff --git a/system/doc/design_principles/statem.xml b/system/doc/design_principles/statem.xml index d2a9b23570..69d1e8e9fa 100644 --- a/system/doc/design_principles/statem.xml +++ b/system/doc/design_principles/statem.xml @@ -29,7 +29,7 @@ statem.xml - +

This section is to be read with the gen_statem(3) @@ -199,7 +199,10 @@ handle_event(EventType, EventContent, State, Data) -> State Enter Calls

The gen_statem behavior can regardless of callback mode - automatically call the state function + automatically + + call the state function + with special arguments whenever the state changes so you can write state entry actions near the rest of the state transition rules. @@ -214,8 +217,13 @@ StateName(EventType, EventContent, Data) -> {next_state, NewStateName, NewData}.

Depending on how your state machine is specified, - this can be a very useful feature, but if you use it - you will have to handle the state enter call in all states. + this can be a very useful feature, + but it forces you to handle the state enter calls in all states. + See also the + + State Entry Actions + + chapter.

@@ -964,6 +972,7 @@ do_unlock() ->
+ State Entry Actions

Say you have a state machine specification -- cgit v1.2.3 From 33296501241d80df3dec8ee422bf8743558258af Mon Sep 17 00:00:00 2001 From: Doug Rohrer Date: Tue, 4 Oct 2016 17:10:40 -0400 Subject: Fix reference to automatic `undefined` field declared types. In 8ce35b287fb50a6845fccf6a13c672aae303dc91 automatic insertion of `undefined` for record fields without initializers was removed, but this was not noted in the documentation. Add a warning about this change using similar verbiage as the original docs. --- system/doc/reference_manual/typespec.xml | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) (limited to 'system/doc') diff --git a/system/doc/reference_manual/typespec.xml b/system/doc/reference_manual/typespec.xml index 1899efd5f3..4421529dda 100644 --- a/system/doc/reference_manual/typespec.xml +++ b/system/doc/reference_manual/typespec.xml @@ -409,11 +409,13 @@ The initial values for fields are to be compatible with (that is, a member of) the corresponding types. This is checked by the compiler and results in a compilation error - if a violation is detected. For fields without initial values, - the singleton type 'undefined' is added to all declared types. - In other words, the following two record declarations have identical - effects: + if a violation is detected.

+ +

In previous (pre-19) versions of Erlang, for fields without initial values, + the singleton type 'undefined' was added to all declared types. + In other words, the following two record declarations had identical + effects:

   -record(rec, {f1 = 42 :: integer(),
                 f2      :: float(),
@@ -423,9 +425,10 @@
                 f2      :: 'undefined' | float(),
                 f3      :: 'undefined' | 'a' | 'b'}).

- For this reason, it is recommended that records contain initializers, - whenever possible. + This is no longer the case. If you require 'undefined' in your record field + type, you must explicitly add it to the typespec, as in the 2nd example.

+

Any record, containing type information or not, once defined, can be used as a type using the following syntax: -- cgit v1.2.3 From 0411bfded2ee9aefb8178a47d139b54913490d5b Mon Sep 17 00:00:00 2001 From: Doug Rohrer Date: Wed, 5 Oct 2016 11:05:44 -0400 Subject: Update per review comments. --- system/doc/reference_manual/typespec.xml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'system/doc') diff --git a/system/doc/reference_manual/typespec.xml b/system/doc/reference_manual/typespec.xml index 4421529dda..ced584ed35 100644 --- a/system/doc/reference_manual/typespec.xml +++ b/system/doc/reference_manual/typespec.xml @@ -411,8 +411,8 @@ This is checked by the compiler and results in a compilation error if a violation is detected.

- -

In previous (pre-19) versions of Erlang, for fields without initial values, + +

Before Erlang/OTP 19, for fields without initial values, the singleton type 'undefined' was added to all declared types. In other words, the following two record declarations had identical effects:

@@ -428,7 +428,7 @@ This is no longer the case. If you require 'undefined' in your record field type, you must explicitly add it to the typespec, as in the 2nd example.

-
+

Any record, containing type information or not, once defined, can be used as a type using the following syntax: -- cgit v1.2.3 From 77e175589b0ee3c1a4c94aef3cdcdf54cd84c53c Mon Sep 17 00:00:00 2001 From: Raimo Niskanen Date: Fri, 30 Sep 2016 18:00:38 +0200 Subject: Implement state timeouts --- system/doc/design_principles/code_lock.dia | Bin 2932 -> 2945 bytes system/doc/design_principles/code_lock.png | Bin 59160 -> 59827 bytes system/doc/design_principles/code_lock_2.dia | Bin 2621 -> 2956 bytes system/doc/design_principles/code_lock_2.png | Bin 48927 -> 55553 bytes system/doc/design_principles/statem.xml | 581 +++++++++++++++++---------- 5 files changed, 377 insertions(+), 204 deletions(-) (limited to 'system/doc') diff --git a/system/doc/design_principles/code_lock.dia b/system/doc/design_principles/code_lock.dia index 8e6ff8a898..eaa2aca5b0 100644 Binary files a/system/doc/design_principles/code_lock.dia and b/system/doc/design_principles/code_lock.dia differ diff --git a/system/doc/design_principles/code_lock.png b/system/doc/design_principles/code_lock.png index 745fd91920..40bd35fc74 100644 Binary files a/system/doc/design_principles/code_lock.png and b/system/doc/design_principles/code_lock.png differ diff --git a/system/doc/design_principles/code_lock_2.dia b/system/doc/design_principles/code_lock_2.dia index 142909a2f5..3b9ba554d8 100644 Binary files a/system/doc/design_principles/code_lock_2.dia and b/system/doc/design_principles/code_lock_2.dia differ diff --git a/system/doc/design_principles/code_lock_2.png b/system/doc/design_principles/code_lock_2.png index ecf7b0d799..3aca9dd5aa 100644 Binary files a/system/doc/design_principles/code_lock_2.png and b/system/doc/design_principles/code_lock_2.png differ diff --git a/system/doc/design_principles/statem.xml b/system/doc/design_principles/statem.xml index 69d1e8e9fa..9a50bef7b1 100644 --- a/system/doc/design_principles/statem.xml +++ b/system/doc/design_principles/statem.xml @@ -29,7 +29,7 @@ statem.xml - +

This section is to be read with the gen_statem(3) @@ -50,6 +50,7 @@

+ Event-Driven State Machines

Established Automata Theory does not deal much with @@ -94,7 +95,7 @@ State(S) x Event(E) -> Actions(A), State(S')

- + Callback Modes

The gen_statem behavior supports two callback modes: @@ -110,7 +111,12 @@ State(S) x Event(E) -> Actions(A), State(S')

 StateName(EventType, EventContent, Data) ->
     ... code for actions here ...
-    {next_state, NewStateName, NewData}.
+ {next_state, NewStateName, NewData}. + +

+ This form is used in most examples here for example in section + Example. +

@@ -121,7 +127,13 @@ StateName(EventType, EventContent, Data) ->

 handle_event(EventType, EventContent, State, Data) ->
     ... code for actions here ...
-    {next_state, NewState, NewData}
+ {next_state, NewState, NewData} + +

+ Se section + One Event Handler + for an example. +

@@ -134,10 +146,11 @@ handle_event(EventType, EventContent, State, Data) ->

+ Choosing the Callback Mode

The two - callback modes + callback modes give different possibilities and restrictions, but one goal remains: you want to handle all possible combinations of @@ -195,7 +208,7 @@ handle_event(EventType, EventContent, State, Data) ->

- + State Enter Calls

The gen_statem behavior can regardless of callback mode @@ -230,10 +243,160 @@ StateName(EventType, EventContent, Data) ->

+ + Actions +

+ In the first section + + Event-Driven State Machines + + actions were mentioned as a part of + the general state machine model. These general actions + are implemented with the code that callback module + gen_statem executes in an event-handling + callback function before returning + to the gen_statem engine. +

+

+ There are more specific state-transition actions + that a callback function can order the gen_statem + engine to do after the callback function return. + These are ordered by returning a list of + actions + in the + return tuple + from the + callback function. + These state transition actions affect the gen_statem + engine itself and can do the following: +

+ + + + Postpone + + the current event, see section + Postponing Events + + + + Hibernate + + the gen_statem, treated in + Hibernation + + + Start a + + state time-out, + read more in section + State Time-Outs + + + Start an + event time-out, + see more in section + Event Time-Outs + + + + Reply + + to a caller, mentioned at the end of section + All State Events + + + Generate the + + next event + + to handle, see section + Self-Generated Events + + +

+ For details, see the + + gen_statem(3) + + manual page. + You can, for example, reply to many callers + and generate multiple next events to handle. +

+
+ + + +
+ + Event Types +

+ Events are categorized in different + event types. + Events of all types are handled in the same callback function, + for a given state, and the function gets + EventType and EventContent as arguments. +

+

+ The following is a complete list of event types and where + they come from: +

+ + cast + + Generated by + gen_statem:cast. + + {call,From} + + Generated by + gen_statem:call, + where From is the reply address to use + when replying either through the state transition action + {reply,From,Msg} or by calling + gen_statem:reply. + + info + + Generated by any regular process message sent to + the gen_statem process. + + state_timeout + + Generated by state transition action + + {state_timeout,Time,EventContent} + + state timer timing out. + + timeout + + Generated by state transition action + + {timeout,Time,EventContent} + + (or its short form Time) + event timer timing out. + + internal + + Generated by state transition + action + {next_event,internal,EventContent}. + All event types above can also be generated using + {next_event,EventType,EventContent}. + + +
+ + + +
+ Example

This example starts off as equivalent to the example in section - gen_fsm-Behavior. + gen_fsm Behavior. In later sections, additions and tweaks are made using features in gen_statem that gen_fsm does not have. The end of this chapter provides the example again @@ -256,7 +419,6 @@ StateName(EventType, EventContent, Data) -> This code lock state machine can be implemented using gen_statem with the following callback module:

- init(Code) -> do_lock(), Data = #{code => Code, remaining => Code}, - {ok,locked,Data}. + {ok, locked, Data}. callback_mode() -> state_functions. @@ -287,19 +449,19 @@ locked( case Remaining of [Digit] -> do_unlock(), - {next_state,open,Data#{remaining := Code},10000}; + {next_state, open, Data#{remaining := Code}, + [{state_timeout,10000,lock}]; [Digit|Rest] -> % Incomplete - {next_state,locked,Data#{remaining := Rest}}; + {next_state, locked, Data#{remaining := Rest}}; _Wrong -> - {next_state,locked,Data#{remaining := Code}} + {next_state, locked, Data#{remaining := Code}} end. -open(timeout, _, Data) -> +open(state_timeout, lock, Data) -> do_lock(), - {next_state,locked,Data}; + {next_state, locked, Data}; open(cast, {button,_}, Data) -> - do_lock(), - {next_state,locked,Data}. + {next_state, open, Data}. do_lock() -> io:format("Lock~n", []). @@ -310,7 +472,7 @@ terminate(_Reason, State, _Data) -> State =/= locked andalso do_lock(), ok. code_change(_Vsn, State, Data, _Extra) -> - {ok,State,Data}. + {ok, State, Data}. ]]>

The code is explained in the next sections.

@@ -318,6 +480,7 @@ code_change(_Vsn, State, Data, _Extra) ->
+ Starting gen_statem

In the example in the previous section, gen_statem is @@ -380,7 +543,7 @@ start_link(Code) ->

If name registration succeeds, the new gen_statem process calls callback function code_lock:init(Code). - This function is expected to return {ok,State,Data}, + This function is expected to return {ok, State, Data}, where State is the initial state of the gen_statem, in this case locked; assuming that the door is locked to begin with. Data is the internal server data of the gen_statem. @@ -421,7 +584,7 @@ callback_mode() -> Function Module:callback_mode/0 selects the - CallbackMode + CallbackMode for the callback module, in this case state_functions. That is, each state has got its own handler function. @@ -432,6 +595,7 @@ callback_mode() ->

+ Handling Events

The function notifying the code lock about a button event is implemented using @@ -451,11 +615,13 @@ button(Digit) -> The event is made into a message and sent to the gen_statem. When the event is received, the gen_statem calls StateName(cast, Event, Data), which is expected to - return a tuple {next_state,NewStateName,NewData}. + return a tuple {next_state, NewStateName, NewData}, + or {next_state, NewStateName, NewData, Actions}. StateName is the name of the current state and NewStateName is the name of the next state to go to. NewData is a new value for the server data of - the gen_statem. + the gen_statem, and Actions is a list of + actions on the gen_statem engine.

% Complete do_unlock(), - {next_state,open,Data#{remaining := Code},10000}; + {next_state, open, Data#{remaining := Code}, + [{state_timeout,10000,lock}]}; [Digit|Rest] -> % Incomplete - {next_state,locked,Data#{remaining := Rest}}; + {next_state, locked, Data#{remaining := Rest}}; [_|_] -> % Wrong - {next_state,locked,Data#{remaining := Code}} + {next_state, locked, Data#{remaining := Code}} end. -open(timeout, _, Data) -> +open(state_timeout, lock, Data) -> do_lock(), - {next_state,locked,Data}; + {next_state, locked, Data}; open(cast, {button,_}, Data) -> - do_lock(), - {next_state,locked,Data}. + {next_state, open, Data}. ]]>

If the door is locked and a button is pressed, the pressed @@ -490,38 +656,55 @@ open(cast, {button,_}, Data) -> restarts from the start of the code sequence.

- In state open, any button locks the door, as - any event cancels the event timer, so no - time-out event occurs after a button event. + If the whole code is correct, the server changes states + to open. +

+

+ In state open, a button event is ignored + by staying in the same state. This can also be done + by returning {keep_state, Data} or in this case + since Data unchanged even by returning + keep_state_and_data.

- Event Time-Outs + + State Time-Outs

When a correct code has been given, the door is unlocked and the following tuple is returned from locked/2:

10,000 is a time-out value in milliseconds. After this time (10 seconds), a time-out occurs. - Then, StateName(timeout, 10000, Data) is called. + Then, StateName(state_timeout, lock, Data) is called. The time-out occurs when the door has been in state open for 10 seconds. After that the door is locked again:

+open(state_timeout, lock, Data) -> do_lock(), - {next_state,locked,Data}; + {next_state, locked, Data}; ]]> +

+ The timer for a state time-out is automatically cancelled + when the state machine changes states. You can restart + a state time-out by setting it to a new time, which cancels + the running timer and starts a new. This implies that + you can cancel a state time-out by restarting it with + time infinity. +

+ All State Events

Sometimes events can arrive in any state of the gen_statem. @@ -554,21 +737,24 @@ open(EventType, EventContent, Data) -> handle_event(EventType, EventContent, Data). handle_event({call,From}, code_length, #{code := Code} = Data) -> - {keep_state,Data,[{reply,From,length(Code)}]}. + {keep_state, Data, [{reply,From,length(Code)}]}. ]]>

This example uses gen_statem:call/2, which waits for a reply from the server. The reply is sent with a {reply,From,Reply} tuple - in an action list in the {keep_state,...} tuple - that retains the current state. + in an action list in the {keep_state, ...} tuple + that retains the current state. This return form is convenient + when you want to stay in the current state but do not know or + care about what it is.

+ One Event Handler

If mode handle_event_function is used, @@ -592,19 +778,19 @@ handle_event(cast, {button,Digit}, State, #{code := Code} = Data) -> case maps:get(remaining, Data) of [Digit] -> % Complete do_unlock(), - {next_state,open,Data#{remaining := Code},10000}; + {next_state, open, Data#{remaining := Code}, + [{state_timeout,10000,lock}}; [Digit|Rest] -> % Incomplete - {keep_state,Data#{remaining := Rest}}; + {keep_state, Data#{remaining := Rest}}; [_|_] -> % Wrong - {keep_state,Data#{remaining := Code}} + {keep_state, Data#{remaining := Code}} end; open -> - do_lock(), - {next_state,locked,Data} + keep_state_and_data end; -handle_event(timeout, _, open, Data) -> +handle_event(state_timeout, lock, open, Data) -> do_lock(), - {next_state,locked,Data}. + {next_state, locked, Data}. ... ]]> @@ -613,9 +799,11 @@ handle_event(timeout, _, open, Data) ->

+ Stopping
+ In a Supervision Tree

If the gen_statem is part of a supervision tree, @@ -655,6 +843,7 @@ terminate(_Reason, State, _Data) ->

+ Standalone gen_statem

If the gen_statem is not part of a supervision tree, @@ -681,127 +870,77 @@ stop() ->

- Actions + + Event Time-Outs

- In the first sections actions were mentioned as a part of - the general state machine model. These general actions - are implemented with the code that callback module - gen_statem executes in an event-handling - callback function before returning - to the gen_statem engine. + A timeout feature inherited from gen_statem's predecessor + gen_fsm, + is an event time-out, that is, + if an event arrives the timer is cancelled. + You get either an event or a time-out, but not both.

- There are more specific state-transition actions - that a callback function can order the gen_statem - engine to do after the callback function return. - These are ordered by returning a list of - actions - in the - return tuple - from the - callback function. - These state transition actions affect the gen_statem - engine itself and can do the following: + It is ordered by the state transition action + {timeout,Time,EventContent}, or just Time, + or even just Time instead of an action list + (the latter is a form inherited from gen_fsm.

- - Postpone the current event - Hibernate the gen_statem - Start an event time-out - Reply to a caller - Generate the next event to handle -

- In the example earlier was mentioned the event time-out - and replying to a caller. - An example of event postponing is included later in this chapter. - For details, see the - gen_statem(3) - manual page. - You can, for example, reply to many callers - and generate multiple next events to handle. + This type of time-out is useful to for example act on inactivity. + Let us start restart the code sequence + if no button is pressed for say 30 seconds:

-
- - + - Event Types +locked( + timeout, _, + #{code := Code, remaining := Remaining} = Data) -> + {next_state, locked, Data#{remaining := Code}}; +locked( + cast, {button,Digit}, + #{code := Code, remaining := Remaining} = Data) -> +... + [Digit|Rest] -> % Incomplete + {next_state, locked, Data#{remaining := Rest}, 30000}; +... + ]]>

- The previous sections mentioned a few - event types. - Events of all types are handled in the same callback function, - for a given state, and the function gets - EventType and EventContent as arguments. + Whenever we receive a button event we start an event timeout + of 30 seconds, and if we get an event type timeout + we reset the remaining code sequence.

- The following is a complete list of event types and where - they come from: + An event timeout is cancelled by any other event so you either + get some other event or the timeout event. It is therefore + not possible nor needed to cancel or restart an event timeout. + Whatever event you act on has already cancelled + the event timeout...

- - cast - - Generated by - gen_statem:cast. - - {call,From} - - Generated by - gen_statem:call, - where From is the reply address to use - when replying either through the state transition action - {reply,From,Msg} or by calling - gen_statem:reply. - - info - - Generated by any regular process message sent to - the gen_statem process. - - timeout - - Generated by state transition action - {timeout,Time,EventContent} (or its short form Time) - timer timing out. - - internal - - Generated by state transition action - {next_event,internal,EventContent}. - All event types above can also be generated using - {next_event,EventType,EventContent}. - -
- State Time-Outs -

- The time-out event generated by state transition action - {timeout,Time,EventContent} is an event time-out, - that is, if an event arrives the timer is cancelled. - You get either an event or a time-out, but not both. -

+ + Erlang Timers

- Often you want a timer not to be cancelled by any event - or you want to start a timer in one state and respond - to the time-out in another. This can be accomplished - with a regular Erlang timer: - erlang:start_timer. + The previous example of state time-outs only work if + the state machine stays in the same state during the + time-out time. And event time-outs only work if no + disturbing unrelated events occur.

- For the example so far in this chapter: using the - gen_statem event timer has the consequence that - if a button event is generated while in the open state, - the time-out is cancelled and the button event is delivered. - So, we choose to lock the door if this occurred. + You may want to start a timer in one state and respond + to the time-out in another, maybe cancel the time-out + without changing states, or perhaps run multiple + time-outs in parallel. All this can be accomplished + with Erlang Timers: + erlang:start_timer3,4.

- Suppose that we do not want a button to lock the door, - instead we want to ignore button events in the open state. - Then we start a timer when entering the open state - and wait for it to expire while ignoring button events: + Here is how to accomplish the state time-out + in the previous example by insted using an Erlang Timer:

do_unlock(), Tref = erlang:start_timer(10000, self(), lock), - {next_state,open,Data#{remaining := Code, timer := Tref}}; + {next_state, open, Data#{remaining := Code, timer => Tref}}; ... open(info, {timeout,Tref,lock}, #{timer := Tref} = Data) -> do_lock(), - {next_state,locked,Data}; + {next_state,locked,maps:remove(timer, Data)}; open(cast, {button,_}, Data) -> {keep_state,Data}; ... ]]> +

+ Removing the timer key from the map when we + change to state locked is not strictly + necessary since we can only get into state open + with an updated timer map value. But it can be nice + to not have outdated values in the state Data! +

If you need to cancel a timer because of some other event, you can use erlang:cancel_timer(Tref). - Notice that a time-out message cannot arrive after this, - unless you have postponed it (see the next section) before, + Note that a time-out message cannot arrive after this, + unless you have postponed it before (see the next section), so ensure that you do not accidentally postpone such messages. + Also note that a time-out message may have arrived + just before you cancelling it, so you may have to read out + such a message from the process mailbox depending on + the return value from + erlang:cancel_timer(Tref).

- Another way to cancel a timer is not to cancel it, + Another way to handle a late time-out can be to not cancel it, but to ignore it if it arrives in a state where it is known to be late.

@@ -839,6 +990,7 @@ open(cast, {button,_}, Data) ->
+ Postponing Events

If you want to ignore a particular event in the current state @@ -877,6 +1029,7 @@ open(cast, {button,_}, Data) ->

+ Fuzzy State Diagrams

It is not uncommon that a state diagram does not specify @@ -893,6 +1046,7 @@ open(cast, {button,_}, Data) ->

+ Selective Receive

Erlang's selective receive statement is often used to @@ -972,7 +1126,7 @@ do_unlock() ->

- + State Entry Actions

Say you have a state machine specification @@ -981,7 +1135,7 @@ do_unlock() -> (described in the next section), especially if just one or a few states has got state entry actions, this is a perfect use case for the built in - state enter calls. + state enter calls.

You return a list containing state_enter from your @@ -1012,11 +1166,10 @@ locked( {next_state, open, Data}; ... -open(enter, _OldState, Data) -> - Tref = erlang:start_timer(10000, self(), lock), +open(enter, _OldState, _Data) -> do_unlock(), - {keep_state,Data#{timer => Tref}}; -open(info, {timeout,Tref,lock}, #{timer := Tref} = Data) -> + {keep_state_and_data, [{state_timeout,10000,lock}]}; +open(state_timeout, lock, Data) -> {next_state, locked, Data}; ... ]]> @@ -1025,6 +1178,7 @@ open(info, {timeout,Tref,lock}, #{timer := Tref} = Data) ->

+ Self-Generated Events

It can sometimes be beneficial to be able to generate events @@ -1054,7 +1208,7 @@ open(info, {timeout,Tref,lock}, #{timer := Tref} = Data) -> to the main state machine.

- The following example use an input model where you give the lock + The following example uses an input model where you give the lock characters with put_chars(Chars) and then call enter() to finish the input.

@@ -1102,10 +1256,11 @@ handle_event({call,From}, enter, #{buf := Buf} = Data) ->
+ Example Revisited

- This section includes the example after all mentioned modifications - and some more using state enter calls, + This section includes the example after most of the mentioned + modifications and some more using state enter calls, which deserves a new state diagram:

@@ -1121,6 +1276,7 @@ handle_event({call,From}, enter, #{buf := Buf} = Data) ->

+ Callback Mode: state_functions

Using state functions: @@ -1155,7 +1311,11 @@ callback_mode() -> locked(enter, _OldState, #{code := Code} = Data) -> do_lock(), - {keep_state,Data#{remaining => Code}}; + {keep_state, Data#{remaining => Code}}; +locked( + timeout, _, + #{code := Code, remaining := Remaining} = Data) -> + {keep_state, Data#{remaining := Code}}; locked( cast, {button,Digit}, #{code := Code, remaining := Remaining} = Data) -> @@ -1163,26 +1323,25 @@ locked( [Digit] -> % Complete {next_state, open, Data}; [Digit|Rest] -> % Incomplete - {keep_state,Data#{remaining := Rest}}; + {keep_state, Data#{remaining := Rest}, 30000}; [_|_] -> % Wrong - {keep_state,Data#{remaining := Code}} + {keep_state, Data#{remaining := Code}} end; locked(EventType, EventContent, Data) -> handle_event(EventType, EventContent, Data). -open(enter, _OldState, Data) -> - Tref = erlang:start_timer(10000, self(), lock), +open(enter, _OldState, _Data) -> do_unlock(), - {keep_state,Data#{timer => Tref}}; -open(info, {timeout,Tref,lock}, #{timer := Tref} = Data) -> + {keep_state_and_data, [{state_timeout,10000,lock}]}; +open(state_timeout, lock, Data) -> {next_state, locked, Data}; open(cast, {button,_}, _) -> - {keep_state_and_data,[postpone]}; + {keep_state_and_data, [postpone]}; open(EventType, EventContent, Data) -> handle_event(EventType, EventContent, Data). handle_event({call,From}, code_length, #{code := Code}) -> - {keep_state_and_data,[{reply,From,length(Code)}]}. + {keep_state_and_data, [{reply,From,length(Code)}]}. do_lock() -> io:format("Locked~n", []). @@ -1198,6 +1357,7 @@ code_change(_Vsn, State, Data, _Extra) ->

+ Callback Mode: handle_event_function

This section describes what to change in the example @@ -1215,9 +1375,15 @@ callback_mode() -> [handle_event_function,state_enter]. %% State: locked -handle_event(enter, _OldState, locked, #{code := Code} = Data) -> +handle_event( + enter, _OldState, locked, + #{code := Code} = Data) -> do_lock(), - {keep_state,Data#{remaining => Code}}; + {keep_state, Data#{remaining => Code}}; +handle_event( + timeout, _, locked, + #{code := Code, remaining := Remaining} = Data) -> + {keep_state, Data#{remaining := Code}}; handle_event( cast, {button,Digit}, locked, #{code := Code, remaining := Remaining} = Data) -> @@ -1225,31 +1391,30 @@ handle_event( [Digit] -> % Complete {next_state, open, Data}; [Digit|Rest] -> % Incomplete - {keep_state,Data#{remaining := Rest}}; + {keep_state, Data#{remaining := Rest}, 30000}; [_|_] -> % Wrong - {keep_state,Data#{remaining := Code}} + {keep_state, Data#{remaining := Code}} end; %% %% State: open -handle_event(enter, _OldState, open, Data) -> - Tref = erlang:start_timer(10000, self(), lock), +handle_event(enter, _OldState, open, _Data) -> do_unlock(), - {keep_state,Data#{timer => Tref}}; -handle_event(info, {timeout,Tref,lock}, open, #{timer := Tref} = Data) -> + {keep_state_and_data, [{state_timeout,10000,lock}]}; +handle_event(state_timeout, lock, open, Data) -> {next_state, locked, Data}; handle_event(cast, {button,_}, open, _) -> {keep_state_and_data,[postpone]}; %% %% Any state handle_event({call,From}, code_length, _State, #{code := Code}) -> - {keep_state_and_data,[{reply,From,length(Code)}]}. + {keep_state_and_data, [{reply,From,length(Code)}]}. ... ]]>

Notice that postponing buttons from the locked state - to the open state feels like the wrong thing to do + to the open state feels like a strange thing to do for a code lock, but it at least illustrates event postponing.

@@ -1257,6 +1422,7 @@ handle_event({call,From}, code_length, _State, #{code := Code}) ->
+ Filter the State

The example servers so far in this chapter @@ -1317,12 +1483,13 @@ format_status(Opt, [_PDict,State,Data]) ->

+ Complex State

The callback mode handle_event_function enables using a non-atom state as described in section - Callback Modes, + Callback Modes, for example, a complex state term like a tuple.

@@ -1396,7 +1563,7 @@ set_lock_button(LockButton) -> init({Code,LockButton}) -> process_flag(trap_exit, true), - Data = #{code => Code, remaining => undefined, timer => undefined}, + Data = #{code => Code, remaining => undefined}, {ok, {locked,LockButton}, Data}. callback_mode() -> @@ -1405,29 +1572,31 @@ callback_mode() -> handle_event( {call,From}, {set_lock_button,NewLockButton}, {StateName,OldLockButton}, Data) -> - {next_state,{StateName,NewLockButton},Data, + {next_state, {StateName,NewLockButton}, Data, [{reply,From,OldLockButton}]}; handle_event( {call,From}, code_length, {_StateName,_LockButton}, #{code := Code}) -> {keep_state_and_data, - [{reply,From,length(Code)}]}; + [{reply,From,length(Code)}]}; %% %% State: locked handle_event( EventType, EventContent, {locked,LockButton}, #{code := Code, remaining := Remaining} = Data) -> - case {EventType,EventContent} of - {enter,_OldState} -> + case {EventType, EventContent} of + {enter, _OldState} -> do_lock(), - {keep_state,Data#{remaining := Code}}; - {{call,From},{button,Digit}} -> + {keep_state, Data#{remaining := Code}}; + {timeout, _} -> + {keep_state, Data#{remaining := Code}}; + {{call,From}, {button,Digit}} -> case Remaining of [Digit] -> % Complete {next_state, {open,LockButton}, Data, [{reply,From,ok}]}; [Digit|Rest] -> % Incomplete - {keep_state, Data#{remaining := Rest}, + {keep_state, Data#{remaining := Rest, 30000}, [{reply,From,ok}]}; [_|_] -> % Wrong {keep_state, Data#{remaining := Code}, @@ -1438,18 +1607,16 @@ handle_event( %% State: open handle_event( EventType, EventContent, - {open,LockButton}, #{timer := Timer} = Data) -> - case {EventType,EventContent} of - {enter,_OldState} -> - Tref = erlang:start_timer(10000, self(), lock), + {open,LockButton}, Data) -> + case {EventType, EventContent} of + {enter, _OldState} -> do_unlock(), - {keep_state,Data#{timer := Tref}}; - {info,{timeout,Timer,lock}} -> + {keep_state_and_data, [{state_timeout,10000,lock}]}; + {state_timeout, lock} -> {next_state, {locked,LockButton}, Data}; - {{call,From},{button,Digit}} -> + {{call,From}, {button,Digit}} -> if Digit =:= LockButton -> - erlang:cancel_timer(Timer), {next_state, {locked,LockButton}, Data, [{reply,From,locked}]); true -> @@ -1494,6 +1661,7 @@ format_status(Opt, [_PDict,State,Data]) ->

+ Hibernation

If you have many servers in one node @@ -1519,20 +1687,21 @@ format_status(Opt, [_PDict,State,Data]) ->

- case {EventType,EventContent} of - {enter,_OldState} -> - Tref = erlang:start_timer(10000, self(), lock), + {open,LockButton}, Data) -> + case {EventType, EventContent} of + {enter, _OldState} -> do_unlock(), - {keep_state,Data#{timer := Tref},[hibernate]}; + {keep_state_and_data, + [{state_timeout,10000,lock},hibernate]}; ... ]]>

- The - [hibernate] - action list on the last line + The atom + hibernate + in the action list on the last line when entering the {open,_} state is the only change. If any event arrives in the {open,_}, state, we do not bother to rehibernate, so the server stays @@ -1546,6 +1715,10 @@ handle_event( be aware of using hibernate while in the {open,_} state, which would clutter the code.

+

+ Another not uncommon scenario is to use the event time-out + to triger hibernation after a certain time of inactivity. +

This server probably does not use heap memory worth hibernating for. -- cgit v1.2.3 From f4de3f5887be010db178a178e1f20027f3e5d22b Mon Sep 17 00:00:00 2001 From: Raimo Niskanen Date: Wed, 12 Oct 2016 17:49:26 +0200 Subject: Use parameterized types --- system/doc/design_principles/statem.xml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'system/doc') diff --git a/system/doc/design_principles/statem.xml b/system/doc/design_principles/statem.xml index 9a50bef7b1..bece95e6b8 100644 --- a/system/doc/design_principles/statem.xml +++ b/system/doc/design_principles/statem.xml @@ -214,7 +214,7 @@ handle_event(EventType, EventContent, State, Data) -> The gen_statem behavior can regardless of callback mode automatically - call the state function + call the state callback with special arguments whenever the state changes so you can write state entry actions @@ -264,7 +264,7 @@ StateName(EventType, EventContent, Data) -> These are ordered by returning a list of actions in the - return tuple + return tuple from the callback function. These state transition actions affect the gen_statem @@ -1141,7 +1141,7 @@ do_unlock() -> You return a list containing state_enter from your callback_mode/0 function and the gen_statem engine will call your - state function once with the arguments + state callback once with the arguments (enter, OldState, ...) whenever the state changes. Then you just need to handle these event-like calls in all states.

-- cgit v1.2.3 From f3f2b83e873592bcec47431a787c7cfffdd60685 Mon Sep 17 00:00:00 2001 From: Raimo Niskanen Date: Tue, 25 Oct 2016 09:29:21 +0200 Subject: Clarify the chapter 'Postponing Events' (ERL-284) --- system/doc/design_principles/statem.xml | 29 ++++++++++++++++++----------- 1 file changed, 18 insertions(+), 11 deletions(-) (limited to 'system/doc') diff --git a/system/doc/design_principles/statem.xml b/system/doc/design_principles/statem.xml index bece95e6b8..f627145f9f 100644 --- a/system/doc/design_principles/statem.xml +++ b/system/doc/design_principles/statem.xml @@ -1015,17 +1015,24 @@ open(cast, {button,_}, Data) -> ... ]]>

- The fact that a postponed event is only retried after a state change - translates into a requirement on the event and state space. - If you have a choice between storing a state data item - in the State or in the Data: - if a change in the item value affects which events that - are handled, then this item is to be part of the state. -

-

- You want to avoid that you maybe much later decide - to postpone an event in one state and by misfortune it is never retried, - as the code only changes the Data but not the State. + Since a postponed event is only retried after a state change, + you have to think about where to keep a state data item. + You can keep it in the server Data + or in the State itself, + for example by having two more or less identical states + to keep a boolean value, or by using a complex state with + callback mode + handle_event_function. + If a change in the value changes the set of events that is handled, + then the value should be kept in the State. + Otherwise no postponed events will be retried + since only the server Data changes. +

+

+ This is not important if you do not postpone events. + But if you later decide to start postponing some events, + then the design flaw of not having separate states + when they should be, might become a hard to find bug.

-- cgit v1.2.3 From b8f201b00198207cbf4959f8f209bb2fa302515c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn-Egil=20Dahlberg?= Date: Fri, 28 Oct 2016 16:40:48 +0200 Subject: doc: Clarify application directory structure --- system/doc/design_principles/applications.xml | 160 +++++++++++++++++++++----- 1 file changed, 132 insertions(+), 28 deletions(-) (limited to 'system/doc') diff --git a/system/doc/design_principles/applications.xml b/system/doc/design_principles/applications.xml index 0a1b65ea8e..c673fde07e 100644 --- a/system/doc/design_principles/applications.xml +++ b/system/doc/design_principles/applications.xml @@ -11,7 +11,7 @@ Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at - + http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software @@ -19,7 +19,7 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. - + Applications @@ -172,31 +172,136 @@ ch_app:stop([])
- - Directory Structure -

When packaging code using systools, the code for each - application is placed in a separate directory, - lib/Application-Vsn, where Vsn is the version number.

-

This can be useful to know, even if systools is not used, - since Erlang/OTP is packaged according to the OTP principles - and thus comes with this directory structure. The code server - (see the code(3) manual page in Kernel) automatically - uses code from - the directory with the highest version number, if more than one - version of an application is present.

-

The application directory structure can also be used in the - development environment. The version number can then - be omitted from the name.

-

The application directory has the following sub-directories:

- - src - Contains the Erlang source code. - ebin - Contains the Erlang object code, the - beam files. The .app file is also placed here. - priv - Used for application specific files. For - example, C executables are placed here. The function - code:priv_dir/1 is to be used to access this directory. - include - Used for include files. - + + Directory Structure +

When packaging code using systools, the code for each + application is placed in a separate directory, + lib/Application-Vsn, where Vsn is the version number.

+

This can be useful to know, even if systools is not used, + since Erlang/OTP is packaged according to the OTP principles + and thus comes with a specific directory structure. The code server + (see the code(3) manual + page in Kernel) automatically uses code from + the directory with the highest version number, if more than one + version of an application is present.

+
+ Directory Structure guidelines for a Development Environment +

Any directory structure for development will suffice as long as the released directory structure + adhere to the description below, + but it is encouraged that the same directory structure + also be used in a development environment. The version number should be omitted from the + application directory name since this is an artifact of the release step. +

+

Some sub-directories are required. Some sub-directories are optional, meaning that it should + only be used if the application itself requires it. Finally, some sub-directories are recommended, + meaning it is encouraged that it is used and used as described here. For example, both documentation + and tests are encouraged to exist in an application for it to be deemed a proper OTP application.

+ + ─ ${application} +   ├── doc + │   ├── internal + │   ├── examples + │   └── src +   ├── include +   ├── priv +   ├── src + │   └── ${application}.app.src +   └── test + + + src - Required. Contains the Erlang source code, the source of the .app file + and internal include files used by the application itself. Additional sub-directories within + src can be used as namespaces to organize source files. These directories should never + be deeper than one level. + priv - Optional. Used for application specific files. + include - Optional. Used for public include files that must be reachable from + other applications. + doc - Recommended. Any source documentation should be placed in sub-directories here. + doc/internal - Recommended. Any documentation that describes implementation details about + this application, not intended for publication, should be placed here. + doc/examples - Recommended. Source code for examples on how to use this application should + be placed here. It is encouraged that examples are sourced to the public documentation from + this directory. + doc/src - Recommended. All source files for documentation, such as Markdown, AsciiDoc or + XML-files, should be placed here. + test - Recommended. All files regarding tests, such as test suites and test specifications, + should be placed here. + + +

Other directories in the development environment may be needed. If source code from languages other + than Erlang is used, for instance C-code for NIFs, that code should be placed in a separate directory. + By convention it is recommended to prefix such directories with the language name, for example + c_src for C, java_src for Java or go_src for Go. Directories with _src + suffix indicates that it is a part of the application and the compilation step. The final build artifacts + should target the priv/lib or priv/bin directories.

+

The priv directory holds assets that the application needs during runtime. Executables should + reside in priv/bin and dynamically-linked libraries should reside in priv/lib. Other assets + are free to reside within the priv directory but it is recommended it does so in a structured manner.

+

Source files from other languages that generate Erlang code, such as ASN.1 or Mibs, should be placed + in directories, at the top level or in src, with the same name as the source language, for example + asn1 and mibs. Build artifacts should be placed in their respective language directory, + such as src for Erlang code or java_src for Java code.

+

The .app file for release may reside in the ebin-directory in a development environment + but it is encouraged that this is an artifact of the build step. By convention a .app.src file + is used, which resides in the src directory. This file is nearly identical as the + .app file but certain fields may be replaced during the build step, such as the application version.

+

Directory names should not be capitalized.

+

It is encouraged to omit empty directories.

+ +
+ +
+ + Directory Structure for a Released System +

A released application must follow a certain structure. +

+ + ─ ${application}-${version} +   ├── bin +   ├── doc + │   ├── html + │   ├── man[1-9] + │   ├── pdf + │   ├── internal + │   └── examples +   ├── ebin + │   └── ${application}.app +   ├── include +   ├── priv + │   ├── lib + │   └── bin +   └── src + + + src - Optional. Contains the Erlang source code and internal include files + used by the application itself. This directory is no longer required in a released application. + ebin - Required. Contains the Erlang object code, the beam files. + The .app file must also be placed here. + priv - Optional. Used for application specific files. code:priv_dir/1 + is to be used to access this directory. + priv/lib - Recommended. Any shared-object files that are used by the application, + such as NIFs or linked-in-drivers, should be placed here. + priv/bin - Recommended. Any executable that is used by the application, + such as port-programs, should be placed here. + include - Optional. Used for public include files that must be reachable from + other applications. + bin - Optional. Any executable that is a product of the application, + such as escripts or shell-scripts, should be placed here. + doc - Optional. Any released documentation should be placed in + sub-directories here. + doc/man1 - Recommended. Man pages for Application executables. + doc/man3 - Recommended. Man pages for module APIs. + doc/man6 - Recommended. Man pages for Application overview. + doc/html - Optional. HTML pages for the entire Application. + doc/pdf - Optional. PDF documentation for the entire Application. + + +

The src directory could be useful to release for debugging purposes but is not required. + The include directory should only be released if the applications has public include files.

+

The only documentation that is recommended to be released in this way are the man pages. HTML and PDF + will normally be distributed in some other manner.

+

It is encouraged to omit empty directories.

+
@@ -381,4 +486,3 @@ application:start(Application, Type) shutdown, not normal.

- -- cgit v1.2.3 From 26b0619b05d36e87849ff249f0e68cf9bfd1d1fd Mon Sep 17 00:00:00 2001 From: Brujo Benavides Date: Thu, 3 Nov 2016 12:59:27 -0300 Subject: Expand on the behavior of supervisors Add additional details on the behavior of supervisors when reaching maximum restart intensity, as stated by @rvirding at [Medium](https://goo.gl/XhwpSL) --- system/doc/design_principles/sup_princ.xml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'system/doc') diff --git a/system/doc/design_principles/sup_princ.xml b/system/doc/design_principles/sup_princ.xml index 0a24e97950..c24177d842 100644 --- a/system/doc/design_principles/sup_princ.xml +++ b/system/doc/design_principles/sup_princ.xml @@ -163,7 +163,9 @@ SupFlags = #{strategy => Strategy, ...} SupFlags = #{intensity => MaxR, period => MaxT, ...}

If more than MaxR number of restarts occur in the last MaxT seconds, the supervisor terminates all the child - processes and then itself.

+ processes and then itself. + The termination reason for the supervisor itself in that case will be + shutdown.

When the supervisor terminates, then the next higher-level supervisor takes some action. It either restarts the terminated supervisor or terminates itself.

-- cgit v1.2.3 From 3eddb0f762de248d3230b38bc9d478bfbc8e7331 Mon Sep 17 00:00:00 2001 From: Erlang/OTP Date: Wed, 7 Dec 2016 13:15:31 +0100 Subject: Update copyright-year --- system/doc/reference_manual/code_loading.xml | 2 +- system/doc/reference_manual/macros.xml | 2 +- system/doc/tutorial/c_port.xmlsrc | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) (limited to 'system/doc') diff --git a/system/doc/reference_manual/code_loading.xml b/system/doc/reference_manual/code_loading.xml index f6fd2911fa..f5e5e74841 100644 --- a/system/doc/reference_manual/code_loading.xml +++ b/system/doc/reference_manual/code_loading.xml @@ -4,7 +4,7 @@
- 20032015 + 20032016 Ericsson AB. All Rights Reserved. diff --git a/system/doc/reference_manual/macros.xml b/system/doc/reference_manual/macros.xml index 350bb1d123..5f24473557 100644 --- a/system/doc/reference_manual/macros.xml +++ b/system/doc/reference_manual/macros.xml @@ -4,7 +4,7 @@
- 20032015 + 20032016 Ericsson AB. All Rights Reserved. diff --git a/system/doc/tutorial/c_port.xmlsrc b/system/doc/tutorial/c_port.xmlsrc index 3c3bc48044..ff0997fb54 100644 --- a/system/doc/tutorial/c_port.xmlsrc +++ b/system/doc/tutorial/c_port.xmlsrc @@ -4,7 +4,7 @@
- 20002015 + 20002016 Ericsson AB. All Rights Reserved. -- cgit v1.2.3 From 0d016cdce1c688335dc265056137890d7a7850c9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn-Egil=20Dahlberg?= Date: Mon, 12 Dec 2016 17:00:19 +0100 Subject: Remove whitespace errors --- system/doc/reference_manual/typespec.xml | 71 ++++++++++++++++---------------- 1 file changed, 35 insertions(+), 36 deletions(-) (limited to 'system/doc') diff --git a/system/doc/reference_manual/typespec.xml b/system/doc/reference_manual/typespec.xml index ced584ed35..1a3669c736 100644 --- a/system/doc/reference_manual/typespec.xml +++ b/system/doc/reference_manual/typespec.xml @@ -11,7 +11,7 @@ Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at - + http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software @@ -161,7 +161,7 @@ that M or N, or both, are zero.

- Because lists are commonly used, they have shorthand type notations. + Because lists are commonly used, they have shorthand type notations. The types list(T) and nonempty_list(T) have the shorthands [T] and [T,...], respectively. The only difference between the two shorthands is that [T] can be an @@ -169,7 +169,7 @@

Notice that the shorthand for list(), that is, the list of - elements of unknown type, is [_] (or [any()]), not []. + elements of unknown type, is [_] (or [any()]), not []. The notation [] specifies the singleton type for the empty list.

@@ -184,8 +184,8 @@ The notation #{} specifies the singleton type for the empty map.

- For convenience, the following types are also built-in. - They can be thought as predefined aliases for the type unions also shown in + For convenience, the following types are also built-in. + They can be thought as predefined aliases for the type unions also shown in the table.

@@ -201,37 +201,37 @@ bitstring()<<_:_*1>> - + boolean()'false' | 'true' - + byte()0..255 char()0..16#10ffff - + nil()[] number()integer() | float() - + list()[any()] - + maybe_improper_list()maybe_improper_list(any(), any()) - + nonempty_list()nonempty_list(any()) string()[char()] - + nonempty_string()[char(),...] - + iodata()iolist() | binary() @@ -243,7 +243,7 @@ module()atom() - + mfa(){module(),atom(),arity()} @@ -259,7 +259,7 @@ timeout()'infinity' | non_neg_integer() - no_return()none() + no_return()none() Built-in types, predefined aliases
@@ -284,11 +284,11 @@ Additional built-in types - +

Users are not allowed to define types with the same names as the predefined or built-in ones. This is checked by the compiler and - its violation results in a compilation error. + its violation results in a compilation error.

@@ -394,13 +394,13 @@

   -record(rec, {field1 :: Type1, field2, field3 :: Type3}).

- For fields without type annotations, their type defaults to any(). + For fields without type annotations, their type defaults to any(). That is, the previous example is a shorthand for the following:

   -record(rec, {field1 :: Type1, field2 :: any(), field3 :: Type3}).

- In the presence of initial values for fields, + In the presence of initial values for fields, the type must be declared after the initialization, as follows:

@@ -409,12 +409,12 @@
       The initial values for fields are to be compatible
       with (that is, a member of) the corresponding types.
       This is checked by the compiler and results in a compilation error
-      if a violation is detected. 
+      if a violation is detected.
     

Before Erlang/OTP 19, for fields without initial values, the singleton type 'undefined' was added to all declared types. - In other words, the following two record declarations had identical + In other words, the following two record declarations had identical effects:

   -record(rec, {f1 = 42 :: integer(),
@@ -430,22 +430,22 @@
     

- Any record, containing type information or not, once defined, + Any record, containing type information or not, once defined, can be used as a type using the following syntax:

  #rec{}

- In addition, the record fields can be further specified when using + In addition, the record fields can be further specified when using a record type by adding type information about the field as follows:

  #rec{some_field :: Type}

- Any unspecified fields are assumed to have the type in the original + Any unspecified fields are assumed to have the type in the original record declaration.

- +
Specifications for Functions

@@ -459,9 +459,9 @@ else a compilation error occurs.

- This form can also be used in header files (.hrl) to declare type - information for exported functions. - Then these header files can be included in files that (implicitly or + This form can also be used in header files (.hrl) to declare type + information for exported functions. + Then these header files can be included in files that (implicitly or explicitly) import these functions.

@@ -475,14 +475,14 @@

   -spec Function(ArgName1 :: Type1, ..., ArgNameN :: TypeN) -> RT.

- A function specification can be overloaded. + A function specification can be overloaded. That is, it can have several types, separated by a semicolon (;):

   -spec foo(T1, T2) -> T3
          ; (T4, T5) -> T6.

- A current restriction, which currently results in a warning + A current restriction, which currently results in a warning (not an error) by the compiler, is that the domains of the argument types cannot overlap. For example, the following specification results in a warning: @@ -491,9 +491,9 @@ -spec foo(pos_integer()) -> pos_integer() ; (integer()) -> integer().

- Type variables can be used in specifications to specify relations for - the input and output arguments of a function. - For example, the following specification defines the type of a + Type variables can be used in specifications to specify relations for + the input and output arguments of a function. + For example, the following specification defines the type of a polymorphic identity function:

@@ -542,8 +542,8 @@
   -spec foo({X, integer()}) -> X when X :: atom()
          ; ([Y]) -> Y when Y :: number().

- Some functions in Erlang are not meant to return; - either because they define servers or because they are used to + Some functions in Erlang are not meant to return; + either because they define servers or because they are used to throw exceptions, as in the following function:

  my_error(Err) -> erlang:throw({error, Err}).
@@ -555,4 +555,3 @@
  -spec my_error(term()) -> no_return().
- -- cgit v1.2.3 From 74f4aa2897e7b2a3bac688d808b9b396fc35d1aa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn-Egil=20Dahlberg?= Date: Mon, 12 Dec 2016 14:50:28 +0100 Subject: doc: Change "stands for" to "denotes" in typespec --- system/doc/reference_manual/typespec.xml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'system/doc') diff --git a/system/doc/reference_manual/typespec.xml b/system/doc/reference_manual/typespec.xml index 1a3669c736..c117b6e1d0 100644 --- a/system/doc/reference_manual/typespec.xml +++ b/system/doc/reference_manual/typespec.xml @@ -63,7 +63,7 @@ Types consist of, and are built from, a set of predefined types, for example, integer(), atom(), and pid(). Predefined types represent a typically infinite set of Erlang terms that - belong to this type. For example, the type atom() stands for the + belong to this type. For example, the type atom() denotes the set of all Erlang atoms.

@@ -131,11 +131,11 @@ | nonempty_improper_list(Type1, Type2) %% Type1 and Type2 as above | nonempty_list(Type) %% Proper non-empty list - Map :: map() %% stands for a map of any size - | #{} %% stands for the empty map + Map :: map() %% denotes a map of any size + | #{} %% denotes the empty map | #{PairList} - Tuple :: tuple() %% stands for a tuple of any size + Tuple :: tuple() %% denotes a tuple of any size | {} | {TList} -- cgit v1.2.3 From 4fbe5a6ea946de03693ffa1be671cf9af93e55eb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn-Egil=20Dahlberg?= Date: Mon, 12 Dec 2016 16:54:42 +0100 Subject: doc: Enchance map pair optional/mandatory notes --- system/doc/reference_manual/typespec.xml | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) (limited to 'system/doc') diff --git a/system/doc/reference_manual/typespec.xml b/system/doc/reference_manual/typespec.xml index c117b6e1d0..a0ea41cb3b 100644 --- a/system/doc/reference_manual/typespec.xml +++ b/system/doc/reference_manual/typespec.xml @@ -142,8 +142,8 @@ PairList :: Pair | Pair, PairList - Pair :: Type := Type %% denotes a pair that must be present - | Type => Type + Pair :: Type := Type %% denotes a mandatory pair + | Type => Type %% denotes an optional pair TList :: Type | Type, TList @@ -176,7 +176,11 @@ The general form of maps is #{PairList}. The key types in PairList are allowed to overlap, and if they do, the leftmost pair takes precedence. A map pair has a key in - PairList if it belongs to this type. + PairList if it belongs to this type. A PairList may contain + both 'mandatory' and 'optional' pairs where 'mandatory' denotes that + a key type, and its associated value type, must be present. + In the case of an 'optional' pair it is not required for the key type to + be present.

Notice that the syntactic representation of map() is -- cgit v1.2.3 From 21307fdf279e87b15146f975b3e540d280a4a421 Mon Sep 17 00:00:00 2001 From: Amir Ghassemi Nasr Date: Tue, 13 Dec 2016 17:05:35 +0330 Subject: fix library open error in linked-in port driver tutorial --- system/doc/tutorial/c_portdriver.xmlsrc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'system/doc') diff --git a/system/doc/tutorial/c_portdriver.xmlsrc b/system/doc/tutorial/c_portdriver.xmlsrc index 933e2395a3..da680642b6 100644 --- a/system/doc/tutorial/c_portdriver.xmlsrc +++ b/system/doc/tutorial/c_portdriver.xmlsrc @@ -161,8 +161,8 @@ decode([Int]) -> Int. Running the Example

Step 1. Compile the C code:

-unix> gcc -o exampledrv -fpic -shared complex.c port_driver.c
-windows> cl -LD -MD -Fe exampledrv.dll complex.c port_driver.c
+unix> gcc -o example_drv.so -fpic -shared complex.c port_driver.c +windows> cl -LD -MD -Fe example_drv.dll complex.c port_driver.c

Step 2. Start Erlang and compile the Erlang code:

 > erl
-- 
cgit v1.2.3


From 1cc8044ffc6073749e34dcf1434f02272fe4b457 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Bj=C3=B6rn=20Gustavsson?= 
Date: Tue, 7 Jun 2016 15:14:16 +0200
Subject: Retire two myths

---
 system/doc/efficiency_guide/myths.xml         | 31 ++-----------
 system/doc/efficiency_guide/part.xml          |  1 +
 system/doc/efficiency_guide/retired_myths.xml | 63 +++++++++++++++++++++++++++
 3 files changed, 67 insertions(+), 28 deletions(-)
 create mode 100644 system/doc/efficiency_guide/retired_myths.xml

(limited to 'system/doc')

diff --git a/system/doc/efficiency_guide/myths.xml b/system/doc/efficiency_guide/myths.xml
index 5d3ad78b23..7e2f3c8465 100644
--- a/system/doc/efficiency_guide/myths.xml
+++ b/system/doc/efficiency_guide/myths.xml
@@ -24,7 +24,7 @@
   The Initial Developer of the Original Code is Ericsson AB.
     
 
-    The Eight Myths of Erlang Performance
+    The Six Myths of Erlang Performance
     Bjorn Gustavsson
     
     2007-11-10
@@ -35,37 +35,12 @@
   
   

Some truths seem to live on well beyond their best-before date, perhaps because "information" spreads faster from person-to-person - than a single release note that says, for example, that funs - have become faster.

+ than a single release note that says, for example, that body-recursive + calls have become faster.

This section tries to kill the old truths (or semi-truths) that have become myths.

-
- Myth: Funs are Slow -

Funs used to be very slow, slower than apply/3. - Originally, funs were implemented using nothing more than - compiler trickery, ordinary tuples, apply/3, and a great - deal of ingenuity.

- -

But that is history. Funs was given its own data type - in R6B and was further optimized in R7B. - Now the cost for a fun call falls roughly between the cost for a call - to a local function and apply/3.

-
- -
- Myth: List Comprehensions are Slow - -

List comprehensions used to be implemented using funs, and in the - old days funs were indeed slow.

- -

Nowadays, the compiler rewrites list comprehensions into an ordinary - recursive function. Using a tail-recursive function with - a reverse at the end would be still faster. Or would it? - That leads us to the next myth.

-
-
Myth: Tail-Recursive Functions are Much Faster Than Recursive Functions diff --git a/system/doc/efficiency_guide/part.xml b/system/doc/efficiency_guide/part.xml index 6e10a0c031..5673ddd320 100644 --- a/system/doc/efficiency_guide/part.xml +++ b/system/doc/efficiency_guide/part.xml @@ -39,5 +39,6 @@ + diff --git a/system/doc/efficiency_guide/retired_myths.xml b/system/doc/efficiency_guide/retired_myths.xml new file mode 100644 index 0000000000..37f46566cd --- /dev/null +++ b/system/doc/efficiency_guide/retired_myths.xml @@ -0,0 +1,63 @@ + + + + +
+ + 2016 + 2016 + Ericsson AB, All Rights Reserved + + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + The Initial Developer of the Original Code is Ericsson AB. + + + Retired Myths + Bjorn Gustavsson + + 2016-06-07 + + retired_myths.xml +
+ +

We belive that the truth finally has caught with the following, + retired myths.

+ +
+ Myth: Funs are Slow +

Funs used to be very slow, slower than apply/3. + Originally, funs were implemented using nothing more than + compiler trickery, ordinary tuples, apply/3, and a great + deal of ingenuity.

+ +

But that is history. Funs was given its own data type + in R6B and was further optimized in R7B. + Now the cost for a fun call falls roughly between the cost for a call + to a local function and apply/3.

+
+ +
+ Myth: List Comprehensions are Slow + +

List comprehensions used to be implemented using funs, and in the + old days funs were indeed slow.

+ +

Nowadays, the compiler rewrites list comprehensions into an ordinary + recursive function. Using a tail-recursive function with + a reverse at the end would be still faster. Or would it? + That leads us to the myth that tail-recursive functions are faster + than body-recursive functions.

+
+
-- cgit v1.2.3 From 1c82039a53fa0885fc8a292a841c6939e04a0da2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Gustavsson?= Date: Tue, 7 Jun 2016 16:16:26 +0200 Subject: Add a myth about NIFs Thanks to Max Lapshin for suggesting this myth. --- system/doc/efficiency_guide/myths.xml | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) (limited to 'system/doc') diff --git a/system/doc/efficiency_guide/myths.xml b/system/doc/efficiency_guide/myths.xml index 7e2f3c8465..d6cb27ddf0 100644 --- a/system/doc/efficiency_guide/myths.xml +++ b/system/doc/efficiency_guide/myths.xml @@ -24,7 +24,7 @@ The Initial Developer of the Original Code is Ericsson AB. - The Six Myths of Erlang Performance + The Seven Myths of Erlang Performance Bjorn Gustavsson 2007-11-10 @@ -175,5 +175,23 @@ vanilla_reverse([], Acc) ->

That was once true, but from R6B the BEAM compiler can see that a variable is not used.

+ +
+ Myth: A NIF Always Speeds Up Your Program + +

Rewriting Erlang code to a NIF to make it faster should be + seen as a last resort. It is only guaranteed to be dangerous, + but not guaranteed to speed up the program.

+ +

Doing too much work in each NIF call will + degrade responsiveness + of the VM. Doing too little work may mean that + the gain of the faster processing in the NIF is eaten up by + the overhead of calling the NIF and checking the arguments.

+ +

Be sure to read about + Long-running NIFs + before writing a NIF.

+
-- cgit v1.2.3 From 15da52e7c74d3a0406efdfd469a040a5a226704e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Gustavsson?= Date: Tue, 13 Dec 2016 14:02:34 +0100 Subject: Shorten the tail-recursion myth The myth about tail recursion being faster than body recursion still seems to be alive, but we don't need to spend that much space discussing it as we needed earlier. Shorten the discussion and include a link to to Fred Hebert's excellent blog post. --- system/doc/efficiency_guide/myths.xml | 54 +++++++++++------------------------ 1 file changed, 16 insertions(+), 38 deletions(-) (limited to 'system/doc') diff --git a/system/doc/efficiency_guide/myths.xml b/system/doc/efficiency_guide/myths.xml index d6cb27ddf0..168aa3d35c 100644 --- a/system/doc/efficiency_guide/myths.xml +++ b/system/doc/efficiency_guide/myths.xml @@ -46,44 +46,22 @@ Than Recursive Functions

According to the myth, - recursive functions leave references - to dead terms on the stack and the garbage collector has to copy - all those dead terms, while tail-recursive functions immediately - discard those terms.

- -

That used to be true before R7B. In R7B, the compiler started - to generate code that overwrites references to terms that will never - be used with an empty list, so that the garbage collector would not - keep dead values any longer than necessary.

- -

Even after that optimization, a tail-recursive function is - still most of the times faster than a body-recursive function. Why?

- -

It has to do with how many words of stack that are used in each - recursive call. In most cases, a recursive function uses more words - on the stack for each recursion than the number of words a tail-recursive - would allocate on the heap. As more memory is used, the garbage - collector is invoked more frequently, and it has more work traversing - the stack.

- -

In R12B and later releases, there is an optimization that - in many cases reduces the number of words used on the stack in - body-recursive calls. A body-recursive list function and a - tail-recursive function that calls lists:reverse/1 at - the end will use the same amount of memory. - lists:map/2, lists:filter/2, list comprehensions, - and many other recursive functions now use the same amount of space - as their tail-recursive equivalents.

- -

So, which is faster? - It depends. On Solaris/Sparc, the body-recursive function seems to - be slightly faster, even for lists with a lot of elements. On the x86 - architecture, tail-recursion was up to about 30% faster.

- -

So, the choice is now mostly a matter of taste. If you really do need - the utmost speed, you must measure. You can no longer be - sure that the tail-recursive list function always is the fastest.

+ using a tail-recursive function that builds a list in reverse + followed by a call to lists:reverse/1 is faster than + a body-recursive function that builds the list in correct order; + the reason being that body-recursive functions use more memory than + tail-recursive functions.

+ +

That was true to some extent before R12B. It was even more true + before R7B. Today, not so much. A body-recursive function + generally uses the same amount of memory as a tail-recursive + function. It is generally not possible to predict whether the + tail-recursive or the body-recursive version will be + faster. Therefore, use the version that makes your code cleaner + (hint: it is usually the body-recursive version).

+ +

For a more thorough discussion about tail and body recursion, + see Erlang's Tail Recursion is Not a Silver Bullet.

A tail-recursive function that does not need to reverse the list at the end is faster than a body-recursive function, -- cgit v1.2.3 From 6ecbfdcce4dc8b1c58a4f34e2edd8eaabd54793f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Gustavsson?= Date: Tue, 13 Dec 2016 14:17:03 +0100 Subject: Extend the text for "_" myth Thanks to Joe Armstrong for the suggestion. --- system/doc/efficiency_guide/myths.xml | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'system/doc') diff --git a/system/doc/efficiency_guide/myths.xml b/system/doc/efficiency_guide/myths.xml index 168aa3d35c..778cd06c09 100644 --- a/system/doc/efficiency_guide/myths.xml +++ b/system/doc/efficiency_guide/myths.xml @@ -152,6 +152,11 @@ vanilla_reverse([], Acc) ->

That was once true, but from R6B the BEAM compiler can see that a variable is not used.

+ +

Similarly, trivial transformations on the source-code level + such as converting a case statement to clauses at the + top-level of the function seldom makes any difference to the + generated code.

-- cgit v1.2.3 From 9a048a8743c3d384b5e33d6383be97dc4858126e Mon Sep 17 00:00:00 2001 From: Sverker Eriksson Date: Tue, 20 Dec 2016 14:36:25 +0100 Subject: erts: Correct memory footprint for maps Small map was wrong as we should include our own top Eterm and exclude them for keys and values. Large maps was wrong as it described the theoretical minimum of a full tree, which does not happen in reality. --- system/doc/efficiency_guide/advanced.xml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'system/doc') diff --git a/system/doc/efficiency_guide/advanced.xml b/system/doc/efficiency_guide/advanced.xml index eee2648f34..e1760d0ded 100644 --- a/system/doc/efficiency_guide/advanced.xml +++ b/system/doc/efficiency_guide/advanced.xml @@ -87,15 +87,15 @@ Small Map - 4 words + 2 words per entry (key and value) + the size of each key and value pair. + 5 words + the size of all keys and values. - Large Map + Large Map (> 32 keys) - At least, 2 words + 2 x N words + 2 x log16(N) words + - the size of each key and value pair, where N is the number of pairs in the Map. - A large Map is represented as a tree internally where each node in the tree is a - "sparse tuple" of arity 16. + N x F words + the size of all keys and values.

+ N is the number of keys in the Map.

+ F is a sparsity factor that can vary between 1.6 and 1.8 + due to the probabilistic nature of the internal HAMT data structure.
-- cgit v1.2.3 From 0264d301de02c5dd7b2a9a389294ea4a36127046 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Gustavsson?= Date: Tue, 10 Jan 2017 13:51:19 +0100 Subject: Remove paragraph mentioning improvements in R12B --- system/doc/efficiency_guide/introduction.xml | 8 -------- 1 file changed, 8 deletions(-) (limited to 'system/doc') diff --git a/system/doc/efficiency_guide/introduction.xml b/system/doc/efficiency_guide/introduction.xml index ca4a41c798..b650008ae8 100644 --- a/system/doc/efficiency_guide/introduction.xml +++ b/system/doc/efficiency_guide/introduction.xml @@ -46,14 +46,6 @@ to find out where the performance bottlenecks are and optimize only the bottlenecks. Let other code stay as clean as possible.

-

Fortunately, compiler and runtime optimizations introduced in - Erlang/OTP R12B makes it easier to write code that is both clean and - efficient. For example, the ugly workarounds needed in R11B and earlier - releases to get the most speed out of binary pattern matching are - no longer necessary. In fact, the ugly code is slower - than the clean code (because the clean code has become faster, not - because the uglier code has become slower).

-

This Efficiency Guide cannot really teach you how to write efficient code. It can give you a few pointers about what to avoid and what to use, and some understanding of how certain language features are implemented. -- cgit v1.2.3 From 184b2627f8908c8e6af033991ee831c3fb2f9f82 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Gustavsson?= Date: Tue, 10 Jan 2017 13:54:08 +0100 Subject: Don't call byte_size/1 and tuple_size/1 "new" --- system/doc/efficiency_guide/commoncaveats.xml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'system/doc') diff --git a/system/doc/efficiency_guide/commoncaveats.xml b/system/doc/efficiency_guide/commoncaveats.xml index ecfeff0349..94b1c0b222 100644 --- a/system/doc/efficiency_guide/commoncaveats.xml +++ b/system/doc/efficiency_guide/commoncaveats.xml @@ -148,10 +148,10 @@ multiple_setelement(T0) ->

size/1 returns the size for both tuples and binaries.

-

Using the new BIFs tuple_size/1 and byte_size/1, introduced - in R12B, gives the compiler and the runtime system more opportunities for - optimization. Another advantage is that the new BIFs can help Dialyzer to - find more bugs in your program.

+

Using the BIFs tuple_size/1 and byte_size/1 + gives the compiler and the runtime system more opportunities for + optimization. Another advantage is that the BIFs give Dialyzer more + type information.

-- cgit v1.2.3 From 071b8c4470cc9f0d6bee6f00e00ca325531b4a01 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Gustavsson?= Date: Tue, 10 Jan 2017 13:55:27 +0100 Subject: Don't mention "tuple funs" at all "Tuples funs" was removed a long time ago. There is no need to even mention them. --- system/doc/efficiency_guide/functions.xml | 9 --------- 1 file changed, 9 deletions(-) (limited to 'system/doc') diff --git a/system/doc/efficiency_guide/functions.xml b/system/doc/efficiency_guide/functions.xml index 4a8248e65c..1c34888bb5 100644 --- a/system/doc/efficiency_guide/functions.xml +++ b/system/doc/efficiency_guide/functions.xml @@ -183,15 +183,6 @@ explicit_map_pairs(Map, Xs0, Ys0) -> A fun contains an (indirect) pointer to the function that implements the fun.

-

Tuples are not fun(s). - A "tuple fun", {Module,Function}, is not a fun. - The cost for calling a "tuple fun" is similar to that - of apply/3 or worse. - Using "tuple funs" is strongly discouraged, - as they might not be supported in a future Erlang/OTP release, - and because there exists a superior alternative from R10B, - namely the fun Module:Function/Arity syntax.

-

apply/3 must look up the code for the function to execute in a hash table. It is therefore always slower than a direct call or a fun call.

-- cgit v1.2.3 From 953f57e3a86f3b714a634177e32f630b56a05240 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Gustavsson?= Date: Tue, 10 Jan 2017 14:29:08 +0100 Subject: Remove comparisons of binary handling between R11B and R12B Shorten the text by removing superfluous details about how binary handling was different in R11B. --- system/doc/efficiency_guide/binaryhandling.xml | 81 +++++++++----------------- 1 file changed, 26 insertions(+), 55 deletions(-) (limited to 'system/doc') diff --git a/system/doc/efficiency_guide/binaryhandling.xml b/system/doc/efficiency_guide/binaryhandling.xml index 0295d18644..91fd9a7cd9 100644 --- a/system/doc/efficiency_guide/binaryhandling.xml +++ b/system/doc/efficiency_guide/binaryhandling.xml @@ -32,12 +32,9 @@ binaryhandling.xml -

In R12B, the most natural way to construct and match binaries is - significantly faster than in earlier releases.

+

Binaries can be efficiently built in the following way:

-

To construct a binary, you can simply write as follows:

- -

DO (in R12B) / REALLY DO NOT (in earlier releases)

+

DO

my_list_to_binary(List, <<>>). @@ -47,21 +44,13 @@ my_list_to_binary([H|T], Acc) -> my_list_to_binary([], Acc) -> Acc.]]> -

In releases before R12B, Acc is copied in every iteration. - In R12B, Acc is copied only in the first iteration and extra - space is allocated at the end of the copied binary. In the next iteration, - H is written into the extra space. When the extra space runs out, - the binary is reallocated with more extra space. The extra space allocated - (or reallocated) is twice the size of the - existing binary data, or 256, whichever is larger.

- -

The most natural way to match binaries is now the fastest:

+

Binaries can be efficiently matched like this:

-

DO (in R12B)

+

DO

>) -> [H|my_binary_to_list(T)]; -my_binary_to_list(<<>>) -> [].]]> +my_binary_to_list(<<>>) -> [].]]>
How Binaries are Implemented @@ -138,10 +127,7 @@ my_binary_to_list(<<>>) -> [].]]> pointer to the binary data. For each field that is matched out of a binary, the position in the match context is incremented.

-

In R11B, a match context was only used during a binary matching - operation.

- -

In R12B, the compiler tries to avoid generating code that +

The compiler tries to avoid generating code that creates a sub binary, only to shortly afterwards create a new match context and discard the sub binary. Instead of creating a sub binary, the match context is kept.

@@ -155,7 +141,7 @@ my_binary_to_list(<<>>) -> [].]]>
Constructing Binaries -

In R12B, appending to a binary or bitstring +

Appending to a binary or bitstring is specially optimized by the runtime system:

> %% Bin1 will be COPIED

Let us revisit the example in the beginning of the previous section:

-

DO (in R12B)

+

DO

>) -> [H|my_binary_to_list(T)]; @@ -304,15 +290,14 @@ my_binary_to_list(<<>>) -> [].]]> byte of the binary. 1 byte is matched out and the match context is updated to point to the second byte in the binary.

-

In R11B, at this point a - sub binary - would be created. In R12B, - the compiler sees that there is no point in creating a sub binary, - because there will soon be a call to a function (in this case, +

At this point it would make sense to create a + sub binary, + but in this particular example the compiler sees that + there will soon be a call to a function (in this case, to my_binary_to_list/1 itself) that immediately will create a new match context and discard the sub binary.

-

Therefore, in R12B, my_binary_to_list/1 calls itself +

Therefore my_binary_to_list/1 calls itself with the match context instead of with a sub binary. The instruction that initializes the matching operation basically does nothing when it sees that it was passed a match context instead of a binary.

@@ -321,34 +306,10 @@ my_binary_to_list(<<>>) -> [].]]>
the match context will simply be discarded (removed in the next garbage collection, as there is no longer any reference to it).

-

To summarize, my_binary_to_list/1 in R12B only needs to create - one match context and no sub binaries. In R11B, if the binary - contains N bytes, N+1 match contexts and N - sub binaries are created.

- -

In R11B, the fastest way to match binaries is as follows:

+

To summarize, my_binary_to_list/1 only needs to create + one match context and no sub binaries.

-

DO NOT (in R12B)

- - my_complicated_binary_to_list(Bin, 0). - -my_complicated_binary_to_list(Bin, Skip) -> - case Bin of - <<_:Skip/binary,Byte,_/binary>> -> - [Byte|my_complicated_binary_to_list(Bin, Skip+1)]; - <<_:Skip/binary>> -> - [] - end.]]> - -

This function cleverly avoids building sub binaries, but it cannot - avoid building a match context in each recursion step. - Therefore, in both R11B and R12B, - my_complicated_binary_to_list/1 builds N+1 match - contexts. (In a future Erlang/OTP release, the compiler might be able - to generate code that reuses the match context.)

- -

Returning to my_binary_to_list/1, notice that the match context +

Notice that the match context in my_binary_to_list/1 was discarded when the entire binary had been traversed. What happens if the iteration stops before it has reached the end of the binary? Will the optimization still work?

@@ -544,5 +505,15 @@ count3(<<>>, Count) -> Count.]]> not matched out.

+ +
+ Historical Note + +

Binary handling was significantly improved in R12B. Because + code that was efficient in R11B might not be efficient in R12B, + and vice versa, earlier revisions of this Efficiency Guide contained + some information about binary handling in R11B.

+
+ -- cgit v1.2.3 From fa04f8212d282ea1535c07683660de1a23565b0f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Gustavsson?= Date: Tue, 10 Jan 2017 14:44:00 +0100 Subject: Modernize section about list handling and list comprehensions --- system/doc/efficiency_guide/listhandling.xml | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) (limited to 'system/doc') diff --git a/system/doc/efficiency_guide/listhandling.xml b/system/doc/efficiency_guide/listhandling.xml index 2ebc877820..ec258d7c2a 100644 --- a/system/doc/efficiency_guide/listhandling.xml +++ b/system/doc/efficiency_guide/listhandling.xml @@ -90,7 +90,7 @@ tail_recursive_fib(N, Current, Next, Fibs) ->

Lists comprehensions still have a reputation for being slow. They used to be implemented using funs, which used to be slow.

-

In recent Erlang/OTP releases (including R12B), a list comprehension:

+

A list comprehension:

@@ -102,7 +102,7 @@ tail_recursive_fib(N, Current, Next, Fibs) -> [Expr(E)|'lc^0'(Tail, Expr)]; 'lc^0'([], _Expr) -> []. -

In R12B, if the result of the list comprehension will obviously +

If the result of the list comprehension will obviously not be used, a list will not be constructed. For example, in this code:

[]. +

The compiler also understands that assigning to '_' means that + the value will not used. Therefore, the code in the following example + will also be optimized:

+ + +
@@ -209,11 +217,11 @@ some_function(...),
Recursive List Functions -

In Section 7.2, the following myth was exposed: +

In section about myths, the following myth was exposed: Tail-Recursive Functions are Much Faster Than Recursive Functions.

-

To summarize, in R12B there is usually not much difference between +

There is usually not much difference between a body-recursive list function and tail-recursive function that reverses the list at the end. Therefore, concentrate on writing beautiful code and forget about the performance of your list functions. In the -- cgit v1.2.3 From 9595a90fd301e2049b822c8a4d712b5033a3e9d0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Gustavsson?= Date: Tue, 10 Jan 2017 14:48:26 +0100 Subject: Fix a typo in functions.xml --- system/doc/efficiency_guide/functions.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'system/doc') diff --git a/system/doc/efficiency_guide/functions.xml b/system/doc/efficiency_guide/functions.xml index 1c34888bb5..1d0f1f68b7 100644 --- a/system/doc/efficiency_guide/functions.xml +++ b/system/doc/efficiency_guide/functions.xml @@ -65,7 +65,7 @@ atom_map1(six) -> 6. thus, quite efficient even if there are many values) to select which one of the first three clauses to execute (if any). - >If none of the first three clauses match, the fourth clause + If none of the first three clauses match, the fourth clause match as a variable always matches. If the guard test is_integer(Int) succeeds, the fourth -- cgit v1.2.3 From 947169af61bdd67d34fabd47a56be04e8468120d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Gustavsson?= Date: Tue, 10 Jan 2017 14:53:03 +0100 Subject: Remove mention of R12B Also don't say that there are no plans to make sharing-preserving copying default; it has been seriously suggested. --- system/doc/efficiency_guide/processes.xml | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) (limited to 'system/doc') diff --git a/system/doc/efficiency_guide/processes.xml b/system/doc/efficiency_guide/processes.xml index f2d9712f51..bc9daa6666 100644 --- a/system/doc/efficiency_guide/processes.xml +++ b/system/doc/efficiency_guide/processes.xml @@ -146,14 +146,14 @@ loop() ->

Constant Pool -

Constant Erlang terms (also called literals) are now +

Constant Erlang terms (also called literals) are kept in constant pools; each loaded module has its own pool. - The following function does no longer build the tuple every time + The following function does not build the tuple every time it is called (only to have it discarded the next time the garbage collector was run), but the tuple is located in the module's constant pool:

-

DO (in R12B and later)

+

DO

days_in_month(M) -> element(M, {31,28,31,30,31,30,31,31,30,31,30,31}). @@ -235,9 +235,7 @@ true return the same value. Sharing has been lost.

In a future Erlang/OTP release, it might be implemented a - way to (optionally) preserve sharing. There are no plans to make - preserving of sharing the default behaviour, as that would - penalize the vast majority of Erlang applications.

+ way to (optionally) preserve sharing.

-- cgit v1.2.3 From 05ecb863d08ab49176cd9c1159a5b5dbebcb23ae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Gustavsson?= Date: Wed, 11 Jan 2017 14:46:54 +0100 Subject: Say that features after R13A are mentioned in the text The text mentions any changes that occurred in R7A and later. Change that to only mention changes that occurred after R12B. --- system/doc/reference_manual/introduction.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'system/doc') diff --git a/system/doc/reference_manual/introduction.xml b/system/doc/reference_manual/introduction.xml index abb4ed407d..5701462443 100644 --- a/system/doc/reference_manual/introduction.xml +++ b/system/doc/reference_manual/introduction.xml @@ -80,8 +80,8 @@ A list is any number of items. For example, an argument list can consist of zero, one, or more arguments. -

If a feature has been added recently, in Erlang 5.0/OTP R7 or - later, this is mentioned in the text.

+

If a feature has been added in R13A or later, + this is mentioned in the text.

-- cgit v1.2.3 From 19034aa8c9e9c1b24b91f4e1a73b9b09ffe1c92c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Gustavsson?= Date: Wed, 11 Jan 2017 14:38:12 +0100 Subject: data_types.xml: Remove superfluous reference to R9B --- system/doc/reference_manual/data_types.xml | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) (limited to 'system/doc') diff --git a/system/doc/reference_manual/data_types.xml b/system/doc/reference_manual/data_types.xml index e63825b97d..107e403903 100644 --- a/system/doc/reference_manual/data_types.xml +++ b/system/doc/reference_manual/data_types.xml @@ -50,10 +50,7 @@ base#value

Integer with the base base, that must be an - integer in the range 2..36.

- - In Erlang 5.2/OTP R9B and earlier versions, the allowed range - is 2..16.
+ integer in the range 2..36.

Examples:

-- 
cgit v1.2.3


From aff9b4210d0bbc151a1611e260417b0d76ee4a8d Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Bj=C3=B6rn=20Gustavsson?= 
Date: Wed, 11 Jan 2017 14:41:34 +0100
Subject: errors.xml: Remove superfluous references to R10B

---
 system/doc/reference_manual/errors.xml | 8 +++-----
 1 file changed, 3 insertions(+), 5 deletions(-)

(limited to 'system/doc')

diff --git a/system/doc/reference_manual/errors.xml b/system/doc/reference_manual/errors.xml
index e764cf431f..3e2d306561 100644
--- a/system/doc/reference_manual/errors.xml
+++ b/system/doc/reference_manual/errors.xml
@@ -49,8 +49,7 @@
       The Erlang programming language has built-in features for
       handling of run-time errors.

A run-time error can also be emulated by calling - erlang:error(Reason) or erlang:error(Reason, Args) - (those appeared in Erlang 5.4/OTP-R10).

+ erlang:error(Reason) or erlang:error(Reason, Args).

A run-time error is another name for an exception of class error.

@@ -79,7 +78,6 @@

Exceptions are run-time errors or generated errors and are of three different classes, with different origins. The try expression - (new in Erlang 5.4/OTP R10B) can distinguish between the different classes, whereas the catch expression cannot. They are described in @@ -94,7 +92,7 @@ error Run-time error, for example, 1+a, or the process called - erlang:error/1,2 (new in Erlang 5.4/OTP R10B) + erlang:error/1,2 exit @@ -111,7 +109,7 @@ and a stack trace (which aids in finding the code location of the exception).

The stack trace can be retrieved using - erlang:get_stacktrace/0 (new in Erlang 5.4/OTP R10B) + erlang:get_stacktrace/0 from within a try expression, and is returned for exceptions of class error from a catch expression.

An exception of class error is also known as a run-time -- cgit v1.2.3 From 14de54495030e746b475afa13aead9e86d8bc3ec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Gustavsson?= Date: Wed, 11 Jan 2017 14:44:57 +0100 Subject: expressions.xml: Remove superfluous references to OTP R7/R10 --- system/doc/reference_manual/expressions.xml | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) (limited to 'system/doc') diff --git a/system/doc/reference_manual/expressions.xml b/system/doc/reference_manual/expressions.xml index 1a3d19aed1..acd1dec901 100644 --- a/system/doc/reference_manual/expressions.xml +++ b/system/doc/reference_manual/expressions.xml @@ -123,10 +123,9 @@ member(_Elem, []) -> or receive expression must be bound in all branches to have a value outside the expression. Otherwise they are regarded as 'unsafe' outside the expression.

-

For the try expression introduced in - Erlang 5.4/OTP R10B, variable scoping is limited so that +

For the try expression variable scoping is limited so that variables bound in the expression are always 'unsafe' outside - the expression. This is to be improved.

+ the expression.

@@ -189,7 +188,6 @@ f([$p,$r,$e,$f,$i,$x | Str]) -> ...
 case {Value, Result} of
     {?THRESHOLD+1, ok} -> ...
-

This feature was added in Erlang 5.0/OTP R7.

@@ -1348,8 +1346,8 @@ catch ExceptionBodyN end

This is an enhancement of - catch that appeared in - Erlang 5.4/OTP R10B. It gives the possibility to:

+ catch. + It gives the possibility to:

Distinguish between different exception classes. Choose to handle only the desired ones. -- cgit v1.2.3 From ed3307e38a22c7dc02057b75c8dbc12410c11ea4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Gustavsson?= Date: Wed, 11 Jan 2017 14:50:47 +0100 Subject: macros.xml: Remove a reference to OTP R7 --- system/doc/reference_manual/macros.xml | 1 - 1 file changed, 1 deletion(-) (limited to 'system/doc') diff --git a/system/doc/reference_manual/macros.xml b/system/doc/reference_manual/macros.xml index 5f24473557..b6c740dd10 100644 --- a/system/doc/reference_manual/macros.xml +++ b/system/doc/reference_manual/macros.xml @@ -286,7 +286,6 @@ t.erl:5: Warning: -warning("Macro VERSION not defined -- using default version." argument, is expanded to a string containing the tokens of the argument. This is similar to the #arg stringifying construction in C.

-

The feature was added in Erlang 5.0/OTP R7.

Example:

-define(TESTCALL(Call), io:format("Call ~s: ~w~n", [??Call, Call])). -- cgit v1.2.3 From 33fe60df7c1661d0a2af979351ae8f3c8a9e5494 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Gustavsson?= Date: Wed, 11 Jan 2017 14:52:22 +0100 Subject: records.xml: Remove a superfluous reference to OTP R8 --- system/doc/reference_manual/records.xml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'system/doc') diff --git a/system/doc/reference_manual/records.xml b/system/doc/reference_manual/records.xml index 12a3e697cd..1eb13b353e 100644 --- a/system/doc/reference_manual/records.xml +++ b/system/doc/reference_manual/records.xml @@ -72,9 +72,9 @@
 #Name{Field1=Expr1,...,FieldK=ExprK, _=ExprL}

Omitted fields then get the value of evaluating ExprL - instead of their default values. This feature was added in - Erlang 5.1/OTP R8 and is primarily intended to be used to create - patterns for ETS and Mnesia match functions.

+ instead of their default values. This feature is primarily + intended to be used to create patterns for ETS and Mnesia match + functions.

Example:

 -record(person, {name, phone, address}).
-- 
cgit v1.2.3


From d917e51b6a53b44bcb45a8ede9eecd39042c6627 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Bj=C3=B6rn=20Gustavsson?= 
Date: Wed, 11 Jan 2017 14:54:21 +0100
Subject: character_set.xml: Remove a superfluous reference to OTP R5

---
 system/doc/reference_manual/character_set.xml | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

(limited to 'system/doc')

diff --git a/system/doc/reference_manual/character_set.xml b/system/doc/reference_manual/character_set.xml
index d25f2c001d..f0f4c23608 100644
--- a/system/doc/reference_manual/character_set.xml
+++ b/system/doc/reference_manual/character_set.xml
@@ -32,9 +32,9 @@
 
   
Character Set -

Since Erlang 4.8/OTP R5A, the syntax of Erlang tokens is extended to - allow the use of the full ISO-8859-1 (Latin-1) character set. This - is noticeable in the following ways:

+

The syntax of Erlang tokens allow the use of the full + ISO-8859-1 (Latin-1) character set. This is noticeable in the + following ways:

All the Latin-1 printable characters can be used and are -- cgit v1.2.3 From 6912c3db95b4ca0d78b5c388daae262321645624 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn-Egil=20Dahlberg?= Date: Fri, 20 Jan 2017 14:12:18 +0100 Subject: otp: Don't mention percept in documentation --- system/doc/efficiency_guide/processes.xml | 4 ---- 1 file changed, 4 deletions(-) (limited to 'system/doc') diff --git a/system/doc/efficiency_guide/processes.xml b/system/doc/efficiency_guide/processes.xml index f2d9712f51..b9982353be 100644 --- a/system/doc/efficiency_guide/processes.xml +++ b/system/doc/efficiency_guide/processes.xml @@ -261,10 +261,6 @@ true The estone benchmark, for example, is entirely sequential. So is the most common implementation of the "ring benchmark"; usually one process is active, while the others wait in a receive statement.

- -

The percept application - can be used to profile your application to see how much potential (or lack - thereof) it has for concurrency.

-- cgit v1.2.3 From 1bcacc64d5f33d674fa50c85ed9a982ade380bd5 Mon Sep 17 00:00:00 2001 From: Richard Carlsson Date: Fri, 16 Dec 2016 11:40:38 +0100 Subject: Add design principles restart intensity howto --- system/doc/design_principles/sup_princ.xml | 63 ++++++++++++++++++++++++++++++ 1 file changed, 63 insertions(+) (limited to 'system/doc') diff --git a/system/doc/design_principles/sup_princ.xml b/system/doc/design_principles/sup_princ.xml index c24177d842..478d1bf714 100644 --- a/system/doc/design_principles/sup_princ.xml +++ b/system/doc/design_principles/sup_princ.xml @@ -175,6 +175,69 @@ SupFlags = #{intensity => MaxR, period => MaxT, ...}

The keys intensity and period are optional in the supervisor flags map. If they are not given, they default to 1 and 5, respectively.

+
+ Tuning the intensity and period +

The default values are 1 restart per 5 seconds. This was chosen to + be safe for most systems, even with deep supervision hierarchies, + but you will probably want to tune the settings for your particular + use case.

+

First, the intensity decides how big bursts of restarts you want + to tolerate. For example, you might want to accept a burst of at + most 5 or 10 attempts, even within the same second, if it results + in a successful restart.

+

Second, you need to consider the sustained failure rate, if + crashes keep happening but not often enough to make the supervisor + give up. If you set intensity to 10 and set the period as low as 1, + the supervisor will allow child processes to keep restarting up to + 10 times per second, forever, filling your logs with crash reports + until someone intervenes manually.

+

You should therefore set the period to be long enough that you can + accept that the supervisor keeps going at that rate. For example, + if you have picked an intensity value of 5, then setting the period + to 30 seconds will give you at most one restart per 6 seconds for + any longer period of time, which means that your logs won't fill up + too quickly, and you will have a chance to observe the failures and + apply a fix.

+

These choices depend a lot on your problem domain. If you don't + have real time monitoring and ability to fix problems quickly, for + example in an embedded system, you might want to accept at most + one restart per minute before the supervisor should give up and + escalate to the next level to try to clear the error automatically. + On the other hand, if it is more important that you keep trying + even at a high failure rate, you might want a sustained rate of as + much as 1-2 restarts per second.

+

Avoiding common mistakes: + + +

Do not forget to consider the burst rate. If you set intensity + to 1 and period to 6, it gives the same sustained error rate as + 5/30 or 10/60, but will not allow even 2 restart attempts in + quick succession. This is probably not what you wanted.

+ + +

Do not set the period to a very high value if you want to + tolerate bursts. If you set intensity to 5 and period to 3600 + (one hour), the supervisor will allow a short burst of 5 + restarts, but then gives up if it sees another single restart + almost an hour later. You probably want to regard those crashes + as separate incidents, so setting the period to 5 or 10 minutes + will be more reasonable.

+
+ +

If your application has multiple levels of supervision, then + do not simply set the restart intensities to the same values on + all levels. Keep in mind that the total number of restarts + (before the top level supervisor gives up and terminates the + application) will be the product of the intensity values of all + the supervisors above the failing child process.

+

For example, if the top level allows 10 restarts, and the next + level also allows 10, a crashing child below that level will be + restarted 100 times, which is probably excessive. Allowing at + most 3 restarts for the top level supervisor might be a better + choice in this case.

+
+

+
-- cgit v1.2.3 From 85e9fed232a6d89e3659cabbb2169cf3e21127e3 Mon Sep 17 00:00:00 2001 From: Raimo Niskanen Date: Tue, 24 Jan 2017 14:15:26 +0100 Subject: Implement repeat_state and repeat_state_and_data --- system/doc/design_principles/statem.xml | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'system/doc') diff --git a/system/doc/design_principles/statem.xml b/system/doc/design_principles/statem.xml index f627145f9f..8e7f496d9e 100644 --- a/system/doc/design_principles/statem.xml +++ b/system/doc/design_principles/statem.xml @@ -1180,6 +1180,17 @@ open(state_timeout, lock, Data) -> {next_state, locked, Data}; ... ]]> +

+ You can repeat the state entry code by returning one of + {repeat_state, ...}, {repeat_state_and_data,_} + or repeat_state_and_data that otherwise behaves + exactly like their keep_state siblings. + See the type + + state_callback_result() + + in the reference manual. +

-- cgit v1.2.3 From bbc16d5c48cb8657214a270f899cb37834d7d744 Mon Sep 17 00:00:00 2001 From: Kim Shrier Date: Wed, 1 Feb 2017 23:07:23 -0700 Subject: fix a few statem typos --- system/doc/design_principles/statem.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'system/doc') diff --git a/system/doc/design_principles/statem.xml b/system/doc/design_principles/statem.xml index f627145f9f..d08ddd0036 100644 --- a/system/doc/design_principles/statem.xml +++ b/system/doc/design_principles/statem.xml @@ -130,7 +130,7 @@ handle_event(EventType, EventContent, State, Data) -> {next_state, NewState, NewData}

- Se section + See section One Event Handler for an example.

@@ -887,7 +887,7 @@ stop() ->

This type of time-out is useful to for example act on inactivity. - Let us start restart the code sequence + Let us restart the code sequence if no button is pressed for say 30 seconds:

Date: Tue, 14 Feb 2017 11:30:58 +0200 Subject: Fixed typos in system/doc --- system/doc/efficiency_guide/bench.erl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'system/doc') diff --git a/system/doc/efficiency_guide/bench.erl b/system/doc/efficiency_guide/bench.erl index 1f60e858f6..a1be24b051 100644 --- a/system/doc/efficiency_guide/bench.erl +++ b/system/doc/efficiency_guide/bench.erl @@ -355,7 +355,7 @@ create_html_report(ResultList) -> {ok, OutputFile} = file:open("index.html", [write]), - %% Create the begining of the result html-file. + %% Create the beginning of the result html-file. Head = Title = "Benchmark Results", io:put_chars(OutputFile, "\n"), io:put_chars(OutputFile, "\n"), -- cgit v1.2.3 From 8bbee751000b6a43b4817e81157903e816a4cb3c Mon Sep 17 00:00:00 2001 From: Stephan Renatus Date: Mon, 20 Feb 2017 09:00:21 +0100 Subject: Documentation: fix link to erlang(3) man page I don't see why this should point to process_flag/2. Let's make it not do that. --- system/doc/reference_manual/introduction.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'system/doc') diff --git a/system/doc/reference_manual/introduction.xml b/system/doc/reference_manual/introduction.xml index 5701462443..c9ce45bbcc 100644 --- a/system/doc/reference_manual/introduction.xml +++ b/system/doc/reference_manual/introduction.xml @@ -87,7 +87,7 @@
Complete List of BIFs

For a complete list of BIFs, their arguments and return values, - see erlang(3) + see erlang(3) manual page in ERTS.

-- cgit v1.2.3 From 9ad1fd887b0f5989933b5ad82fbb1acbce72e4b5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Gustavsson?= Date: Fri, 10 Mar 2017 14:28:22 +0100 Subject: retired_myths.xml: Move marker to adhere to DTD --- system/doc/efficiency_guide/retired_myths.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'system/doc') diff --git a/system/doc/efficiency_guide/retired_myths.xml b/system/doc/efficiency_guide/retired_myths.xml index 37f46566cd..7c6a1262c7 100644 --- a/system/doc/efficiency_guide/retired_myths.xml +++ b/system/doc/efficiency_guide/retired_myths.xml @@ -23,7 +23,6 @@ The Initial Developer of the Original Code is Ericsson AB. - Retired Myths Bjorn Gustavsson @@ -36,6 +35,7 @@ retired myths.

+ Myth: Funs are Slow

Funs used to be very slow, slower than apply/3. Originally, funs were implemented using nothing more than -- cgit v1.2.3 From 26c3cd82529836cb5b6eefbf7f92f318fd91f847 Mon Sep 17 00:00:00 2001 From: Rickard Green Date: Fri, 10 Mar 2017 15:00:46 +0100 Subject: Update copyright year --- system/doc/design_principles/statem.xml | 2 +- system/doc/tutorial/c_portdriver.xmlsrc | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'system/doc') diff --git a/system/doc/design_principles/statem.xml b/system/doc/design_principles/statem.xml index f4d84ab163..22b622ec5f 100644 --- a/system/doc/design_principles/statem.xml +++ b/system/doc/design_principles/statem.xml @@ -4,7 +4,7 @@

- 2016 + 20162017 Ericsson AB. All Rights Reserved. diff --git a/system/doc/tutorial/c_portdriver.xmlsrc b/system/doc/tutorial/c_portdriver.xmlsrc index da680642b6..c4cf6daa3b 100644 --- a/system/doc/tutorial/c_portdriver.xmlsrc +++ b/system/doc/tutorial/c_portdriver.xmlsrc @@ -4,7 +4,7 @@
- 20002015 + 20002017 Ericsson AB. All Rights Reserved. -- cgit v1.2.3 From 45bda44b08d01c0835b7402b752b9c7b07a4b77c Mon Sep 17 00:00:00 2001 From: Mariano Guerra Date: Fri, 21 Oct 2016 13:40:58 +0100 Subject: center erlang logo on left panel --- system/doc/top/templates/index.html.src | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'system/doc') diff --git a/system/doc/top/templates/index.html.src b/system/doc/top/templates/index.html.src index d2a6736d34..967c33719d 100644 --- a/system/doc/top/templates/index.html.src +++ b/system/doc/top/templates/index.html.src @@ -29,14 +29,14 @@ limitations under the License. - +
-Erlang logo -

+

+ +
Applications
Modules

-- cgit v1.2.3 From 802900e22708ff5258d1a3619e4241ef09a159e6 Mon Sep 17 00:00:00 2001 From: Mariano Guerra Date: Fri, 21 Oct 2016 13:46:46 +0100 Subject: improve docs landing page title and subtitle --- system/doc/top/templates/index.html.src | 22 ++++------------------ 1 file changed, 4 insertions(+), 18 deletions(-) (limited to 'system/doc') diff --git a/system/doc/top/templates/index.html.src b/system/doc/top/templates/index.html.src index 967c33719d..e7b9d8ac6d 100644 --- a/system/doc/top/templates/index.html.src +++ b/system/doc/top/templates/index.html.src @@ -73,24 +73,10 @@ limitations under the License.

-
-Erlang/OTP #otp_base_vsn#
-
-
-

-Welcome to Erlang/OTP, a complete
-development environment
-for concurrent programming.
-

-
-
-
-
-

- -Some hints that may get you started faster - -

+

Erlang/OTP #otp_base_vsn#

+

Welcome to Erlang/OTP, a complete development environment for concurrent programming.

+ +

Some hints that may get you started faster

    -- cgit v1.2.3 From 140adf0584f2ff5e0853b5dc763dc8082afb7750 Mon Sep 17 00:00:00 2001 From: Mariano Guerra Date: Fri, 21 Oct 2016 14:38:25 +0100 Subject: use title tags on titles --- system/doc/top/templates/index.html.src | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'system/doc') diff --git a/system/doc/top/templates/index.html.src b/system/doc/top/templates/index.html.src index e7b9d8ac6d..951b3a79fe 100644 --- a/system/doc/top/templates/index.html.src +++ b/system/doc/top/templates/index.html.src @@ -60,8 +60,7 @@ limitations under the License.
-Application Groups -
+

Application Groups

    #applinks# -- cgit v1.2.3 From 6be6bb8a81d875ddb7cbe5c19766d7050236589b Mon Sep 17 00:00:00 2001 From: Mariano Guerra Date: Fri, 21 Oct 2016 14:39:33 +0100 Subject: use list on list of links --- system/doc/top/templates/index.html.src | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) (limited to 'system/doc') diff --git a/system/doc/top/templates/index.html.src b/system/doc/top/templates/index.html.src index 951b3a79fe..bfc0ba9f51 100644 --- a/system/doc/top/templates/index.html.src +++ b/system/doc/top/templates/index.html.src @@ -37,12 +37,16 @@ limitations under the License.
    -Applications
    -Modules
    -

    -Expand All
    -Contract All -

    + +

    + +
    • System Documentation -- cgit v1.2.3 From b234f1de2c8eaba384b30014f01cfc8d58b096bd Mon Sep 17 00:00:00 2001 From: Mariano Guerra Date: Fri, 21 Oct 2016 16:42:40 +0100 Subject: improve left panel section info and menu --- system/doc/top/templates/index.html.src | 29 ++++++++++++++++------------- 1 file changed, 16 insertions(+), 13 deletions(-) (limited to 'system/doc') diff --git a/system/doc/top/templates/index.html.src b/system/doc/top/templates/index.html.src index bfc0ba9f51..b7fff0993d 100644 --- a/system/doc/top/templates/index.html.src +++ b/system/doc/top/templates/index.html.src @@ -34,19 +34,19 @@ limitations under the License.
      -
      - -
      +
      + +
      - + - +
      • System Documentation @@ -64,6 +64,7 @@ limitations under the License.
    +

    Application Groups

      @@ -77,8 +78,10 @@ limitations under the License.

      Erlang/OTP #otp_base_vsn#

      -

      Welcome to Erlang/OTP, a complete development environment for concurrent programming.

      - +

      + Welcome to Erlang/OTP, a complete development environment for concurrent programming. +

      +

      Some hints that may get you started faster

        -- cgit v1.2.3 From c46da866eb1a6396ae1d670436dd6d87b4b8e442 Mon Sep 17 00:00:00 2001 From: Mariano Guerra Date: Fri, 21 Oct 2016 16:44:28 +0100 Subject: improve applications and modules list styles --- system/doc/top/src/erl_html_tools.erl | 47 +++++--------------- system/doc/top/src/otp_man_index.erl | 61 +++++++++++++------------- system/doc/top/templates/applications.html.src | 54 ++++++++++++++++------- 3 files changed, 78 insertions(+), 84 deletions(-) (limited to 'system/doc') diff --git a/system/doc/top/src/erl_html_tools.erl b/system/doc/top/src/erl_html_tools.erl index d55c2e1164..28a0649658 100644 --- a/system/doc/top/src/erl_html_tools.erl +++ b/system/doc/top/src/erl_html_tools.erl @@ -387,9 +387,7 @@ subst("#copyright#", _Info, _Group) -> "copyright Copyright © 1991-2004"; subst("#groups#", Info, _Group) -> [ - "\n", - subst_groups(Info), - "
        \n" + subst_groups(Info) ]; subst("#applinks#", Info, Group) -> subst_applinks(Info, Group); @@ -476,16 +474,10 @@ subst_unknown_groups([{_Group,Heading,Apps} | Groups], Text0, Left) -> group_table(Heading,Apps) -> - [ - " \n", - " \n", - " ",Heading,"\n", - " \n", - " \n", + ["

        ",Heading,"

        ", + "\n", subst_apps(Apps), - " \n", - " \n", - " \n" + "
         
        \n" ]. % Count and split the applications in half to get the right sort @@ -500,17 +492,11 @@ subst_apps([]) -> subst_app(App, [{VSN,_Path,Link,Text}]) -> [ " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
        \n", + " \n", " ",uc(App),"\n", " ",VSN,"\n", - "
        \n" " \n", - " \n", + " \n", Text,"\n", " \n", " \n" @@ -518,27 +504,14 @@ subst_app(App, [{VSN,_Path,Link,Text}]) -> subst_app(App, [{VSN,_Path,Link,Text} | VerInfos]) -> [ " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
        \n", + " \n", " ",uc(App), - "  
        \n", + "\n", " ",VSN,"\n", - "
        \n", - " \n", - " \n", - " \n", - " \n", - "
        \n", + " \n", subst_vsn(VerInfos), - "
        \n" - "
        \n" " \n", - " \n", + " \n", Text,"\n", " \n", " \n" diff --git a/system/doc/top/src/otp_man_index.erl b/system/doc/top/src/otp_man_index.erl index 12aaba1423..655d7265f7 100644 --- a/system/doc/top/src/otp_man_index.erl +++ b/system/doc/top/src/otp_man_index.erl @@ -154,10 +154,10 @@ gen_html(RefPages, OutFile)-> SortedPages = lists:sort(RefPages), lists:foreach(fun({_,Module, App, AppDocDir, RefPagePath}) -> - io:fwrite(Out, " \n",[]), - io:fwrite(Out, " ~s\n", + io:fwrite(Out, " \n",[]), + io:fwrite(Out, " ~s\n", [RefPagePath, Module]), - io:fwrite(Out, " ~s\n", + io:fwrite(Out, " ~s\n", [filename:join(AppDocDir, "index.html"), App]), io:fwrite(Out, " \n",[]) @@ -175,41 +175,40 @@ gen_html(RefPages, OutFile)-> html_header() -> "\n" "\n" - "\n" - "\n" + "\n" + "\n" " \n" - " Erlang/OTP Manual Page Index\n" - "\n" - "\n" - "
        \n" + " Erlang/OTP Manual Page Index\n" + "\n" + "\n" + "
        \n" "\n" - "\n" - "[Up | Erlang]\n" - "
        \n" - "

        OTP Reference Page Index
        \n" - "

        \n" - "
        \n" - "

        \n" - "\n" - "\n" - " \n" - "\n". + "
        \n" + "\n" + "[ Up | Homepage ]\n" + "
        \n" + "

        OTP Reference Page Index

        \n" + "\n" + "
        \n" + "
        Manual PageApplication
        \n" + "\n" + " \n" + "\n". html_footer(Year) -> - "
        Manual PageApplication
        \n" - "

        \n" - "

        \n" - "

        \n" - "
        \n" - "\n" + "\n" + "
        \n" + "

        \n" + "

        \n" + "
        \n" + "\n" "Copyright © 1991-" ++ Year ++ "\n" "\n" "Ericsson AB\n" - "\n" - "
        \n" - "\n" - "\n". + "
        \n" + "
        \n" + "\n" + "\n". diff --git a/system/doc/top/templates/applications.html.src b/system/doc/top/templates/applications.html.src index 1f73c44d69..001234ad32 100644 --- a/system/doc/top/templates/applications.html.src +++ b/system/doc/top/templates/applications.html.src @@ -24,31 +24,53 @@ limitations under the License. Erlang/OTP #version# Applications - -
        + +

        Erlang/OTP Applications

        #groups# -
        -- cgit v1.2.3 From 706ad2d5735ee7b17a60251822cdf34d2b5ede8c Mon Sep 17 00:00:00 2001 From: Mariano Guerra Date: Sat, 22 Oct 2016 22:51:10 +0100 Subject: applications font-family matches docs --- system/doc/top/templates/applications.html.src | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'system/doc') diff --git a/system/doc/top/templates/applications.html.src b/system/doc/top/templates/applications.html.src index 001234ad32..7e939ddcd6 100644 --- a/system/doc/top/templates/applications.html.src +++ b/system/doc/top/templates/applications.html.src @@ -26,7 +26,7 @@ limitations under the License.
        - - Erlang Timers + + Generic Time-Outs

        The previous example of state time-outs only work if the state machine stays in the same state during the @@ -934,13 +950,68 @@ locked( You may want to start a timer in one state and respond to the time-out in another, maybe cancel the time-out without changing states, or perhaps run multiple - time-outs in parallel. All this can be accomplished - with Erlang Timers: + time-outs in parallel. All this can be accomplished with + generic time-outs. + They may look a little bit like + event time-outs + but contain a name to allow for any number of them simultaneously + and they are not automatically cancelled. +

        +

        + Here is how to accomplish the state time-out + in the previous example by instead using a generic time-out + named open_tm: +

        + + case Remaining of + [Digit] -> + do_unlock(), + {next_state, open, Data#{remaining := Code}, + [{{timeout,open_tm},10000,lock}]}; +... + +open({timeout,open_tm}, lock, Data) -> + do_lock(), + {next_state,locked,Data}; +open(cast, {button,_}, Data) -> + {keep_state,Data}; +... + ]]> +

        + Just as + state time-outs + you can restart or cancel a specific generic time-out + by setting it to a new time or infinity. +

        +

        + Another way to handle a late time-out can be to not cancel it, + but to ignore it if it arrives in a state + where it is known to be late. +

        +
        + + + +
        + + Erlang Timers +

        + The most versatile way to handle time-outs is to use + Erlang Timers; see erlang:start_timer3,4. + Most time-out tasks can be performed with the + time-out features in gen_statem, + but an example of one that can not is if you should need + the return value from + erlang:cancel_timer(Tref), that is; the remaining time of the timer.

        Here is how to accomplish the state time-out - in the previous example by insted using an Erlang Timer: + in the previous example by instead using an Erlang Timer:

        {keep_state_and_data, - [{reply,From,length(Code)}]}; + [{reply,From,length(Code)}]}; %% %% State: locked handle_event( @@ -1636,7 +1707,7 @@ handle_event( if Digit =:= LockButton -> {next_state, {locked,LockButton}, Data, - [{reply,From,locked}]); + [{reply,From,locked}]}; true -> {keep_state_and_data, [postpone]} @@ -1710,10 +1781,10 @@ handle_event( EventType, EventContent, {open,LockButton}, Data) -> case {EventType, EventContent} of - {enter, _OldState} -> - do_unlock(), - {keep_state_and_data, - [{state_timeout,10000,lock},hibernate]}; + {enter, _OldState} -> + do_unlock(), + {keep_state_and_data, + [{state_timeout,10000,lock},hibernate]}; ... ]]>

        -- cgit v1.2.3 From a75bda102900c4a7ae3184efa8250c46a86f8588 Mon Sep 17 00:00:00 2001 From: Siri Hansen Date: Fri, 21 Apr 2017 15:17:31 +0200 Subject: Document that app names and nodes names are restricted to latin-1 --- system/doc/reference_manual/character_set.xml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'system/doc') diff --git a/system/doc/reference_manual/character_set.xml b/system/doc/reference_manual/character_set.xml index 1129ad63d8..8e41142fb4 100644 --- a/system/doc/reference_manual/character_set.xml +++ b/system/doc/reference_manual/character_set.xml @@ -110,7 +110,8 @@ Guide.

        From Erlang/OTP 20, atoms and function names are also allowed to contain Unicode characters outside the ISO-Latin-1 range. - Module names are still restricted to the ISO-Latin-1 range.

        + Module names, application names, and node names are still + restricted to the ISO-Latin-1 range.

        Source File Encoding -- cgit v1.2.3 From 6edb6a45d8b2d2993f50176b3324d3fff97fe123 Mon Sep 17 00:00:00 2001 From: Hans Bolinder Date: Thu, 9 Mar 2017 10:12:31 +0100 Subject: stdlib: Improve the Erlang shell's handling of references As of Erlang/OTP 20.0, the type of ETS tables, ets:tid(), is a reference(). A request was put forward that the Erlang shell should be able to handle references in its input. This commit introduces an extended parser in module lib. It can parse pids, ports, references, and external funs under the condition that they can be created in the running system. The parser is meant to be used internally in Erlang/OTP. The alternative, to extend erl_scan and erl_parse, was deemed inferior as it would require the abstract format be able to represent pids, ports, references, and funs, which would be confusing as they are not expressions as such, but data types. --- system/doc/efficiency_guide/processes.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'system/doc') diff --git a/system/doc/efficiency_guide/processes.xml b/system/doc/efficiency_guide/processes.xml index afa4325d8e..3b64c863ff 100644 --- a/system/doc/efficiency_guide/processes.xml +++ b/system/doc/efficiency_guide/processes.xml @@ -4,7 +4,7 @@
        - 20012016 + 20012017 Ericsson AB. All Rights Reserved. @@ -222,7 +222,7 @@ kilo_byte(N, Acc) ->
         4> T = ets:new(tab, []).
        -17
        +#Ref<0.1662103692.2407923716.214181>
         5> ets:insert(T, {key,efficiency_guide:kilo_byte()}).
         true
         6> erts_debug:size(element(2, hd(ets:lookup(T, key)))).
        -- 
        cgit v1.2.3
        
        
        From c6bdd67b33b70d862e2a2d0f582106f2e930d970 Mon Sep 17 00:00:00 2001
        From: Ingela Anderton Andin 
        Date: Thu, 6 Apr 2017 16:03:11 +0200
        Subject: stdlib: Deprecate gen_fsm
        
        ---
         system/doc/design_principles/fsm.xml       | 338 -----------------------------
         system/doc/design_principles/part.xml      |   1 -
         system/doc/design_principles/spec_proc.xml |  86 ++++----
         system/doc/design_principles/sup_princ.xml |   3 +-
         system/doc/design_principles/xmlfiles.mk   |   1 -
         system/doc/reference_manual/modules.xml    |   1 -
         6 files changed, 45 insertions(+), 385 deletions(-)
         delete mode 100644 system/doc/design_principles/fsm.xml
        
        (limited to 'system/doc')
        
        diff --git a/system/doc/design_principles/fsm.xml b/system/doc/design_principles/fsm.xml
        deleted file mode 100644
        index 4f2b75e6e8..0000000000
        --- a/system/doc/design_principles/fsm.xml
        +++ /dev/null
        @@ -1,338 +0,0 @@
        -
        -
        -
        -
        -  
        - - 19972016 - Ericsson AB. All Rights Reserved. - - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - - - - gen_fsm Behaviour - - - - - fsm.xml -
        - - -

        - There is a new behaviour - gen_statem - that is intended to replace gen_fsm for new code. - It has the same features and add some really useful. - This module will not be removed for the foreseeable future - to keep old state machine implementations running. -

        -
        -

        This section is to be read with the gen_fsm(3) manual page - in STDLIB, where all interface functions and callback - functions are described in detail.

        - -
        - Finite-State Machines -

        A Finite-State Machine (FSM) can be described as a set of - relations of the form:

        -
        -State(S) x Event(E) -> Actions(A), State(S')
        -

        These relations are interpreted as meaning:

        - -

        If we are in state S and event E occurs, we - are to perform actions A and make a transition to - state S'.

        -
        -

        For an FSM implemented using the gen_fsm behaviour, - the state transition rules are written as a number of Erlang - functions, which conform to the following convention:

        -
        -StateName(Event, StateData) ->
        -    .. code for actions here ...
        -    {next_state, StateName', StateData'}
        -
        - -
        - Example -

        A door with a code lock can be viewed as an FSM. Initially, - the door is locked. Anytime someone presses a button, this - generates an event. Depending on what buttons have been pressed - before, the sequence so far can be correct, incomplete, or wrong.

        -

        If it is correct, the door is unlocked for 30 seconds (30,000 ms). - If it is incomplete, we wait for another button to be pressed. If - it is is wrong, we start all over, waiting for a new button - sequence.

        -

        Implementing the code lock FSM using gen_fsm results in - the following callback module:

        - - - gen_fsm:start_link({local, code_lock}, code_lock, lists:reverse(Code), []). - -button(Digit) -> - gen_fsm:send_event(code_lock, {button, Digit}). - -init(Code) -> - {ok, locked, {[], Code}}. - -locked({button, Digit}, {SoFar, Code}) -> - case [Digit|SoFar] of - Code -> - do_unlock(), - {next_state, open, {[], Code}, 30000}; - Incomplete when length(Incomplete) - {next_state, locked, {Incomplete, Code}}; - _Wrong -> - {next_state, locked, {[], Code}} - end. - -open(timeout, State) -> - do_lock(), - {next_state, locked, State}.]]> -

        The code is explained in the next sections.

        -
        - -
        - Starting gen_fsm -

        In the example in the previous section, the gen_fsm is - started by calling code_lock:start_link(Code):

        - -start_link(Code) -> - gen_fsm:start_link({local, code_lock}, code_lock, lists:reverse(Code), []). - -

        start_link calls the function gen_fsm:start_link/4, - which spawns and links to a new process, a gen_fsm.

        - - -

        The first argument, {local, code_lock}, specifies - the name. In this case, the gen_fsm is locally - registered as code_lock.

        -

        If the name is omitted, the gen_fsm is not registered. - Instead its pid must be used. The name can also be given - as {global, Name}, in which case the gen_fsm is - registered using global:register_name/2.

        -
        - -

        The second argument, code_lock, is the name of - the callback module, that is, the module where the callback - functions are located.

        -

        The interface functions (start_link and button) - are then located in the same module as the callback - functions (init, locked, and open). This - is normally good programming practice, to have the code - corresponding to one process contained in one module.

        -
        - -

        The third argument, Code, is a list of digits that - which is passed reversed to the callback function init. - Here, init - gets the correct code for the lock as indata.

        -
        - -

        The fourth argument, [], is a list of options. See - the gen_fsm(3) manual page for available options.

        -
        -
        -

        If name registration succeeds, the new gen_fsm process calls - the callback function code_lock:init(Code). This function - is expected to return {ok, StateName, StateData}, where - StateName is the name of the initial state of the - gen_fsm. In this case locked, assuming the door is - locked to begin with. StateData is the internal state of - the gen_fsm. (For gen_fsm, the internal state is - often referred to 'state data' to - distinguish it from the state as in states of a state machine.) - In this case, the state data is the button sequence so far (empty - to begin with) and the correct code of the lock.

        - -init(Code) -> - {ok, locked, {[], Code}}. -

        gen_fsm:start_link is synchronous. It does not return until - the gen_fsm has been initialized and is ready to - receive notifications.

        -

        gen_fsm:start_link must be used if the gen_fsm is - part of a supervision tree, that is, started by a supervisor. There - is another function, gen_fsm:start, to start a standalone - gen_fsm, that is, a gen_fsm that is not part of a - supervision tree.

        -
        - -
        - Notifying about Events -

        The function notifying the code lock about a button event is - implemented using gen_fsm:send_event/2:

        - -button(Digit) -> - gen_fsm:send_event(code_lock, {button, Digit}). -

        code_lock is the name of the gen_fsm and must - agree with the name used to start it. - {button, Digit} is the actual event.

        -

        The event is made into a message and sent to the gen_fsm. - When the event is received, the gen_fsm calls - StateName(Event, StateData), which is expected to return a - tuple {next_state,StateName1,StateData1}. - StateName is the name of the current state and - StateName1 is the name of the next state to go to. - StateData1 is a new value for the state data of - the gen_fsm.

        - - case [Digit|SoFar] of - Code -> - do_unlock(), - {next_state, open, {[], Code}, 30000}; - Incomplete when length(Incomplete) - {next_state, locked, {Incomplete, Code}}; - _Wrong -> - {next_state, locked, {[], Code}}; - end. - -open(timeout, State) -> - do_lock(), - {next_state, locked, State}.]]> -

        If the door is locked and a button is pressed, the complete - button sequence so far is compared with the correct code for - the lock and, depending on the result, the door is either unlocked - and the gen_fsm goes to state open, or the door - remains in state locked.

        -
        - -
        - Time-Outs -

        When a correct code has been given, the door is unlocked and - the following tuple is returned from locked/2:

        - -{next_state, open, {[], Code}, 30000}; -

        30,000 is a time-out value in milliseconds. After this time, - that is, 30 seconds, a time-out occurs. Then, - StateName(timeout, StateData) is called. The time-out - then occurs when the door has been in state open for 30 - seconds. After that the door is locked again:

        - -open(timeout, State) -> - do_lock(), - {next_state, locked, State}. -
        - -
        - All State Events -

        Sometimes an event can arrive at any state of the gen_fsm. - Instead of sending the message with gen_fsm:send_event/2 - and writing one clause handling the event for each state function, - the message can be sent with gen_fsm:send_all_state_event/2 - and handled with Module:handle_event/3:

        - --module(code_lock). -... --export([stop/0]). -... - -stop() -> - gen_fsm:send_all_state_event(code_lock, stop). - -... - -handle_event(stop, _StateName, StateData) -> - {stop, normal, StateData}. -
        - -
        - Stopping - -
        - In a Supervision Tree -

        If the gen_fsm is part of a supervision tree, no stop - function is needed. The gen_fsm is automatically - terminated by its supervisor. Exactly how this is done is - defined by a - shutdown strategy - set in the supervisor.

        -

        If it is necessary to clean up before termination, the shutdown - strategy must be a time-out value and the gen_fsm must be - set to trap exit signals in the init function. When ordered - to shutdown, the gen_fsm then calls the callback function - terminate(shutdown, StateName, StateData):

        - -init(Args) -> - ..., - process_flag(trap_exit, true), - ..., - {ok, StateName, StateData}. - -... - -terminate(shutdown, StateName, StateData) -> - ..code for cleaning up here.. - ok. -
        - -
        - Standalone gen_fsm -

        If the gen_fsm is not part of a supervision tree, a stop - function can be useful, for example:

        - -... --export([stop/0]). -... - -stop() -> - gen_fsm:send_all_state_event(code_lock, stop). -... - -handle_event(stop, _StateName, StateData) -> - {stop, normal, StateData}. - -... - -terminate(normal, _StateName, _StateData) -> - ok. -

        The callback function handling the stop event returns a - tuple, {stop,normal,StateData1}, where normal - specifies that it is a normal termination and StateData1 - is a new value for the state data of the gen_fsm. This - causes the gen_fsm to call - terminate(normal,StateName,StateData1) and then - it terminates gracefully:

        -
        -
        - -
        - Handling Other Messages -

        If the gen_fsm is to be able to receive other messages - than events, the callback function - handle_info(Info, StateName, StateData) must be implemented - to handle them. Examples of - other messages are exit messages, if the gen_fsm is linked to - other processes (than the supervisor) and trapping exit signals.

        - -handle_info({'EXIT', Pid, Reason}, StateName, StateData) -> - ..code to handle exits here.. - {next_state, StateName1, StateData1}. -

        The code_change method must also be implemented.

        - -code_change(OldVsn, StateName, StateData, Extra) -> - ..code to convert state (and more) during code change - {ok, NextStateName, NewStateData} -
        -
        - diff --git a/system/doc/design_principles/part.xml b/system/doc/design_principles/part.xml index 6495211e04..d52070a674 100644 --- a/system/doc/design_principles/part.xml +++ b/system/doc/design_principles/part.xml @@ -30,7 +30,6 @@
        - diff --git a/system/doc/design_principles/spec_proc.xml b/system/doc/design_principles/spec_proc.xml index 5b156ac263..d663c5df79 100644 --- a/system/doc/design_principles/spec_proc.xml +++ b/system/doc/design_principles/spec_proc.xml @@ -45,61 +45,63 @@

        The sys module has functions for simple debugging of processes implemented using behaviours. The code_lock example from - gen_fsm Behaviour + gen_statem Behaviour is used to illustrate this:

        -% erl
        -Erlang (BEAM) emulator version 5.2.3.6 [hipe] [threads:0]
        +Erlang/OTP 20 [DEVELOPMENT] [erts-9.0] [source-5ace45e] [64-bit] [smp:8:8] [ds:8:8:10] [async-threads:10] [hipe] [kernel-poll:false]
         
        -Eshell V5.2.3.6  (abort with ^G)
        -1> code_lock:start_link([1,2,3,4]).
        -{ok,<0.32.0>}
        -2> sys:statistics(code_lock, true).
        +Eshell V9.0  (abort with ^G)
        +1>  code_lock:start_link([1,2,3,4]).
        +Lock
        +{ok,<0.63.0>}
        +2> sys:statistics(code_lock, true).
         ok
        -3> sys:trace(code_lock, true).
        +3>  sys:trace(code_lock, true).
         ok
        -4> code_lock:button(4).
        -*DBG* code_lock got event {button,4} in state closed
        +4>  code_lock:button(1).
        +*DBG* code_lock receive cast {button,1} in state locked
         ok
        -*DBG* code_lock switched to state closed
        -5> code_lock:button(3).
        -*DBG* code_lock got event {button,3} in state closed
        +*DBG* code_lock consume cast {button,1} in state locked
        +5>  code_lock:button(2).
        +*DBG* code_lock receive cast {button,2} in state locked
         ok
        -*DBG* code_lock switched to state closed
        -6> code_lock:button(2).
        -*DBG* code_lock got event {button,2} in state closed
        +*DBG* code_lock consume cast {button,2} in state locked
        +6>  code_lock:button(3).
        +*DBG* code_lock receive cast {button,3} in state locked
         ok
        -*DBG* code_lock switched to state closed
        -7> code_lock:button(1).
        -*DBG* code_lock got event {button,1} in state closed
        +*DBG* code_lock consume cast {button,3} in state locked
        +7>  code_lock:button(4).
        +*DBG* code_lock receive cast {button,4} in state locked
         ok
        -OPEN DOOR
        -*DBG* code_lock switched to state open
        -*DBG* code_lock got event timeout in state open
        -CLOSE DOOR
        -*DBG* code_lock switched to state closed
        -8> sys:statistics(code_lock, get). 
        -{ok,[{start_time,{{2003,6,12},{14,11,40}}},
        -     {current_time,{{2003,6,12},{14,12,14}}},
        -     {reductions,333},
        +Unlock
        +*DBG* code_lock consume cast {button,4} in state locked
        +*DBG* code_lock receive state_timeout lock in state open
        +Lock
        +*DBG* code_lock consume state_timeout lock in state open
        +8> sys:statistics(code_lock, get).
        +{ok,[{start_time,{{2017,4,21},{16,8,7}}},
        +     {current_time,{{2017,4,21},{16,9,42}}},
        +     {reductions,2973},
              {messages_in,5},
              {messages_out,0}]}
        -9> sys:statistics(code_lock, false).
        +9> sys:statistics(code_lock, false).
         ok
        -10> sys:trace(code_lock, false).     
        +10> sys:trace(code_lock, false).
         ok
        -11> sys:get_status(code_lock).
        -{status,<0.32.0>,
        -        {module,gen_fsm},
        -        [[{'$ancestors',[<0.30.0>]},
        -          {'$initial_call',{gen,init_it,
        -                                [gen_fsm,<0.30.0>,<0.30.0>,
        -                                 {local,code_lock},
        -                                 code_lock,
        -                                 [1,2,3,4],
        -                                 []]}}],
        -         running,<0.30.0>,[],
        -         [code_lock,closed,{[],[1,2,3,4]},code_lock,infinity]]}
        +11> sys:get_status(code_lock). +{status,<0.63.0>, + {module,gen_statem}, + [[{'$initial_call',{code_lock,init,1}}, + {'$ancestors',[<0.61.0>]}], + running,<0.61.0>,[], + [{header,"Status for state machine code_lock"}, + {data,[{"Status",running}, + {"Parent",<0.61.0>}, + {"Logged Events",[]}, + {"Postponed",[]}]}, + {data,[{"State", + {locked,#{code => [1,2,3,4],remaining => [1,2,3,4]}}}]}]]} +
        diff --git a/system/doc/design_principles/sup_princ.xml b/system/doc/design_principles/sup_princ.xml index 478d1bf714..4fd210aa48 100644 --- a/system/doc/design_principles/sup_princ.xml +++ b/system/doc/design_principles/sup_princ.xml @@ -276,7 +276,6 @@ child_spec() = #{id => child_id(), % mandatory supervisor:start_link gen_server:start_link - gen_fsm:start_link gen_statem:start_link gen_event:start_link A function compliant with these functions. For details, @@ -341,7 +340,7 @@ child_spec() = #{id => child_id(), % mandatory

        modules are to be a list with one element [Module], where Module is the name of the callback module, if the child process is a supervisor, - gen_server, gen_fsm or gen_statem. + gen_server, gen_statem. If the child process is a gen_event, the value shall be dynamic.

        This information is used by the release handler during diff --git a/system/doc/design_principles/xmlfiles.mk b/system/doc/design_principles/xmlfiles.mk index e476255d62..8877e94f39 100644 --- a/system/doc/design_principles/xmlfiles.mk +++ b/system/doc/design_principles/xmlfiles.mk @@ -24,7 +24,6 @@ DESIGN_PRINCIPLES_CHAPTER_FILES = \ des_princ.xml \ distributed_applications.xml \ events.xml \ - fsm.xml \ statem.xml \ gen_server_concepts.xml \ included_applications.xml \ diff --git a/system/doc/reference_manual/modules.xml b/system/doc/reference_manual/modules.xml index 96968b547e..6fe6680c84 100644 --- a/system/doc/reference_manual/modules.xml +++ b/system/doc/reference_manual/modules.xml @@ -143,7 +143,6 @@ fact(0) -> % | standard behaviours:

        gen_server - gen_fsm gen_statem gen_event supervisor -- cgit v1.2.3 From 6fa089792c1e323ded81031da17a379d134ccb0c Mon Sep 17 00:00:00 2001 From: mr c0b Date: Tue, 2 May 2017 12:23:00 +1130 Subject: system/doc/reference_manual/: fix a typo --- system/doc/reference_manual/data_types.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'system/doc') diff --git a/system/doc/reference_manual/data_types.xml b/system/doc/reference_manual/data_types.xml index 107e403903..64e9d54a3c 100644 --- a/system/doc/reference_manual/data_types.xml +++ b/system/doc/reference_manual/data_types.xml @@ -452,7 +452,7 @@ hello <<"77">> 16> float_to_binary(7.0). <<"7.00000000000000000000e+00">> -17> binary_to_float(<<"7.000e+00>>"). +17> binary_to_float(<<"7.000e+00">>). 7.0
        -- cgit v1.2.3 From 83e20c62057ebc1d8064bf57b01be560cd244e1d Mon Sep 17 00:00:00 2001 From: Raimo Niskanen Date: Thu, 4 May 2017 15:42:21 +0200 Subject: Update copyright year --- system/doc/design_principles/part.xml | 2 +- system/doc/design_principles/spec_proc.xml | 2 +- system/doc/design_principles/sup_princ.xml | 2 +- system/doc/design_principles/xmlfiles.mk | 2 +- system/doc/efficiency_guide/binaryhandling.xml | 2 +- system/doc/efficiency_guide/commoncaveats.xml | 2 +- system/doc/efficiency_guide/functions.xml | 2 +- system/doc/efficiency_guide/introduction.xml | 2 +- system/doc/efficiency_guide/listhandling.xml | 2 +- system/doc/efficiency_guide/retired_myths.xml | 2 +- system/doc/reference_manual/character_set.xml | 2 +- system/doc/reference_manual/data_types.xml | 2 +- system/doc/reference_manual/errors.xml | 2 +- system/doc/reference_manual/expressions.xml | 2 +- system/doc/reference_manual/introduction.xml | 2 +- system/doc/reference_manual/macros.xml | 2 +- system/doc/reference_manual/modules.xml | 2 +- system/doc/reference_manual/records.xml | 2 +- system/doc/tutorial/c_portdriver.xmlsrc | 2 +- system/doc/tutorial/erl_interface.xmlsrc | 2 +- 20 files changed, 20 insertions(+), 20 deletions(-) (limited to 'system/doc') diff --git a/system/doc/design_principles/part.xml b/system/doc/design_principles/part.xml index d52070a674..899c7f2afe 100644 --- a/system/doc/design_principles/part.xml +++ b/system/doc/design_principles/part.xml @@ -4,7 +4,7 @@
        - 19972016 + 19972017 Ericsson AB. All Rights Reserved. diff --git a/system/doc/design_principles/spec_proc.xml b/system/doc/design_principles/spec_proc.xml index d663c5df79..5f4e7ac685 100644 --- a/system/doc/design_principles/spec_proc.xml +++ b/system/doc/design_principles/spec_proc.xml @@ -4,7 +4,7 @@
        - 19972016 + 19972017 Ericsson AB. All Rights Reserved. diff --git a/system/doc/design_principles/sup_princ.xml b/system/doc/design_principles/sup_princ.xml index 48b1905e94..06ca44a9f6 100644 --- a/system/doc/design_principles/sup_princ.xml +++ b/system/doc/design_principles/sup_princ.xml @@ -4,7 +4,7 @@
        - 19972016 + 19972017 Ericsson AB. All Rights Reserved. diff --git a/system/doc/design_principles/xmlfiles.mk b/system/doc/design_principles/xmlfiles.mk index 8877e94f39..fbcaf9c7d9 100644 --- a/system/doc/design_principles/xmlfiles.mk +++ b/system/doc/design_principles/xmlfiles.mk @@ -1,7 +1,7 @@ # # %CopyrightBegin% # -# Copyright Ericsson AB 2009-2016. All Rights Reserved. +# Copyright Ericsson AB 2009-2017. All Rights Reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/system/doc/efficiency_guide/binaryhandling.xml b/system/doc/efficiency_guide/binaryhandling.xml index 91fd9a7cd9..19f40c9abe 100644 --- a/system/doc/efficiency_guide/binaryhandling.xml +++ b/system/doc/efficiency_guide/binaryhandling.xml @@ -5,7 +5,7 @@
        2007 - 2016 + 2017 Ericsson AB, All Rights Reserved diff --git a/system/doc/efficiency_guide/commoncaveats.xml b/system/doc/efficiency_guide/commoncaveats.xml index 94b1c0b222..b41ffc3902 100644 --- a/system/doc/efficiency_guide/commoncaveats.xml +++ b/system/doc/efficiency_guide/commoncaveats.xml @@ -4,7 +4,7 @@
        - 20012016 + 20012017 Ericsson AB. All Rights Reserved. diff --git a/system/doc/efficiency_guide/functions.xml b/system/doc/efficiency_guide/functions.xml index 1d0f1f68b7..0a8ee7eb34 100644 --- a/system/doc/efficiency_guide/functions.xml +++ b/system/doc/efficiency_guide/functions.xml @@ -4,7 +4,7 @@
        - 20012016 + 20012017 Ericsson AB. All Rights Reserved. diff --git a/system/doc/efficiency_guide/introduction.xml b/system/doc/efficiency_guide/introduction.xml index b650008ae8..dca2dec95e 100644 --- a/system/doc/efficiency_guide/introduction.xml +++ b/system/doc/efficiency_guide/introduction.xml @@ -4,7 +4,7 @@
        - 20012016 + 20012017 Ericsson AB. All Rights Reserved. diff --git a/system/doc/efficiency_guide/listhandling.xml b/system/doc/efficiency_guide/listhandling.xml index ec258d7c2a..4f2497359d 100644 --- a/system/doc/efficiency_guide/listhandling.xml +++ b/system/doc/efficiency_guide/listhandling.xml @@ -4,7 +4,7 @@
        - 20012016 + 20012017 Ericsson AB. All Rights Reserved. diff --git a/system/doc/efficiency_guide/retired_myths.xml b/system/doc/efficiency_guide/retired_myths.xml index 7c6a1262c7..9b914a3b6e 100644 --- a/system/doc/efficiency_guide/retired_myths.xml +++ b/system/doc/efficiency_guide/retired_myths.xml @@ -5,7 +5,7 @@
        2016 - 2016 + 2017 Ericsson AB, All Rights Reserved diff --git a/system/doc/reference_manual/character_set.xml b/system/doc/reference_manual/character_set.xml index 8e41142fb4..ef14bf1372 100644 --- a/system/doc/reference_manual/character_set.xml +++ b/system/doc/reference_manual/character_set.xml @@ -4,7 +4,7 @@
        - 20142015 + 20142017 Ericsson AB. All Rights Reserved. diff --git a/system/doc/reference_manual/data_types.xml b/system/doc/reference_manual/data_types.xml index 107e403903..58734dcd3c 100644 --- a/system/doc/reference_manual/data_types.xml +++ b/system/doc/reference_manual/data_types.xml @@ -4,7 +4,7 @@
        - 20032015 + 20032017 Ericsson AB. All Rights Reserved. diff --git a/system/doc/reference_manual/errors.xml b/system/doc/reference_manual/errors.xml index 3e2d306561..b16c5da6eb 100644 --- a/system/doc/reference_manual/errors.xml +++ b/system/doc/reference_manual/errors.xml @@ -4,7 +4,7 @@
        - 20032015 + 20032017 Ericsson AB. All Rights Reserved. diff --git a/system/doc/reference_manual/expressions.xml b/system/doc/reference_manual/expressions.xml index acd1dec901..cf2d5034aa 100644 --- a/system/doc/reference_manual/expressions.xml +++ b/system/doc/reference_manual/expressions.xml @@ -4,7 +4,7 @@
        - 20032016 + 20032017 Ericsson AB. All Rights Reserved. diff --git a/system/doc/reference_manual/introduction.xml b/system/doc/reference_manual/introduction.xml index c9ce45bbcc..afbdfa7434 100644 --- a/system/doc/reference_manual/introduction.xml +++ b/system/doc/reference_manual/introduction.xml @@ -4,7 +4,7 @@
        - 20032015 + 20032017 Ericsson AB. All Rights Reserved. diff --git a/system/doc/reference_manual/macros.xml b/system/doc/reference_manual/macros.xml index b6c740dd10..a341307ab7 100644 --- a/system/doc/reference_manual/macros.xml +++ b/system/doc/reference_manual/macros.xml @@ -4,7 +4,7 @@
        - 20032016 + 20032017 Ericsson AB. All Rights Reserved. diff --git a/system/doc/reference_manual/modules.xml b/system/doc/reference_manual/modules.xml index 6fe6680c84..4a97bfeb7b 100644 --- a/system/doc/reference_manual/modules.xml +++ b/system/doc/reference_manual/modules.xml @@ -4,7 +4,7 @@
        - 20032016 + 20032017 Ericsson AB. All Rights Reserved. diff --git a/system/doc/reference_manual/records.xml b/system/doc/reference_manual/records.xml index 1eb13b353e..6b26e2c242 100644 --- a/system/doc/reference_manual/records.xml +++ b/system/doc/reference_manual/records.xml @@ -4,7 +4,7 @@
        - 20032015 + 20032017 Ericsson AB. All Rights Reserved. diff --git a/system/doc/tutorial/c_portdriver.xmlsrc b/system/doc/tutorial/c_portdriver.xmlsrc index da680642b6..c4cf6daa3b 100644 --- a/system/doc/tutorial/c_portdriver.xmlsrc +++ b/system/doc/tutorial/c_portdriver.xmlsrc @@ -4,7 +4,7 @@
        - 20002015 + 20002017 Ericsson AB. All Rights Reserved. diff --git a/system/doc/tutorial/erl_interface.xmlsrc b/system/doc/tutorial/erl_interface.xmlsrc index ee648c2e88..bf9bd36597 100644 --- a/system/doc/tutorial/erl_interface.xmlsrc +++ b/system/doc/tutorial/erl_interface.xmlsrc @@ -4,7 +4,7 @@
        - 20002015 + 20002017 Ericsson AB. All Rights Reserved. -- cgit v1.2.3 From b8d4bd38e343488b5e8539f913650b150cab3ade Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Gustavsson?= Date: Wed, 17 May 2017 06:24:02 +0200 Subject: Add a link to the Reference Manual from the example page When doing a Google search for "bit syntax", you could end up on the programming examples page about bit syntax. The example page has some reference material, but is far from complete. Therefore, add a link to the page about bit syntax in the Reference Manual. https://bugs.erlang.org/browse/ERL-387 --- system/doc/programming_examples/bit_syntax.xml | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'system/doc') diff --git a/system/doc/programming_examples/bit_syntax.xml b/system/doc/programming_examples/bit_syntax.xml index 0af295b7b7..03645bba1b 100644 --- a/system/doc/programming_examples/bit_syntax.xml +++ b/system/doc/programming_examples/bit_syntax.xml @@ -32,6 +32,8 @@
        Introduction +

        The complete specification for the bit syntax appears in the + Reference Manual.

        In Erlang, a Bin is used for constructing binaries and matching binary patterns. A Bin is written with the following syntax:

        separated by hyphens.

        Type - The type can be integer, float, or - binary. + The most commonly used types are integer, float, and binary. + See Bit Syntax Expressions in the Reference Manual for a complete description. + Signedness The signedness specification can be either signed or unsigned. Notice that signedness only matters for -- cgit v1.2.3 From 96d9a00223aaaf1df7698395be17157a836461ec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Gustavsson?= Date: Wed, 17 May 2017 06:34:00 +0200 Subject: Don't mention R12B --- system/doc/programming_examples/bit_syntax.xml | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) (limited to 'system/doc') diff --git a/system/doc/programming_examples/bit_syntax.xml b/system/doc/programming_examples/bit_syntax.xml index 03645bba1b..98ad2808cf 100644 --- a/system/doc/programming_examples/bit_syntax.xml +++ b/system/doc/programming_examples/bit_syntax.xml @@ -47,7 +47,7 @@ Bin = <>]]> <> = Bin ]]>

        Here, Bin is bound and the elements are bound or unbound, as in any match.

        -

        Since Erlang R12B, a Bin does not need to consist of a whole number of bytes.

        +

        A Bin does not need to consist of a whole number of bytes.

        A bitstring is a sequence of zero or more bits, where the number of bits does not need to be divisible by 8. If the number @@ -184,7 +184,7 @@ end.]]> The unit size is given as unit:IntegerLiteral. The allowed range is 1-256. It is multiplied by the Size specifier to give the effective size of - the segment. Since Erlang R12B, the unit size specifies the alignment + the segment. The unit size specifies the alignment for binary segments without size.

        Example:

        @@ -322,21 +322,15 @@ foo(<>) ->]]>
        Appending to a Binary -

        Since Erlang R12B, the following function for creating a binary out of - a list of triples of integers is efficient:

        +

        Appending to a binary in an efficient way can be done as follows:

        triples_to_bin(T, <<>>). triples_to_bin([{X,Y,Z} | T], Acc) -> - triples_to_bin(T, <>); % inefficient before R12B + triples_to_bin(T, <>); triples_to_bin([], Acc) -> Acc.]]> -

        In previous releases, this function was highly inefficient, because - the binary constructed so far (Acc) was copied in each recursion step. - That is no longer the case. For more information, see - - Efficiency Guide.

        -- cgit v1.2.3 From 51c44f09553b13194ee8346266b0930d1a135590 Mon Sep 17 00:00:00 2001 From: Raimo Niskanen Date: Fri, 19 May 2017 11:52:35 +0200 Subject: Fix documentation details --- system/doc/design_principles/statem.xml | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) (limited to 'system/doc') diff --git a/system/doc/design_principles/statem.xml b/system/doc/design_principles/statem.xml index f01615fdcd..7febe31df3 100644 --- a/system/doc/design_principles/statem.xml +++ b/system/doc/design_principles/statem.xml @@ -4,7 +4,7 @@
        - 2016-2017 + 20162017 Ericsson AB. All Rights Reserved. @@ -1582,10 +1582,12 @@ format_status(Opt, [_PDict,State,Data]) -> for example, a complex state term like a tuple.

        - One reason to use this is when you have - a state item that affects the event handling, - in particular in combination with postponing events. - We complicate the previous example + One reason to use this is when you have a state item + that when changed should cancel the + state time-out, + or one that affects the event handling + in combination with postponing events. + We will complicate the previous example by introducing a configurable lock button (this is the state item in question), which in the open state immediately locks the door, -- cgit v1.2.3 From 30f4fc6963e5793368713897f32afd2172dc1578 Mon Sep 17 00:00:00 2001 From: Lukas Larsson Date: Thu, 18 May 2017 16:11:11 +0200 Subject: otp: Extend secure distribution docs warnings Warnings have been added to the relevant documentation about not using un-secure distributed nodes in exposed environments. --- system/doc/getting_started/conc_prog.xml | 4 ++-- system/doc/reference_manual/distributed.xml | 13 +++++++++++++ 2 files changed, 15 insertions(+), 2 deletions(-) (limited to 'system/doc') diff --git a/system/doc/getting_started/conc_prog.xml b/system/doc/getting_started/conc_prog.xml index f3136898ad..4b19095d95 100644 --- a/system/doc/getting_started/conc_prog.xml +++ b/system/doc/getting_started/conc_prog.xml @@ -355,8 +355,8 @@ pong ! {ping, self()},

        Let us rewrite the ping pong program with "ping" and "pong" on different computers. First a few things are needed to set up to get this to work. The distributed Erlang - implementation provides a basic security mechanism to prevent - unauthorized access to an Erlang system on another computer. + implementation provides a very basic authentication mechanism to prevent + unintentional access to an Erlang system on another computer. Erlang systems which talk to each other must have the same magic cookie. The easiest way to achieve this is by having a file called .erlang.cookie in your home diff --git a/system/doc/reference_manual/distributed.xml b/system/doc/reference_manual/distributed.xml index 0a4a323fe9..01d78436c5 100644 --- a/system/doc/reference_manual/distributed.xml +++ b/system/doc/reference_manual/distributed.xml @@ -42,6 +42,19 @@

        The distribution mechanism is implemented using TCP/IP sockets. How to implement an alternative carrier is described in the ERTS User's Guide.

        + +

        + Starting a distributed node without also specifying + -proto_dist inet_tls + will expose the node to attacks that may give the attacker + complete access to the node and in extension the cluster. + When using un-secure distributed nodes, make sure that the + network is configured to keep potential attackers out. + See the + Using SSL for Erlang Distribution User's Guide + for details on how to setup a secure distributed node. +

        +
        -- cgit v1.2.3 From 43718d3b81d7f3d08e25047e22d579801bbe5044 Mon Sep 17 00:00:00 2001 From: Hans Nilsson Date: Wed, 14 Jun 2017 15:36:21 +0200 Subject: Update copyright year --- system/doc/getting_started/conc_prog.xml | 2 +- system/doc/programming_examples/bit_syntax.xml | 2 +- system/doc/reference_manual/distributed.xml | 2 +- system/doc/top/templates/index.html.src | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) (limited to 'system/doc') diff --git a/system/doc/getting_started/conc_prog.xml b/system/doc/getting_started/conc_prog.xml index 4b19095d95..7936e0d484 100644 --- a/system/doc/getting_started/conc_prog.xml +++ b/system/doc/getting_started/conc_prog.xml @@ -4,7 +4,7 @@
        - 20032016 + 20032017 Ericsson AB. All Rights Reserved. diff --git a/system/doc/programming_examples/bit_syntax.xml b/system/doc/programming_examples/bit_syntax.xml index 98ad2808cf..d1dd52c5ab 100644 --- a/system/doc/programming_examples/bit_syntax.xml +++ b/system/doc/programming_examples/bit_syntax.xml @@ -4,7 +4,7 @@
        - 20032015 + 20032017 Ericsson AB. All Rights Reserved. diff --git a/system/doc/reference_manual/distributed.xml b/system/doc/reference_manual/distributed.xml index 01d78436c5..b519609717 100644 --- a/system/doc/reference_manual/distributed.xml +++ b/system/doc/reference_manual/distributed.xml @@ -4,7 +4,7 @@
        - 20032015 + 20032017 Ericsson AB. All Rights Reserved. diff --git a/system/doc/top/templates/index.html.src b/system/doc/top/templates/index.html.src index b987fb4722..747d19cf7e 100644 --- a/system/doc/top/templates/index.html.src +++ b/system/doc/top/templates/index.html.src @@ -2,7 +2,7 @@