diff options
Diffstat (limited to 'system/doc')
54 files changed, 742 insertions, 880 deletions
diff --git a/system/doc/Makefile b/system/doc/Makefile index eb900b933f..0c4adf6554 100644 --- a/system/doc/Makefile +++ b/system/doc/Makefile @@ -9,11 +9,11 @@ # 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 Utvecklings AB. # Portions created by Ericsson are Copyright 1999, Ericsson Utvecklings # AB. All Rights Reserved.'' -# +# # $Id$ # include $(ERL_TOP)/make/target.mk @@ -38,10 +38,9 @@ SUB_DIRECTORIES = design_principles \ # pics \ -SPECIAL_TARGETS = +SPECIAL_TARGETS = # # Default Subdir Targets # include $(ERL_TOP)/make/otp_subdir.mk - diff --git a/system/doc/design_principles/Makefile b/system/doc/design_principles/Makefile index 506c433f3b..1465f430a5 100644 --- a/system/doc/design_principles/Makefile +++ b/system/doc/design_principles/Makefile @@ -1,8 +1,8 @@ # # %CopyrightBegin% -# +# # Copyright Ericsson AB 1997-2016. 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 @@ -14,7 +14,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. -# +# # %CopyrightEnd% # # @@ -37,7 +37,7 @@ RELSYSDIR = "$(RELEASE_PATH)/doc/design_principles" # ---------------------------------------------------- XML_PART_FILES = part.xml -include xmlfiles.mk +include xmlfiles.mk XML_CHAPTER_FILES=$(DESIGN_PRINCIPLES_CHAPTER_FILES) @@ -46,7 +46,6 @@ TOPDOCDIR=.. BOOK_FILES = book.xml GIF_FILES = \ - note.gif \ clientserver.gif \ dist1.gif \ dist2.gif \ @@ -66,7 +65,7 @@ IMAGE_FILES = $(GIF_FILES) $(PNG_FILES) XML_FILES = \ $(BOOK_FILES) $(XML_CHAPTER_FILES) \ - $(XML_PART_FILES) + $(XML_PART_FILES) # ---------------------------------------------------- @@ -78,10 +77,10 @@ HTMLDIR = ../html/design_principles HTML_UG_FILE = $(HTMLDIR)/users_guide.html # ---------------------------------------------------- -# FLAGS +# FLAGS # ---------------------------------------------------- -XML_FLAGS += -DVIPS_FLAGS += +XML_FLAGS += +DVIPS_FLAGS += # ---------------------------------------------------- # Targets @@ -101,16 +100,16 @@ html: $(HTML_UG_FILE) images images: $(IMAGE_FILES:%=$(HTMLDIR)/%) -debug opt: +debug opt: clean clean_docs: rm -f $(HTMLDIR)/*.gif $(HTMLDIR)/*.html rm -f $(TOP_PDF_FILE) $(TOP_PDF_FILE:%.pdf=%.fo) - rm -f errs core *~ + rm -f errs core *~ # ---------------------------------------------------- # Release Target -# ---------------------------------------------------- +# ---------------------------------------------------- include $(ERL_TOP)/make/otp_release_targets.mk release_docs_spec: docs @@ -122,5 +121,3 @@ release_docs_spec: docs release_spec: - - diff --git a/system/doc/design_principles/des_princ.xml b/system/doc/design_principles/des_princ.xml index 8ab8661c2d..e21f2a7f4e 100644 --- a/system/doc/design_principles/des_princ.xml +++ b/system/doc/design_principles/des_princ.xml @@ -4,7 +4,7 @@ <chapter> <header> <copyright> - <year>1997</year><year>2016</year> + <year>1997</year><year>2017</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> @@ -225,10 +225,8 @@ free(Ch, {Alloc, Free} = Channels) -> <list type="bulleted"> <item><p><seealso marker="gen_server_concepts">gen_server</seealso></p> <p>For implementing the server of a client-server relation</p></item> - <item><p><seealso marker="fsm">gen_fsm</seealso></p> - <p>For implementing finite-state machines (Old)</p></item> <item><p><seealso marker="statem">gen_statem</seealso></p> - <p>For implementing state machines (New)</p></item> + <p>For implementing state machines</p></item> <item><p><seealso marker="events">gen_event</seealso></p> <p>For implementing event handling functionality</p></item> <item><p><seealso marker="sup_princ">supervisor</seealso></p> 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 @@ -<?xml version="1.0" encoding="utf-8" ?> -<!DOCTYPE chapter SYSTEM "chapter.dtd"> - -<chapter> - <header> - <copyright> - <year>1997</year><year>2016</year> - <holder>Ericsson AB. All Rights Reserved.</holder> - </copyright> - <legalnotice> - 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. - - </legalnotice> - - <title>gen_fsm Behaviour</title> - <prepared></prepared> - <docno></docno> - <date></date> - <rev></rev> - <file>fsm.xml</file> - </header> - <marker id="gen_fsm behaviour"></marker> - <note> - <p> - There is a new behaviour - <seealso marker="statem"><c>gen_statem</c></seealso> - that is intended to replace <c>gen_fsm</c> 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. - </p> - </note> - <p>This section is to be read with the <c>gen_fsm(3)</c> manual page - in STDLIB, where all interface functions and callback - functions are described in detail.</p> - - <section> - <title>Finite-State Machines</title> - <p>A Finite-State Machine (FSM) can be described as a set of - relations of the form:</p> - <pre> -State(S) x Event(E) -> Actions(A), State(S')</pre> - <p>These relations are interpreted as meaning:</p> - <quote> - <p>If we are in state <c>S</c> and event <c>E</c> occurs, we - are to perform actions <c>A</c> and make a transition to - state <c>S'</c>.</p> - </quote> - <p>For an FSM implemented using the <c>gen_fsm</c> behaviour, - the state transition rules are written as a number of Erlang - functions, which conform to the following convention:</p> - <pre> -StateName(Event, StateData) -> - .. code for actions here ... - {next_state, StateName', StateData'}</pre> - </section> - - <section> - <title>Example</title> - <p>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.</p> - <p>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.</p> - <p>Implementing the code lock FSM using <c>gen_fsm</c> results in - the following callback module:</p> - <marker id="ex"></marker> - <code type="none"><![CDATA[ --module(code_lock). --behaviour(gen_fsm). - --export([start_link/1]). --export([button/1]). --export([init/1, locked/2, open/2]). - -start_link(Code) -> - 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)<length(Code) -> - {next_state, locked, {Incomplete, Code}}; - _Wrong -> - {next_state, locked, {[], Code}} - end. - -open(timeout, State) -> - do_lock(), - {next_state, locked, State}.]]></code> - <p>The code is explained in the next sections.</p> - </section> - - <section> - <title>Starting gen_fsm</title> - <p>In the example in the previous section, the <c>gen_fsm</c> is - started by calling <c>code_lock:start_link(Code)</c>:</p> - <code type="none"> -start_link(Code) -> - gen_fsm:start_link({local, code_lock}, code_lock, lists:reverse(Code), []). - </code> - <p><c>start_link</c> calls the function <c>gen_fsm:start_link/4</c>, - which spawns and links to a new process, a <c>gen_fsm</c>.</p> - <list type="bulleted"> - <item> - <p>The first argument, <c>{local, code_lock}</c>, specifies - the name. In this case, the <c>gen_fsm</c> is locally - registered as <c>code_lock</c>.</p> - <p>If the name is omitted, the <c>gen_fsm</c> is not registered. - Instead its pid must be used. The name can also be given - as <c>{global, Name}</c>, in which case the <c>gen_fsm</c> is - registered using <c>global:register_name/2</c>.</p> - </item> - <item> - <p>The second argument, <c>code_lock</c>, is the name of - the callback module, that is, the module where the callback - functions are located.</p> - <p>The interface functions (<c>start_link</c> and <c>button</c>) - are then located in the same module as the callback - functions (<c>init</c>, <c>locked</c>, and <c>open</c>). This - is normally good programming practice, to have the code - corresponding to one process contained in one module.</p> - </item> - <item> - <p>The third argument, <c>Code</c>, is a list of digits that - which is passed reversed to the callback function <c>init</c>. - Here, <c>init</c> - gets the correct code for the lock as indata.</p> - </item> - <item> - <p>The fourth argument, <c>[]</c>, is a list of options. See - the <c>gen_fsm(3)</c> manual page for available options.</p> - </item> - </list> - <p>If name registration succeeds, the new <c>gen_fsm</c> process calls - the callback function <c>code_lock:init(Code)</c>. This function - is expected to return <c>{ok, StateName, StateData}</c>, where - <c>StateName</c> is the name of the initial state of the - <c>gen_fsm</c>. In this case <c>locked</c>, assuming the door is - locked to begin with. <c>StateData</c> is the internal state of - the <c>gen_fsm</c>. (For <c>gen_fsm</c>, 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.</p> - <code type="none"> -init(Code) -> - {ok, locked, {[], Code}}.</code> - <p><c>gen_fsm:start_link</c> is synchronous. It does not return until - the <c>gen_fsm</c> has been initialized and is ready to - receive notifications.</p> - <p><c>gen_fsm:start_link</c> must be used if the <c>gen_fsm</c> is - part of a supervision tree, that is, started by a supervisor. There - is another function, <c>gen_fsm:start</c>, to start a standalone - <c>gen_fsm</c>, that is, a <c>gen_fsm</c> that is not part of a - supervision tree.</p> - </section> - - <section> - <title>Notifying about Events</title> - <p>The function notifying the code lock about a button event is - implemented using <c>gen_fsm:send_event/2</c>:</p> - <code type="none"> -button(Digit) -> - gen_fsm:send_event(code_lock, {button, Digit}).</code> - <p><c>code_lock</c> is the name of the <c>gen_fsm</c> and must - agree with the name used to start it. - <c>{button, Digit}</c> is the actual event.</p> - <p>The event is made into a message and sent to the <c>gen_fsm</c>. - When the event is received, the <c>gen_fsm</c> calls - <c>StateName(Event, StateData)</c>, which is expected to return a - tuple <c>{next_state,StateName1,StateData1}</c>. - <c>StateName</c> is the name of the current state and - <c>StateName1</c> is the name of the next state to go to. - <c>StateData1</c> is a new value for the state data of - the <c>gen_fsm</c>.</p> - <code type="none"><![CDATA[ -locked({button, Digit}, {SoFar, Code}) -> - case [Digit|SoFar] of - Code -> - do_unlock(), - {next_state, open, {[], Code}, 30000}; - Incomplete when length(Incomplete)<length(Code) -> - {next_state, locked, {Incomplete, Code}}; - _Wrong -> - {next_state, locked, {[], Code}}; - end. - -open(timeout, State) -> - do_lock(), - {next_state, locked, State}.]]></code> - <p>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 <c>gen_fsm</c> goes to state <c>open</c>, or the door - remains in state <c>locked</c>.</p> - </section> - - <section> - <title>Time-Outs</title> - <p>When a correct code has been given, the door is unlocked and - the following tuple is returned from <c>locked/2</c>:</p> - <code type="none"> -{next_state, open, {[], Code}, 30000};</code> - <p>30,000 is a time-out value in milliseconds. After this time, - that is, 30 seconds, a time-out occurs. Then, - <c>StateName(timeout, StateData)</c> is called. The time-out - then occurs when the door has been in state <c>open</c> for 30 - seconds. After that the door is locked again:</p> - <code type="none"> -open(timeout, State) -> - do_lock(), - {next_state, locked, State}.</code> - </section> - - <section> - <title>All State Events</title> - <p>Sometimes an event can arrive at any state of the <c>gen_fsm</c>. - Instead of sending the message with <c>gen_fsm:send_event/2</c> - and writing one clause handling the event for each state function, - the message can be sent with <c>gen_fsm:send_all_state_event/2</c> - and handled with <c>Module:handle_event/3</c>:</p> - <code type="none"> --module(code_lock). -... --export([stop/0]). -... - -stop() -> - gen_fsm:send_all_state_event(code_lock, stop). - -... - -handle_event(stop, _StateName, StateData) -> - {stop, normal, StateData}.</code> - </section> - - <section> - <title>Stopping</title> - - <section> - <title>In a Supervision Tree</title> - <p>If the <c>gen_fsm</c> is part of a supervision tree, no stop - function is needed. The <c>gen_fsm</c> is automatically - terminated by its supervisor. Exactly how this is done is - defined by a - <seealso marker="sup_princ#shutdown">shutdown strategy</seealso> - set in the supervisor.</p> - <p>If it is necessary to clean up before termination, the shutdown - strategy must be a time-out value and the <c>gen_fsm</c> must be - set to trap exit signals in the <c>init</c> function. When ordered - to shutdown, the <c>gen_fsm</c> then calls the callback function - <c>terminate(shutdown, StateName, StateData)</c>:</p> - <code type="none"> -init(Args) -> - ..., - process_flag(trap_exit, true), - ..., - {ok, StateName, StateData}. - -... - -terminate(shutdown, StateName, StateData) -> - ..code for cleaning up here.. - ok.</code> - </section> - - <section> - <title>Standalone gen_fsm</title> - <p>If the <c>gen_fsm</c> is not part of a supervision tree, a stop - function can be useful, for example:</p> - <code type="none"> -... --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.</code> - <p>The callback function handling the <c>stop</c> event returns a - tuple, <c>{stop,normal,StateData1}</c>, where <c>normal</c> - specifies that it is a normal termination and <c>StateData1</c> - is a new value for the state data of the <c>gen_fsm</c>. This - causes the <c>gen_fsm</c> to call - <c>terminate(normal,StateName,StateData1)</c> and then - it terminates gracefully:</p> - </section> - </section> - - <section> - <title>Handling Other Messages</title> - <p>If the <c>gen_fsm</c> is to be able to receive other messages - than events, the callback function - <c>handle_info(Info, StateName, StateData)</c> must be implemented - to handle them. Examples of - other messages are exit messages, if the <c>gen_fsm</c> is linked to - other processes (than the supervisor) and trapping exit signals.</p> - <code type="none"> -handle_info({'EXIT', Pid, Reason}, StateName, StateData) -> - ..code to handle exits here.. - {next_state, StateName1, StateData1}.</code> - <p>The code_change method must also be implemented.</p> - <code type="none"> -code_change(OldVsn, StateName, StateData, Extra) -> - ..code to convert state (and more) during code change - {ok, NextStateName, NewStateData}</code> - </section> -</chapter> - diff --git a/system/doc/design_principles/note.gif b/system/doc/design_principles/note.gif Binary files differdeleted file mode 100644 index 6fffe30419..0000000000 --- a/system/doc/design_principles/note.gif +++ /dev/null diff --git a/system/doc/design_principles/part.xml b/system/doc/design_principles/part.xml index 6495211e04..899c7f2afe 100644 --- a/system/doc/design_principles/part.xml +++ b/system/doc/design_principles/part.xml @@ -4,7 +4,7 @@ <part xmlns:xi="http://www.w3.org/2001/XInclude"> <header> <copyright> - <year>1997</year><year>2016</year> + <year>1997</year><year>2017</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> @@ -30,7 +30,6 @@ </header> <xi:include href="des_princ.xml"/> <xi:include href="gen_server_concepts.xml"/> - <xi:include href="fsm.xml"/> <xi:include href="statem.xml"/> <xi:include href="events.xml"/> <xi:include href="sup_princ.xml"/> diff --git a/system/doc/design_principles/spec_proc.xml b/system/doc/design_principles/spec_proc.xml index 5b156ac263..5f4e7ac685 100644 --- a/system/doc/design_principles/spec_proc.xml +++ b/system/doc/design_principles/spec_proc.xml @@ -4,7 +4,7 @@ <chapter> <header> <copyright> - <year>1997</year><year>2016</year> + <year>1997</year><year>2017</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> @@ -45,61 +45,63 @@ <p>The <c>sys</c> module has functions for simple debugging of processes implemented using behaviours. The <c>code_lock</c> example from - <seealso marker="fsm#ex">gen_fsm Behaviour</seealso> + <seealso marker="statem#Example">gen_statem Behaviour</seealso> is used to illustrate this:</p> <pre> -% <input>erl</input> -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> <input>code_lock:start_link([1,2,3,4]).</input> -{ok,<0.32.0>} -2> <input>sys:statistics(code_lock, true).</input> +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> <input>sys:trace(code_lock, true).</input> +3> sys:trace(code_lock, true). ok -4> <input>code_lock:button(4).</input> -*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> <input>code_lock:button(3).</input> -*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> <input>code_lock:button(2).</input> -*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> <input>code_lock:button(1).</input> -*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> <input>sys:statistics(code_lock, get).</input> -{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> <input>sys:statistics(code_lock, false).</input> +9> sys:statistics(code_lock, false). ok -10> <input>sys:trace(code_lock, false).</input> +10> sys:trace(code_lock, false). ok -11> <input>sys:get_status(code_lock).</input> -{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]]}</pre> +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]}}}]}]]} + </pre> </section> <section> diff --git a/system/doc/design_principles/statem.xml b/system/doc/design_principles/statem.xml index 22b622ec5f..1006485e30 100644 --- a/system/doc/design_principles/statem.xml +++ b/system/doc/design_principles/statem.xml @@ -293,6 +293,13 @@ StateName(EventType, EventContent, Data) -> <seealso marker="#State Time-Outs">State Time-Outs</seealso> </item> <item> + Start a + <seealso marker="stdlib:gen_statem#type-generic_timeout"> + generic time-out</seealso>, + read more in section + <seealso marker="#Generic Time-Outs">Generic Time-Outs</seealso> + </item> + <item> Start an <seealso marker="stdlib:gen_statem#type-event_timeout">event time-out</seealso>, see more in section @@ -320,8 +327,9 @@ StateName(EventType, EventContent, Data) -> <c>gen_statem(3)</c> </seealso> manual page. - You can, for example, reply to many callers - and generate multiple next events to handle. + You can, for example, reply to many callers, + generate multiple next events, + and set time-outs to relative or absolute times. </p> </section> @@ -369,6 +377,14 @@ StateName(EventType, EventContent, Data) -> </seealso> state timer timing out. </item> + <tag><c>{timeout,Name}</c></tag> + <item> + Generated by state transition action + <seealso marker="stdlib:gen_statem#type-generic_timeout"> + <c>{{timeout,Name},Time,EventContent}</c> + </seealso> + generic timer timing out. + </item> <tag><c>timeout</c></tag> <item> Generated by state transition action @@ -395,14 +411,6 @@ StateName(EventType, EventContent, Data) -> <marker id="Example" /> <title>Example</title> <p> - This example starts off as equivalent to the example in section - <seealso marker="fsm"><c>gen_fsm</c> Behavior</seealso>. - In later sections, additions and tweaks are made - using features in <c>gen_statem</c> that <c>gen_fsm</c> does not have. - The end of this chapter provides the example again - with all the added features. - </p> - <p> A door with a code lock can be seen as a state machine. Initially, the door is locked. When someone presses a button, an event is generated. @@ -450,7 +458,7 @@ locked( [Digit] -> do_unlock(), {next_state, open, Data#{remaining := Code}, - [{state_timeout,10000,lock}]; + [{state_timeout,10000,lock}]}; [Digit|Rest] -> % Incomplete {next_state, locked, Data#{remaining := Rest}}; _Wrong -> @@ -779,7 +787,7 @@ handle_event(cast, {button,Digit}, State, #{code := Code} = Data) -> [Digit] -> % Complete do_unlock(), {next_state, open, Data#{remaining := Code}, - [{state_timeout,10000,lock}}; + [{state_timeout,10000,lock}]}; [Digit|Rest] -> % Incomplete {keep_state, Data#{remaining := Rest}}; [_|_] -> % Wrong @@ -873,7 +881,7 @@ stop() -> <marker id="Event Time-Outs" /> <title>Event Time-Outs</title> <p> - A timeout feature inherited from <c>gen_statem</c>'s predecessor + A time-out feature inherited from <c>gen_statem</c>'s predecessor <seealso marker="stdlib:gen_fsm"><c>gen_fsm</c></seealso>, is an event time-out, that is, if an event arrives the timer is cancelled. @@ -906,24 +914,24 @@ locked( ... ]]></code> <p> - Whenever we receive a button event we start an event timeout + Whenever we receive a button event we start an event time-out of 30 seconds, and if we get an event type <c>timeout</c> we reset the remaining code sequence. </p> <p> - 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. + An event time-out is cancelled by any other event so you either + get some other event or the time-out event. It is therefore + not possible nor needed to cancel or restart an event time-out. Whatever event you act on has already cancelled - the event timeout... + the event time-out... </p> </section> <!-- =================================================================== --> <section> - <marker id="Erlang Timers" /> - <title>Erlang Timers</title> + <marker id="Generic Time-Outs" /> + <title>Generic Time-Outs</title> <p> The previous example of state time-outs only work if the state machine stays in the same state during the @@ -934,13 +942,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 + <seealso marker="stdlib:gen_statem#type-generic_timeout">generic time-outs</seealso>. + They may look a little bit like + <seealso marker="stdlib:gen_statem#type-event_timeout">event time-outs</seealso> + but contain a name to allow for any number of them simultaneously + and they are not automatically cancelled. + </p> + <p> + Here is how to accomplish the state time-out + in the previous example by instead using a generic time-out + named <c>open_tm</c>: + </p> + <code type="erl"><![CDATA[ +... +locked( + cast, {button,Digit}, + #{code := Code, remaining := Remaining} = Data) -> + 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}; +... + ]]></code> + <p> + Just as + <seealso marker="#State Time-Outs">state time-outs</seealso> + you can restart or cancel a specific generic time-out + by setting it to a new time or <c>infinity</c>. + </p> + <p> + 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. + </p> + </section> + +<!-- =================================================================== --> + + <section> + <marker id="Erlang Timers" /> + <title>Erlang Timers</title> + <p> + The most versatile way to handle time-outs is to use + Erlang Timers; see <seealso marker="erts:erlang#start_timer/4"><c>erlang:start_timer3,4</c></seealso>. + Most time-out tasks can be performed with the + time-out features in <c>gen_statem</c>, + but an example of one that can not is if you should need + the return value from + <seealso marker="erts:erlang#cancel_timer/2"><c>erlang:cancel_timer(Tref)</c></seealso>, that is; the remaining time of the timer. </p> <p> 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: </p> <code type="erl"><![CDATA[ ... @@ -1511,10 +1574,12 @@ format_status(Opt, [_PDict,State,Data]) -> for example, a complex state term like a tuple. </p> <p> - 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 + <seealso marker="#State Time-Outs">state time-out</seealso>, + 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 <c>open</c> state immediately locks the door, @@ -1596,7 +1661,7 @@ 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( @@ -1614,8 +1679,8 @@ handle_event( {next_state, {open,LockButton}, Data, [{reply,From,ok}]}; [Digit|Rest] -> % Incomplete - {keep_state, Data#{remaining := Rest, 30000}, - [{reply,From,ok}]}; + {keep_state, Data#{remaining := Rest}, + [{reply,From,ok}, 30000]}; [_|_] -> % Wrong {keep_state, Data#{remaining := Code}, [{reply,From,ok}]} @@ -1636,7 +1701,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 +1775,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]}; ... ]]></code> <p> diff --git a/system/doc/design_principles/sup_princ.xml b/system/doc/design_principles/sup_princ.xml index 0a24e97950..06ca44a9f6 100644 --- a/system/doc/design_principles/sup_princ.xml +++ b/system/doc/design_principles/sup_princ.xml @@ -4,7 +4,7 @@ <chapter> <header> <copyright> - <year>1997</year><year>2016</year> + <year>1997</year><year>2017</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> @@ -163,7 +163,9 @@ SupFlags = #{strategy => Strategy, ...}</code> SupFlags = #{intensity => MaxR, period => MaxT, ...}</code> <p>If more than <c>MaxR</c> number of restarts occur in the last <c>MaxT</c> seconds, the supervisor terminates all the child - processes and then itself.</p> + processes and then itself. + The termination reason for the supervisor itself in that case will be + <c>shutdown</c>.</p> <p>When the supervisor terminates, then the next higher-level supervisor takes some action. It either restarts the terminated supervisor or terminates itself.</p> @@ -173,6 +175,69 @@ SupFlags = #{intensity => MaxR, period => MaxT, ...}</code> <p>The keys <c>intensity</c> and <c>period</c> are optional in the supervisor flags map. If they are not given, they default to <c>1</c> and <c>5</c>, respectively.</p> + <section> + <title>Tuning the intensity and period</title> + <p>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.</p> + <p>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.</p> + <p>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.</p> + <p>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.</p> + <p>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.</p> + <p>Avoiding common mistakes:</p> + <list type="bulleted"> + <item> + <p>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.</p> + </item> + <item> + <p>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.</p> + </item> + <item> + <p>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.</p> + <p>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.</p> + </item> + </list> + </section> </section> <section> @@ -211,7 +276,6 @@ child_spec() = #{id => child_id(), % mandatory <list type="bulleted"> <item><c>supervisor:start_link</c></item> <item><c>gen_server:start_link</c></item> - <item><c>gen_fsm:start_link</c></item> <item><c>gen_statem:start_link</c></item> <item><c>gen_event:start_link</c></item> <item>A function compliant with these functions. For details, @@ -276,7 +340,7 @@ child_spec() = #{id => child_id(), % mandatory <p><c>modules</c> are to be a list with one element <c>[Module]</c>, where <c>Module</c> 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 <c>dynamic</c>.</p> <p>This information is used by the release handler during diff --git a/system/doc/design_principles/warning.gif b/system/doc/design_principles/warning.gif Binary files differdeleted file mode 100644 index 96af52360e..0000000000 --- a/system/doc/design_principles/warning.gif +++ /dev/null diff --git a/system/doc/design_principles/xmlfiles.mk b/system/doc/design_principles/xmlfiles.mk index e476255d62..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. @@ -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/efficiency_guide/advanced.xml b/system/doc/efficiency_guide/advanced.xml index e1760d0ded..7f719849cc 100644 --- a/system/doc/efficiency_guide/advanced.xml +++ b/system/doc/efficiency_guide/advanced.xml @@ -151,7 +151,7 @@ <row> <cell>Processes</cell> <cell>The maximum number of simultaneously alive Erlang processes - is by default 32,768. This limit can be configured at startup. + is by default 262,144. This limit can be configured at startup. For more information, see the <seealso marker="erts:erl#max_processes"><c>+P</c></seealso> command-line flag in the @@ -264,21 +264,26 @@ </row> <row> <cell><marker id="unique_integers"/>Unique Integers on a Runtime System Instance</cell> - <cell>There are two types of unique integers both created using the - <seealso marker="erts:erlang#unique_integer/1">erlang:unique_integer()</seealso> - BIF. Unique integers created: - <taglist> - <tag>with the <c>monotonic</c> modifier</tag> - <item>consist of a set of <c>2⁶⁴ - 1</c> unique integers.</item> - <tag>without the <c>monotonic</c> modifier</tag> - <item>consist of a set of <c>2⁶⁴ - 1</c> unique integers per scheduler - thread and a set of <c>2⁶⁴ - 1</c> unique integers shared by - other threads. That is the total amount of unique integers without - the <c>monotonic</c> modifier is <c>(NoSchedulers + 1) * (2⁶⁴ - 1)</c></item> - </taglist> - If a unique integer is created each nano second, unique integers - will at earliest be reused after more than 584 years. That is, for - the foreseeable future they are unique enough.</cell> + <cell> + There are two types of unique integers both created using the + <seealso marker="erts:erlang#unique_integer/1">erlang:unique_integer()</seealso> + BIF: + <br/><br/> + <em>1.</em> Unique integers created <em>with</em> the + <c>monotonic</c> modifier consist of a set of <c>2⁶⁴ - 1</c> + unique integers. + <br/><br/> + <em>2.</em> Unique integers created <em>without</em> the + <c>monotonic</c> modifier consist of a set of <c>2⁶⁴ - 1</c> + unique integers per scheduler thread and a set of <c>2⁶⁴ - 1</c> + unique integers shared by other threads. That is, the total + amount of unique integers without the <c>monotonic</c> modifier + is <c>(NoSchedulers + 1) × (2⁶⁴ - 1)</c>. + <br/><br/> + If a unique integer is created each nano second, unique integers + will at earliest be reused after more than 584 years. That is, for + the foreseeable future they are unique enough. + </cell> </row> <tcaption>System Limits</tcaption> </table> 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, "<html>\n"), io:put_chars(OutputFile, "<head>\n"), diff --git a/system/doc/efficiency_guide/binaryhandling.xml b/system/doc/efficiency_guide/binaryhandling.xml index 0295d18644..19f40c9abe 100644 --- a/system/doc/efficiency_guide/binaryhandling.xml +++ b/system/doc/efficiency_guide/binaryhandling.xml @@ -5,7 +5,7 @@ <header> <copyright> <year>2007</year> - <year>2016</year> + <year>2017</year> <holder>Ericsson AB, All Rights Reserved</holder> </copyright> <legalnotice> @@ -32,12 +32,9 @@ <file>binaryhandling.xml</file> </header> - <p>In R12B, the most natural way to construct and match binaries is - significantly faster than in earlier releases.</p> + <p>Binaries can be efficiently built in the following way:</p> - <p>To construct a binary, you can simply write as follows:</p> - - <p><em>DO</em> (in R12B) / <em>REALLY DO NOT</em> (in earlier releases)</p> + <p><em>DO</em></p> <code type="erl"><![CDATA[ my_list_to_binary(List) -> my_list_to_binary(List, <<>>). @@ -47,21 +44,13 @@ my_list_to_binary([H|T], Acc) -> my_list_to_binary([], Acc) -> Acc.]]></code> - <p>In releases before R12B, <c>Acc</c> is copied in every iteration. - In R12B, <c>Acc</c> is copied only in the first iteration and extra - space is allocated at the end of the copied binary. In the next iteration, - <c>H</c> 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.</p> - - <p>The most natural way to match binaries is now the fastest:</p> + <p>Binaries can be efficiently matched like this:</p> - <p><em>DO</em> (in R12B)</p> + <p><em>DO</em></p> <code type="erl"><![CDATA[ my_binary_to_list(<<H,T/binary>>) -> [H|my_binary_to_list(T)]; -my_binary_to_list(<<>>) -> [].]]></code> +my_binary_to_list(<<>>) -> [].]]></code> <section> <title>How Binaries are Implemented</title> @@ -138,10 +127,7 @@ my_binary_to_list(<<>>) -> [].]]></code> pointer to the binary data. For each field that is matched out of a binary, the position in the match context is incremented.</p> - <p>In R11B, a match context was only used during a binary matching - operation.</p> - - <p>In R12B, the compiler tries to avoid generating code that + <p>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.</p> @@ -155,7 +141,7 @@ my_binary_to_list(<<>>) -> [].]]></code> <section> <title>Constructing Binaries</title> - <p>In R12B, appending to a binary or bitstring + <p>Appending to a binary or bitstring is specially optimized by the <em>runtime system</em>:</p> <code type="erl"><![CDATA[ @@ -292,7 +278,7 @@ Bin = <<Bin1,...>> %% Bin1 will be COPIED <p>Let us revisit the example in the beginning of the previous section:</p> - <p><em>DO</em> (in R12B)</p> + <p><em>DO</em></p> <code type="erl"><![CDATA[ my_binary_to_list(<<H,T/binary>>) -> [H|my_binary_to_list(T)]; @@ -304,15 +290,14 @@ my_binary_to_list(<<>>) -> [].]]></code> byte of the binary. 1 byte is matched out and the match context is updated to point to the second byte in the binary.</p> - <p>In R11B, at this point a - <seealso marker="#sub_binary">sub binary</seealso> - 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, + <p>At this point it would make sense to create a + <seealso marker="#sub_binary">sub binary</seealso>, + but in this particular example the compiler sees that + there will soon be a call to a function (in this case, to <c>my_binary_to_list/1</c> itself) that immediately will create a new match context and discard the sub binary.</p> - <p>Therefore, in R12B, <c>my_binary_to_list/1</c> calls itself + <p>Therefore <c>my_binary_to_list/1</c> 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.</p> @@ -321,34 +306,10 @@ my_binary_to_list(<<>>) -> [].]]></code> the match context will simply be discarded (removed in the next garbage collection, as there is no longer any reference to it).</p> - <p>To summarize, <c>my_binary_to_list/1</c> in R12B only needs to create - <em>one</em> match context and no sub binaries. In R11B, if the binary - contains <em>N</em> bytes, <em>N+1</em> match contexts and <em>N</em> - sub binaries are created.</p> - - <p>In R11B, the fastest way to match binaries is as follows:</p> + <p>To summarize, <c>my_binary_to_list/1</c> only needs to create + <em>one</em> match context and no sub binaries.</p> - <p><em>DO NOT</em> (in R12B)</p> - <code type="erl"><![CDATA[ -my_complicated_binary_to_list(Bin) -> - 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.]]></code> - - <p>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, - <c>my_complicated_binary_to_list/1</c> builds <em>N+1</em> match - contexts. (In a future Erlang/OTP release, the compiler might be able - to generate code that reuses the match context.)</p> - - <p>Returning to <c>my_binary_to_list/1</c>, notice that the match context + <p>Notice that the match context in <c>my_binary_to_list/1</c> 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?</p> @@ -544,5 +505,15 @@ count3(<<>>, Count) -> Count.]]></code> not matched out.</p> </section> </section> + + <section> + <title>Historical Note</title> + + <p>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.</p> + </section> + </chapter> diff --git a/system/doc/efficiency_guide/commoncaveats.xml b/system/doc/efficiency_guide/commoncaveats.xml index ecfeff0349..b41ffc3902 100644 --- a/system/doc/efficiency_guide/commoncaveats.xml +++ b/system/doc/efficiency_guide/commoncaveats.xml @@ -4,7 +4,7 @@ <chapter> <header> <copyright> - <year>2001</year><year>2016</year> + <year>2001</year><year>2017</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> @@ -148,10 +148,10 @@ multiple_setelement(T0) -> <p><c>size/1</c> returns the size for both tuples and binaries.</p> - <p>Using the new BIFs <c>tuple_size/1</c> and <c>byte_size/1</c>, 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.</p> + <p>Using the BIFs <c>tuple_size/1</c> and <c>byte_size/1</c> + gives the compiler and the runtime system more opportunities for + optimization. Another advantage is that the BIFs give Dialyzer more + type information.</p> </section> <section> diff --git a/system/doc/efficiency_guide/functions.xml b/system/doc/efficiency_guide/functions.xml index 4a8248e65c..0a8ee7eb34 100644 --- a/system/doc/efficiency_guide/functions.xml +++ b/system/doc/efficiency_guide/functions.xml @@ -4,7 +4,7 @@ <chapter> <header> <copyright> - <year>2001</year><year>2016</year> + <year>2001</year><year>2017</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> @@ -65,7 +65,7 @@ atom_map1(six) -> 6.</code> thus, quite efficient even if there are many values) to select which one of the first three clauses to execute (if any).</item> - <item>>If none of the first three clauses match, the fourth clause + <item>If none of the first three clauses match, the fourth clause match as a variable always matches.</item> <item>If the guard test <c>is_integer(Int)</c> succeeds, the fourth @@ -183,15 +183,6 @@ explicit_map_pairs(Map, Xs0, Ys0) -> A fun contains an (indirect) pointer to the function that implements the fun.</p> - <warning><p><em>Tuples are not fun(s)</em>. - A "tuple fun", <c>{Module,Function}</c>, is not a fun. - The cost for calling a "tuple fun" is similar to that - of <c>apply/3</c> or worse. - Using "tuple funs" is <em>strongly discouraged</em>, - as they might not be supported in a future Erlang/OTP release, - and because there exists a superior alternative from R10B, - namely the <c>fun Module:Function/Arity</c> syntax.</p></warning> - <p><c>apply/3</c> 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.</p> diff --git a/system/doc/efficiency_guide/introduction.xml b/system/doc/efficiency_guide/introduction.xml index ca4a41c798..dca2dec95e 100644 --- a/system/doc/efficiency_guide/introduction.xml +++ b/system/doc/efficiency_guide/introduction.xml @@ -4,7 +4,7 @@ <chapter> <header> <copyright> - <year>2001</year><year>2016</year> + <year>2001</year><year>2017</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> @@ -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.</p> - <p>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).</p> - <p>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. diff --git a/system/doc/efficiency_guide/listhandling.xml b/system/doc/efficiency_guide/listhandling.xml index 2ebc877820..4f2497359d 100644 --- a/system/doc/efficiency_guide/listhandling.xml +++ b/system/doc/efficiency_guide/listhandling.xml @@ -4,7 +4,7 @@ <chapter> <header> <copyright> - <year>2001</year><year>2016</year> + <year>2001</year><year>2017</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> @@ -90,7 +90,7 @@ tail_recursive_fib(N, Current, Next, Fibs) -> <p>Lists comprehensions still have a reputation for being slow. They used to be implemented using funs, which used to be slow.</p> - <p>In recent Erlang/OTP releases (including R12B), a list comprehension:</p> + <p>A list comprehension:</p> <code type="erl"><![CDATA[ [Expr(E) || E <- List]]]></code> @@ -102,7 +102,7 @@ tail_recursive_fib(N, Current, Next, Fibs) -> [Expr(E)|'lc^0'(Tail, Expr)]; 'lc^0'([], _Expr) -> [].</code> - <p>In R12B, if the result of the list comprehension will <em>obviously</em> + <p>If the result of the list comprehension will <em>obviously</em> not be used, a list will not be constructed. For example, in this code:</p> <code type="erl"><![CDATA[ @@ -131,6 +131,14 @@ some_function(...), 'lc^0'(Tail, Expr); 'lc^0'([], _Expr) -> [].</code> + <p>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:</p> + + <code type="erl"><![CDATA[ +_ = [io:put_chars(E) || E <- List], +ok.]]></code> + </section> <section> @@ -209,11 +217,11 @@ some_function(...), <section> <title>Recursive List Functions</title> - <p>In Section 7.2, the following myth was exposed: + <p>In section about myths, the following myth was exposed: <seealso marker="myths#tail_recursive">Tail-Recursive Functions are Much Faster Than Recursive Functions</seealso>.</p> - <p>To summarize, in R12B there is usually not much difference between + <p>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 diff --git a/system/doc/efficiency_guide/myths.xml b/system/doc/efficiency_guide/myths.xml index 5d3ad78b23..778cd06c09 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. </legalnotice> - <title>The Eight Myths of Erlang Performance</title> + <title>The Seven Myths of Erlang Performance</title> <prepared>Bjorn Gustavsson</prepared> <docno></docno> <date>2007-11-10</date> @@ -35,80 +35,33 @@ <marker id="myths"></marker> <p>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.</p> + than a single release note that says, for example, that body-recursive + calls have become faster.</p> <p>This section tries to kill the old truths (or semi-truths) that have become myths.</p> <section> - <title>Myth: Funs are Slow</title> - <p>Funs used to be very slow, slower than <c>apply/3</c>. - Originally, funs were implemented using nothing more than - compiler trickery, ordinary tuples, <c>apply/3</c>, and a great - deal of ingenuity.</p> - - <p>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 <c>apply/3</c>.</p> - </section> - - <section> - <title>Myth: List Comprehensions are Slow</title> - - <p>List comprehensions used to be implemented using funs, and in the - old days funs were indeed slow.</p> - - <p>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.</p> - </section> - - <section> <title>Myth: Tail-Recursive Functions are Much Faster Than Recursive Functions</title> <p><marker id="tail_recursive"></marker>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.</p> - - <p>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.</p> - - <p>Even after that optimization, a tail-recursive function is - still most of the times faster than a body-recursive function. Why?</p> - - <p>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.</p> - - <p>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 <seealso - marker="stdlib:lists#reverse/1">lists:reverse/1</seealso> at - the end will use the same amount of memory. - <c>lists:map/2</c>, <c>lists:filter/2</c>, list comprehensions, - and many other recursive functions now use the same amount of space - as their tail-recursive equivalents.</p> - - <p>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.</p> - - <p>So, the choice is now mostly a matter of taste. If you really do need - the utmost speed, you must <em>measure</em>. You can no longer be - sure that the tail-recursive list function always is the fastest.</p> + using a tail-recursive function that builds a list in reverse + followed by a call to <c>lists:reverse/1</c> 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.</p> + + <p>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).</p> + + <p>For a more thorough discussion about tail and body recursion, + see <url href="http://ferd.ca/erlang-s-tail-recursion-is-not-a-silver-bullet.html">Erlang's Tail Recursion is Not a Silver Bullet</url>.</p> <note><p>A tail-recursive function that does not need to reverse the list at the end is faster than a body-recursive function, @@ -199,6 +152,29 @@ vanilla_reverse([], Acc) -> <p>That was once true, but from R6B the BEAM compiler can see that a variable is not used.</p> + + <p>Similarly, trivial transformations on the source-code level + such as converting a <c>case</c> statement to clauses at the + top-level of the function seldom makes any difference to the + generated code.</p> + </section> + + <section> + <title>Myth: A NIF Always Speeds Up Your Program</title> + + <p>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.</p> + + <p>Doing too much work in each NIF call will + <seealso marker="erts:erl_nif#WARNING">degrade responsiveness + of the VM</seealso>. 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.</p> + + <p>Be sure to read about + <seealso marker="erts:erl_nif#lengthy_work">Long-running NIFs</seealso> + before writing a NIF.</p> </section> </chapter> 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 @@ <xi:include href="drivers.xml"/> <xi:include href="advanced.xml"/> <xi:include href="profiling.xml"/> + <xi:include href="retired_myths.xml"/> </part> diff --git a/system/doc/efficiency_guide/processes.xml b/system/doc/efficiency_guide/processes.xml index f2d9712f51..3b64c863ff 100644 --- a/system/doc/efficiency_guide/processes.xml +++ b/system/doc/efficiency_guide/processes.xml @@ -4,7 +4,7 @@ <chapter> <header> <copyright> - <year>2001</year><year>2016</year> + <year>2001</year><year>2017</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> @@ -146,14 +146,14 @@ loop() -> <section> <title>Constant Pool</title> - <p>Constant Erlang terms (also called <em>literals</em>) are now + <p>Constant Erlang terms (also called <em>literals</em>) 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:</p> - <p><em>DO</em> (in R12B and later)</p> + <p><em>DO</em></p> <code type="erl"> days_in_month(M) -> element(M, {31,28,31,30,31,30,31,31,30,31,30,31}).</code> @@ -222,7 +222,7 @@ kilo_byte(N, Acc) -> <pre> 4> <input>T = ets:new(tab, []).</input> -17 +#Ref<0.1662103692.2407923716.214181> 5> <input>ets:insert(T, {key,efficiency_guide:kilo_byte()}).</input> true 6> <input>erts_debug:size(element(2, hd(ets:lookup(T, key)))).</input> @@ -235,9 +235,7 @@ true return the same value. Sharing has been lost.</p> <p>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.</p> + way to (optionally) preserve sharing.</p> </section> </section> @@ -261,10 +259,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 <c>receive</c> statement.</p> - - <p>The <seealso marker="percept:percept">percept</seealso> application - can be used to profile your application to see how much potential (or lack - thereof) it has for concurrency.</p> </section> </chapter> diff --git a/system/doc/efficiency_guide/profiling.xml b/system/doc/efficiency_guide/profiling.xml index bf50a03fa6..f185456158 100644 --- a/system/doc/efficiency_guide/profiling.xml +++ b/system/doc/efficiency_guide/profiling.xml @@ -41,30 +41,87 @@ <p>Erlang/OTP contains several tools to help finding bottlenecks:</p> <list type="bulleted"> - <item><c>fprof</c> provides the most detailed information about - where the program time is spent, but it significantly slows down the - program it profiles.</item> - - <item><p><c>eprof</c> provides time information of each function - used in the program. No call graph is produced, but <c>eprof</c> has - considerable less impact on the program it profiles.</p> - <p>If the program is too large to be profiled by <c>fprof</c> or - <c>eprof</c>, the <c>cover</c> and <c>cprof</c> tools can be used - to locate code parts that are to be more thoroughly profiled using - <c>fprof</c> or <c>eprof</c>.</p></item> - - <item><c>cover</c> provides execution counts per line per - process, with less overhead than <c>fprof</c>. Execution counts - can, with some caution, be used to locate potential performance - bottlenecks.</item> - - <item><c>cprof</c> is the most lightweight tool, but it only - provides execution counts on a function basis (for all processes, - not per process).</item> + <item><p><seealso marker="tools:fprof"><c>fprof</c></seealso> provides + the most detailed information about where the program time is spent, + but it significantly slows down the program it profiles.</p></item> + + <item><p><seealso marker="tools:eprof"><c>eprof</c></seealso> provides + time information of each function used in the program. No call graph is + produced, but <c>eprof</c> has considerable less impact on the program it + profiles.</p> + <p>If the program is too large to be profiled by <c>fprof</c> or + <c>eprof</c>, <c>cprof</c> can be used to locate code parts that + are to be more thoroughly profiled using <c>fprof</c> or <c>eprof</c>.</p></item> + + <item><p><seealso marker="tools:cprof"><c>cprof</c></seealso> is the + most lightweight tool, but it only provides execution counts on a + function basis (for all processes, not per process).</p></item> + + <item><p><seealso marker="runtime_tools:dbg"><c>dbg</c></seealso> is the + generic erlang tracing frontend. By using the <c>timestamp</c> or + <c>cpu_timestamp</c> options it can be used to time how long function + calls in a live system take.</p></item> + + <item><p><seealso marker="tools:lcnt"><c>lcnt</c></seealso> is used + to find contention points in the Erlang Run-Time System's internal + locking mechanisms. It is useful when looking for bottlenecks in + interaction between process, port, ets tables and other entities + that can be run in parallel.</p></item> + </list> <p>The tools are further described in <seealso marker="#profiling_tools">Tools</seealso>.</p> + + <p>There are also several open source tools outside of Erlang/OTP + that can be used to help profiling. Some of them are:</p> + + <list type="bulleted"> + <item><url href="https://github.com/isacssouza/erlgrind">erlgrind</url> + can be used to visualize fprof data in kcachegrind.</item> + <item><url href="https://github.com/proger/eflame">eflame</url> + is an alternative to fprof that displays the profiling output as a flamegraph.</item> + <item><url href="https://ferd.github.io/recon/index.html">recon</url> + is a collection of Erlang profiling and debugging tools. + This tool comes with an accompanying E-book called + <url href="https://www.erlang-in-anger.com/">Erlang in Anger</url>.</item> + </list> + </section> + + <section> + <title>Memory profiling</title> + <pre>eheap_alloc: Cannot allocate 1234567890 bytes of memory (of type "heap").</pre> + <p>The above slogan is one of the more common reasons for Erlang to terminate. + For unknown reasons the Erlang Run-Time System failed to allocate memory to + use. When this happens a crash dump is generated that contains information + about the state of the system as it ran out of mmeory. Use the + <seealso marker="observer:cdv"><c>crashdump_viewer</c></seealso> to get a + view of the memory is being used. Look for processes with large heaps or + many messages, large ets tables, etc.</p> + <p>When looking at memory usage in a running system the most basic function + to get information from is <seealso marker="erts:erlang#memory/0"><c> + erlang:memory()</c></seealso>. It returns the current memory usage + of the system. <seealso marker="tools:instrument"><c>instrument(3)</c></seealso> + can be used to get a more detailed breakdown of where memory is used.</p> + <p>Processes, ports and ets tables can then be inspecting using their + respective info functions, i.e. + <seealso marker="erts:erlang#process_info_memory"><c>erlang:process_info/2 + </c></seealso>, + <seealso marker="erts:erlang#port_info_memory"><c>erlang:port_info/2 + </c></seealso> and + <seealso marker="stdlib:ets#info/1"><c>ets:info/1</c></seealso>. + </p> + <p>Sometimes the system can enter a state where the reported memory + from <c>erlang:memory(total)</c> is very different from the + memory reported by the OS. This can be because of internal + fragmentation within the Erlang Run-Time System. Data about + how memory is allocated can be retrieved using + <seealso marker="erts:erlang#system_info_allocator"> + <c>erlang:system_info(allocator)</c></seealso>. + The data you get from that function is very raw and not very plesant to read. + <url href="http://ferd.github.io/recon/recon_alloc.html">recon_alloc</url> + can be used to extract useful information from system_info + statistics counters.</p> </section> <section> @@ -80,6 +137,22 @@ tools on the whole system. Instead you want to concentrate on central processes and modules, which contribute for a big part of the execution.</p> + + <p>There are also some tools that can be used to get a view of the + whole system with more or less overhead.</p> + <list type="bulleted"> + <item><seealso marker="observer:observer"><c>observer</c></seealso> + is a GUI tool that can connect to remote nodes and display a + variety of information about the running system.</item> + <item><seealso marker="observer:etop"><c>etop</c></seealso> + is a command line tool that can connect to remote nodes and + display information similar to what the UNIX tool top shows.</item> + <item><seealso marker="runtime_tools:msacc"><c>msacc</c></seealso> + allows the user to get a view of what the Erlang Run-Time system + is spending its time doing. Has a very low overhead, which makes it + useful to run in heavily loaded systems to get some idea of where + to start doing more granular profiling.</item> + </list> </section> <section> @@ -128,7 +201,7 @@ performance impact. Using <c>fprof</c> is just a matter of calling a few library functions, see the <seealso marker="tools:fprof">fprof</seealso> manual page in - Tools .<c>fprof</c> was introduced in R8.</p> + Tools.</p> </section> <section> @@ -142,20 +215,6 @@ </section> <section> - <title>cover</title> - <p>The primary use of <c>cover</c> is coverage analysis to verify - test cases, making sure that all relevant code is covered. - <c>cover</c> counts how many times each executable line of code - is executed when a program is run, on a per module basis.</p> - <p>Clearly, this information can be used to determine what - code is run very frequently and can therefore be subject for - optimization. Using <c>cover</c> is just a matter of calling a - few library functions, see the - <seealso marker="tools:cover">cover</seealso> manual page in - Tools.</p> - </section> - - <section> <title>cprof</title> <p><c>cprof</c> is something in between <c>fprof</c> and <c>cover</c> regarding features. It counts how many times each @@ -202,16 +261,6 @@ <cell>No</cell> </row> <row> - <cell><c>cover</c></cell> - <cell>Per module to screen/file</cell> - <cell>Small</cell> - <cell>Moderate slowdown</cell> - <cell>Yes, per line</cell> - <cell>No</cell> - <cell>No</cell> - <cell>No</cell> - </row> - <row> <cell><c>cprof</c></cell> <cell>Per module to caller</cell> <cell>Small</cell> @@ -224,6 +273,37 @@ <tcaption>Tool Summary</tcaption> </table> </section> + + <section> + <title>dbg</title> + <p><c>dbg</c> is a generic Erlang trace tool. By using the + <c>timestamp</c> or <c>cpu_timestamp</c> options it can be used + as a precision instrument to profile how long time a function + call takes for a specific process. This can be very useful when + trying to understand where time is spent in a heavily loaded + system as it is possible to limit the scope of what is profiled + to be very small. + For more information, see the + <seealso marker="runtime_tools:dbg">dbg</seealso> manual page in + Runtime Tools.</p> + </section> + + <section> + <title>lcnt</title> + <p><c>lcnt</c> is used to profile interactions inbetween + entities that run in parallel. For example if you have + a process that all other processes in the system needs + to interact with (maybe it has some global configuration), + then <c>lcnt</c> can be used to figure out if the interaction + with that process is a problem.</p> + <p>In the Erlang Run-time System entities are only run in parallel + when there are multiple schedulers. Therefore <c>lcnt</c> will + show more contention points (and thus be more useful) on systems + using many schedulers on many cores.</p> + <p>For more information, see the + <seealso marker="tools:lcnt">lcnt</seealso> manual page in Tools.</p> + </section> + </section> <section> @@ -282,4 +362,3 @@ </list> </section> </chapter> - diff --git a/system/doc/efficiency_guide/retired_myths.xml b/system/doc/efficiency_guide/retired_myths.xml new file mode 100644 index 0000000000..9b914a3b6e --- /dev/null +++ b/system/doc/efficiency_guide/retired_myths.xml @@ -0,0 +1,63 @@ +<?xml version="1.0" encoding="utf-8" ?> +<!DOCTYPE chapter SYSTEM "chapter.dtd"> + +<chapter> + <header> + <copyright> + <year>2016</year> + <year>2017</year> + <holder>Ericsson AB, All Rights Reserved</holder> + </copyright> + <legalnotice> + 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. + </legalnotice> + <title>Retired Myths</title> + <prepared>Bjorn Gustavsson</prepared> + <docno></docno> + <date>2016-06-07</date> + <rev></rev> + <file>retired_myths.xml</file> + </header> + + <p>We belive that the truth finally has caught with the following, + retired myths.</p> + + <section> + <marker id="retired_myths"/> + <title>Myth: Funs are Slow</title> + <p>Funs used to be very slow, slower than <c>apply/3</c>. + Originally, funs were implemented using nothing more than + compiler trickery, ordinary tuples, <c>apply/3</c>, and a great + deal of ingenuity.</p> + + <p>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 <c>apply/3</c>.</p> + </section> + + <section> + <title>Myth: List Comprehensions are Slow</title> + + <p>List comprehensions used to be implemented using funs, and in the + old days funs were indeed slow.</p> + + <p>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.</p> + </section> +</chapter> diff --git a/system/doc/efficiency_guide/xmlfiles.mk b/system/doc/efficiency_guide/xmlfiles.mk index 88df9417f5..23c0d991b4 100644 --- a/system/doc/efficiency_guide/xmlfiles.mk +++ b/system/doc/efficiency_guide/xmlfiles.mk @@ -29,5 +29,5 @@ EFF_GUIDE_CHAPTER_FILES = \ processes.xml \ profiling.xml \ tablesDatabases.xml \ - drivers.xml - + drivers.xml \ + retired_myths.xml diff --git a/system/doc/embedded/note.gif b/system/doc/embedded/note.gif Binary files differdeleted file mode 100644 index 6fffe30419..0000000000 --- a/system/doc/embedded/note.gif +++ /dev/null diff --git a/system/doc/embedded/warning.gif b/system/doc/embedded/warning.gif Binary files differdeleted file mode 100644 index 96af52360e..0000000000 --- a/system/doc/embedded/warning.gif +++ /dev/null diff --git a/system/doc/getting_started/conc_prog.xml b/system/doc/getting_started/conc_prog.xml index f3136898ad..7936e0d484 100644 --- a/system/doc/getting_started/conc_prog.xml +++ b/system/doc/getting_started/conc_prog.xml @@ -4,7 +4,7 @@ <chapter> <header> <copyright> - <year>2003</year><year>2016</year> + <year>2003</year><year>2017</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> @@ -355,8 +355,8 @@ pong ! {ping, self()},</code> <p>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 <em>magic cookie</em>. The easiest way to achieve this is by having a file called <c>.erlang.cookie</c> in your home diff --git a/system/doc/installation_guide/note.gif b/system/doc/installation_guide/note.gif Binary files differdeleted file mode 100644 index 6fffe30419..0000000000 --- a/system/doc/installation_guide/note.gif +++ /dev/null diff --git a/system/doc/installation_guide/warning.gif b/system/doc/installation_guide/warning.gif Binary files differdeleted file mode 100644 index 96af52360e..0000000000 --- a/system/doc/installation_guide/warning.gif +++ /dev/null diff --git a/system/doc/oam/note.gif b/system/doc/oam/note.gif Binary files differdeleted file mode 100644 index 6fffe30419..0000000000 --- a/system/doc/oam/note.gif +++ /dev/null diff --git a/system/doc/oam/oam_intro.xml b/system/doc/oam/oam_intro.xml index 8b8d69e638..ead8c026b9 100644 --- a/system/doc/oam/oam_intro.xml +++ b/system/doc/oam/oam_intro.xml @@ -4,7 +4,7 @@ <chapter> <header> <copyright> - <year>1997</year><year>2016</year> + <year>1997</year><year>2017</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> @@ -211,7 +211,7 @@ snmp:c("MY-MIB", [{il, ["sasl/priv/mibs"]}]).</code> <p>The following MIBs are defined in the OTP system:</p> <list type="bulleted"> - <item><p><c>OTP-REG)</c> (in SASL) contains the top-level + <item><p><c>OTP-REG</c> (in SASL) contains the top-level OTP registration objects, used by all other MIBs.</p></item> <item><p><c>OTP-TC</c> (in SASL) contains the general Textual Conventions, which can be used by any other MIB.</p></item> @@ -243,8 +243,8 @@ snmp:c("MY-MIB", [{il, ["sasl/priv/mibs"]}]).</code> loading the MIBs into the agent. Some MIB implementations are code-only, while others need a server. One way, used by the code-only MIB implementations, is for the user to call a - function such as <c>otp_mib:init(Agent)</c> to load the MIB, - and <c>otp_mib:stop(Agent)</c> to unload the MIB. See the + function such as <c>otp_mib:load(Agent)</c> to load the MIB, + and <c>otp_mib:unload(Agent)</c> to unload the MIB. See the manual page for each application for a description of how to load each MIB.</p> </section> diff --git a/system/doc/oam/warning.gif b/system/doc/oam/warning.gif Binary files differdeleted file mode 100644 index 96af52360e..0000000000 --- a/system/doc/oam/warning.gif +++ /dev/null diff --git a/system/doc/programming_examples/bit_syntax.xml b/system/doc/programming_examples/bit_syntax.xml index 0af295b7b7..d1dd52c5ab 100644 --- a/system/doc/programming_examples/bit_syntax.xml +++ b/system/doc/programming_examples/bit_syntax.xml @@ -4,7 +4,7 @@ <chapter> <header> <copyright> - <year>2003</year><year>2015</year> + <year>2003</year><year>2017</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> @@ -32,6 +32,8 @@ <section> <title>Introduction</title> + <p>The complete specification for the bit syntax appears in the + <seealso marker="doc/reference_manual:expressions#bit_syntax">Reference Manual</seealso>.</p> <p>In Erlang, a Bin is used for constructing binaries and matching binary patterns. A Bin is written with the following syntax:</p> <code type="none"><![CDATA[ @@ -45,7 +47,7 @@ Bin = <<E1, E2, ... En>>]]></code> <<E1, E2, ... En>> = Bin ]]></code> <p>Here, <c>Bin</c> is bound and the elements are bound or unbound, as in any match.</p> - <p>Since Erlang R12B, a Bin does not need to consist of a whole number of bytes.</p> + <p>A Bin does not need to consist of a whole number of bytes.</p> <p>A <em>bitstring</em> is a sequence of zero or more bits, where the number of bits does not need to be divisible by 8. If the number @@ -165,8 +167,9 @@ end.]]></code> separated by hyphens.</p> <taglist> <tag>Type</tag> - <item>The type can be <c>integer</c>, <c>float</c>, or - <c>binary</c>.</item> + <item>The most commonly used types are <c>integer</c>, <c>float</c>, and <c>binary</c>. + See <seealso marker="doc/reference_manual:expressions#bit_syntax">Bit Syntax Expressions in the Reference Manual</seealso> for a complete description. +</item> <tag>Signedness</tag> <item>The signedness specification can be either <c>signed</c> or <c>unsigned</c>. Notice that signedness only matters for @@ -181,7 +184,7 @@ end.]]></code> <item>The unit size is given as <c>unit:IntegerLiteral</c>. The allowed range is 1-256. It is multiplied by the <c>Size</c> 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.</item> </taglist> <p><em>Example:</em></p> @@ -319,21 +322,15 @@ foo(<<A:8,Rest/bitstring>>) ->]]></code> <section> <title>Appending to a Binary</title> - <p>Since Erlang R12B, the following function for creating a binary out of - a list of triples of integers is efficient:</p> + <p>Appending to a binary in an efficient way can be done as follows:</p> <code type="none"><![CDATA[ triples_to_bin(T) -> triples_to_bin(T, <<>>). triples_to_bin([{X,Y,Z} | T], Acc) -> - triples_to_bin(T, <<Acc/binary,X:32,Y:32,Z:32>>); % inefficient before R12B + triples_to_bin(T, <<Acc/binary,X:32,Y:32,Z:32>>); triples_to_bin([], Acc) -> Acc.]]></code> - <p>In previous releases, this function was highly inefficient, because - the binary constructed so far (<c>Acc</c>) was copied in each recursion step. - That is no longer the case. For more information, see - <seealso marker="doc/efficiency_guide:introduction"> - Efficiency Guide</seealso>.</p> </section> </chapter> diff --git a/system/doc/reference_manual/character_set.xml b/system/doc/reference_manual/character_set.xml index d25f2c001d..ef14bf1372 100644 --- a/system/doc/reference_manual/character_set.xml +++ b/system/doc/reference_manual/character_set.xml @@ -4,7 +4,7 @@ <chapter> <header> <copyright> - <year>2014</year><year>2015</year> + <year>2014</year><year>2017</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> @@ -32,9 +32,9 @@ <section> <title>Character Set</title> - <p>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:</p> + <p>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:</p> <list type="bulleted"> <item> <p>All the Latin-1 printable characters can be used and are @@ -102,13 +102,16 @@ <tcaption>Character Classes</tcaption> </table> <p>In Erlang/OTP R16B the syntax of Erlang tokens was extended to - handle Unicode. The support is limited to - string literals and comments. Atoms, module names, and - function names are restricted to the ISO-Latin-1 range. + handle Unicode. The support was limited to + string literals and comments. More about the usage of Unicode in Erlang source files can be found in <seealso marker="stdlib:unicode_usage#unicode_in_erlang">STDLIB's User's Guide</seealso>.</p> + <p>From Erlang/OTP 20, atoms and function names are also allowed + to contain Unicode characters outside the ISO-Latin-1 range. + Module names, application names, and node names are still + restricted to the ISO-Latin-1 range.</p> </section> <section> <title>Source File Encoding</title> diff --git a/system/doc/reference_manual/data_types.xml b/system/doc/reference_manual/data_types.xml index e63825b97d..93c679357b 100644 --- a/system/doc/reference_manual/data_types.xml +++ b/system/doc/reference_manual/data_types.xml @@ -4,7 +4,7 @@ <chapter> <header> <copyright> - <year>2003</year><year>2015</year> + <year>2003</year><year>2017</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> @@ -50,10 +50,7 @@ <item><em><c>base</c></em><c>#</c><em><c>value</c></em> <br></br> Integer with the base <em><c>base</c></em>, that must be an - integer in the range 2..36. <br></br> - - In Erlang 5.2/OTP R9B and earlier versions, the allowed range - is 2..16.</item> + integer in the range 2..36.</item> </list> <p><em>Examples:</em></p> <pre> @@ -455,7 +452,7 @@ hello <<"77">> 16> <input>float_to_binary(7.0).</input> <<"7.00000000000000000000e+00">> -17> <input>binary_to_float(<<"7.000e+00>>").</input> +17> <input>binary_to_float(<<"7.000e+00">>).</input> 7.0</pre> </section> </chapter> diff --git a/system/doc/reference_manual/distributed.xml b/system/doc/reference_manual/distributed.xml index 0a4a323fe9..b519609717 100644 --- a/system/doc/reference_manual/distributed.xml +++ b/system/doc/reference_manual/distributed.xml @@ -4,7 +4,7 @@ <chapter> <header> <copyright> - <year>2003</year><year>2015</year> + <year>2003</year><year>2017</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> @@ -42,6 +42,19 @@ <p>The distribution mechanism is implemented using TCP/IP sockets. How to implement an alternative carrier is described in the <seealso marker="erts:alt_dist">ERTS User's Guide</seealso>.</p> + <warning> + <p> + Starting a distributed node without also specifying + <seealso marker="erts:erl#proto_dist"><c>-proto_dist inet_tls</c></seealso> + 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 <seealso marker="ssl:ssl_distribution"> + Using SSL for Erlang Distribution</seealso> User's Guide + for details on how to setup a secure distributed node. + </p> + </warning> </section> <section> diff --git a/system/doc/reference_manual/errors.xml b/system/doc/reference_manual/errors.xml index e764cf431f..b16c5da6eb 100644 --- a/system/doc/reference_manual/errors.xml +++ b/system/doc/reference_manual/errors.xml @@ -4,7 +4,7 @@ <chapter> <header> <copyright> - <year>2003</year><year>2015</year> + <year>2003</year><year>2017</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> @@ -49,8 +49,7 @@ The Erlang programming language has built-in features for handling of run-time errors.</p> <p>A run-time error can also be emulated by calling - <c>erlang:error(Reason)</c> or <c>erlang:error(Reason, Args)</c> - (those appeared in Erlang 5.4/OTP-R10).</p> + <c>erlang:error(Reason)</c> or <c>erlang:error(Reason, Args)</c>.</p> <p>A run-time error is another name for an exception of class <c>error</c>. </p> @@ -79,7 +78,6 @@ <p>Exceptions are run-time errors or generated errors and are of three different classes, with different origins. The <seealso marker="expressions#try">try</seealso> expression - (new in Erlang 5.4/OTP R10B) can distinguish between the different classes, whereas the <seealso marker="expressions#catch">catch</seealso> expression cannot. They are described in @@ -94,7 +92,7 @@ <cell align="left" valign="middle"><c>error</c></cell> <cell align="left" valign="middle">Run-time error, for example, <c>1+a</c>, or the process called - <c>erlang:error/1,2</c> (new in Erlang 5.4/OTP R10B)</cell> + <c>erlang:error/1,2</c></cell> </row> <row> <cell align="left" valign="middle"><c>exit</c></cell> @@ -111,7 +109,7 @@ and a stack trace (which aids in finding the code location of the exception).</p> <p>The stack trace can be retrieved using - <c>erlang:get_stacktrace/0</c> (new in Erlang 5.4/OTP R10B) + <c>erlang:get_stacktrace/0</c> from within a <c>try</c> expression, and is returned for exceptions of class <c>error</c> from a <c>catch</c> expression.</p> <p>An exception of class <c>error</c> is also known as a run-time diff --git a/system/doc/reference_manual/expressions.xml b/system/doc/reference_manual/expressions.xml index 1a3d19aed1..cf2d5034aa 100644 --- a/system/doc/reference_manual/expressions.xml +++ b/system/doc/reference_manual/expressions.xml @@ -4,7 +4,7 @@ <chapter> <header> <copyright> - <year>2003</year><year>2016</year> + <year>2003</year><year>2017</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> @@ -123,10 +123,9 @@ member(_Elem, []) -> or <c>receive</c> expression must be bound in all branches to have a value outside the expression. Otherwise they are regarded as 'unsafe' outside the expression.</p> - <p>For the <c>try</c> expression introduced in - Erlang 5.4/OTP R10B, variable scoping is limited so that + <p>For the <c>try</c> expression variable scoping is limited so that variables bound in the expression are always 'unsafe' outside - the expression. This is to be improved.</p> + the expression.</p> </section> <section> @@ -189,7 +188,6 @@ f([$p,$r,$e,$f,$i,$x | Str]) -> ...</pre> <pre> case {Value, Result} of {?THRESHOLD+1, ok} -> ...</pre> - <p>This feature was added in Erlang 5.0/OTP R7.</p> </section> </section> @@ -1348,8 +1346,8 @@ catch ExceptionBodyN end</code> <p>This is an enhancement of - <seealso marker="#catch">catch</seealso> that appeared in - Erlang 5.4/OTP R10B. It gives the possibility to:</p> + <seealso marker="#catch">catch</seealso>. + It gives the possibility to:</p> <list type="bulleted"> <item>Distinguish between different exception classes.</item> <item>Choose to handle only the desired ones.</item> diff --git a/system/doc/reference_manual/introduction.xml b/system/doc/reference_manual/introduction.xml index abb4ed407d..afbdfa7434 100644 --- a/system/doc/reference_manual/introduction.xml +++ b/system/doc/reference_manual/introduction.xml @@ -4,7 +4,7 @@ <chapter> <header> <copyright> - <year>2003</year><year>2015</year> + <year>2003</year><year>2017</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> @@ -80,14 +80,14 @@ <item>A <em>list</em> is any number of items. For example, an argument list can consist of zero, one, or more arguments.</item> </list> - <p>If a feature has been added recently, in Erlang 5.0/OTP R7 or - later, this is mentioned in the text.</p> + <p>If a feature has been added in R13A or later, + this is mentioned in the text.</p> </section> <section> <title>Complete List of BIFs</title> <p>For a complete list of BIFs, their arguments and return values, - see <seealso marker="erts:erlang#process_flag/2">erlang(3)</seealso> + see <seealso marker="erts:erlang">erlang(3)</seealso> manual page in ERTS.</p> </section> diff --git a/system/doc/reference_manual/macros.xml b/system/doc/reference_manual/macros.xml index 5f24473557..a341307ab7 100644 --- a/system/doc/reference_manual/macros.xml +++ b/system/doc/reference_manual/macros.xml @@ -4,7 +4,7 @@ <chapter> <header> <copyright> - <year>2003</year><year>2016</year> + <year>2003</year><year>2017</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> @@ -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 <c>#arg</c> stringifying construction in C.</p> - <p>The feature was added in Erlang 5.0/OTP R7.</p> <p><em>Example:</em></p> <code type="none"> -define(TESTCALL(Call), io:format("Call ~s: ~w~n", [??Call, Call])). diff --git a/system/doc/reference_manual/modules.xml b/system/doc/reference_manual/modules.xml index 96968b547e..4a97bfeb7b 100644 --- a/system/doc/reference_manual/modules.xml +++ b/system/doc/reference_manual/modules.xml @@ -4,7 +4,7 @@ <chapter> <header> <copyright> - <year>2003</year><year>2016</year> + <year>2003</year><year>2017</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> @@ -143,7 +143,6 @@ fact(0) -> % | standard behaviours:</p> <list type="bulleted"> <item><c>gen_server</c></item> - <item><c>gen_fsm</c></item> <item><c>gen_statem</c></item> <item><c>gen_event</c></item> <item><c>supervisor</c></item> diff --git a/system/doc/reference_manual/records.xml b/system/doc/reference_manual/records.xml index 12a3e697cd..6b26e2c242 100644 --- a/system/doc/reference_manual/records.xml +++ b/system/doc/reference_manual/records.xml @@ -4,7 +4,7 @@ <chapter> <header> <copyright> - <year>2003</year><year>2015</year> + <year>2003</year><year>2017</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> @@ -72,9 +72,9 @@ <pre> #Name{Field1=Expr1,...,FieldK=ExprK, _=ExprL}</pre> <p>Omitted fields then get the value of evaluating <c>ExprL</c> - 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.</p> + instead of their default values. This feature is primarily + intended to be used to create patterns for ETS and Mnesia match + functions.</p> <p><em>Example:</em></p> <pre> -record(person, {name, phone, address}). diff --git a/system/doc/reference_manual/typespec.xml b/system/doc/reference_manual/typespec.xml index a0ea41cb3b..f6a19397c3 100644 --- a/system/doc/reference_manual/typespec.xml +++ b/system/doc/reference_manual/typespec.xml @@ -4,7 +4,7 @@ <chapter> <header> <copyright> - <year>2003</year><year>2016</year> + <year>2003</year><year>2017</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> @@ -133,17 +133,17 @@ Map :: map() %% denotes a map of any size | #{} %% denotes the empty map - | #{PairList} + | #{AssociationList} Tuple :: tuple() %% denotes a tuple of any size | {} | {TList} - PairList :: Pair - | Pair, PairList + AssociationList :: Association + | Association, AssociationList - Pair :: Type := Type %% denotes a mandatory pair - | Type => Type %% denotes an optional pair + Association :: Type := Type %% denotes a mandatory association + | Type => Type %% denotes an optional association TList :: Type | Type, TList @@ -173,14 +173,17 @@ The notation <c>[]</c> specifies the singleton type for the empty list. </p> <p> - The general form of maps is <c>#{PairList}</c>. The key types in - <c>PairList</c> are allowed to overlap, and if they do, the - leftmost pair takes precedence. A map pair has a key in - <c>PairList</c> if it belongs to this type. A <c>PairList</c> 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. + The general form of map types is <c>#{AssociationList}</c>. + The key types in + <c>AssociationList</c> are allowed to overlap, and if they do, the + leftmost association takes precedence. A map association has a key in + <c>AssociationList</c> if it belongs to this type. + <c>AssociationList</c> can contain both mandatory and optional + association types. + If an association type is mandatory, an association with that type + is to be present. + In the case of an optional association type it is not required for + the key type to be present. </p> <p> Notice that the syntactic representation of <c>map()</c> is @@ -512,8 +515,8 @@ <p> Currently, the <c>::</c> constraint (read as «is a subtype of») is - the only guard constraint that can be used in the <c>'when'</c> - part of a <c>'-spec'</c> attribute. + the only guard constraint that can be used in the <c>when</c> + part of a <c>-spec</c> attribute. </p> <note> <p> diff --git a/system/doc/reference_manual/xmlfiles.mk b/system/doc/reference_manual/xmlfiles.mk index 61637ae701..fffcbdd911 100644 --- a/system/doc/reference_manual/xmlfiles.mk +++ b/system/doc/reference_manual/xmlfiles.mk @@ -30,5 +30,6 @@ REF_MAN_CHAPTER_FILES = \ processes.xml \ distributed.xml \ code_loading.xml \ - ports.xml - + ports.xml \ + character_set.xml \ + typespec.xml diff --git a/system/doc/system_architecture_intro/note.gif b/system/doc/system_architecture_intro/note.gif Binary files differdeleted file mode 100644 index 6fffe30419..0000000000 --- a/system/doc/system_architecture_intro/note.gif +++ /dev/null diff --git a/system/doc/system_architecture_intro/warning.gif b/system/doc/system_architecture_intro/warning.gif Binary files differdeleted file mode 100644 index 96af52360e..0000000000 --- a/system/doc/system_architecture_intro/warning.gif +++ /dev/null diff --git a/system/doc/system_principles/warning.gif b/system/doc/system_principles/warning.gif Binary files differdeleted file mode 100644 index 96af52360e..0000000000 --- a/system/doc/system_principles/warning.gif +++ /dev/null diff --git a/system/doc/top/Makefile b/system/doc/top/Makefile index 0f4307bdfb..42309a0936 100644 --- a/system/doc/top/Makefile +++ b/system/doc/top/Makefile @@ -50,6 +50,8 @@ include ../tutorial/xmlfiles.mk include ../design_principles/xmlfiles.mk include ../oam/xmlfiles.mk +BOOK_FILES = book.xml + XML_FILES = \ $(INST_GUIDE_CHAPTER_FILES:%=../installation_guide/%) \ $(SYSTEM_PRINCIPLES_CHAPTER_FILES:%=../system_principles/%) \ @@ -70,9 +72,9 @@ XML_FILES = \ ../efficiency_guide/part.xml \ ../tutorial/part.xml \ ../design_principles/part.xml \ - ../oam/part.xml + ../oam/part.xml \ + $(BOOK_FILES) -BOOK_FILES = book.xml XMLLINT_SRCDIRS= ../installation_guide:../system_principles:../embedded:../getting_started:../reference_manual:../programming_examples:../efficiency_guide:../tutorial:../design_principles:../oam HTMLDIR= ../html diff --git a/system/doc/top/src/erl_html_tools.erl b/system/doc/top/src/erl_html_tools.erl index d55c2e1164..dee1871342 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) -> [ - "<table border=0 width=\"90%\" cellspacing=3 cellpadding=5>\n", - subst_groups(Info), - "</table>\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) -> - [ - " <tr>\n", - " <td colspan=2 class=header>\n", - " <font size=\"+1\"><b>",Heading,"</b></font>\n", - " </td>\n", - " </tr>\n", + ["<h2>",Heading,"</h2>", + "<table class=\"group-table\">\n", subst_apps(Apps), - " <tr>\n", - " <td colspan=2><font size=1> </font></td>\n", - " </tr>\n" + "</table>\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}]) -> [ " <tr class=app>\n", - " <td align=left valign=top>\n", - " <table border=0 width=\"100%\" cellspacing=0 cellpadding=0>\n", - " <tr class=app>\n", - " <td align=left valign=top>\n", + " <td>\n", " <a href=\"",Link,"\" target=\"_top\">",uc(App),"</a>\n", " <a href=\"",Link,"\" target=\"_top\">",VSN,"</a>\n", - " </td>\n", - " </tr>\n", - " </table>\n" " </td>\n", - " <td align=left valign=top>\n", + " <td>\n", Text,"\n", " </td>\n", " </tr>\n" @@ -518,27 +504,14 @@ subst_app(App, [{VSN,_Path,Link,Text}]) -> subst_app(App, [{VSN,_Path,Link,Text} | VerInfos]) -> [ " <tr class=app>\n", - " <td align=left valign=top>\n", - " <table border=0 width=\"100%\" cellspacing=0 cellpadding=0>\n", - " <tr class=app>\n", - " <td align=left valign=top>\n", + " <td>\n", " <a href=\"",Link,"\" target=\"_top\">",uc(App), - "</a> <br>\n", + "</a>\n", " <a href=\"",Link,"\" target=\"_top\">",VSN,"</a>\n", - " </td>\n", - " <td align=right valign=top width=50>\n", - " <table border=0 width=40 cellspacing=0 cellpadding=0>\n", - " <tr class=app>\n", - " <td align=left valign=top class=appnums>\n", + " <br/>\n", subst_vsn(VerInfos), - " </td>\n", - " </tr>\n", - " </table>\n" - " </td>\n", - " </tr>\n", - " </table>\n" " </td>\n", - " <td align=left valign=top>\n", + " <td>\n", Text,"\n", " </td>\n", " </tr>\n" @@ -549,7 +522,7 @@ subst_vsn([{VSN,_Path,Link,_Text} | VSNs]) -> [ " <font size=\"2\"><a class=anum href=\"",Link,"\" target=\"_top\">", VSN, - "</a></font><br>\n", + "</a></font><br/>\n", subst_vsn(VSNs) ]; subst_vsn([]) -> 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, " <TR>\n",[]), - io:fwrite(Out, " <TD><A HREF=\"~s\">~s</A></TD>\n", + io:fwrite(Out, " <tr>\n",[]), + io:fwrite(Out, " <td><a href=\"~s\">~s</a></td>\n", [RefPagePath, Module]), - io:fwrite(Out, " <TD><A HREF=\"~s\">~s</A></TD>\n", + io:fwrite(Out, " <td><a HREF=\"~s\">~s</a></td>\n", [filename:join(AppDocDir, "index.html"), App]), io:fwrite(Out, " </TR>\n",[]) @@ -175,41 +175,40 @@ gen_html(RefPages, OutFile)-> html_header() -> "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\">\n" "<!-- This file was generated by the otp_man_index -->\n" - "<HTML>\n" - "<HEAD>\n" + "<html>\n" + "<head>\n" " <link rel=\"stylesheet\" href=\"otp_doc.css\" type=\"text/css\"/>\n" - " <TITLE>Erlang/OTP Manual Page Index</TITLE>\n" - "</HEAD>\n" - "<BODY BGCOLOR=\"#FFFFFF\" TEXT=\"#000000\" LINK=\"#0000FF\" VLINK=\"#FF00FF\" ALINK=\"#FF0000\">\n" - "<CENTER>\n" + " <title>Erlang/OTP Manual Page Index</title>\n" + "</head>\n" + "<body>\n" + "<center>\n" "<!-- A HREF=\"http://www.erlang.org/\">\n" "<img alt=\"Erlang logo\" src=\"erlang-logo.png\"/>\n" - "</A><BR -->\n" - "<SMALL>\n" - "[<A HREF=\"index.html\">Up</A> | <A HREF=\"http://www.erlang.org/\">Erlang</A>]\n" - "</SMALL><BR>\n" - "<P/><FONT SIZE=\"+4\">OTP Reference Page Index</FONT><BR>\n" - "</CENTER>\n" - "<CENTER>\n" - "<P/>\n" - "<TABLE BORDER=1>\n" - "<TR>\n" - " <TH>Manual Page</TH><TH>Application</TH>\n" - "</TR>\n". + "</a><br -->\n" + "<small>\n" + "[ <A HREF=\"index.html\">Up</A> | <A HREF=\"http://www.erlang.org/\">Homepage</A> ]\n" + "</small><br>\n" + "<h1>OTP Reference Page Index</h1>\n" + "</center>\n" + "<center>\n" + "<table class=\"man-index\">\n" + "<tr>\n" + " <th>Manual Page</th><th>Application</th>\n" + "</tr>\n". html_footer(Year) -> - "</TABLE>\n" - "</CENTER>\n" - "<P/>\n" - "<CENTER>\n" - "<HR/>\n" - "<SMALL>\n" + "</table>\n" + "</center>\n" + "<p/>\n" + "<center>\n" + "<hr/>\n" + "<small>\n" "Copyright © 1991-" ++ Year ++ "\n" "<a href=\"http://www.ericsson.com/technology/opensource/erlang/\">\n" "Ericsson AB</a>\n" - "</SMALL>\n" - "</CENTER>\n" - "</BODY>\n" - "</HTML>\n". + "</small>\n" + "</center>\n" + "</body>\n" + "</html>\n". diff --git a/system/doc/top/templates/applications.html.src b/system/doc/top/templates/applications.html.src index 1f73c44d69..7e939ddcd6 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. <title>Erlang/OTP #version# Applications</title> <style type="text/css"> <!-- - BODY { background: white } + BODY { background: #fefefe; color: #111; } - BODY { font-family: Verdana, Arial, Helvetica, sans-serif } - TH { font-family: Verdana, Arial, Helvetica, sans-serif } - TD { font-family: Verdana, Arial, Helvetica, sans-serif } - P { font-family: Verdana, Arial, Helvetica, sans-serif } + BODY { font-family: sans-serif } - .header { background: #222; color: #fff } - .app { background: #ccc } + .header { background: #333; color: #fefefe; } - a.anum:link { color: green; text-decoration: none } - a.anum:active { color: green; text-decoration: none } - a.anum:visited { color: green; text-decoration: none } + a:link { color: #303f9f; text-decoration: none } + a:active { color: #303f9f; text-decoration: none } + a:visited { color: #303f9f; text-decoration: none } - a:link { text-decoration: none } - a:active { text-decoration: none } - a:visited { text-decoration: none } + h1,h2{ + text-align: center; + } + table { + margin: 1em 10%; + width: 80%; + border-collapse: collapse; + min-width: 50%; + } + + table, th, td { + border: 1px solid #666; + } + + th, td { + padding: 0.5em; + text-align: left; + } + + tr:hover { + background-color: #f5f5f5; + } + + tr:nth-child(even) { + background-color: #f2f2f2; + } + + th { + background-color: #777; + color: #fefefe; + } --> </style> </head> -<body bgcolor=white text="#000000" link="#0000ff" vlink="#ff00ff" - alink="#ff0000"> -<center> +<body> + <h1>Erlang/OTP Applications</h1> #groups# -</center> </body> </html> diff --git a/system/doc/top/templates/index.html.src b/system/doc/top/templates/index.html.src index d2a6736d34..747d19cf7e 100644 --- a/system/doc/top/templates/index.html.src +++ b/system/doc/top/templates/index.html.src @@ -2,7 +2,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. @@ -29,20 +29,24 @@ limitations under the License. </script> </head> -<body bgcolor=white text="#000000" link="#0000ff" vlink="#ff00ff" - alink="#ff0000"> +<body> <div id="container"> <div id="leftnav"> <div class="innertube"> -<img alt="Erlang logo" src="erlang-logo.png"/ > -<p/> -<small><a href="applications.html">Applications</a><br> -<a href="man_index.html">Modules</a></small> -<p/> -<a href="javascript:openAllFlips()">Expand All</a><br> -<a href="javascript:closeAllFlips()">Contract All</a> -<p/> +<div class="erlang-logo-wrapper"> + <img alt="Erlang logo" src="erlang-logo.png" class="erlang-logo"/ > +</div> + +<ul class="section-links"> + <li><a href="applications.html">Applications</a></li> + <li><a href="man_index.html" class="modules">Modules</a></li> +</ul> + +<ul class="expand-collapse-items"> + <li><a href="javascript:openAllFlips()">Expand All</a></li> + <li><a href="javascript:closeAllFlips()">Contract All</a></li> +</ul> <ul class="flipMenu"> <li>System Documentation @@ -60,8 +64,8 @@ limitations under the License. </ul> </li> </ul> -<b>Application Groups</b> -<br/> + +<h3>Application Groups</h3> <ul class="flipMenu"> #applinks# @@ -73,24 +77,12 @@ limitations under the License. <div id="content"> <div class="innertube"> -<center> -<font size="+1"><b>Erlang/OTP #otp_base_vsn#</b></font><br> -</center> -<center> -<p> -<font size="+1">Welcome to Erlang/OTP, a complete<br> -development environment<br> -for concurrent programming.</font> -</p> -</center> -<br> -<br> -<br> -<p><b> -<font size="+1"> -Some hints that may get you started faster -</font> -</b></p> + <h1 class="main-title">Erlang/OTP #otp_base_vsn#</h1> + <p class="main-description"> + Welcome to Erlang/OTP, a complete development environment for concurrent programming. + </p> + + <h2>Some hints that may get you started faster</h2> <ul> @@ -149,10 +141,11 @@ verification, comment support including paragraph filling, skeletons, tags support and more. See the <a href="#tools#/index.html"> Tools</a> application for details. <p> -There are also Erlang plugins for +There are also Erlang plugins for other code editors +<a href="http://github.com/vim-erlang">Vim (vim-erlang)</a> , +<a href="http://atom.io/packages/language-erlang"> Atom </a> , <a href="http://erlide.org/index.html">Eclipse (ErlIDE)</a> and -<a href="http://ignatov.github.io/intellij-erlang/">IntelliJ IDEA</a> -if you prefer a more graphical environment, which are both under active development. +<a href="http://ignatov.github.io/intellij-erlang/">IntelliJ IDEA</a>. <li>When developing with Erlang/OTP you usually test your programs from the interactive shell (see <a href="getting_started/users_guide.html"> Getting Started With Erlang</a>) where you can call individual 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 <erl_nif.h> extern int foo(int x); extern int bar(int y); diff --git a/system/doc/tutorial/erl_interface.xmlsrc b/system/doc/tutorial/erl_interface.xmlsrc index de50af42cf..bf9bd36597 100644 --- a/system/doc/tutorial/erl_interface.xmlsrc +++ b/system/doc/tutorial/erl_interface.xmlsrc @@ -4,7 +4,7 @@ <chapter> <header> <copyright> - <year>2000</year><year>2015</year> + <year>2000</year><year>2017</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> @@ -162,9 +162,9 @@ int main() { the include files <c>erl_interface.h</c> and <c>ei.h</c>, and also to the libraries <c>erl_interface</c> and <c>ei</c>:</p> <pre> -unix> <input>gcc -o extprg -I/usr/local/otp/lib/erl_interface-3.2.1/include \\ </input> -<input> -L/usr/local/otp/lib/erl_interface-3.2.1/lib \\ </input> -<input> complex.c erl_comm.c ei.c -lerl_interface -lei</input></pre> +unix> <input>gcc -o extprg -I/usr/local/otp/lib/erl_interface-3.9.2/include \\ </input> +<input> -L/usr/local/otp/lib/erl_interface-3.9.2/lib \\ </input> +<input> complex.c erl_comm.c ei.c -lerl_interface -lei -lpthread</input></pre> <p>In Erlang/OTP R5B and later versions of OTP, the <c>include</c> and <c>lib</c> directories are situated under <c>OTPROOT/lib/erl_interface-VSN</c>, where <c>OTPROOT</c> is @@ -184,7 +184,7 @@ Eshell V4.9.1.2 (abort with ^G) {ok,complex2}</pre> <p><em>Step 3.</em> Run the example:</p> <pre> -2> <input>complex2:start("extprg").</input> +2> <input>complex2:start("./extprg").</input> <0.34.0> 3> <input>complex2:foo(3).</input> 4 |