aboutsummaryrefslogtreecommitdiffstats
path: root/system
diff options
context:
space:
mode:
Diffstat (limited to 'system')
-rw-r--r--system/COPYRIGHT37
-rw-r--r--system/doc/Makefile1
-rw-r--r--system/doc/design_principles/Makefile19
-rw-r--r--system/doc/design_principles/applications.xml14
-rw-r--r--system/doc/design_principles/code_lock.diabin2945 -> 2605 bytes
-rw-r--r--system/doc/design_principles/code_lock.pngbin59827 -> 0 bytes
-rw-r--r--system/doc/design_principles/code_lock.svg132
-rw-r--r--system/doc/design_principles/code_lock_2.diabin2956 -> 2854 bytes
-rw-r--r--system/doc/design_principles/code_lock_2.pngbin55553 -> 0 bytes
-rw-r--r--system/doc/design_principles/code_lock_2.svg140
-rw-r--r--system/doc/design_principles/des_princ.xml4
-rw-r--r--system/doc/design_principles/gen_server_concepts.xml4
-rw-r--r--system/doc/design_principles/release_structure.xml8
-rw-r--r--system/doc/design_principles/spec_proc.xml4
-rw-r--r--system/doc/design_principles/statem.xml1782
-rw-r--r--system/doc/design_principles/sup_princ.xml11
-rw-r--r--system/doc/efficiency_guide/Makefile7
-rw-r--r--system/doc/efficiency_guide/advanced.xml20
-rw-r--r--system/doc/efficiency_guide/binaryhandling.xml92
-rw-r--r--system/doc/efficiency_guide/commoncaveats.xml53
-rw-r--r--system/doc/efficiency_guide/efficiency_guide.erl24
-rw-r--r--system/doc/efficiency_guide/profiling.xml4
-rw-r--r--system/doc/efficiency_guide/retired_myths.xml14
-rw-r--r--system/doc/efficiency_guide/xmlfiles.mk2
-rw-r--r--system/doc/embedded/Makefile7
-rw-r--r--system/doc/embedded/starting.xml2
-rw-r--r--system/doc/general_info/Makefile99
-rw-r--r--system/doc/general_info/book.xml44
-rw-r--r--system/doc/general_info/deprecations.xml98
-rw-r--r--system/doc/general_info/part.xml34
-rw-r--r--system/doc/general_info/scheduled_for_removal.xml61
-rw-r--r--system/doc/general_info/xmlfiles.mk22
-rw-r--r--system/doc/getting_started/Makefile7
-rw-r--r--system/doc/getting_started/conc_prog.xml4
-rw-r--r--system/doc/getting_started/seq_prog.xml13
-rw-r--r--system/doc/html/design_principles/.gitignore0
-rw-r--r--system/doc/html/efficiency_guide/.gitignore0
-rw-r--r--system/doc/html/embedded/.gitignore0
-rw-r--r--system/doc/html/general_info/.gitignore0
-rw-r--r--system/doc/html/getting_started/.gitignore0
-rw-r--r--system/doc/html/installation_guide/.gitignore0
-rw-r--r--system/doc/html/installation_guide/source/.gitignore0
-rw-r--r--system/doc/html/js/.gitignore0
-rw-r--r--system/doc/html/oam/.gitignore0
-rw-r--r--system/doc/html/programming_examples/.gitignore0
-rw-r--r--system/doc/html/reference_manual/.gitignore0
-rw-r--r--system/doc/html/system_architecture_intro/.gitignore0
-rw-r--r--system/doc/html/system_principles/.gitignore0
-rw-r--r--system/doc/html/tutorial/.gitignore0
-rw-r--r--system/doc/installation_guide/Makefile25
-rw-r--r--system/doc/installation_guide/xmlfiles.mk6
-rw-r--r--system/doc/oam/Makefile9
-rw-r--r--system/doc/oam/oam_intro.xml55
-rw-r--r--system/doc/programming_examples/Makefile11
-rw-r--r--system/doc/programming_examples/xmlfiles.mk6
-rw-r--r--system/doc/reference_manual/Makefile7
-rw-r--r--system/doc/reference_manual/errors.xml47
-rw-r--r--system/doc/reference_manual/expressions.xml47
-rw-r--r--system/doc/reference_manual/introduction.xml4
-rw-r--r--system/doc/reference_manual/macros.xml37
-rw-r--r--system/doc/reference_manual/modules.xml8
-rw-r--r--system/doc/reference_manual/typespec.xml26
-rw-r--r--system/doc/reference_manual/xmlfiles.mk2
-rw-r--r--system/doc/system_architecture_intro/Makefile7
-rw-r--r--system/doc/system_architecture_intro/sys_arch_intro.xml16
-rw-r--r--system/doc/system_principles/Makefile9
-rw-r--r--system/doc/system_principles/create_target.xmlsrc12
-rw-r--r--system/doc/system_principles/error_logging.xml117
-rw-r--r--system/doc/system_principles/misc.xml206
-rw-r--r--system/doc/system_principles/part.xml3
-rw-r--r--system/doc/system_principles/system_principles.xml4
-rw-r--r--system/doc/system_principles/versions.xml70
-rw-r--r--system/doc/system_principles/xmlfiles.mk9
-rw-r--r--system/doc/top/Makefile155
-rw-r--r--system/doc/top/book.xml23
-rw-r--r--system/doc/top/src/erl_html_tools.erl4
-rw-r--r--system/doc/top/src/erlresolvelinks.erl90
-rw-r--r--system/doc/top/templates/index.html.src2
-rw-r--r--system/doc/tutorial/Makefile12
-rw-r--r--system/doc/tutorial/overview.xml6
-rw-r--r--system/doc/tutorial/port_driver.c3
-rw-r--r--system/doc/tutorial/xmlfiles.mk7
-rw-r--r--system/doc/xml/design_principles/.gitignore0
-rw-r--r--system/doc/xml/efficiency_guide/.gitignore0
-rw-r--r--system/doc/xml/embedded/.gitignore0
-rw-r--r--system/doc/xml/general_info/.gitignore0
-rw-r--r--system/doc/xml/getting_started/.gitignore0
-rw-r--r--system/doc/xml/installation_guide/.gitignore0
-rw-r--r--system/doc/xml/oam/.gitignore0
-rw-r--r--system/doc/xml/programming_examples/.gitignore0
-rw-r--r--system/doc/xml/reference_manual/.gitignore0
-rw-r--r--system/doc/xml/system_architecture_intro/.gitignore0
-rw-r--r--system/doc/xml/system_principles/.gitignore0
-rw-r--r--system/doc/xml/tutorial/.gitignore0
94 files changed, 2685 insertions, 1123 deletions
diff --git a/system/COPYRIGHT b/system/COPYRIGHT
index 5d47e0ca38..91cf0bbfb3 100644
--- a/system/COPYRIGHT
+++ b/system/COPYRIGHT
@@ -5,7 +5,7 @@ This software is subject to the following Copyrights and Licenses:
%CopyrightBegin%
-Copyright Ericsson AB 1997-2017. All Rights Reserved.
+Copyright Ericsson AB 1997-2018. 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.
@@ -41,12 +41,15 @@ PCRE LICENCE
PCRE is a library of functions to support regular expressions whose syntax
and semantics are as close as possible to those of the Perl 5 language.
-Release 7 of PCRE is distributed under the terms of the "BSD" licence, as
+Release 8 of PCRE is distributed under the terms of the "BSD" licence, as
specified below. The documentation for PCRE, supplied in the "doc"
-directory, is distributed under the same terms as the software itself.
+directory, is distributed under the same terms as the software itself. The data
+in the testdata directory is not copyrighted and is in the public domain.
The basic library functions are written in C and are freestanding. Also
-included in the distribution is a set of C++ wrapper functions.
+included in the distribution is a set of C++ wrapper functions, and a
+just-in-time compiler that can be used to optimize pattern matching. These
+are both optional features that can be omitted when the library is built.
THE BASIC LIBRARY FUNCTIONS
@@ -59,7 +62,29 @@ Email domain: cam.ac.uk
University of Cambridge Computing Service,
Cambridge, England.
-Copyright (c) 1997-2008 University of Cambridge
+Copyright (c) 1997-2018 University of Cambridge
+All rights reserved.
+
+
+PCRE JUST-IN-TIME COMPILATION SUPPORT
+-------------------------------------
+
+Written by: Zoltan Herczeg
+Email local part: hzmester
+Emain domain: freemail.hu
+
+Copyright(c) 2010-2018 Zoltan Herczeg
+All rights reserved.
+
+
+STACK-LESS JUST-IN-TIME COMPILER
+--------------------------------
+
+Written by: Zoltan Herczeg
+Email local part: hzmester
+Emain domain: freemail.hu
+
+Copyright(c) 2009-2018 Zoltan Herczeg
All rights reserved.
@@ -68,7 +93,7 @@ THE C++ WRAPPER FUNCTIONS
Contributed by: Google Inc.
-Copyright (c) 2007-2008, Google Inc.
+Copyright (c) 2007-2012, Google Inc.
All rights reserved.
diff --git a/system/doc/Makefile b/system/doc/Makefile
index 0c4adf6554..8f2faeee04 100644
--- a/system/doc/Makefile
+++ b/system/doc/Makefile
@@ -24,6 +24,7 @@ include $(ERL_TOP)/make/$(TARGET)/otp.mk
#
SUB_DIRECTORIES = design_principles \
+ general_info \
getting_started \
system_architecture_intro \
embedded \
diff --git a/system/doc/design_principles/Makefile b/system/doc/design_principles/Makefile
index 5743a50b47..2fbd7d087f 100644
--- a/system/doc/design_principles/Makefile
+++ b/system/doc/design_principles/Makefile
@@ -1,7 +1,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 1997-2016. All Rights Reserved.
+# Copyright Ericsson AB 1997-2018. 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.
@@ -18,6 +18,7 @@
# %CopyrightEnd%
#
#
+
include $(ERL_TOP)/make/target.mk
include $(ERL_TOP)/make/$(TARGET)/otp.mk
@@ -27,6 +28,8 @@ include $(ERL_TOP)/make/$(TARGET)/otp.mk
include $(ERL_TOP)/erts/vsn.mk
APPLICATION=otp-system-documentation
+XMLDIR := $(XMLDIR)/design_principles
+
# ----------------------------------------------------
# Release directory specification
# ----------------------------------------------------
@@ -57,11 +60,11 @@ GIF_FILES = \
sup5.gif \
sup6.gif
-PNG_FILES = \
- code_lock.png \
- code_lock_2.png
+SVG_FILES = \
+ code_lock.svg \
+ code_lock_2.svg
-IMAGE_FILES = $(GIF_FILES) $(PNG_FILES)
+IMAGE_FILES = $(GIF_FILES) $(SVG_FILES)
XML_FILES = \
$(BOOK_FILES) $(XML_CHAPTER_FILES) \
@@ -85,12 +88,11 @@ DVIPS_FLAGS +=
# ----------------------------------------------------
# Targets
# ----------------------------------------------------
-_create_dirs := $(shell mkdir -p $(HTMLDIR))
$(HTMLDIR)/%.gif: %.gif
$(INSTALL_DATA) $< $@
-$(HTMLDIR)/%.png: %.png
+$(HTMLDIR)/%.svg: %.svg
$(INSTALL_DATA) $< $@
docs: html
@@ -104,7 +106,8 @@ images: $(IMAGE_FILES:%=$(HTMLDIR)/%)
debug opt:
clean clean_docs:
- rm -rf $(HTMLDIR)
+ rm -f $(XMLDIR)/*.xml
+ rm -f $(HTMLDIR)/*.gif $(HTMLDIR)/*.html
rm -f $(TOP_PDF_FILE) $(TOP_PDF_FILE:%.pdf=%.fo)
rm -f errs core *~
diff --git a/system/doc/design_principles/applications.xml b/system/doc/design_principles/applications.xml
index c673fde07e..8f1969ff29 100644
--- a/system/doc/design_principles/applications.xml
+++ b/system/doc/design_principles/applications.xml
@@ -4,7 +4,7 @@
<chapter>
<header>
<copyright>
- <year>1997</year><year>2016</year>
+ <year>1997</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -185,7 +185,7 @@ ch_app:stop([])</code>
the directory with the highest version number, if more than one
version of an application is present.</p>
<section>
- <title>Directory Structure guidelines for a Development Environment</title>
+ <title>Directory Structure Guidelines for a Development Environment</title>
<p>Any directory structure for development will suffice as long as the released directory structure
adhere to the <seealso marker="#app_dir_released">description below</seealso>,
but it is encouraged that the same directory structure
@@ -363,9 +363,13 @@ ok
application are running.</p>
<marker id="application_master"></marker>
<p>The application controller then creates an
- <em>application master</em> for the application. The application master
- is the group leader of all the processes in the application.
- The application master starts the application by calling
+ <em>application master</em> for the application. The application
+ master becomes the group leader of all the processes in the
+ application. I/O is forwarded to the previous group leader,
+ though, this is just a way to identify processes that belong to
+ the application. Used for example to find itself from any process,
+ or, reciprocally, to kill them all when it terminates.</p>
+ <p>The application master starts the application by calling
the application callback function <c>start/2</c> in the module,
and with the start argument, defined by the <c>mod</c> key in
the <c>.app</c> file.</p>
diff --git a/system/doc/design_principles/code_lock.dia b/system/doc/design_principles/code_lock.dia
index eaa2aca5b0..fe43d6da2c 100644
--- a/system/doc/design_principles/code_lock.dia
+++ b/system/doc/design_principles/code_lock.dia
Binary files differ
diff --git a/system/doc/design_principles/code_lock.png b/system/doc/design_principles/code_lock.png
deleted file mode 100644
index 40bd35fc74..0000000000
--- a/system/doc/design_principles/code_lock.png
+++ /dev/null
Binary files differ
diff --git a/system/doc/design_principles/code_lock.svg b/system/doc/design_principles/code_lock.svg
new file mode 100644
index 0000000000..223e121486
--- /dev/null
+++ b/system/doc/design_principles/code_lock.svg
@@ -0,0 +1,132 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.0//EN" "http://www.w3.org/TR/2001/PR-SVG-20010719/DTD/svg10.dtd">
+<svg width="41cm" height="52cm" viewBox="-2 -2 806 1023" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
+ <polyline style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #000000" points="492.782,860 600,860 600,900 "/>
+ <polyline style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #000000" points="380,900 380,900 380,931.6 "/>
+ <polyline style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #000000" points="640,560 640,580 640,580 640,600 "/>
+ <polyline style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #000000" points="492.782,300 640,300 640,340 "/>
+ <g>
+ <path style="fill: #d5d5f7" d="M 289.774 260 L 470.226,260 C 492.782,276 500,284 500,300 C 500,316 492.782,324 470.226,340 L 289.774,340 C 267.218,324 260,316 260,300 C 260,284 267.218,276 289.774,260z"/>
+ <path style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #000000" d="M 289.774 260 L 470.226,260 C 492.782,276 500,284 500,300 C 500,316 492.782,324 470.226,340 L 289.774,340 C 267.218,324 260,316 260,300 C 260,284 267.218,276 289.774,260"/>
+ <text font-size="27.0933" style="fill: #000000;text-anchor:middle;font-family:sans-serif;font-style:normal;font-weight:700" x="380" y="308.467">
+ <tspan x="380" y="308.467">locked</tspan>
+ </text>
+ </g>
+ <g>
+ <path style="fill: #d5d5f7" d="M 289.774 820 L 470.226,820 C 492.782,836 500,844 500,860 C 500,876 492.782,884 470.226,900 L 289.774,900 C 267.218,884 260,876 260,860 C 260,844 267.218,836 289.774,820z"/>
+ <path style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #000000" d="M 289.774 820 L 470.226,820 C 492.782,836 500,844 500,860 C 500,876 492.782,884 470.226,900 L 289.774,900 C 267.218,884 260,876 260,860 C 260,844 267.218,836 289.774,820"/>
+ <text font-size="27.0933" style="fill: #000000;text-anchor:middle;font-family:sans-serif;font-style:normal;font-weight:700" x="380" y="868.467">
+ <tspan x="380" y="868.467">open</tspan>
+ </text>
+ </g>
+ <g>
+ <polygon style="fill: #aad7aa" points="520,340 760,340 736,360 760,380 520,380 "/>
+ <polygon style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #000000" points="520,340 760,340 736,360 760,380 520,380 "/>
+ <text font-size="20.32" style="fill: #000000;text-anchor:start;font-family:sans-serif;font-style:italic;font-weight:normal" x="546" y="366.35">
+ <tspan x="546" y="366.35">{button,Button}</tspan>
+ </text>
+ </g>
+ <g>
+ <polygon style="fill: #f3cccc" points="640,480 800,520 640,560 480,520 "/>
+ <polygon style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #000000" points="640,480 800,520 640,560 480,520 "/>
+ <text font-size="20.32" style="fill: #000000;text-anchor:middle;font-family:sans-serif;font-style:normal;font-weight:normal" x="643.2" y="527.15">
+ <tspan x="643.2" y="527.15">Correct Code?</tspan>
+ </text>
+ </g>
+ <g>
+ <polygon style="fill: #ffff8f" points="0,940 160,940 160,980 0,980 "/>
+ <polygon style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #000000" points="0,940 160,940 160,980 0,980 "/>
+ <text font-size="20.32" style="fill: #000000;text-anchor:middle;font-family:sans-serif;font-style:normal;font-weight:normal" x="80" y="966.35">
+ <tspan x="80" y="966.35">do_lock()</tspan>
+ </text>
+ </g>
+ <g>
+ <polygon style="fill: #aad7aa" points="280,931.6 480,931.6 460,960 480,988.4 280,988.4 "/>
+ <polygon style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #000000" points="280,931.6 480,931.6 460,960 480,988.4 280,988.4 "/>
+ <text font-size="20.32" style="fill: #000000;text-anchor:middle;font-family:sans-serif;font-style:italic;font-weight:normal" x="380" y="966.35">
+ <tspan x="380" y="966.35">state_timeout</tspan>
+ </text>
+ </g>
+ <g>
+ <ellipse style="fill: #d5d5f7" cx="380" cy="40" rx="40" ry="40"/>
+ <ellipse style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #000000" cx="380" cy="40" rx="40" ry="40"/>
+ <text font-size="27.0933" style="fill: #000000;text-anchor:middle;font-family:sans-serif;font-style:normal;font-weight:normal" x="380" y="48.4667">
+ <tspan x="380" y="48.4667">init</tspan>
+ </text>
+ </g>
+ <g>
+ <line style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #000000" x1="380.719" y1="180" x2="380.087" y2="250.264"/>
+ <polygon style="fill: #000000" points="380.02,257.764 375.11,247.72 380.087,250.264 385.11,247.809 "/>
+ <polygon style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #000000" points="380.02,257.764 375.11,247.72 380.087,250.264 385.11,247.809 "/>
+ </g>
+ <g>
+ <line style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #000000" x1="640.438" y1="440" x2="640.106" y2="470.265"/>
+ <polygon style="fill: #000000" points="640.024,477.764 635.134,467.71 640.106,470.265 645.134,467.819 "/>
+ <polygon style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #000000" points="640.024,477.764 635.134,467.71 640.106,470.265 645.134,467.819 "/>
+ </g>
+ <polyline style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #000000" points="640,700 640,740 380,740 380,740 "/>
+ <text font-size="20.32" style="fill: #000000;text-anchor:start;font-family:sans-serif;font-style:normal;font-weight:normal" x="640" y="578.9">
+ <tspan x="640" y="578.9">Y</tspan>
+ </text>
+ <text font-size="20.32" style="fill: #000000;text-anchor:end;font-family:sans-serif;font-style:normal;font-weight:normal" x="480" y="538.9">
+ <tspan x="480" y="538.9">N</tspan>
+ </text>
+ <g>
+ <polyline style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #000000" points="80,940 80,220 370.623,220 "/>
+ <polygon style="fill: #000000" points="378.123,220 368.123,225 370.623,220 368.123,215 "/>
+ <polygon style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #000000" points="378.123,220 368.123,225 370.623,220 368.123,215 "/>
+ </g>
+ <g>
+ <polygon style="fill: #aad7aa" points="500,900 700,900 680,920 700,940 500,940 "/>
+ <polygon style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #000000" points="500,900 700,900 680,920 700,940 500,940 "/>
+ <text font-size="20.32" style="fill: #000000;text-anchor:start;font-family:sans-serif;font-style:italic;font-weight:normal" x="522" y="926.35">
+ <tspan x="522" y="926.35">{button,Digit}</tspan>
+ </text>
+ </g>
+ <g>
+ <polyline style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #000000" points="600,940 600,980 760,980 760,780 389.736,780 "/>
+ <polygon style="fill: #000000" points="382.236,780 392.236,775 389.736,780 392.236,785 "/>
+ <polygon style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #000000" points="382.236,780 392.236,775 389.736,780 392.236,785 "/>
+ </g>
+ <g>
+ <polygon style="fill: #ffff8f" points="260,120 501.438,120 501.438,180 260,180 "/>
+ <polygon style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #000000" points="260,120 501.438,120 501.438,180 260,180 "/>
+ <text font-size="20.32" style="fill: #000000;text-anchor:start;font-family:sans-serif;font-style:normal;font-weight:normal" x="286.144" y="143.65">
+ <tspan x="286.144" y="143.65">do_lock()</tspan>
+ <tspan x="286.144" y="169.05">Clear Buttons</tspan>
+ </text>
+ </g>
+ <g>
+ <polygon style="fill: #ffff8f" points="500,600 780,600 780,700 500,700 "/>
+ <polygon style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #000000" points="500,600 780,600 780,700 500,700 "/>
+ <text font-size="20.32" style="fill: #000000;text-anchor:start;font-family:sans-serif;font-style:normal;font-weight:normal" x="530" y="630.95">
+ <tspan x="530" y="630.95">do_unlock()</tspan>
+ <tspan x="530" y="656.35">Clear Buttons</tspan>
+ <tspan x="530" y="681.75">state_timeout 10 s</tspan>
+ </text>
+ </g>
+ <g>
+ <line style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #000000" x1="380" y1="80" x2="380.544" y2="110.266"/>
+ <polygon style="fill: #000000" points="380.679,117.764 375.5,107.856 380.544,110.266 385.498,107.676 "/>
+ <polygon style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #000000" points="380.679,117.764 375.5,107.856 380.544,110.266 385.498,107.676 "/>
+ </g>
+ <g>
+ <line style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #000000" x1="380" y1="740" x2="380" y2="810.264"/>
+ <polygon style="fill: #000000" points="380,817.764 375,807.764 380,810.264 385,807.764 "/>
+ <polygon style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #000000" points="380,817.764 375,807.764 380,810.264 385,807.764 "/>
+ </g>
+ <polyline style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #000000" points="380,988.4 380,1020 80,1020 80,980 "/>
+ <g>
+ <polygon style="fill: #ffff8f" points="540,400 740.875,400 740.875,440 540,440 "/>
+ <polygon style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #000000" points="540,400 740.875,400 740.875,440 540,440 "/>
+ <text font-size="20.32" style="fill: #000000;text-anchor:middle;font-family:sans-serif;font-style:normal;font-weight:normal" x="640.438" y="426.35">
+ <tspan x="640.438" y="426.35">Collect Buttons</tspan>
+ </text>
+ </g>
+ <line style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #000000" x1="640" y1="380" x2="640.438" y2="400"/>
+ <g>
+ <polyline style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #000000" points="480,520 380,520 380,351 "/>
+ <polygon style="fill: #000000" points="385,351 380,341 375,351 "/>
+ <polygon style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #000000" points="385,351 380,341 375,351 "/>
+ </g>
+</svg>
diff --git a/system/doc/design_principles/code_lock_2.dia b/system/doc/design_principles/code_lock_2.dia
index 3b9ba554d8..31eb0fb6eb 100644
--- a/system/doc/design_principles/code_lock_2.dia
+++ b/system/doc/design_principles/code_lock_2.dia
Binary files differ
diff --git a/system/doc/design_principles/code_lock_2.png b/system/doc/design_principles/code_lock_2.png
deleted file mode 100644
index 3aca9dd5aa..0000000000
--- a/system/doc/design_principles/code_lock_2.png
+++ /dev/null
Binary files differ
diff --git a/system/doc/design_principles/code_lock_2.svg b/system/doc/design_principles/code_lock_2.svg
new file mode 100644
index 0000000000..d3e15e7577
--- /dev/null
+++ b/system/doc/design_principles/code_lock_2.svg
@@ -0,0 +1,140 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.0//EN" "http://www.w3.org/TR/2001/PR-SVG-20010719/DTD/svg10.dtd">
+<svg width="41cm" height="52cm" viewBox="-1 0 806 1021" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
+ <polyline style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #000000" points="380,300.55 380,300 140,300 140,360 "/>
+ <polyline style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #000000" points="412.782,900 412.782,900 560,900 560,940 "/>
+ <g>
+ <polyline style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #000000" points="560,980 560,1020 0,1020 0,120.55 370.264,120.55 "/>
+ <polygon style="fill: #000000" points="377.764,120.55 367.764,125.55 370.264,120.55 367.764,115.55 "/>
+ <polygon style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #000000" points="377.764,120.55 367.764,125.55 370.264,120.55 367.764,115.55 "/>
+ </g>
+ <polyline style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #000000" points="640,680 640,720 300,720 300,760 "/>
+ <polyline style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #000000" points="492.782,300.55 492.782,300 640,300 640,360 "/>
+ <g>
+ <path style="fill: #d5d5f7" d="M 289.774 261.1 L 470.226,261.1 C 492.782,276.88 500,284.77 500,300.55 C 500,316.33 492.782,324.22 470.226,340 L 289.774,340 C 267.218,324.22 260,316.33 260,300.55 C 260,284.77 267.218,276.88 289.774,261.1z"/>
+ <path style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #000000" d="M 289.774 261.1 L 470.226,261.1 C 492.782,276.88 500,284.77 500,300.55 C 500,316.33 492.782,324.22 470.226,340 L 289.774,340 C 267.218,324.22 260,316.33 260,300.55 C 260,284.77 267.218,276.88 289.774,261.1"/>
+ <text font-size="27.0933" style="fill: #000000;text-anchor:middle;font-family:sans-serif;font-style:normal;font-weight:700" x="380" y="309.017">
+ <tspan x="380" y="309.017">locked</tspan>
+ </text>
+ </g>
+ <g>
+ <path style="fill: #d5d5f7" d="M 209.774 860 L 390.226,860 C 412.782,876 420,884 420,900 C 420,916 412.782,924 390.226,940 L 209.774,940 C 187.218,924 180,916 180,900 C 180,884 187.218,876 209.774,860z"/>
+ <path style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #000000" d="M 209.774 860 L 390.226,860 C 412.782,876 420,884 420,900 C 420,916 412.782,924 390.226,940 L 209.774,940 C 187.218,924 180,916 180,900 C 180,884 187.218,876 209.774,860"/>
+ <text font-size="27.0933" style="fill: #000000;text-anchor:middle;font-family:sans-serif;font-style:normal;font-weight:700" x="300" y="908.467">
+ <tspan x="300" y="908.467">open</tspan>
+ </text>
+ </g>
+ <g>
+ <polygon style="fill: #aad7aa" points="520,360 760,360 736,380 760,400 520,400 "/>
+ <polygon style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #000000" points="520,360 760,360 736,380 760,400 520,400 "/>
+ <text font-size="20.32" style="fill: #000000;text-anchor:start;font-family:sans-serif;font-style:italic;font-weight:normal" x="546" y="386.35">
+ <tspan x="546" y="386.35">{button,Button}</tspan>
+ </text>
+ </g>
+ <g>
+ <polygon style="fill: #ffff8f" points="140,760 460,760 460,816.8 140,816.8 "/>
+ <polygon style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #000000" points="140,760 460,760 460,816.8 140,816.8 "/>
+ <text font-size="20.32" style="fill: #000000;text-anchor:start;font-family:sans-serif;font-style:normal;font-weight:normal" x="174" y="782.05">
+ <tspan x="174" y="782.05">do_unlock()</tspan>
+ <tspan x="174" y="807.45">state_timeout 10 s</tspan>
+ </text>
+ </g>
+ <g>
+ <polygon style="fill: #ffff8f" points="260,160 500,160 500,222.2 260,222.2 "/>
+ <polygon style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #000000" points="260,160 500,160 500,222.2 260,222.2 "/>
+ <text font-size="20.32" style="fill: #000000;text-anchor:middle;font-family:sans-serif;font-style:normal;font-weight:normal" x="380" y="184.75">
+ <tspan x="380" y="184.75">do_lock()</tspan>
+ <tspan x="380" y="210.15">Clear Buttons</tspan>
+ </text>
+ </g>
+ <g>
+ <polygon style="fill: #aad7aa" points="460,940 660,940 640,960 660,980 460,980 "/>
+ <polygon style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #000000" points="460,940 660,940 640,960 660,980 460,980 "/>
+ <text font-size="20.32" style="fill: #000000;text-anchor:middle;font-family:sans-serif;font-style:italic;font-weight:normal" x="560" y="966.35">
+ <tspan x="560" y="966.35">state_timeout</tspan>
+ </text>
+ </g>
+ <g>
+ <ellipse style="fill: #d5d5f7" cx="380" cy="41.1" rx="40" ry="40"/>
+ <ellipse style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #000000" cx="380" cy="41.1" rx="40" ry="40"/>
+ <text font-size="27.0933" style="fill: #000000;text-anchor:middle;font-family:sans-serif;font-style:normal;font-weight:normal" x="380" y="49.5667">
+ <tspan x="380" y="49.5667">init</tspan>
+ </text>
+ </g>
+ <g>
+ <line style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #000000" x1="380" y1="81.1" x2="380" y2="150.264"/>
+ <polygon style="fill: #000000" points="380,157.764 375,147.764 380,150.264 385,147.764 "/>
+ <polygon style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #000000" points="380,157.764 375,147.764 380,150.264 385,147.764 "/>
+ </g>
+ <g>
+ <line style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #000000" x1="380" y1="222.2" x2="380" y2="251.364"/>
+ <polygon style="fill: #000000" points="380,258.864 375,248.864 380,251.364 385,248.864 "/>
+ <polygon style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #000000" points="380,258.864 375,248.864 380,251.364 385,248.864 "/>
+ </g>
+ <g>
+ <line style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #000000" x1="300" y1="816.8" x2="300" y2="850.264"/>
+ <polygon style="fill: #000000" points="300,857.764 295,847.764 300,850.264 305,847.764 "/>
+ <polygon style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #000000" points="300,857.764 295,847.764 300,850.264 305,847.764 "/>
+ </g>
+ <g>
+ <line style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #000000" x1="380" y1="560" x2="380" y2="349.736"/>
+ <polygon style="fill: #000000" points="380,342.236 385,352.236 380,349.736 375,352.236 "/>
+ <polygon style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #000000" points="380,342.236 385,352.236 380,349.736 375,352.236 "/>
+ </g>
+ <g>
+ <polygon style="fill: #ffff8f" points="240,560 520,560 520,600 240,600 "/>
+ <polygon style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #000000" points="240,560 520,560 520,600 240,600 "/>
+ <text font-size="20.32" style="fill: #000000;text-anchor:middle;font-family:sans-serif;font-style:normal;font-weight:normal" x="380" y="586.35">
+ <tspan x="380" y="586.35">state_timeout 30 s</tspan>
+ </text>
+ </g>
+ <g>
+ <polygon style="fill: #aad7aa" points="40,360 240,360 220,380 240,400 40,400 "/>
+ <polygon style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #000000" points="40,360 240,360 220,380 240,400 40,400 "/>
+ <text font-size="20.32" style="fill: #000000;text-anchor:start;font-family:sans-serif;font-style:italic;font-weight:normal" x="62" y="386.35">
+ <tspan x="62" y="386.35">state_timeout</tspan>
+ </text>
+ </g>
+ <g>
+ <polygon style="fill: #ffff8f" points="540,440 741.438,440 741.438,480 540,480 "/>
+ <polygon style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #000000" points="540,440 741.438,440 741.438,480 540,480 "/>
+ <text font-size="20.32" style="fill: #000000;text-anchor:middle;font-family:sans-serif;font-style:normal;font-weight:normal" x="640.719" y="466.35">
+ <tspan x="640.719" y="466.35">Collect Buttons</tspan>
+ </text>
+ </g>
+ <line style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #000000" x1="640" y1="400" x2="640.719" y2="440"/>
+ <g>
+ <line style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #000000" x1="640.611" y1="480.995" x2="640.056" y2="589"/>
+ <polygon style="fill: #000000" points="635.057,588.974 640.005,599 645.056,589.026 "/>
+ <polygon style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #000000" points="635.057,588.974 640.005,599 645.056,589.026 "/>
+ </g>
+ <g>
+ <polygon style="fill: #ffff8f" points="40,440 240,440 240,480 40,480 "/>
+ <polygon style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #000000" points="40,440 240,440 240,480 40,480 "/>
+ <text font-size="20.32" style="fill: #000000;text-anchor:middle;font-family:sans-serif;font-style:normal;font-weight:normal" x="140" y="466.35">
+ <tspan x="140" y="466.35">Clear Buttons</tspan>
+ </text>
+ </g>
+ <polyline style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #000000" points="480,640 380,640 380,600 "/>
+ <line style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #000000" x1="140" y1="400" x2="140" y2="440"/>
+ <g>
+ <g>
+ <polygon style="fill: #f3cccc" points="640,600 800,640 640,680 480,640 "/>
+ <polygon style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #000000" points="640,600 800,640 640,680 480,640 "/>
+ <text font-size="20.32" style="fill: #000000;text-anchor:middle;font-family:sans-serif;font-style:normal;font-weight:normal" x="643.2" y="647.15">
+ <tspan x="643.2" y="647.15">Correct Code?</tspan>
+ </text>
+ </g>
+ <text font-size="20.32" style="fill: #000000;text-anchor:end;font-family:sans-serif;font-style:normal;font-weight:normal" x="480" y="658.9">
+ <tspan x="480" y="658.9">N</tspan>
+ </text>
+ <text font-size="20.32" style="fill: #000000;text-anchor:start;font-family:sans-serif;font-style:normal;font-weight:normal" x="640" y="698.9">
+ <tspan x="640" y="698.9">Y</tspan>
+ </text>
+ </g>
+ <g>
+ <polyline style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #000000" points="140,480 140,516 369,516 "/>
+ <polygon style="fill: #000000" points="369,521 379,516 369,511 "/>
+ <polygon style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #000000" points="369,521 379,516 369,511 "/>
+ </g>
+</svg>
diff --git a/system/doc/design_principles/des_princ.xml b/system/doc/design_principles/des_princ.xml
index e21f2a7f4e..2bfb8eb3c7 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>2017</year>
+ <year>1997</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -64,7 +64,7 @@
the supervisors are similar in structure. The only difference
between them is which child processes they supervise. Many
of the workers are servers in a server-client relation,
- finite-state machines, or event handlers such as error loggers.</p>
+ finite-state machines, or event handlers.</p>
<p><em>Behaviours</em> are formalizations of these common patterns.
The idea is to divide the code for a process in a generic part
(a behaviour module) and a specific part (a
diff --git a/system/doc/design_principles/gen_server_concepts.xml b/system/doc/design_principles/gen_server_concepts.xml
index c1b98189d5..06413a3d93 100644
--- a/system/doc/design_principles/gen_server_concepts.xml
+++ b/system/doc/design_principles/gen_server_concepts.xml
@@ -4,7 +4,7 @@
<chapter>
<header>
<copyright>
- <year>1997</year><year>2016</year>
+ <year>1997</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -32,7 +32,7 @@
<marker id="gen_server"></marker>
<p>This section is to be read with the
<seealso marker="stdlib:gen_server">gen_server(3)</seealso>
- manual page in <c>stdblib</c>, where all interface functions and
+ manual page in <c>stdlib</c>, where all interface functions and
callback functions are described in detail.</p>
<section>
diff --git a/system/doc/design_principles/release_structure.xml b/system/doc/design_principles/release_structure.xml
index a0ab21c43f..e8dfcad805 100644
--- a/system/doc/design_principles/release_structure.xml
+++ b/system/doc/design_principles/release_structure.xml
@@ -4,7 +4,7 @@
<chapter>
<header>
<copyright>
- <year>2003</year><year>2016</year>
+ <year>2003</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -208,8 +208,8 @@ releases/ch_rel-1.rel</pre>
is therefore now instead duplicated in the tar file so no manual
copying is necessary.</p>
<p>If a <c>relup</c> file and/or a system configuration file called
- <c>sys.config</c> is found, these files are also included in
- the release package. See
+ <c>sys.config</c>, or a <c>sys.config.src</c>, is found, these files
+ are also included in the release package. See
<seealso marker="release_handling#req">Release Handling</seealso>.</p>
<p>Options can be set to make the release package include source
code and the ERTS binary as well.</p>
@@ -240,7 +240,7 @@ $ROOT/lib/App1-AVsn1/ebin
<item><c>erts-EVsn/bin</c> - Erlang runtime system executables</item>
<item><c>releases/Vsn</c> - <c>.rel</c> file and boot script
<c>start.boot</c>; if present in the release package, <c>relup</c>
- and/or <c>sys.config</c></item>
+ and/or <c>sys.config</c> or <c>sys.config.src</c></item>
<item><c>bin</c> - Top-level Erlang runtime system executables</item>
</list>
<p>Applications are not required to be located under directory
diff --git a/system/doc/design_principles/spec_proc.xml b/system/doc/design_principles/spec_proc.xml
index 5f4e7ac685..65f5492bdd 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>2017</year>
+ <year>1997</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -312,7 +312,7 @@ sys:handle_debug(Deb, Func, Info, Event) => Deb1</code>
define what a system event is and how it is to be
represented. Typically at least incoming and outgoing
messages are considered system events and represented by
- the tuples <c>{in,Msg[,From]}</c> and <c>{out,Msg,To}</c>,
+ the tuples <c>{in,Msg[,From]}</c> and <c>{out,Msg,To[,State]}</c>,
respectively.</item>
</list>
<p><c>handle_debug</c> returns an updated debug structure
diff --git a/system/doc/design_principles/statem.xml b/system/doc/design_principles/statem.xml
index 1006485e30..23e9054547 100644
--- a/system/doc/design_principles/statem.xml
+++ b/system/doc/design_principles/statem.xml
@@ -4,7 +4,7 @@
<chapter>
<header>
<copyright>
- <year>2016</year><year>2017</year>
+ <year>2016</year><year>2019</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -36,16 +36,6 @@
manual page in STDLIB, where all interface functions and callback
functions are described in detail.
</p>
- <note>
- <p>
- This is a new behavior in Erlang/OTP 19.0.
- It has been thoroughly reviewed, is stable enough
- to be used by at least two heavy OTP applications, and is here to stay.
- Depending on user feedback, we do not expect
- but can find it necessary to make minor
- not backward compatible changes into Erlang/OTP 20.0.
- </p>
- </note>
<!-- =================================================================== -->
@@ -54,31 +44,44 @@
<title>Event-Driven State Machines</title>
<p>
Established Automata Theory does not deal much with
- how a state transition is triggered,
+ how a <em>state transition</em> is triggered,
but assumes that the output is a function
of the input (and the state) and that they are
some kind of values.
</p>
<p>
For an Event-Driven State Machine, the input is an event
- that triggers a state transition and the output
- is actions executed during the state transition.
+ that triggers a <em>state transition</em> and the output
+ is actions executed during the <em>state transition</em>.
It can analogously to the mathematical model of a
- Finite-State Machine be described as
+ Finite State Machine be described as
a set of relations of the following form:
</p>
<pre>
State(S) x Event(E) -> Actions(A), State(S')</pre>
- <p>These relations are interpreted as follows:
+ <p>
+ These relations are interpreted as follows:
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>. Notice that <c>S'</c> can be equal to <c>S</c>.
+ state <c>S'</c>. Notice that <c>S'</c> can be equal to <c>S</c>
+ and that <c>A</c> can be empty.
+ </p>
+ <p>
+ In <c>gen_statem</c> we define
+ a <em>state change</em> as a <em>state transition</em>
+ in which the new state <c>S'</c> is different from
+ the current state <c>S</c>, where "different" means
+ Erlang's strict inequality: <c>=/=</c>
+ also know as "does not match".
+ During a <em>state changes</em>,
+ <c>gen_statem</c> does more things
+ than during other <em>state transitions</em>.
</p>
<p>
As <c>A</c> and <c>S'</c> depend only on
<c>S</c> and <c>E</c>, the kind of state machine described
- here is a Mealy Machine
- (see, for example, the corresponding Wikipedia article).
+ here is a Mealy machine
+ (see, for example, the Wikipedia article "Mealy machine").
</p>
<p>
Like most <c>gen_</c> behaviors, <c>gen_statem</c> keeps
@@ -88,7 +91,95 @@ State(S) x Event(E) -> Actions(A), State(S')</pre>
or on the number of distinct input events,
a state machine implemented with this behavior
is in fact Turing complete.
- But it feels mostly like an Event-Driven Mealy Machine.
+ But it feels mostly like an Event-Driven Mealy machine.
+ </p>
+ </section>
+
+<!-- =================================================================== -->
+
+ <section>
+ <marker id="When to use gen_statem" />
+ <title>When to use gen_statem</title>
+ <p>
+ If your process logic is convenient to describe as a state machine,
+ and you want any of these <c>gen_statem</c> key features:
+ </p>
+ <list type="bulleted">
+ <item>
+ Co-located callback code for each state,
+ for all
+ <seealso marker="#Event Types"><em>Event Types</em></seealso>
+ (such as <em>call</em>, <em>cast</em> and <em>info</em>)
+ </item>
+ <item>
+ <seealso marker="#Postponing Events">
+ Postponing Events
+ </seealso>
+ (a substitute for selective receive)
+ </item>
+ <item>
+ <seealso marker="#Inserted Events">
+ Inserted Events
+ </seealso>
+ that is: events from the state machine to itself
+ (in particular purely internal events)
+ </item>
+ <item>
+ <seealso marker="#State Enter Calls">
+ <em>State Enter Calls</em>
+ </seealso>
+ (callback on state entry co-located with the rest
+ of each state's callback code)
+ </item>
+ <item>
+ Easy-to-use time-outs
+ (<seealso marker="#State Time-Outs">State Time-Outs</seealso>,
+ <seealso marker="#Event Time-Outs">Event Time-Outs</seealso>
+ and
+ <seealso marker="#Generic Time-Outs">Generic Time-outs</seealso>
+ (named time-outs))
+ </item>
+ </list>
+ <p>
+ If so, or if possibly needed in future versions,
+ then you should consider using <c>gen_statem</c> over
+ <seealso marker="stdlib:gen_server"><c>gen_server</c></seealso>.
+ </p>
+ <p>
+ For simple state machines not needing these features
+ <seealso marker="stdlib:gen_server"><c>gen_server</c></seealso>
+ works just fine.
+ It also has got smaller call overhead,
+ but we are talking about something like 2 vs 3.3 microseconds
+ call roundtrip time here, so if the server callback
+ does just a little bit more than just replying,
+ or if the call is not extremely frequent,
+ that difference will be hard to notice.
+ </p>
+ </section>
+
+<!-- =================================================================== -->
+
+ <section>
+ <marker id="Callback Module" />
+ <title>Callback Module</title>
+ <p>
+ The <em>callback module</em> contains functions that implement
+ the state machine.
+ When an event occurs,
+ the <c>gen_statem</c> behaviour engine
+ calls a function in the <em>callback module</em> with the event,
+ current state and server data.
+ This function performs the actions for this event,
+ and returns the new state and server data
+ and also actions to be performed by the behaviour engine.
+ </p>
+ <p>
+ The behaviour engine holds the state machine state,
+ server data, timer references, a queue of posponed messages
+ and other metadata. It receives all process messages,
+ handles the system messages, and calls the <em>callback module</em>
+ with machine specific events.
</p>
</section>
@@ -98,63 +189,76 @@ State(S) x Event(E) -> Actions(A), State(S')</pre>
<marker id="Callback Modes" />
<title>Callback Modes</title>
<p>
- The <c>gen_statem</c> behavior supports two callback modes:
+ The <c>gen_statem</c> behavior supports two <em>callback modes</em>:
</p>
- <list type="bulleted">
+ <taglist>
+ <tag>
+ <seealso marker="stdlib:gen_statem#type-callback_mode">
+ <c>state_functions</c>
+ </seealso>
+ </tag>
<item>
<p>
- In mode
- <seealso marker="stdlib:gen_statem#type-callback_mode"><c>state_functions</c></seealso>,
- the state transition rules are written as some Erlang
- functions, which conform to the following convention:
- </p>
- <pre>
-StateName(EventType, EventContent, Data) ->
- ... code for actions here ...
- {next_state, NewStateName, NewData}.
- </pre>
- <p>
- This form is used in most examples here for example in section
- <seealso marker="#Example">Example</seealso>.
+ Events are handled by one callback function per state.
</p>
</item>
+ <tag>
+ <seealso marker="stdlib:gen_statem#type-callback_mode">
+ <c>handle_event_function</c>
+ </seealso>
+ </tag>
<item>
<p>
- In mode
- <seealso marker="stdlib:gen_statem#type-callback_mode"><c>handle_event_function</c></seealso>,
- only one Erlang function provides all state transition rules:
- </p>
- <pre>
-handle_event(EventType, EventContent, State, Data) ->
- ... code for actions here ...
- {next_state, NewState, NewData}
- </pre>
- <p>
- See section
- <seealso marker="#One Event Handler">One Event Handler</seealso>
- for an example.
+ Events are handled by one single callback function.
</p>
</item>
- </list>
+ </taglist>
+ <p>
+ The <em>callback mode</em> is selected at server start
+ and may be changed with a code upgrade/downgrade.
+ </p>
+ <p>
+ See the section
+ <seealso marker="#State Callback"><em>State Callback</em></seealso>
+ that describes the event handling callback function(s).
+ </p>
<p>
- Both these modes allow other return tuples; see
- <seealso marker="stdlib:gen_statem#Module:StateName/3"><c>Module:StateName/3</c></seealso>
- in the <c>gen_statem</c> manual page.
- These other return tuples can, for example, stop the machine,
- execute state transition actions on the machine engine itself,
- and send replies.
+ The <em>callback mode</em> is selected by implementing
+ a mandatory callback function
+ <seealso marker="stdlib:gen_statem#Module:callback_mode/0">
+ <c>Module:callback_mode()</c>
+ </seealso>
+ that returns one of the <em>callback modes</em>.
+ </p>
+ <p>
+ The
+ <seealso marker="stdlib:gen_statem#Module:callback_mode/0">
+ <c>Module:callback_mode()</c>
+ </seealso>
+ function may also return a list containing the <em>callback mode</em>
+ and the atom <c>state_enter</c> in which case
+ <seealso marker="#State Enter Calls">
+ <em>state enter calls</em>
+ </seealso>
+ are activated for the <em>callback mode</em>.
</p>
<section>
<marker id="Choosing the Callback Mode" />
<title>Choosing the Callback Mode</title>
<p>
+ The short version: choose <c>state_functions</c> -
+ it is the one most like <c>gen_fsm</c>.
+ But if you do not want the restriction that the state
+ must be an atom, or if you do not want to write
+ one <em>state callback</em> function per state; please read on...
+ </p>
+ <p>
The two
- <seealso marker="#Callback Modes">callback modes</seealso>
- give different possibilities
- and restrictions, but one goal remains:
- you want to handle all possible combinations of
- events and states.
+ <seealso marker="#Callback Modes"><em>callback modes</em></seealso>
+ give different possibilities and restrictions,
+ with one common goal:
+ to handle all possible combinations of events and states.
</p>
<p>
This can be done, for example, by focusing on one state at the time
@@ -167,7 +271,7 @@ handle_event(EventType, EventContent, State, Data) ->
With <c>state_functions</c>, you are restricted to use
atom-only states, and the <c>gen_statem</c> engine
branches depending on state name for you.
- This encourages the callback module to gather
+ This encourages the <em>callback module</em> to co-locate
the implementation of all event actions particular
to one state in the same place in the code,
hence to focus on one state at the time.
@@ -186,13 +290,17 @@ handle_event(EventType, EventContent, State, Data) ->
This mode works equally well when you want to focus on
one event at the time or on
one state at the time, but function
- <seealso marker="stdlib:gen_statem#Module:handle_event/4"><c>Module:handle_event/4</c></seealso>
+ <seealso marker="stdlib:gen_statem#Module:handle_event/4">
+ <c>Module:handle_event/4</c>
+ </seealso>
quickly grows too large to handle without branching to
helper functions.
</p>
<p>
The mode enables the use of non-atom states, for example,
complex states or even hierarchical states.
+ See section
+ <seealso marker="#Complex State">Complex State</seealso>.
If, for example, a state diagram is largely alike
for the client side and the server side of a protocol,
you can have a state <c>{StateName,server}</c> or
@@ -208,43 +316,200 @@ handle_event(EventType, EventContent, State, Data) ->
<!-- =================================================================== -->
<section>
- <marker id="State Enter Calls" />
- <title>State Enter Calls</title>
+ <marker id="State Callback" />
+ <title>State Callback</title>
<p>
- The <c>gen_statem</c> behavior can regardless of callback mode
- automatically
- <seealso marker="stdlib:gen_statem#type-state_enter">
- call the state callback
- </seealso>
- with special arguments whenever the state changes
- so you can write state entry actions
- near the rest of the state transition rules.
- It typically looks like this:
+ The <em>state callback</em> is the callback function
+ that handles an event in the current state,
+ and which function that is depends on the <em>callback mode</em>:
</p>
- <pre>
-StateName(enter, _OldState, Data) ->
- ... code for state entry actions here ...
- {keep_state, NewData};
-StateName(EventType, EventContent, Data) ->
- ... code for actions here ...
- {next_state, NewStateName, NewData}.</pre>
+ <taglist>
+ <tag><c>state_functions</c></tag>
+ <item>
+ The event is handled by:<br />
+ <seealso marker="stdlib:gen_statem#Module:StateName/3">
+ <c>Module:StateName(EventType, EventContent, Data)</c>
+ </seealso>
+ <p>
+ This form is the one mostly used in the
+ <seealso marker="#Example">Example</seealso>
+ section.
+ </p>
+ </item>
+ <tag><c>handle_event_function</c></tag>
+ <item>
+ The event is handled by:<br />
+ <seealso marker="stdlib:gen_statem#Module:handle_event/4">
+ <c>Module:handle_event(EventType, EventContent, State, Data)</c>
+ </seealso>
+ <p>
+ See section
+ <seealso marker="#One State Callback">
+ <em>One State Callback</em>
+ </seealso>
+ for an example.
+ </p>
+ </item>
+ </taglist>
<p>
- Depending on how your state machine is specified,
- this can be a very useful feature,
- but it forces you to handle the state enter calls in all states.
- See also the
- <seealso marker="#State Entry Actions">
- State Entry Actions
+ The state is either the name of the function itself or an argument to it.
+ The other arguments are the <c>EventType</c> described in section
+ <seealso marker="#Event Types">Event Types</seealso>,
+ the event dependent <c>EventContent</c>,
+ and the current server <c>Data</c>.
+ </p>
+ <p>
+ <em>State enter calls</em> are also handled by the event handler
+ and have slightly different arguments. See section
+ <seealso marker="#State Enter Calls">State Enter Calls</seealso>.
+ </p>
+ <p>
+ The <em>state callback</em> return values
+ are defined in the description of
+ <seealso marker="stdlib:gen_statem#Module:StateName/3">
+ <c>Module:StateName/3</c>
</seealso>
- chapter.
+ in the <c>gen_statem</c> manual page, but here is
+ a more readable list:
</p>
+ <taglist>
+ <tag>
+ <c>{next_state, NextState, NewData, Actions}</c><br />
+ <c>{next_state, NextState, NewData}</c>
+ </tag>
+ <item>
+ <p>
+ Set next state and update the server data.
+ If the <c>Actions</c> field is used,
+ execute <em>transition actions</em>.
+ An empty <c>Actions</c> list is equivalent to
+ not returning the field.
+ </p>
+ <p>
+ See section
+ <seealso marker="#Transition Actions">
+ <em>Transition Actions</em>
+ </seealso>
+ for a list of possible
+ <em>transition actions</em>.
+ </p>
+ <p>
+ If <c>NextState =/= State</c> this is a <em>state change</em>
+ so the extra things <c>gen_statem</c> does are: the event queue
+ is restarted from the oldest
+ <seealso marker="#Postponing Events">postponed event</seealso>,
+ any current
+ <seealso marker="#State Time-Outs">state time-out</seealso>
+ is cancelled, and a
+ <seealso marker="#State Enter Calls">state enter call</seealso>
+ is performed, if enabled.
+ </p>
+ </item>
+ <tag>
+ <c>{keep_state, NewData, Actions}</c><br />
+ <c>{keep_state, NewData}</c>
+ </tag>
+ <item>
+ <p>
+ Same as the <c>next_state</c> values with
+ <c>NextState =:= State</c>, that is, no <em>state change</em>.
+ </p>
+ </item>
+ <tag>
+ <c>{keep_state_and_data, Actions}</c><br />
+ <c>keep_state_and_data</c>
+ </tag>
+ <item>
+ <p>
+ Same as the <c>keep_state</c> values with
+ <c>NextData =:= Data</c>, that is, no change in server data.
+ </p>
+ </item>
+ <tag>
+ <c>{repeat_state, NewData, Actions}</c><br />
+ <c>{repeat_state, NewData}</c><br />
+ <c>{repeat_state_and_data, Actions}</c><br />
+ <c>repeat_state_and_data</c>
+ </tag>
+ <item>
+ <p>
+ Same as the <c>keep_state</c> or <c>keep_state_and_data</c> values,
+ and if
+ <seealso marker="#State Enter Calls">
+ State Enter Calls
+ </seealso>
+ are enabled, repeat the <em>state enter call</em>
+ as if this state was entered again.
+ </p>
+ <p>
+ If these return values are used from a
+ <em>state enter call</em> the <c>OldState</c> does not change,
+ but if used from an event handling <em>state callback</em>
+ the new <em>state enter call's</em> <c>OldState</c>
+ will be the current state.
+ </p>
+ </item>
+ <tag>
+ <c>{stop, Reason, NewData}</c><br />
+ <c>{stop, Reason}</c>
+ </tag>
+ <item>
+ <p>
+ Stop the server with reason <c>Reason</c>.
+ If the <c>NewData</c> field is used, first update the server data.
+ </p>
+ </item>
+ <tag>
+ <c>{stop_and_reply, Reason, NewData, ReplyActions}</c><br />
+ <c>{stop_and_reply, Reason, ReplyActions}</c>
+ </tag>
+ <item>
+ <p>
+ Same as the <c>stop</c> values, but first execute the given
+ <seealso marker="#Transition Actions">
+ <em>transition actions</em>
+ </seealso>
+ that may only be reply actions.
+ </p>
+ </item>
+ </taglist>
+
+ <section>
+ <marker id="The First State" />
+ <title>The First State</title>
+ <p>
+ To decide the first state the
+ <seealso marker="stdlib:gen_statem#Module:init/1">
+ <c>Module:init(Args)</c>
+ </seealso>
+ callback function is called before any
+ <seealso marker="#State Callback"><em>state callback</em></seealso>
+ is called. This function behaves like an <em>state callback</em>
+ function, but gets its only argument <c>Args</c> from
+ the <c>gen_statem</c>
+ <seealso marker="stdlib:gen_statem#start/3">
+ <c>start/3,4</c>
+ </seealso>
+ or
+ <seealso marker="stdlib:gen_statem#start_link/3">
+ <c>start_link/3,4</c>
+ </seealso>
+ function, and returns <c>{ok, State, Data}</c>
+ or <c>{ok, State, Data, Actions}</c>.
+ If you use the
+ <seealso marker="#Postponing Events"><c>postpone</c></seealso>
+ action from this function, that action is ignored,
+ since there is no event to postpone.
+ </p>
+ </section>
+
</section>
<!-- =================================================================== -->
<section>
- <marker id="Actions" />
- <title>Actions</title>
+ <marker id="Transition Actions" />
+ <title>Transition Actions</title>
<p>
In the first section
<seealso marker="#Event-Driven State Machines">
@@ -252,84 +517,112 @@ StateName(EventType, EventContent, Data) ->
</seealso>
actions were mentioned as a part of
the general state machine model. These general actions
- are implemented with the code that callback module
+ are implemented with the code that <em>callback module</em>
<c>gen_statem</c> executes in an event-handling
callback function before returning
to the <c>gen_statem</c> engine.
</p>
<p>
- There are more specific state-transition actions
- that a callback function can order the <c>gen_statem</c>
+ There are more specific <em>transition actions</em>
+ that a callback function can command the <c>gen_statem</c>
engine to do after the callback function return.
- These are ordered by returning a list of
+ These are commanded by returning a list of
<seealso marker="stdlib:gen_statem#type-action">actions</seealso>
in the
- <seealso marker="stdlib:gen_statem#type-state_callback_result">return tuple</seealso>
+ <seealso marker="stdlib:gen_statem#type-state_callback_result">
+ return value
+ </seealso>
from the
<seealso marker="stdlib:gen_statem#Module:StateName/3">callback function</seealso>.
- These state transition actions affect the <c>gen_statem</c>
- engine itself and can do the following:
+ These are the possible <em>transition actions</em>:
</p>
- <list type="bulleted">
- <item>
+ <taglist>
+ <tag>
<seealso marker="stdlib:gen_statem#type-postpone">
- Postpone
+ <c>postpone</c>
</seealso>
- the current event, see section
- <seealso marker="#Postponing Events">Postponing Events</seealso>
- </item>
+ <br />
+ <c>{postpone, Boolean}</c>
+ </tag>
<item>
+ If set postpone the current event, see section
+ <seealso marker="#Postponing Events">Postponing Events</seealso>.
+ </item>
+ <tag>
<seealso marker="stdlib:gen_statem#type-hibernate">
- Hibernate
+ <c>hibernate</c>
</seealso>
- the <c>gen_statem</c>, treated in
- <seealso marker="#Hibernation">Hibernation</seealso>
- </item>
+ <br />
+ <c>{hibernate, Boolean}</c>
+ </tag>
<item>
- Start a
- <seealso marker="stdlib:gen_statem#type-state_timeout">
- state time-out</seealso>,
- read more in section
- <seealso marker="#State Time-Outs">State Time-Outs</seealso>
+ If set hibernate the <c>gen_statem</c>, treated in section
+ <seealso marker="#Hibernation">Hibernation</seealso>.
</item>
+ <tag>
+ <seealso marker="stdlib:gen_statem#type-state_timeout">
+ <c>{state_timeout, EventContent, Time}</c>
+ </seealso>
+ <br />
+ <c>{state_timeout, EventContent, Time, Opts}</c>
+ </tag>
<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>
+ Start a state time-out, read more in sections
+ <seealso marker="#Time-Outs">Time-Outs</seealso> and
+ <seealso marker="#State Time-Outs">State Time-Outs</seealso>.
</item>
+ <tag>
+ <seealso marker="stdlib:gen_statem#type-generic_timeout">
+ <c>{{timeout, Name}, EventContent, Time}</c>
+ </seealso>
+ <br />
+ <c>{{timeout, Name}, EventContent, Time, Opts}</c>
+ </tag>
<item>
- Start an
- <seealso marker="stdlib:gen_statem#type-event_timeout">event time-out</seealso>,
- see more in section
- <seealso marker="#Event Time-Outs">Event Time-Outs</seealso>
+ Start a generic time-out, read more in sections
+ <seealso marker="#Time-Outs">Time-Outs</seealso> and
+ <seealso marker="#Generic Time-Outs">Generic Time-Outs</seealso>.
</item>
+ <tag>
+ <seealso marker="stdlib:gen_statem#type-event_timeout">
+ <c>{timeout, EventContent, Time}</c>
+ </seealso>
+ <br />
+ <c>{timeout, EventContent, Time, Opts}</c><br />
+ <c>Time</c>
+ </tag>
<item>
+ Start an event time-out, see more in sections
+ <seealso marker="#Time-Outs">Time-Outs</seealso> and
+ <seealso marker="#Event Time-Outs">Event Time-Outs</seealso>.
+ </item>
+ <tag>
<seealso marker="stdlib:gen_statem#type-reply_action">
- Reply
+ <c>{reply, From, Reply}</c>
</seealso>
- to a caller, mentioned at the end of section
- <seealso marker="#All State Events">All State Events</seealso>
- </item>
+ </tag>
<item>
- Generate the
+ Reply to a caller, mentioned at the end of section
+ <seealso marker="#All State Events">All State Events</seealso>.
+ </item>
+ <tag>
<seealso marker="stdlib:gen_statem#type-action">
- next event
+ <c>{next_event, EventType, EventContent}</c>
</seealso>
- to handle, see section
- <seealso marker="#Self-Generated Events">Self-Generated Events</seealso>
+ </tag>
+ <item>
+ Generate the next event to handle, see section
+ <seealso marker="#Inserted Events">Inserted Events</seealso>.
</item>
- </list>
+ </taglist>
<p>
- For details, see the
- <seealso marker="stdlib:gen_statem#type-action">
- <c>gen_statem(3)</c>
- </seealso>
- manual page.
+ For details, see the <c>gen_statem(3)</c>
+ manual page for type
+ <seealso marker="stdlib:gen_statem#type-action"><c>action()</c></seealso>.
You can, for example, reply to many callers,
generate multiple next events,
- and set time-outs to relative or absolute times.
+ and set a time-out to use absolute instead of relative time
+ (using the <c>Opts</c> field).
</p>
</section>
@@ -340,66 +633,100 @@ StateName(EventType, EventContent, Data) ->
<title>Event Types</title>
<p>
Events are categorized in different
- <seealso marker="stdlib:gen_statem#type-event_type">event types</seealso>.
- Events of all types are handled in the same callback function,
- for a given state, and the function gets
+ <seealso marker="stdlib:gen_statem#type-event_type"><em>event types</em></seealso>.
+ Events of all types are for a given state
+ handled in the same callback function, and that function gets
<c>EventType</c> and <c>EventContent</c> as arguments.
</p>
<p>
- The following is a complete list of event types and where
+ The following is a complete list of <em>event types</em> and where
they come from:
</p>
<taglist>
- <tag><c>cast</c></tag>
+ <tag>
+ <seealso marker="stdlib:gen_statem#type-external_event_type">
+ <c>cast</c>
+ </seealso>
+ </tag>
<item>
Generated by
<seealso marker="stdlib:gen_statem#cast/2"><c>gen_statem:cast</c></seealso>.
</item>
- <tag><c>{call,From}</c></tag>
+ <tag>
+ <seealso marker="stdlib:gen_statem#type-external_event_type">
+ <c>{call,From}</c>
+ </seealso>
+ </tag>
<item>
Generated by
<seealso marker="stdlib:gen_statem#call/2"><c>gen_statem:call</c></seealso>,
where <c>From</c> is the reply address to use
- when replying either through the state transition action
+ when replying either through the <em>transition action</em>
<c>{reply,From,Msg}</c> or by calling
<seealso marker="stdlib:gen_statem#reply/1"><c>gen_statem:reply</c></seealso>.
</item>
- <tag><c>info</c></tag>
+ <tag>
+ <seealso marker="stdlib:gen_statem#type-external_event_type">
+ <c>info</c>
+ </seealso>
+ </tag>
<item>
Generated by any regular process message sent to
the <c>gen_statem</c> process.
</item>
- <tag><c>state_timeout</c></tag>
+ <tag>
+ <seealso marker="stdlib:gen_statem#type-timeout_event_type">
+ <c>state_timeout</c>
+ </seealso>
+ </tag>
<item>
- Generated by state transition action
- <seealso marker="stdlib:gen_statem#type-state_timeout">
+ Generated by <em>transition action</em>
+ <seealso marker="stdlib:gen_statem#type-timeout_action">
<c>{state_timeout,Time,EventContent}</c>
</seealso>
- state timer timing out.
+ state timer timing out. Read more in sections
+ <seealso marker="#Time-Outs">Time-Outs</seealso> and
+ <seealso marker="#State Time-Outs">State Time-Outs</seealso>.
</item>
- <tag><c>{timeout,Name}</c></tag>
+ <tag>
+ <seealso marker="stdlib:gen_statem#type-timeout_event_type">
+ <c>{timeout,Name}</c>
+ </seealso>
+ </tag>
<item>
- Generated by state transition action
- <seealso marker="stdlib:gen_statem#type-generic_timeout">
+ Generated by <em>transition action</em>
+ <seealso marker="stdlib:gen_statem#type-timeout_action">
<c>{{timeout,Name},Time,EventContent}</c>
</seealso>
- generic timer timing out.
+ generic timer timing out. Read more in sections
+ <seealso marker="#Time-Outs">Time-Outs</seealso> and
+ <seealso marker="#Generic Time-Outs">Generic Time-Outs</seealso>.
</item>
- <tag><c>timeout</c></tag>
+ <tag>
+ <seealso marker="stdlib:gen_statem#type-timeout_event_type">
+ <c>timeout</c>
+ </seealso>
+ </tag>
<item>
- Generated by state transition action
- <seealso marker="stdlib:gen_statem#type-event_timeout">
+ Generated by <em>transition action</em>
+ <seealso marker="stdlib:gen_statem#type-timeout_action">
<c>{timeout,Time,EventContent}</c>
</seealso>
(or its short form <c>Time</c>)
- event timer timing out.
+ event timer timing out. Read more in sections
+ <seealso marker="#Time-Outs">Time-Outs</seealso> and
+ <seealso marker="#Event Time-Outs">Event Time-Outs</seealso>.
</item>
- <tag><c>internal</c></tag>
+ <tag>
+ <seealso marker="stdlib:gen_statem#type-event_type">
+ <c>internal</c>
+ </seealso>
+ </tag>
<item>
- Generated by state transition
- <seealso marker="stdlib:gen_statem#type-action">action</seealso>
- <c>{next_event,internal,EventContent}</c>.
- All event types above can also be generated using
+ Generated by <em>transition action</em>
+ <seealso marker="stdlib:gen_statem#type-enter_action"><c>{next_event,internal,EventContent}</c></seealso>.
+ All <em>event types</em> above can also be generated using
+ the <c>next_event</c> action:
<c>{next_event,EventType,EventContent}</c>.
</item>
</taglist>
@@ -408,24 +735,184 @@ StateName(EventType, EventContent, Data) ->
<!-- =================================================================== -->
<section>
+ <marker id="State Enter Calls" />
+ <title>State Enter Calls</title>
+ <p>
+ The <c>gen_statem</c> behavior can if this is enabled,
+ regardless of <em>callback mode</em>,
+ automatically
+ <seealso marker="stdlib:gen_statem#type-state_enter">
+ call the state callback
+ </seealso>
+ with special arguments whenever the state changes
+ so you can write state enter actions
+ near the rest of the <em>state transition</em> rules.
+ It typically looks like this:
+ </p>
+ <pre>
+StateName(enter, OldState, Data) ->
+ ... code for state enter actions here ...
+ {keep_state, NewData};
+StateName(EventType, EventContent, Data) ->
+ ... code for actions here ...
+ {next_state, NewStateName, NewData}.</pre>
+ <p>
+ Since the <em>state enter call</em> is not an event there are restrictions
+ on the allowed return value and
+ <seealso marker="#Transition Actions">State Transition Actions</seealso>.
+ You may not change the state,
+ <seealso marker="#Postponing Events">postpone</seealso>
+ this non-event, or
+ <seealso marker="#Inserted Events">insert any events</seealso>.
+ </p>
+ <p>
+ The first state that is entered
+ will get a <em>state enter call</em>
+ with <c>OldState</c> equal to the current state.
+ </p>
+ <p>
+ You may repeat the <em>state enter call</em>
+ using the <c>{repeat_state,...}</c>
+ return value from the
+ <seealso marker="#State Callback">state callback</seealso>.
+ In this case <c>OldState</c> will also be equal to the current state.
+ </p>
+ <p>
+ Depending on how your state machine is specified,
+ this can be a very useful feature, but it forces you to handle
+ the <em>state enter calls</em> in all states.
+ See also the
+ <seealso marker="#State Enter Actions">
+ State Enter Actions
+ </seealso>
+ section.
+ </p>
+ </section>
+
+<!-- =================================================================== -->
+
+ <section>
+ <marker id="Time-Outs" />
+ <title>Time-outs</title>
+ <p>
+ Time-outs in <c>gen_statem</c> are started from a
+ <seealso marker="#Transition Actions">
+ <em>transition action</em>
+ </seealso>
+ during a state transition that is when exiting from the
+ <seealso marker="#State Callback"><em>state callback</em></seealso>.
+ </p>
+ <p>
+ There are 3 types of time-outs in <c>gen_statem</c>:
+ </p>
+ <taglist>
+ <tag>
+ <seealso marker="stdlib:gen_statem#type-state_timeout">
+ <c>state_timeout</c>
+ </seealso>
+ </tag>
+ <item>
+ There is one
+ <seealso marker="#State Time-Outs">State Time-Out</seealso>
+ that is automatically cancelled by a <em>state change</em>.
+ </item>
+ <tag>
+ <seealso marker="stdlib:gen_statem#type-generic_timeout">
+ <c>{timeout, Name}</c>
+ </seealso>
+ </tag>
+ <item>
+ There are any number of
+ <seealso marker="#Generic Time-Outs">Generic Time-Outs</seealso>
+ differing by their <c>Name</c>.
+ They have no automatic cancelling.
+ </item>
+ <tag>
+ <seealso marker="stdlib:gen_statem#type-event_timeout">
+ <c>timeout</c>
+ </seealso>
+ </tag>
+ <item>
+ There is one
+ <seealso marker="#Event Time-Outs">Event Time-Out</seealso>
+ that is automatically cancelled by any event.
+ Note that
+ <seealso marker="#Postponing Events">postponed </seealso>
+ and
+ <seealso marker="#Inserted Events">inserted</seealso>
+ events cancel this timeout just as external events.
+ </item>
+ </taglist>
+ <p>
+ When a time-out is started any running time-out with the same tag,
+ <c>state_timeout</c>, <c>{timeout, Name}</c> or <c>timeout</c>,
+ is cancelled, that is the time-out is restarted with the new time.
+ </p>
+ <p>
+ All time-outs has got an <c>EventContent</c> that is part of the
+ <seealso marker="#Transition Actions">
+ <em>transition action</em>
+ </seealso>
+ that starts the time-out.
+ Different <c>EventContent</c>s does not create different time-outs.
+ The <c>EventContent</c> is delivered to the
+ <seealso marker="#State Callback"><em>state callback</em></seealso>
+ when the time-out expires.
+ </p>
+ <section>
+ <marker id="Cancelling a Time-Out" />
+ <title>Cancelling a Time-Out</title>
+ <p>
+ If a time-out is started with the time <c>infinity</c> it will
+ never time out, in fact it will not even be started, and any
+ running time-out with the same tag will be cancelled.
+ The <c>EventContent</c> will in this case be ignored,
+ so why not set it to <c>undefined</c>.
+ </p>
+ </section>
+ <section>
+ <marker id="Time-Out Zero" />
+ <title>Time-Out Zero</title>
+ <p>
+ If a time-out is started with the time <c>0</c> it will
+ actually not be started. Instead the time-out event will
+ immediately be inserted to be processed after any events
+ already enqueued, and before any not yet received external events.
+ Note that some time-outs are automatically cancelled
+ so if you for example combine
+ <seealso marker="#Postponing Events">postponing</seealso>
+ an event in a <em>state change</em> with starting an
+ <seealso marker="#Event Time-Outs">event time-out</seealso>
+ with time <c>0</c> there will be no timeout event inserted
+ since the event time-out is cancelled by the postponed
+ event that is delivered due to the state change.
+ </p>
+ </section>
+ </section>
+
+
+<!-- =================================================================== -->
+
+ <section>
<marker id="Example" />
<title>Example</title>
<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.
- Depending on what buttons have been pressed before,
- the sequence so far can be correct, incomplete, or wrong.
- If correct, the door is unlocked for 10 seconds (10,000 milliseconds).
- If incomplete, we wait for another button to be pressed. If
- wrong, we start all over, waiting for a new button sequence.
- </p>
- <image file="../design_principles/code_lock.png">
+ The pressed buttons are collected, up to the number of buttons
+ in the correct code.
+ If correct, the door is unlocked for 10 seconds.
+ If not correct, we wait for a new button to be pressed.
+ </p>
+ <!-- The image is edited with dia in a .dia file,
+ then exported to Scalable Vector Graphics. -->
+ <image file="../design_principles/code_lock.svg" width="80%">
<icaption>Code Lock State Diagram</icaption>
</image>
<p>
This code lock state machine can be implemented using
- <c>gen_statem</c> with the following callback module:
+ <c>gen_statem</c> with the following <em>callback module</em>:
</p>
<code type="erl"><![CDATA[
-module(code_lock).
@@ -434,43 +921,51 @@ StateName(EventType, EventContent, Data) ->
-export([start_link/1]).
-export([button/1]).
--export([init/1,callback_mode/0,terminate/3,code_change/4]).
+-export([init/1,callback_mode/0,terminate/3]).
-export([locked/3,open/3]).
start_link(Code) ->
gen_statem:start_link({local,?NAME}, ?MODULE, Code, []).
-button(Digit) ->
- gen_statem:cast(?NAME, {button,Digit}).
+button(Button) ->
+ gen_statem:cast(?NAME, {button,Button}).
init(Code) ->
do_lock(),
- Data = #{code => Code, remaining => Code},
+ Data = #{code => Code, length => length(Code), buttons => []},
{ok, locked, Data}.
callback_mode() ->
state_functions.
-
+ ]]></code>
+ <code type="erl"><![CDATA[
locked(
- cast, {button,Digit},
- #{code := Code, remaining := Remaining} = Data) ->
- case Remaining of
- [Digit] ->
+ cast, {button,Button},
+ #{code := Code, length := Length, buttons := Buttons} = Data) ->
+ NewButtons =
+ if
+ length(Buttons) < Length ->
+ Buttons;
+ true ->
+ tl(Buttons)
+ end ++ [Button],
+ if
+ NewButtons =:= Code -> % Correct
do_unlock(),
- {next_state, open, Data#{remaining := Code},
- [{state_timeout,10000,lock}]};
- [Digit|Rest] -> % Incomplete
- {next_state, locked, Data#{remaining := Rest}};
- _Wrong ->
- {next_state, locked, Data#{remaining := Code}}
+ {next_state, open, Data#{buttons := []},
+ [{state_timeout,10000,lock}]}; % Time in milliseconds
+ true -> % Incomplete | Incorrect
+ {next_state, locked, Data#{buttons := NewButtons}}
end.
-
+ ]]></code>
+ <code type="erl"><![CDATA[
open(state_timeout, lock, Data) ->
do_lock(),
{next_state, locked, Data};
open(cast, {button,_}, Data) ->
{next_state, open, Data}.
-
+ ]]></code>
+ <code type="erl"><![CDATA[
do_lock() ->
io:format("Lock~n", []).
do_unlock() ->
@@ -479,8 +974,6 @@ do_unlock() ->
terminate(_Reason, State, _Data) ->
State =/= locked andalso do_lock(),
ok.
-code_change(_Vsn, State, Data, _Extra) ->
- {ok, State, Data}.
]]></code>
<p>The code is explained in the next sections.</p>
</section>
@@ -522,7 +1015,8 @@ start_link(Code) ->
<item>
<p>
The second argument, <c>?MODULE</c>, is the name of
- the callback module, that is, the module where the callback
+ the <em>callback module</em>, that is,
+ the module where the callback
functions are located, which is this module.
</p>
<p>
@@ -556,17 +1050,17 @@ start_link(Code) ->
in this case <c>locked</c>; assuming that the door is locked to begin
with. <c>Data</c> is the internal server data of the <c>gen_statem</c>.
Here the server data is a <seealso marker="stdlib:maps">map</seealso>
- with key <c>code</c> that stores
- the correct button sequence, and key <c>remaining</c>
- that stores the remaining correct button sequence
- (the same as the <c>code</c> to begin with).
+ with key <c>code</c> that stores the correct button sequence,
+ key <c>length</c> store its length,
+ and key <c>buttons</c> that stores the collected buttons
+ up to the same length.
</p>
<code type="erl"><![CDATA[
init(Code) ->
do_lock(),
- Data = #{code => Code, remaining => Code},
- {ok,locked,Data}.
+ Data = #{code => Code, length => length(Code), buttons => []},
+ {ok, locked, Data}.
]]></code>
<p>Function
<seealso marker="stdlib:gen_statem#start_link/3"><c>gen_statem:start_link</c></seealso>
@@ -584,19 +1078,19 @@ init(Code) ->
a <c>gen_statem</c> that is not part of a supervision tree.
</p>
- <code type="erl"><![CDATA[
-callback_mode() ->
- state_functions.
- ]]></code>
<p>
Function
<seealso marker="stdlib:gen_statem#Module:callback_mode/0"><c>Module:callback_mode/0</c></seealso>
selects the
<seealso marker="#Callback Modes"><c>CallbackMode</c></seealso>
- for the callback module, in this case
+ for the <em>callback module</em>, in this case
<seealso marker="stdlib:gen_statem#type-callback_mode"><c>state_functions</c></seealso>.
- That is, each state has got its own handler function.
+ That is, each state has got its own handler function:
</p>
+ <code type="erl"><![CDATA[
+callback_mode() ->
+ state_functions.
+ ]]></code>
</section>
@@ -610,17 +1104,17 @@ callback_mode() ->
<seealso marker="stdlib:gen_statem#cast/2"><c>gen_statem:cast/2</c></seealso>:
</p>
<code type="erl"><![CDATA[
-button(Digit) ->
- gen_statem:cast(?NAME, {button,Digit}).
+button(Button) ->
+ gen_statem:cast(?NAME, {button,Button}).
]]></code>
<p>
The first argument is the name of the <c>gen_statem</c> and must
agree with the name used to start it. So, we use the
same macro <c>?NAME</c> as when starting.
- <c>{button,Digit}</c> is the event content.
+ <c>{button,Button}</c> is the event content.
</p>
<p>
- The event is made into a message and sent to the <c>gen_statem</c>.
+ The event is sent to the <c>gen_statem</c>.
When the event is received, the <c>gen_statem</c> calls
<c>StateName(cast, Event, Data)</c>, which is expected to
return a tuple <c>{next_state, NewStateName, NewData}</c>,
@@ -629,44 +1123,48 @@ button(Digit) ->
<c>NewStateName</c> is the name of the next state to go to.
<c>NewData</c> is a new value for the server data of
the <c>gen_statem</c>, and <c>Actions</c> is a list of
- actions on the <c>gen_statem</c> engine.
+ actions to be performed by the <c>gen_statem</c> engine.
</p>
+
<code type="erl"><![CDATA[
locked(
- cast, {button,Digit},
- #{code := Code, remaining := Remaining} = Data) ->
- case Remaining of
- [Digit] -> % Complete
+ cast, {button,Button},
+ #{code := Code, length := Length, buttons := Buttons} = Data) ->
+ NewButtons =
+ if
+ length(Buttons) < Length ->
+ Buttons;
+ true ->
+ tl(Buttons)
+ end ++ [Button],
+ if
+ NewButtons =:= Code -> % Correct
do_unlock(),
- {next_state, open, Data#{remaining := Code},
- [{state_timeout,10000,lock}]};
- [Digit|Rest] -> % Incomplete
- {next_state, locked, Data#{remaining := Rest}};
- [_|_] -> % Wrong
- {next_state, locked, Data#{remaining := Code}}
+ {next_state, open, Data#{buttons := []},
+ [{state_timeout,10000,lock}]}; % Time in milliseconds
+ true -> % Incomplete | Incorrect
+ {next_state, locked, Data#{buttons := NewButtons}}
end.
-
-open(state_timeout, lock, Data) ->
- do_lock(),
- {next_state, locked, Data};
-open(cast, {button,_}, Data) ->
- {next_state, open, Data}.
]]></code>
<p>
- If the door is locked and a button is pressed, the pressed
- button is compared with the next correct button.
+ In state <c>locked</c>, when a button is pressed,
+ it is collected with the last pressed buttons
+ up to the length of the correct code,
+ and compared with the correct code.
Depending on the result, the door is either unlocked
and the <c>gen_statem</c> goes to state <c>open</c>,
or the door remains in state <c>locked</c>.
</p>
<p>
- If the pressed button is incorrect, the server data
- restarts from the start of the code sequence.
- </p>
- <p>
- If the whole code is correct, the server changes states
- to <c>open</c>.
+ When changing to state <c>open</c>, the collected
+ buttons are reset, the lock unlocked, and a state timer
+ for 10 s is started.
</p>
+
+ <code type="erl"><![CDATA[
+open(cast, {button,_}, Data) ->
+ {next_state, open, Data}.
+ ]]></code>
<p>
In state <c>open</c>, a button event is ignored
by staying in the same state. This can also be done
@@ -684,9 +1182,9 @@ open(cast, {button,_}, Data) ->
the following tuple is returned from <c>locked/2</c>:
</p>
<code type="erl"><![CDATA[
-{next_state, open, Data#{remaining := Code},
- [{state_timeout,10000,lock}]};
- ]]></code>
+{next_state, open, Data#{buttons := []},
+ [{state_timeout,10000,lock}]}; % Time in milliseconds
+ ]]></code>
<p>
10,000 is a time-out value in milliseconds.
After this time (10 seconds), a time-out occurs.
@@ -701,11 +1199,11 @@ open(state_timeout, lock, Data) ->
]]></code>
<p>
The timer for a state time-out is automatically cancelled
- when the state machine changes states. You can restart
- a state time-out by setting it to a new time, which cancels
- the running timer and starts a new. This implies that
- you can cancel a state time-out by restarting it with
- time <c>infinity</c>.
+ when the state machine does a <em>state change</em>.
+ You can restart a state time-out by setting it to a new time,
+ which cancels the running timer and starts a new.
+ This implies that you can cancel a state time-out
+ by restarting it with time <c>infinity</c>.
</p>
</section>
@@ -721,10 +1219,9 @@ open(state_timeout, lock, Data) ->
</p>
<p>
Consider a <c>code_length/0</c> function that returns
- the length of the correct code
- (that should not be sensitive to reveal).
+ the length of the correct code.
We dispatch all events that are not state-specific
- to the common function <c>handle_event/3</c>:
+ to the common function <c>handle_common/3</c>:
</p>
<code type="erl"><![CDATA[
...
@@ -737,16 +1234,46 @@ code_length() ->
...
locked(...) -> ... ;
locked(EventType, EventContent, Data) ->
- handle_event(EventType, EventContent, Data).
+ handle_common(EventType, EventContent, Data).
...
open(...) -> ... ;
open(EventType, EventContent, Data) ->
- handle_event(EventType, EventContent, Data).
+ handle_common(EventType, EventContent, Data).
-handle_event({call,From}, code_length, #{code := Code} = Data) ->
- {keep_state, Data, [{reply,From,length(Code)}]}.
+handle_common({call,From}, code_length, #{code := Code} = Data) ->
+ {keep_state, Data,
+ [{reply,From,length(Code)}]}.
]]></code>
+
+ <p>
+ Another way to do it is through a convenience macro
+ <c>?HANDLE_COMMON/0</c>:
+ </p>
+ <code type="erl"><![CDATA[
+...
+-export([button/1,code_length/0]).
+...
+
+code_length() ->
+ gen_statem:call(?NAME, code_length).
+
+-define(HANDLE_COMMON,
+ ?FUNCTION_NAME(T, C, D) -> handle_common(T, C, D)).
+%%
+handle_common({call,From}, code_length, #{code := Code} = Data) ->
+ {keep_state, Data,
+ [{reply,From,length(Code)}]}.
+
+...
+locked(...) -> ... ;
+?HANDLE_COMMON.
+
+...
+open(...) -> ... ;
+?HANDLE_COMMON.
+]]></code>
+
<p>
This example uses
<seealso marker="stdlib:gen_statem#call/2"><c>gen_statem:call/2</c></seealso>,
@@ -757,15 +1284,27 @@ handle_event({call,From}, code_length, #{code := Code} = Data) ->
when you want to stay in the current state but do not know or
care about what it is.
</p>
+ <p>
+ If the common <em>state callback</em> needs to know the current state
+ a function <c>handle_common/4</c> can be used instead:
+ </p>
+ <code type="erl"><![CDATA[
+-define(HANDLE_COMMON,
+ ?FUNCTION_NAME(T, C, D) -> handle_common(T, C, ?FUNCTION_NAME, D)).
+ ]]></code>
</section>
<!-- =================================================================== -->
<section>
- <marker id="One Event Handler" />
- <title>One Event Handler</title>
+ <marker id="One State Callback" />
+ <title>One State Callback</title>
<p>
- If mode <c>handle_event_function</c> is used,
+ If
+ <seealso marker="#Callback Modes">
+ <em>callback mode</em>
+ </seealso>
+ <c>handle_event_function</c> is used,
all events are handled in
<seealso marker="stdlib:gen_statem#Module:handle_event/4"><c>Module:handle_event/4</c></seealso>
and we can (but do not have to) use an event-centered approach
@@ -780,28 +1319,38 @@ handle_event({call,From}, code_length, #{code := Code} = Data) ->
callback_mode() ->
handle_event_function.
-handle_event(cast, {button,Digit}, State, #{code := Code} = Data) ->
+handle_event(cast, {button,Button}, State, #{code := Code} = Data) ->
case State of
locked ->
- case maps:get(remaining, Data) of
- [Digit] -> % Complete
- do_unlock(),
- {next_state, open, Data#{remaining := Code},
- [{state_timeout,10000,lock}]};
- [Digit|Rest] -> % Incomplete
- {keep_state, Data#{remaining := Rest}};
- [_|_] -> % Wrong
- {keep_state, Data#{remaining := Code}}
- end;
+ #{length := Length, buttons := Buttons} = Data,
+ NewButtons =
+ if
+ length(Buttons) < Length ->
+ Buttons;
+ true ->
+ tl(Buttons)
+ end ++ [Button],
+ if
+ NewButtons =:= Code -> % Correct
+ do_unlock(),
+ {next_state, open, Data#{buttons := []},
+ [{state_timeout,10000,lock}]}; % Time in milliseconds
+ true -> % Incomplete | Incorrect
+ {keep_state, Data#{buttons := NewButtons}}
+ end;
open ->
keep_state_and_data
end;
handle_event(state_timeout, lock, open, Data) ->
do_lock(),
- {next_state, locked, Data}.
+ {next_state, locked, Data};
+handle_event(
+ {call,From}, code_length, _State, #{code := Code} = Data) ->
+ {keep_state, Data,
+ [{reply,From,length(Code)}]}.
...
- ]]></code>
+]]></code>
</section>
<!-- =================================================================== -->
@@ -833,7 +1382,7 @@ init(Args) ->
process_flag(trap_exit, true),
do_lock(),
...
- ]]></code>
+ ]]></code>
<p>
When ordered to shut down, the <c>gen_statem</c> then calls
callback function <c>terminate(shutdown, State, Data)</c>.
@@ -847,7 +1396,7 @@ init(Args) ->
terminate(_Reason, State, _Data) ->
State =/= locked andalso do_lock(),
ok.
- ]]></code>
+ ]]></code>
</section>
<section>
@@ -866,7 +1415,7 @@ terminate(_Reason, State, _Data) ->
...
stop() ->
gen_statem:stop(?NAME).
- ]]></code>
+ ]]></code>
<p>
This makes the <c>gen_statem</c> call callback function
<c>terminate/3</c> just like for a supervised server
@@ -888,34 +1437,36 @@ stop() ->
You get either an event or a time-out, but not both.
</p>
<p>
- It is ordered by the state transition action
- <c>{timeout,Time,EventContent}</c>, or just <c>Time</c>,
- or even just <c>Time</c> instead of an action list
+ It is ordered by the
+ <seealso marker="#Transition Actions">
+ <em>transition action</em>
+ </seealso>
+ <c>{timeout,Time,EventContent}</c>, or just an integer <c>Time</c>,
+ even without the enclosing actions list
(the latter is a form inherited from <c>gen_fsm</c>.
</p>
<p>
- This type of time-out is useful to for example act on inactivity.
+ This type of time-out is useful for example to act on inactivity.
Let us restart the code sequence
if no button is pressed for say 30 seconds:
</p>
<code type="erl"><![CDATA[
...
+locked(timeout, _, Data) ->
+ {next_state, locked, Data#{buttons := []}};
locked(
- timeout, _,
- #{code := Code, remaining := Remaining} = Data) ->
- {next_state, locked, Data#{remaining := Code}};
-locked(
- cast, {button,Digit},
- #{code := Code, remaining := Remaining} = Data) ->
+ cast, {button,Button},
+ #{code := Code, length := Length, buttons := Buttons} = Data) ->
...
- [Digit|Rest] -> % Incomplete
- {next_state, locked, Data#{remaining := Rest}, 30000};
+ true -> % Incomplete | Incorrect
+ {next_state, locked, Data#{buttons := NewButtons},
+ 30000} % Time in milliseconds
...
- ]]></code>
+]]></code>
<p>
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>
+ of 30 seconds, and if we get an <em>event type</em> of <c>timeout</c>
we reset the remaining code sequence.
</p>
<p>
@@ -925,6 +1476,13 @@ locked(
Whatever event you act on has already cancelled
the event time-out...
</p>
+ <p>
+ Note that an event time-out does not work well with
+ when you have for example a status call as in section
+ <seealso marker="#All State Events">All State Events</seealso>,
+ or handle unknown events, since all kinds of events
+ will cancel the event time-out.
+ </p>
</section>
<!-- =================================================================== -->
@@ -952,37 +1510,43 @@ locked(
<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>:
+ named for example <c>open</c>:
</p>
<code type="erl"><![CDATA[
...
locked(
- cast, {button,Digit},
- #{code := Code, remaining := Remaining} = Data) ->
- case Remaining of
- [Digit] ->
+ cast, {button,Button},
+ #{code := Code, length := Length, buttons := Buttons} = Data) ->
+...
+ if
+ NewButtons =:= Code -> % Correct
do_unlock(),
- {next_state, open, Data#{remaining := Code},
- [{{timeout,open_tm},10000,lock}]};
+ {next_state, open, Data#{buttons := []},
+ [{{timeout,open},10000,lock}]}; % Time in milliseconds
...
-open({timeout,open_tm}, lock, Data) ->
+open({timeout,open}, lock, Data) ->
do_lock(),
{next_state,locked,Data};
open(cast, {button,_}, Data) ->
{keep_state,Data};
...
- ]]></code>
+]]></code>
<p>
- Just as
+ Specific generic time-outs can just as
<seealso marker="#State Time-Outs">state time-outs</seealso>
- you can restart or cancel a specific generic time-out
+ be restarted or cancelled
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.
+ In this particular case we do not need to cancel the time-out
+ since the time-out event is the only possible reason to
+ do a <em>state change</em> from <c>open</c> to <c>locked</c>.
+ </p>
+ <p>
+ Instead of bothering with when to cancel a time-out,
+ a late time-out event can be handled by ignoring it
+ if it arrives in a state where it is known to be late.
</p>
</section>
@@ -994,10 +1558,10 @@ open(cast, {button,_}, Data) ->
<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>.
+ <seealso marker="erts:erlang#start_timer/4"><c>erlang:start_timer/3,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
+ but an example of one that cannot 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>
@@ -1008,13 +1572,16 @@ open(cast, {button,_}, Data) ->
<code type="erl"><![CDATA[
...
locked(
- cast, {button,Digit},
- #{code := Code, remaining := Remaining} = Data) ->
- case Remaining of
- [Digit] ->
+ cast, {button,Button},
+ #{code := Code, length := Length, buttons := Buttons} = Data) ->
+...
+ if
+ NewButtons =:= Code -> % Correct
do_unlock(),
- Tref = erlang:start_timer(10000, self(), lock),
- {next_state, open, Data#{remaining := Code, timer => Tref}};
+ Tref =
+ erlang:start_timer(
+ 10000, self(), lock), % Time in milliseconds
+ {next_state, open, Data#{buttons := [], timer => Tref}};
...
open(info, {timeout,Tref,lock}, #{timer := Tref} = Data) ->
@@ -1023,10 +1590,10 @@ open(info, {timeout,Tref,lock}, #{timer := Tref} = Data) ->
open(cast, {button,_}, Data) ->
{keep_state,Data};
...
- ]]></code>
+]]></code>
<p>
Removing the <c>timer</c> key from the map when we
- change to state <c>locked</c> is not strictly
+ do a <em>state change</em> to <c>locked</c> is not strictly
necessary since we can only get into state <c>open</c>
with an updated <c>timer</c> map value. But it can be nice
to not have outdated values in the state <c>Data</c>!
@@ -1058,12 +1625,14 @@ open(cast, {button,_}, Data) ->
<p>
If you want to ignore a particular event in the current state
and handle it in a future state, you can postpone the event.
- A postponed event is retried after the state has
- changed, that is, <c>OldState =/= NewState</c>.
+ A postponed event is retried after a <em>state change</em>,
+ that is, <c>OldState =/= NewState</c>.
</p>
<p>
- Postponing is ordered by the state transition
- <seealso marker="stdlib:gen_statem#type-action">action</seealso>
+ Postponing is ordered by the
+ <seealso marker="#Transition Actions">
+ <em>transition action</em>
+ </seealso>
<c>postpone</c>.
</p>
<p>
@@ -1076,15 +1645,19 @@ open(cast, {button,_}, Data) ->
open(cast, {button,_}, Data) ->
{keep_state,Data,[postpone]};
...
- ]]></code>
+]]></code>
<p>
- Since a postponed event is only retried after a state change,
+ Since a postponed event is only retried
+ after a <em>state change</em>,
you have to think about where to keep a state data item.
You can keep it in the server <c>Data</c>
or in the <c>State</c> itself,
for example by having two more or less identical states
- to keep a boolean value, or by using a complex state with
- <seealso marker="#Callback Modes">callback mode</seealso>
+ to keep a boolean value, or by using a complex state
+ (see section
+ <seealso marker="#Complex State">Complex State</seealso>)
+ with
+ <seealso marker="#Callback Modes"><em>callback mode</em></seealso>
<seealso marker="stdlib:gen_statem#type-callback_mode"><c>handle_event_function</c></seealso>.
If a change in the value changes the set of events that is handled,
then the value should be kept in the State.
@@ -1134,28 +1707,38 @@ start_link(Code) ->
fun () ->
true = register(?NAME, self()),
do_lock(),
- locked(Code, Code)
+ locked(Code, length(Code), [])
end).
-button(Digit) ->
- ?NAME ! {button,Digit}.
-
-locked(Code, [Digit|Remaining]) ->
+button(Button) ->
+ ?NAME ! {button,Button}.
+ ]]></code>
+ <code type="erl"><![CDATA[
+locked(Code, Length, Buttons) ->
receive
- {button,Digit} when Remaining =:= [] ->
- do_unlock(),
- open(Code);
- {button,Digit} ->
- locked(Code, Remaining);
- {button,_} ->
- locked(Code, Code)
+ {button,Button} ->
+ NewButtons =
+ if
+ length(Buttons) < Length ->
+ Buttons;
+ true ->
+ tl(Buttons)
+ end ++ [Button],
+ if
+ NewButtons =:= Code -> % Correct
+ do_unlock(),
+ open(Code, Length);
+ true -> % Incomplete | Incorrect
+ locked(Code, Length, NewButtons)
+ end
end.
-
-open(Code) ->
+ ]]></code>
+ <code type="erl"><![CDATA[
+open(Code, Length) ->
receive
- after 10000 ->
+ after 10000 -> % Time in milliseconds
do_lock(),
- locked(Code, Code)
+ locked(Code, Length, [])
end.
do_lock() ->
@@ -1175,15 +1758,17 @@ do_unlock() ->
<seealso marker="stdlib:sys"><c>sys</c></seealso>
compatible behaviors must respond to system messages and therefore
do that in their engine receive loop,
- passing non-system messages to the callback module.
+ passing non-system messages to the <em>callback module</em>.
</p>
<p>
- The state transition
- <seealso marker="stdlib:gen_statem#type-action">action</seealso>
+ The
+ <seealso marker="#Transition Actions">
+ <em>transition action</em>
+ </seealso>
<c>postpone</c> is designed to model
selective receives. A selective receive implicitly postpones
any not received events, but the <c>postpone</c>
- state transition action explicitly postpones one received event.
+ <em>transition action</em> explicitly postpones one received event.
</p>
<p>
Both mechanisms have the same theoretical
@@ -1196,30 +1781,33 @@ do_unlock() ->
<!-- =================================================================== -->
<section>
- <marker id="State Entry Actions" />
- <title>State Entry Actions</title>
+ <marker id="State Enter Actions" />
+ <title>State Enter Actions</title>
<p>
Say you have a state machine specification
- that uses state entry actions.
- Allthough you can code this using self-generated events
+ that uses state enter actions.
+ Allthough you can code this using inserted events
(described in the next section), especially if just
- one or a few states has got state entry actions,
+ one or a few states has got state enter actions,
this is a perfect use case for the built in
- <seealso marker="#State Enter Calls">state enter calls</seealso>.
+ <seealso marker="#State Enter Calls"><em>state enter calls</em></seealso>.
</p>
<p>
You return a list containing <c>state_enter</c> from your
- <seealso marker="stdlib:gen_statem#Module:callback_mode/0"><c>callback_mode/0</c></seealso>
+ <seealso marker="stdlib:gen_statem#Module:callback_mode/0">
+ <c>callback_mode/0</c>
+ </seealso>
function and the <c>gen_statem</c> engine will call your
- state callback once with the arguments
- <c>(enter, OldState, ...)</c> whenever the state changes.
+ <em>state callback</em> once with an event
+ <c>(enter, OldState, ...)</c>
+ whenever it does a <em>state change</em>.
Then you just need to handle these event-like calls in all states.
</p>
<code type="erl"><![CDATA[
...
init(Code) ->
process_flag(trap_exit, true),
- Data = #{code => Code},
+ Data = #{code => Code, length = length(Code)},
{ok, locked, Data}.
callback_mode() ->
@@ -1227,24 +1815,26 @@ callback_mode() ->
locked(enter, _OldState, Data) ->
do_lock(),
- {keep_state,Data#{remaining => Code}};
+ {keep_state,Data#{buttons => []}};
locked(
- cast, {button,Digit},
- #{code := Code, remaining := Remaining} = Data) ->
- case Remaining of
- [Digit] ->
- {next_state, open, Data};
+ cast, {button,Button},
+ #{code := Code, length := Length, buttons := Buttons} = Data) ->
+...
+ if
+ NewButtons =:= Code -> % Correct
+ {next_state, open, Data};
...
open(enter, _OldState, _Data) ->
do_unlock(),
- {keep_state_and_data, [{state_timeout,10000,lock}]};
+ {keep_state_and_data,
+ [{state_timeout,10000,lock}]}; % Time in milliseconds
open(state_timeout, lock, Data) ->
{next_state, locked, Data};
...
- ]]></code>
+]]></code>
<p>
- You can repeat the state entry code by returning one of
+ You can repeat the state enter code by returning one of
<c>{repeat_state, ...}</c>, <c>{repeat_state_and_data,_}</c>
or <c>repeat_state_and_data</c> that otherwise behaves
exactly like their <c>keep_state</c> siblings.
@@ -1259,13 +1849,15 @@ open(state_timeout, lock, Data) ->
<!-- =================================================================== -->
<section>
- <marker id="Self-Generated Events" />
- <title>Self-Generated Events</title>
+ <marker id="Inserted Events" />
+ <title>Inserted Events</title>
<p>
It can sometimes be beneficial to be able to generate events
to your own state machine.
- This can be done with the state transition
- <seealso marker="stdlib:gen_statem#type-action">action</seealso>
+ This can be done with the
+ <seealso marker="#Transition Actions">
+ <em>transition action</em>
+ </seealso>
<c>{next_event,EventType,EventContent}</c>.
</p>
<p>
@@ -1279,58 +1871,73 @@ open(state_timeout, lock, Data) ->
<p>
One example for this is to pre-process incoming data, for example
decrypting chunks or collecting characters up to a line break.
+ </p>
+ <p>
Purists may argue that this should be modelled with a separate
state machine that sends pre-processed events
- to the main state machine.
- But to decrease overhead the small pre-processing state machine
+ to the main state machine,
+ but to decrease overhead the small pre-processing state machine
can be implemented in the common state event handling
of the main state machine using a few state data variables
that then sends the pre-processed events as internal events
to the main state machine.
+ Using internal events also can make it easier
+ to synchronize the state machines.
</p>
<p>
- The following example uses an input model where you give the lock
- characters with <c>put_chars(Chars)</c> and then call
- <c>enter()</c> to finish the input.
+ A variant of this is to use a
+ <seealso marker="#Complex State">complex state</seealso>
+ with
+ <seealso marker="#One State Callback"><em>one state callback</em></seealso>.
+ The state is then modeled with for example a tuple
+ <c>{MainFSMState,SubFSMState}</c>.
+ </p>
+ <p>
+ To illustrate this we make up an example where the buttons
+ instead generate down and up (press and release) events,
+ and the lock responds to an up event only after
+ the corresponding down event.
</p>
<code type="erl"><![CDATA[
...
--export(put_chars/1, enter/0).
+-export([down/1, up/1]).
...
-put_chars(Chars) when is_binary(Chars) ->
- gen_statem:call(?NAME, {chars,Chars}).
+down(Button) ->
+ gen_statem:cast(?NAME, {down,Button}).
-enter() ->
- gen_statem:call(?NAME, enter).
+up(Button) ->
+ gen_statem:cast(?NAME, {up,Button}).
...
locked(enter, _OldState, Data) ->
do_lock(),
- {keep_state,Data#{remaining => Code, buf => []}};
+ {keep_state,Data#{buttons => []}};
+locked(
+ internal, {button,Button},
+ #{code := Code, length := Length, buttons := Buttons} = Data) ->
...
-
-handle_event({call,From}, {chars,Chars}, #{buf := Buf} = Data) ->
- {keep_state, Data#{buf := [Chars|Buf],
- [{reply,From,ok}]};
-handle_event({call,From}, enter, #{buf := Buf} = Data) ->
- Chars = unicode:characters_to_binary(lists:reverse(Buf)),
- try binary_to_integer(Chars) of
- Digit ->
- {keep_state, Data#{buf := []},
- [{reply,From,ok},
- {next_event,internal,{button,Chars}}]}
- catch
- error:badarg ->
- {keep_state, Data#{buf := []},
- [{reply,From,{error,not_an_integer}}]}
+]]></code>
+ <code type="erl"><![CDATA[
+handle_common(cast, {down,Button}, Data) ->
+ {keep_state, Data#{button => Button}};
+handle_common(cast, {up,Button}, Data) ->
+ case Data of
+ #{button := Button} ->
+ {keep_state,maps:remove(button, Data),
+ [{next_event,internal,{button,Button}}]};
+ #{} ->
+ keep_state_and_data
end;
...
- ]]></code>
+
+open(internal, {button,_}, Data) ->
+ {keep_state,Data,[postpone]};
+...
+]]></code>
<p>
If you start this program with <c>code_lock:start([17])</c>
- you can unlock with <c>code_lock:put_chars(&lt;&lt;"001">>),
- code_lock:put_chars(&lt;&lt;"7">>), code_lock:enter()</c>.
+ you can unlock with <c>code_lock:down(17), code_lock:up(17).</c>
</p>
</section>
@@ -1341,17 +1948,19 @@ handle_event({call,From}, enter, #{buf := Buf} = Data) ->
<title>Example Revisited</title>
<p>
This section includes the example after most of the mentioned
- modifications and some more using state enter calls,
+ modifications and some more using <em>state enter calls</em>,
which deserves a new state diagram:
</p>
- <image file="../design_principles/code_lock_2.png">
+ <!-- The image is edited with dia in a .dia file,
+ then exported to Scalable Vector Graphics. -->
+ <image file="../design_principles/code_lock_2.svg" width="80%">
<icaption>Code Lock State Diagram Revisited</icaption>
</image>
<p>
Notice that this state diagram does not specify how to handle
a button event in the state <c>open</c>. So, you need to
- read somewhere else that unspecified events
- must be ignored as in not consumed but handled in some other state.
+ read in some side notes, that is, here: that unspecified events
+ shall be postponed (handled in some later state).
Also, the state diagram does not show that the <c>code_length/0</c>
call must be handled in every state.
</p>
@@ -1368,8 +1977,8 @@ handle_event({call,From}, enter, #{buf := Buf} = Data) ->
-define(NAME, code_lock_2).
-export([start_link/1,stop/0]).
--export([button/1,code_length/0]).
--export([init/1,callback_mode/0,terminate/3,code_change/4]).
+-export([down/1,up/1,code_length/0]).
+-export([init/1,callback_mode/0,terminate/3]).
-export([locked/3,open/3]).
start_link(Code) ->
@@ -1377,52 +1986,74 @@ start_link(Code) ->
stop() ->
gen_statem:stop(?NAME).
-button(Digit) ->
- gen_statem:cast(?NAME, {button,Digit}).
+down(Button) ->
+ gen_statem:cast(?NAME, {down,Button}).
+up(Button) ->
+ gen_statem:cast(?NAME, {up,Button}).
code_length() ->
gen_statem:call(?NAME, code_length).
-
+ ]]></code>
+ <code type="erl"><![CDATA[
init(Code) ->
process_flag(trap_exit, true),
- Data = #{code => Code},
+ Data = #{code => Code, length => length(Code), buttons => []},
{ok, locked, Data}.
callback_mode() ->
[state_functions,state_enter].
-locked(enter, _OldState, #{code := Code} = Data) ->
+-define(HANDLE_COMMON,
+ ?FUNCTION_NAME(T, C, D) -> handle_common(T, C, D)).
+%%
+handle_common(cast, {down,Button}, Data) ->
+ {keep_state, Data#{button => Button}};
+handle_common(cast, {up,Button}, Data) ->
+ case Data of
+ #{button := Button} ->
+ {keep_state, maps:remove(button, Data),
+ [{next_event,internal,{button,Button}}]};
+ #{} ->
+ keep_state_and_data
+ end;
+handle_common({call,From}, code_length, #{code := Code}) ->
+ {keep_state_and_data,
+ [{reply,From,length(Code)}]}.
+ ]]></code>
+ <code type="erl"><![CDATA[
+locked(enter, _OldState, Data) ->
do_lock(),
- {keep_state, Data#{remaining => Code}};
+ {keep_state, Data#{buttons := []}};
+locked(state_timeout, button, Data) ->
+ {keep_state, Data#{buttons := []}};
locked(
- timeout, _,
- #{code := Code, remaining := Remaining} = Data) ->
- {keep_state, Data#{remaining := Code}};
-locked(
- cast, {button,Digit},
- #{code := Code, remaining := Remaining} = Data) ->
- case Remaining of
- [Digit] -> % Complete
+ internal, {button,Button},
+ #{code := Code, length := Length, buttons := Buttons} = Data) ->
+ NewButtons =
+ if
+ length(Buttons) < Length ->
+ Buttons;
+ true ->
+ tl(Buttons)
+ end ++ [Button],
+ if
+ NewButtons =:= Code -> % Correct
{next_state, open, Data};
- [Digit|Rest] -> % Incomplete
- {keep_state, Data#{remaining := Rest}, 30000};
- [_|_] -> % Wrong
- {keep_state, Data#{remaining := Code}}
+ true -> % Incomplete | Incorrect
+ {keep_state, Data#{buttons := NewButtons},
+ [{state_timeout,30000,button}]} % Time in milliseconds
end;
-locked(EventType, EventContent, Data) ->
- handle_event(EventType, EventContent, Data).
-
+?HANDLE_COMMON.
+]]></code>
+ <code type="erl"><![CDATA[
open(enter, _OldState, _Data) ->
do_unlock(),
- {keep_state_and_data, [{state_timeout,10000,lock}]};
+ {keep_state_and_data,
+ [{state_timeout,10000,lock}]}; % Time in milliseconds
open(state_timeout, lock, Data) ->
{next_state, locked, Data};
-open(cast, {button,_}, _) ->
+open(internal, {button,_}, _) ->
{keep_state_and_data, [postpone]};
-open(EventType, EventContent, Data) ->
- handle_event(EventType, EventContent, Data).
-
-handle_event({call,From}, code_length, #{code := Code}) ->
- {keep_state_and_data, [{reply,From,length(Code)}]}.
+?HANDLE_COMMON.
do_lock() ->
io:format("Locked~n", []).
@@ -1432,9 +2063,7 @@ do_unlock() ->
terminate(_Reason, State, _Data) ->
State =/= locked andalso do_lock(),
ok.
-code_change(_Vsn, State, Data, _Extra) ->
- {ok,State,Data}.
- ]]></code>
+ ]]></code>
</section>
<section>
@@ -1444,58 +2073,76 @@ code_change(_Vsn, State, Data, _Extra) ->
This section describes what to change in the example
to use one <c>handle_event/4</c> function.
The previously used approach to first branch depending on event
- does not work that well here because of the state enter calls,
+ does not work that well here
+ because of the <em>state enter calls</em>,
so this example first branches depending on state:
</p>
<code type="erl"><![CDATA[
-...
-export([handle_event/4]).
-
-...
+]]></code>
+ <code type="erl"><![CDATA[
callback_mode() ->
[handle_event_function,state_enter].
-
+ ]]></code>
+ <code type="erl"><![CDATA[
+%%
%% State: locked
-handle_event(
- enter, _OldState, locked,
- #{code := Code} = Data) ->
+handle_event(enter, _OldState, locked, Data) ->
do_lock(),
- {keep_state, Data#{remaining => Code}};
+ {keep_state, Data#{buttons := []}};
+handle_event(state_timeout, button, locked, Data) ->
+ {keep_state, Data#{buttons := []}};
handle_event(
- timeout, _, locked,
- #{code := Code, remaining := Remaining} = Data) ->
- {keep_state, Data#{remaining := Code}};
-handle_event(
- cast, {button,Digit}, locked,
- #{code := Code, remaining := Remaining} = Data) ->
- case Remaining of
- [Digit] -> % Complete
+ internal, {button,Button}, locked,
+ #{code := Code, length := Length, buttons := Buttons} = Data) ->
+ NewButtons =
+ if
+ length(Buttons) < Length ->
+ Buttons;
+ true ->
+ tl(Buttons)
+ end ++ [Button],
+ if
+ NewButtons =:= Code -> % Correct
{next_state, open, Data};
- [Digit|Rest] -> % Incomplete
- {keep_state, Data#{remaining := Rest}, 30000};
- [_|_] -> % Wrong
- {keep_state, Data#{remaining := Code}}
+ true -> % Incomplete | Incorrect
+ {keep_state, Data#{buttons := NewButtons},
+ [{state_timeout,30000,button}]} % Time in milliseconds
end;
+ ]]></code>
+ <code type="erl"><![CDATA[
%%
%% State: open
handle_event(enter, _OldState, open, _Data) ->
do_unlock(),
- {keep_state_and_data, [{state_timeout,10000,lock}]};
+ {keep_state_and_data,
+ [{state_timeout,10000,lock}]}; % Time in milliseconds
handle_event(state_timeout, lock, open, Data) ->
{next_state, locked, Data};
-handle_event(cast, {button,_}, open, _) ->
+handle_event(internal, {button,_}, open, _) ->
{keep_state_and_data,[postpone]};
-%%
-%% Any state
-handle_event({call,From}, code_length, _State, #{code := Code}) ->
- {keep_state_and_data, [{reply,From,length(Code)}]}.
-
-...
- ]]></code>
+ ]]></code>
+ <code type="erl"><![CDATA[
+%% Common events
+handle_event(cast, {down,Button}, _State, Data) ->
+ {keep_state, Data#{button => Button}};
+handle_event(cast, {up,Button}, _State, Data) ->
+ case Data of
+ #{button := Button} ->
+ {keep_state, maps:remove(button, Data),
+ [{next_event,internal,{button,Button}},
+ {state_timeout,30000,button}]}; % Time in milliseconds
+ #{} ->
+ keep_state_and_data
+ end;
+handle_event({call,From}, code_length, _State, #{length := Length}) ->
+ {keep_state_and_data,
+ [{reply,From,Length}]}.
+ ]]></code>
</section>
<p>
- Notice that postponing buttons from the <c>locked</c> state
- to the <c>open</c> state feels like a strange thing to do
+ Notice that postponing buttons from the <c>open</c> state
+ to the <c>locked</c> state feels like a strange thing to do
for a code lock, but it at least illustrates event postponing.
</p>
</section>
@@ -1532,7 +2179,7 @@ handle_event({call,From}, code_length, _State, #{code := Code}) ->
</p>
<code type="erl"><![CDATA[
...
--export([init/1,terminate/3,code_change/4,format_status/2]).
+-export([init/1,terminate/3,format_status/2]).
...
format_status(Opt, [_PDict,State,Data]) ->
@@ -1540,7 +2187,6 @@ format_status(Opt, [_PDict,State,Data]) ->
{State,
maps:filter(
fun (code, _) -> false;
- (remaining, _) -> false;
(_, _) -> true
end,
Data)},
@@ -1567,7 +2213,7 @@ format_status(Opt, [_PDict,State,Data]) ->
<marker id="Complex State" />
<title>Complex State</title>
<p>
- The callback mode
+ The <em>callback mode</em>
<seealso marker="stdlib:gen_statem#type-callback_mode"><c>handle_event_function</c></seealso>
enables using a non-atom state as described in section
<seealso marker="#Callback Modes">Callback Modes</seealso>,
@@ -1579,7 +2225,7 @@ format_status(Opt, [_PDict,State,Data]) ->
<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
+ We will go for the latter and 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,
@@ -1588,33 +2234,33 @@ format_status(Opt, [_PDict,State,Data]) ->
<p>
Suppose now that we call <c>set_lock_button</c>
while the door is open,
- and have already postponed a button event
- that until now was not the lock button.
- The sensible thing can be to say that
- the button was pressed too early so it is
- not to be recognized as the lock button.
- However, then it can be surprising that a button event
- that now is the lock button event arrives (as retried postponed)
- immediately after the state transits to <c>locked</c>.
- </p>
- <p>
- So we make the <c>button/1</c> function synchronous
- by using
- <seealso marker="stdlib:gen_statem#call/2"><c>gen_statem:call</c></seealso>
- and still postpone its events in the <c>open</c> state.
- Then a call to <c>button/1</c> during the <c>open</c>
- state does not return until the state transits to <c>locked</c>,
- as it is there the event is handled and the reply is sent.
- </p>
- <p>
- If a process now calls <c>set_lock_button/1</c>
- to change the lock button while another process
- hangs in <c>button/1</c> with the new lock button,
- it can be expected that the hanging lock button call
- immediately takes effect and locks the lock.
- Therefore, we make the current lock button a part of the state,
- so that when we change the lock button, the state changes
- and all postponed events are retried.
+ and we have already postponed a button event
+ that was the new lock button:
+ </p>
+ <code type="erl"><![CDATA[
+1> code_lock:start_link([a,b,c], x).
+{ok,<0.666.0>}
+2> code_lock:button(a).
+ok
+3> code_lock:button(b).
+ok
+4> code_lock:button(c).
+ok
+Open
+5> code_lock:button(y).
+ok
+6> code_lock:set_lock_button(y).
+x
+% What should happen here? Immediate lock or nothing?
+]]></code>
+ <p>
+ We could say that the button was pressed too early
+ so it is not to be recognized as the lock button.
+ Or we can make the lock button part of the state so
+ when we then change the lock button in the locked state,
+ the change becomes a <em>state change</em>
+ and all postponed events are retried,
+ therefore the lock is immediately locked!
</p>
<p>
We define the state as <c>{StateName,LockButton}</c>,
@@ -1627,8 +2273,8 @@ format_status(Opt, [_PDict,State,Data]) ->
-define(NAME, code_lock_3).
-export([start_link/2,stop/0]).
--export([button/1,code_length/0,set_lock_button/1]).
--export([init/1,callback_mode/0,terminate/3,code_change/4,format_status/2]).
+-export([button/1,set_lock_button/1]).
+-export([init/1,callback_mode/0,terminate/3]).
-export([handle_event/4]).
start_link(Code, LockButton) ->
@@ -1637,77 +2283,68 @@ start_link(Code, LockButton) ->
stop() ->
gen_statem:stop(?NAME).
-button(Digit) ->
- gen_statem:call(?NAME, {button,Digit}).
-code_length() ->
- gen_statem:call(?NAME, code_length).
+button(Button) ->
+ gen_statem:cast(?NAME, {button,Button}).
set_lock_button(LockButton) ->
gen_statem:call(?NAME, {set_lock_button,LockButton}).
-
+ ]]></code>
+ <code type="erl"><![CDATA[
init({Code,LockButton}) ->
process_flag(trap_exit, true),
- Data = #{code => Code, remaining => undefined},
+ Data = #{code => Code, length => length(Code), buttons => []},
{ok, {locked,LockButton}, Data}.
callback_mode() ->
[handle_event_function,state_enter].
-handle_event(
- {call,From}, {set_lock_button,NewLockButton},
- {StateName,OldLockButton}, Data) ->
- {next_state, {StateName,NewLockButton}, Data,
- [{reply,From,OldLockButton}]};
-handle_event(
- {call,From}, code_length,
- {_StateName,_LockButton}, #{code := Code}) ->
- {keep_state_and_data,
- [{reply,From,length(Code)}]};
-%%
%% State: locked
+handle_event(enter, _OldState, {locked,_}, Data) ->
+ do_lock(),
+ {keep_state, Data#{buttons := []}};
+handle_event(state_timeout, button, {locked,_}, Data) ->
+ {keep_state, Data#{buttons := []}};
handle_event(
- EventType, EventContent,
- {locked,LockButton}, #{code := Code, remaining := Remaining} = Data) ->
- case {EventType, EventContent} of
- {enter, _OldState} ->
- do_lock(),
- {keep_state, Data#{remaining := Code}};
- {timeout, _} ->
- {keep_state, Data#{remaining := Code}};
- {{call,From}, {button,Digit}} ->
- case Remaining of
- [Digit] -> % Complete
- {next_state, {open,LockButton}, Data,
- [{reply,From,ok}]};
- [Digit|Rest] -> % Incomplete
- {keep_state, Data#{remaining := Rest},
- [{reply,From,ok}, 30000]};
- [_|_] -> % Wrong
- {keep_state, Data#{remaining := Code},
- [{reply,From,ok}]}
- end
+ cast, {button,Button}, {locked,LockButton},
+ #{code := Code, length := Length, buttons := Buttons} = Data) ->
+ NewButtons =
+ if
+ length(Buttons) < Length ->
+ Buttons;
+ true ->
+ tl(Buttons)
+ end ++ [Button],
+ if
+ NewButtons =:= Code -> % Correct
+ {next_state, {open,LockButton}, Data};
+ true -> % Incomplete | Incorrect
+ {keep_state, Data#{buttons := NewButtons},
+ [{state_timeout,30000,button}]} % Time in milliseconds
end;
+ ]]></code>
+ <code type="erl"><![CDATA[
%%
%% State: open
+handle_event(enter, _OldState, {open,_}, _Data) ->
+ do_unlock(),
+ {keep_state_and_data,
+ [{state_timeout,10000,lock}]}; % Time in milliseconds
+handle_event(state_timeout, lock, {open,LockButton}, Data) ->
+ {next_state, {locked,LockButton}, Data};
+handle_event(cast, {button,LockButton}, {open,LockButton}, Data) ->
+ {next_state, {locked,LockButton}, Data};
+handle_event(cast, {button,_}, {open,_}, _Data) ->
+ {keep_state_and_data,[postpone]};
+ ]]></code>
+ <code type="erl"><![CDATA[
+%%
+%% Common events
handle_event(
- EventType, EventContent,
- {open,LockButton}, Data) ->
- case {EventType, EventContent} of
- {enter, _OldState} ->
- do_unlock(),
- {keep_state_and_data, [{state_timeout,10000,lock}]};
- {state_timeout, lock} ->
- {next_state, {locked,LockButton}, Data};
- {{call,From}, {button,Digit}} ->
- if
- Digit =:= LockButton ->
- {next_state, {locked,LockButton}, Data,
- [{reply,From,locked}]};
- true ->
- {keep_state_and_data,
- [postpone]}
- end
- end.
-
+ {call,From}, {set_lock_button,NewLockButton},
+ {StateName,OldLockButton}, Data) ->
+ {next_state, {StateName,NewLockButton}, Data,
+ [{reply,From,OldLockButton}]}.
+ ]]></code>
+ <code type="erl"><![CDATA[
do_lock() ->
io:format("Locked~n", []).
do_unlock() ->
@@ -1716,29 +2353,7 @@ do_unlock() ->
terminate(_Reason, State, _Data) ->
State =/= locked andalso do_lock(),
ok.
-code_change(_Vsn, State, Data, _Extra) ->
- {ok,State,Data}.
-format_status(Opt, [_PDict,State,Data]) ->
- StateData =
- {State,
- maps:filter(
- fun (code, _) -> false;
- (remaining, _) -> false;
- (_, _) -> true
- end,
- Data)},
- case Opt of
- terminate ->
- StateData;
- normal ->
- [{data,[{"State",StateData}]}]
- end.
]]></code>
- <p>
- It can be an ill-fitting model for a physical code lock
- that the <c>button/1</c> call can hang until the lock
- is locked. But for an API in general it is not that strange.
- </p>
</section>
<!-- =================================================================== -->
@@ -1770,17 +2385,15 @@ format_status(Opt, [_PDict,State,Data]) ->
</p>
<code type="erl"><![CDATA[
...
+%%
%% State: open
-handle_event(
- EventType, EventContent,
- {open,LockButton}, Data) ->
- case {EventType, EventContent} of
- {enter, _OldState} ->
- do_unlock(),
- {keep_state_and_data,
- [{state_timeout,10000,lock},hibernate]};
+handle_event(enter, _OldState, {open,_}, _Data) ->
+ do_unlock(),
+ {keep_state_and_data,
+ [{state_timeout,10000,lock}, % Time in milliseconds
+ hibernate]};
...
- ]]></code>
+]]></code>
<p>
The atom
<seealso marker="stdlib:gen_statem#type-hibernate"><c>hibernate</c></seealso>
@@ -1793,20 +2406,35 @@ handle_event(
<p>
To change that we would need to insert
action <c>hibernate</c> in more places.
- For example, for the state-independent <c>set_lock_button</c>
- and <c>code_length</c> operations that then would have to
- be aware of using <c>hibernate</c> while in the
+ For example, the state-independent <c>set_lock_button</c>
+ operation would have to use <c>hibernate</c> but only in the
<c>{open,_}</c> state, which would clutter the code.
</p>
<p>
- Another not uncommon scenario is to use the event time-out
- to triger hibernation after a certain time of inactivity.
+ Another not uncommon scenario is to use the
+ <seealso marker="#Event Time-Outs">event time-out</seealso>
+ to trigger hibernation after a certain time of inactivity.
+ There is also a server start option
+ <seealso marker="stdlib:gen_statem#type-enter_loop_opt">
+ <c>{hibernate_after, Timeout}</c>
+ </seealso>
+ for
+ <seealso marker="stdlib:gen_statem#start/3"><c>start/3,4</c></seealso>,
+ <seealso marker="stdlib:gen_statem#start_link/3">
+ <c>start_link/3,4</c>
+ </seealso>
+ or
+ <seealso marker="stdlib:gen_statem#enter_loop/4">
+ <c>enter_loop/4,5,6</c>
+ </seealso>
+ that may be used to automatically hibernate the server.
</p>
<p>
- This server probably does not use
+ This particular server probably does not use
heap memory worth hibernating for.
To gain anything from hibernation, your server would
- have to produce some garbage during callback execution,
+ have to produce non-insignificant garbage
+ during callback execution,
for which this example server can serve as a bad example.
</p>
</section>
diff --git a/system/doc/design_principles/sup_princ.xml b/system/doc/design_principles/sup_princ.xml
index 06ca44a9f6..321fa41e8d 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>2017</year>
+ <year>1997</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -312,12 +312,17 @@ child_spec() = #{id => child_id(), % mandatory
signal back. If no exit signal is received within
the specified time, the child process is unconditionally
terminated using <c>exit(Child, kill)</c>.</item>
- <item>If the child process is another supervisor, it is to be
+ <item>If the child process is another supervisor, it must be
set to <c>infinity</c> to give the subtree enough time to
shut down. It is also allowed to set it to <c>infinity</c>,
- if the child process is a worker. See the warning below:</item>
+ if the child process is a worker. See the warning below:</item>
</list>
<warning>
+ <p>Setting the shutdown time to anything other
+ than <c>infinity</c> for a child of type <c>supervisor</c>
+ can cause a race condition where the child in question
+ unlinks its own children, but fails to terminate them
+ before it is killed.</p>
<p>Be careful when setting the shutdown time to
<c>infinity</c> when the child process is a worker. Because, in this
situation, the termination of the supervision tree depends on the
diff --git a/system/doc/efficiency_guide/Makefile b/system/doc/efficiency_guide/Makefile
index 36e4cd00df..a2742a1354 100644
--- a/system/doc/efficiency_guide/Makefile
+++ b/system/doc/efficiency_guide/Makefile
@@ -1,7 +1,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 2001-2016. All Rights Reserved.
+# Copyright Ericsson AB 2001-2018. 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.
@@ -28,6 +28,7 @@ include $(ERL_TOP)/erts/vsn.mk
#VSN=$(SYSTEM_VSN)
APPLICATION=otp-system-documentation
+XMLDIR := $(XMLDIR)/efficiency_guide
# ----------------------------------------------------
# Release directory specification
# ----------------------------------------------------
@@ -86,7 +87,6 @@ DVIPS_FLAGS +=
# ----------------------------------------------------
# Targets
# ----------------------------------------------------
-_create_dirs := $(shell mkdir -p $(HTMLDIR))
docs: html
@@ -97,7 +97,8 @@ html: $(GIF_FILES) $(HTML_UG_FILE)
debug opt:
clean clean_docs:
- rm -rf $(HTMLDIR)
+ rm -f $(XMLDIR)/*.xml
+ rm -f $(HTMLDIR)/*.gif $(HTMLDIR)/*.html
rm -f $(TOP_PDF_FILE) $(TOP_PDF_FILE:%.pdf=%.fo)
rm -f errs core *~
diff --git a/system/doc/efficiency_guide/advanced.xml b/system/doc/efficiency_guide/advanced.xml
index 7f719849cc..fe77ce8ea4 100644
--- a/system/doc/efficiency_guide/advanced.xml
+++ b/system/doc/efficiency_guide/advanced.xml
@@ -4,7 +4,7 @@
<chapter>
<header>
<copyright>
- <year>2001</year><year>2016</year>
+ <year>2001</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -188,16 +188,9 @@
limit can be raised or lowered using the <c>+t</c> option.</cell>
</row>
<row>
- <cell>Ets tables</cell>
- <cell>Default is 1400. It can be changed with the environment
- variable <c>ERL_MAX_ETS_TABLES</c>.</cell>
- </row>
- <row>
<cell>Elements in a tuple</cell>
- <cell>The maximum number of elements in a tuple is 67,108,863
- (26-bit unsigned integer). Clearly, other factors such as the
- available memory can make it difficult to create a tuple of
- that size.</cell>
+ <cell>The maximum number of elements in a tuple is 16,777,215
+ (24-bit unsigned integer).</cell>
</row>
<row>
<cell>Size of binary</cell>
@@ -255,10 +248,11 @@
<cell><marker id="unique_references"/>Unique References on a Runtime System Instance</cell>
<cell>Each scheduler thread has its own set of references, and all
other threads have a shared set of references. Each set of references
- consist of <c>2⁶⁴ - 1</c> unique references. That is the total
+ consist of <c>2⁶⁴ - 1</c> unique references. That is, the total
amount of unique references that can be produced on a runtime
- system instance is <c>(NoSchedulers + 1) * (2⁶⁴ - 1)</c>. If a
- scheduler thread create a new reference each nano second,
+ system instance is <c>(NoSchedulers + 1) × (2⁶⁴ - 1)</c>.
+ <br/><br/>
+ If a scheduler thread create a new reference each nano second,
references will at earliest be reused after more than 584 years.
That is, for the foreseeable future they are unique enough.</cell>
</row>
diff --git a/system/doc/efficiency_guide/binaryhandling.xml b/system/doc/efficiency_guide/binaryhandling.xml
index 19f40c9abe..d92da17390 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>2017</year>
+ <year>2018</year>
<holder>Ericsson AB, All Rights Reserved</holder>
</copyright>
<legalnotice>
@@ -357,25 +357,8 @@ all_but_zeroes_to_list(<<Byte,T/binary>>, Acc, Remaining) ->
<c>Buffer</c> from a match context to a sub binary (or do nothing if
<c>Buffer</c> is a binary already).</p>
- <p>Before you begin to think that the compiler can optimize any binary
- patterns, the following function cannot be optimized by the compiler
- (currently, at least):</p>
-
- <code type="erl"><![CDATA[
-non_opt_eq([H|T1], <<H,T2/binary>>) ->
- non_opt_eq(T1, T2);
-non_opt_eq([_|_], <<_,_/binary>>) ->
- false;
-non_opt_eq([], <<>>) ->
- true.]]></code>
-
- <p>It was mentioned earlier that the compiler can only delay creation of
- sub binaries if it knows that the binary will not be shared. In this case,
- the compiler cannot know.</p>
-
- <p>Soon it is shown how to rewrite <c>non_opt_eq/2</c> so that the delayed
- sub binary optimization can be applied, and more importantly, it is shown
- how you can find out whether your code can be optimized.</p>
+ <p>But in more complicated code, how can one know whether the
+ optimization is applied or not?</p>
<section>
<marker id="bin_opt_info"></marker>
@@ -401,8 +384,8 @@ export ERL_COMPILER_OPTIONS=bin_opt_info]]></code>
<p>The warnings look as follows:</p>
<code type="erl"><![CDATA[
-./efficiency_guide.erl:60: Warning: NOT OPTIMIZED: sub binary is used or returned
-./efficiency_guide.erl:62: Warning: OPTIMIZED: creation of sub binary delayed]]></code>
+./efficiency_guide.erl:60: Warning: NOT OPTIMIZED: binary is returned from the function
+./efficiency_guide.erl:62: Warning: OPTIMIZED: match context reused]]></code>
<p>To make it clearer exactly what code the warnings refer to, the
warnings in the following examples are inserted as comments
@@ -410,10 +393,10 @@ export ERL_COMPILER_OPTIONS=bin_opt_info]]></code>
<code type="erl"><![CDATA[
after_zero(<<0,T/binary>>) ->
- %% NOT OPTIMIZED: sub binary is used or returned
+ %% BINARY CREATED: binary is returned from the function
T;
after_zero(<<_,T/binary>>) ->
- %% OPTIMIZED: creation of sub binary delayed
+ %% OPTIMIZED: match context reused
after_zero(T);
after_zero(<<>>) ->
<<>>.]]></code>
@@ -422,67 +405,6 @@ after_zero(<<>>) ->
binary cannot be delayed, because it will be returned.
The warning for the second clause says that a sub binary will not be
created (yet).</p>
-
- <p>Let us revisit the earlier example of the code that could not
- be optimized and find out why:</p>
-
- <code type="erl"><![CDATA[
-non_opt_eq([H|T1], <<H,T2/binary>>) ->
- %% INFO: matching anything else but a plain variable to
- %% the left of binary pattern will prevent delayed
- %% sub binary optimization;
- %% SUGGEST changing argument order
- %% NOT OPTIMIZED: called function non_opt_eq/2 does not
- %% begin with a suitable binary matching instruction
- non_opt_eq(T1, T2);
-non_opt_eq([_|_], <<_,_/binary>>) ->
- false;
-non_opt_eq([], <<>>) ->
- true.]]></code>
-
- <p>The compiler emitted two warnings. The <c>INFO</c> warning refers
- to the function <c>non_opt_eq/2</c> as a callee, indicating that any
- function that call <c>non_opt_eq/2</c> cannot make delayed sub binary
- optimization. There is also a suggestion to change argument order.
- The second warning (that happens to refer to the same line) refers to
- the construction of the sub binary itself.</p>
-
- <p>Soon another example will show the difference between the
- <c>INFO</c> and <c>NOT OPTIMIZED</c> warnings somewhat clearer, but
- let us first follow the suggestion to change argument order:</p>
-
- <code type="erl"><![CDATA[
-opt_eq(<<H,T1/binary>>, [H|T2]) ->
- %% OPTIMIZED: creation of sub binary delayed
- opt_eq(T1, T2);
-opt_eq(<<_,_/binary>>, [_|_]) ->
- false;
-opt_eq(<<>>, []) ->
- true.]]></code>
-
- <p>The compiler gives a warning for the following code fragment:</p>
-
- <code type="erl"><![CDATA[
-match_body([0|_], <<H,_/binary>>) ->
- %% INFO: matching anything else but a plain variable to
- %% the left of binary pattern will prevent delayed
- %% sub binary optimization;
- %% SUGGEST changing argument order
- done;
-...]]></code>
-
- <p>The warning means that <em>if</em> there is a call to <c>match_body/2</c>
- (from another clause in <c>match_body/2</c> or another function), the
- delayed sub binary optimization will not be possible. More warnings will
- occur for any place where a sub binary is matched out at the end of and
- passed as the second argument to <c>match_body/2</c>, for example:</p>
-
- <code type="erl"><![CDATA[
-match_head(List, <<_:10,Data/binary>>) ->
- %% NOT OPTIMIZED: called function match_body/2 does not
- %% begin with a suitable binary matching instruction
- match_body(List, Data).]]></code>
-
</section>
<section>
diff --git a/system/doc/efficiency_guide/commoncaveats.xml b/system/doc/efficiency_guide/commoncaveats.xml
index b41ffc3902..7b2128d888 100644
--- a/system/doc/efficiency_guide/commoncaveats.xml
+++ b/system/doc/efficiency_guide/commoncaveats.xml
@@ -36,10 +36,9 @@
<title>Timer Module</title>
<p>Creating timers using <seealso
- marker="erts:erlang#erlang:send_after/3">erlang:send_after/3</seealso>
+ marker="erts:erlang#send_after/3">erlang:send_after/3</seealso>
and
- <seealso marker="erts:erlang#erlang:start_timer/3">erlang:start_timer/3</seealso>
-,
+ <seealso marker="erts:erlang#start_timer/3">erlang:start_timer/3</seealso>,
is much more efficient than using the timers provided by the
<seealso marker="stdlib:timer">timer</seealso> module in STDLIB.
The <c>timer</c> module uses a separate process to manage the timers.
@@ -169,53 +168,5 @@ multiple_setelement(T0) ->
{Bin1,Bin2} = split_binary(Bin, Num)</code>
</section>
- <section>
- <title>Operator "--"</title>
- <p>The "<c>--</c>" operator has a complexity
- proportional to the product of the length of its operands.
- This means that the operator is very slow if both of its operands
- are long lists:</p>
-
- <p><em>DO NOT</em></p>
- <code type="none"><![CDATA[
- HugeList1 -- HugeList2]]></code>
-
- <p>Instead use the <seealso marker="stdlib:ordsets">ordsets</seealso>
- module in STDLIB:</p>
-
- <p><em>DO</em></p>
- <code type="none">
- HugeSet1 = ordsets:from_list(HugeList1),
- HugeSet2 = ordsets:from_list(HugeList2),
- ordsets:subtract(HugeSet1, HugeSet2)</code>
-
- <p>Obviously, that code does not work if the original order
- of the list is important. If the order of the list must be
- preserved, do as follows:</p>
-
- <p><em>DO</em></p>
- <code type="none"><![CDATA[
- Set = gb_sets:from_list(HugeList2),
- [E || E <- HugeList1, not gb_sets:is_element(E, Set)]]]></code>
-
- <note><p>This code behaves differently from "<c>--</c>"
- if the lists contain duplicate elements (one occurrence
- of an element in HugeList2 removes <em>all</em>
- occurrences in HugeList1.)</p>
- <p>Also, this code compares lists elements using the
- "<c>==</c>" operator, while "<c>--</c>" uses the "<c>=:=</c>" operator.
- If that difference is important, <c>sets</c> can be used instead of
- <c>gb_sets</c>, but <c>sets:from_list/1</c> is much
- slower than <c>gb_sets:from_list/1</c> for long lists.</p></note>
-
- <p>Using the "<c>--</c>" operator to delete an element
- from a list is not a performance problem:</p>
-
- <p><em>OK</em></p>
- <code type="none">
- HugeList1 -- [Element]</code>
-
- </section>
-
</chapter>
diff --git a/system/doc/efficiency_guide/efficiency_guide.erl b/system/doc/efficiency_guide/efficiency_guide.erl
index e982bdae65..c57785aaa3 100644
--- a/system/doc/efficiency_guide/efficiency_guide.erl
+++ b/system/doc/efficiency_guide/efficiency_guide.erl
@@ -1,5 +1,5 @@
-module(efficiency_guide).
--compile(export_all).
+-compile([export_all,nowarn_export_all).
%% DO NOT
naive_reverse([H|T]) ->
@@ -71,28 +71,6 @@ all_but_zeroes_to_list(<<0,T/binary>>, Acc, Remaining) ->
all_but_zeroes_to_list(<<Byte,T/binary>>, Acc, Remaining) ->
all_but_zeroes_to_list(T, [Byte|Acc], Remaining-1).
-non_opt_eq([H|T1], <<H,T2/binary>>) ->
- non_opt_eq(T1, T2);
-non_opt_eq([_|_], <<_,_/binary>>) ->
- false;
-non_opt_eq([], <<>>) ->
- true.
-
-opt_eq(<<H,T1/binary>>, [H|T2]) ->
- opt_eq(T1, T2);
-opt_eq(<<_,_/binary>>, [_|_]) ->
- false;
-opt_eq(<<>>, []) ->
- true.
-
-match_head(List, <<_:10,Data/binary>>) ->
- match_body(List, Data).
-
-match_body([0|_], <<H,_/binary>>) ->
- done;
-match_body([H|T1], <<H,T2/binary>>) ->
- {T1,T2}.
-
count1(<<_,T/binary>>, Count) -> count1(T, Count+1);
count1(<<>>, Count) -> Count.
diff --git a/system/doc/efficiency_guide/profiling.xml b/system/doc/efficiency_guide/profiling.xml
index f185456158..5ec1f1be6e 100644
--- a/system/doc/efficiency_guide/profiling.xml
+++ b/system/doc/efficiency_guide/profiling.xml
@@ -4,7 +4,7 @@
<chapter>
<header>
<copyright>
- <year>2001</year><year>2016</year>
+ <year>2001</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -94,7 +94,7 @@
<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
+ about the state of the system as it ran out of memory. 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>
diff --git a/system/doc/efficiency_guide/retired_myths.xml b/system/doc/efficiency_guide/retired_myths.xml
index 9b914a3b6e..144c942c2b 100644
--- a/system/doc/efficiency_guide/retired_myths.xml
+++ b/system/doc/efficiency_guide/retired_myths.xml
@@ -60,4 +60,18 @@
That leads us to the myth that tail-recursive functions are faster
than body-recursive functions.</p>
</section>
+
+ <section>
+ <title>Myth: List subtraction ("--" operator) is slow</title>
+
+ <p>List subtraction used to have a run-time complexity proportional to the
+ product of the length of its operands, so it was extremely slow when both
+ lists were long.</p>
+
+ <p>As of OTP 22 the run-time complexity is "n log n" and the operation will
+ complete quickly even when both lists are very long. In fact, it is
+ faster and uses less memory than the commonly used workaround to convert
+ both lists to ordered sets before subtracting them with
+ <c>ordsets:subtract/2</c>.</p>
+ </section>
</chapter>
diff --git a/system/doc/efficiency_guide/xmlfiles.mk b/system/doc/efficiency_guide/xmlfiles.mk
index 23c0d991b4..e275823dd1 100644
--- a/system/doc/efficiency_guide/xmlfiles.mk
+++ b/system/doc/efficiency_guide/xmlfiles.mk
@@ -1,7 +1,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 2009-2016. All Rights Reserved.
+# Copyright Ericsson AB 2009-2018. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
diff --git a/system/doc/embedded/Makefile b/system/doc/embedded/Makefile
index 40a1b1fb23..1604075312 100644
--- a/system/doc/embedded/Makefile
+++ b/system/doc/embedded/Makefile
@@ -1,7 +1,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 1997-2016. All Rights Reserved.
+# Copyright Ericsson AB 1997-2018. 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.
@@ -28,6 +28,7 @@ include $(ERL_TOP)/erts/vsn.mk
#VSN=$(SYSTEM_VSN)
APPLICATION=otp-system-documentation
+XMLDIR := $(XMLDIR)/embedded
# ----------------------------------------------------
# Release directory specification
# ----------------------------------------------------
@@ -74,7 +75,6 @@ DVIPS_FLAGS +=
# ----------------------------------------------------
# Targets
# ----------------------------------------------------
-_create_dirs := $(shell mkdir -p $(HTMLDIR))
docs: html
@@ -85,7 +85,8 @@ html: $(GIF_FILES) $(HTML_UG_FILE)
debug opt:
clean clean_docs:
- rm -rf $(HTMLDIR)
+ rm -f $(XMLDIR)/*.xml
+ rm -f $(HTMLDIR)/*.gif $(HTMLDIR)/*.html
rm -f $(TOP_PDF_FILE) $(TOP_PDF_FILE:%.pdf=%.fo)
rm -f errs core *~
diff --git a/system/doc/embedded/starting.xml b/system/doc/embedded/starting.xml
index 11bf9b412a..6888f9c959 100644
--- a/system/doc/embedded/starting.xml
+++ b/system/doc/embedded/starting.xml
@@ -231,7 +231,7 @@ exec $BINDIR/erlexec -boot $RELDIR/$VSN/start -config $RELDIR/$VSN/sys $* <
<p>If a diskless and/or read-only client node with the SASL
configuration parameter <c>static_emulator</c> set to <c>true</c>
is about to start the <c>-boot</c> and <c>-config</c> flags must be
- changed. As such a client can not read a new <c>start_erl.data</c>
+ changed. As such a client cannot read a new <c>start_erl.data</c>
file (the file is not possible to change dynamically) the boot and
config files is always fetched from the same place (but with a new
contents if a new release has been installed). The
diff --git a/system/doc/general_info/Makefile b/system/doc/general_info/Makefile
new file mode 100644
index 0000000000..539075280e
--- /dev/null
+++ b/system/doc/general_info/Makefile
@@ -0,0 +1,99 @@
+#
+# %CopyrightBegin%
+#
+# Copyright Ericsson AB 1996-2018. All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# %CopyrightEnd%
+#
+#
+include $(ERL_TOP)/make/target.mk
+include $(ERL_TOP)/make/$(TARGET)/otp.mk
+
+# ----------------------------------------------------
+# Application version
+# ----------------------------------------------------
+include $(ERL_TOP)/erts/vsn.mk
+#VSN=$(SYSTEM_VSN)
+
+APPLICATION=otp-system-documentation
+XMLDIR := $(XMLDIR)/general_info
+# ----------------------------------------------------
+# Release directory specification
+# ----------------------------------------------------
+RELSYSDIR = "$(RELEASE_PATH)/doc/general_info"
+
+# ----------------------------------------------------
+# Target Specs
+# ----------------------------------------------------
+XML_PART_FILES = part.xml
+
+include xmlfiles.mk
+
+XML_CHAPTER_FILES=$(GENERAL_INFO_CHAPTER_FILES)
+
+TOPDOCDIR=..
+
+BOOK_FILES = book.xml
+
+GIF_FILES =
+
+XML_FILES = \
+ $(BOOK_FILES) $(XML_CHAPTER_FILES) \
+ $(XML_PART_FILES)
+
+# ----------------------------------------------------
+
+HTMLDIR = ../html/general_info
+
+HTML_UG_FILE = $(HTMLDIR)/users_guide.html
+
+# ----------------------------------------------------
+# FLAGS
+# ----------------------------------------------------
+XML_FLAGS +=
+DVIPS_FLAGS +=
+
+# ----------------------------------------------------
+# Targets
+# ----------------------------------------------------
+
+docs: html
+
+local_docs: PDFDIR=../../pdf
+
+html: $(GIF_FILES) $(HTML_UG_FILE)
+
+debug opt:
+
+clean clean_docs:
+ rm -f $(XMLDIR)/*.xml
+ rm -f $(HTMLDIR)/*.gif $(HTMLDIR)/*.html
+ rm -f $(TOP_PDF_FILE) $(TOP_PDF_FILE:%.pdf=%.fo)
+ rm -f errs core *~
+
+# ----------------------------------------------------
+# Release Target
+# ----------------------------------------------------
+include $(ERL_TOP)/make/otp_release_targets.mk
+
+release_docs_spec: docs
+# $(INSTALL_DIR) "$(RELEASE_PATH)/pdf"
+# $(INSTALL_DATA) $(TOP_PDF_FILE) "$(RELEASE_PATH)/pdf"
+ $(INSTALL_DIR) $(RELSYSDIR)
+ $(INSTALL_DATA) $(GIF_FILES) $(HTMLDIR)/*.html \
+ $(RELSYSDIR)
+
+release_spec:
+
diff --git a/system/doc/general_info/book.xml b/system/doc/general_info/book.xml
new file mode 100644
index 0000000000..ca9b5fae39
--- /dev/null
+++ b/system/doc/general_info/book.xml
@@ -0,0 +1,44 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<!DOCTYPE book SYSTEM "book.dtd">
+
+<book xmlns:xi="http://www.w3.org/2001/XInclude">
+ <header titlestyle="normal">
+ <copyright>
+ <year>2019</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>General Information</title>
+ <prepared>OTP Team</prepared>
+ <docno></docno>
+ <date>2019-02-23</date>
+ <rev></rev>
+ <file>book.xml</file>
+ </header>
+ <insidecover>
+ </insidecover>
+ <pagetext>General Information</pagetext>
+ <preamble>
+ <contents level="2"></contents>
+ </preamble>
+ <parts lift="no">
+ <xi:include href="part.xml"/>
+ </parts>
+ <listofterms></listofterms>
+ <index></index>
+</book>
+
diff --git a/system/doc/general_info/deprecations.xml b/system/doc/general_info/deprecations.xml
new file mode 100644
index 0000000000..c748e60059
--- /dev/null
+++ b/system/doc/general_info/deprecations.xml
@@ -0,0 +1,98 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<!DOCTYPE chapter SYSTEM "chapter.dtd">
+
+<chapter>
+ <header>
+ <copyright>
+ <year>2019</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>Deprecations</title>
+ <prepared></prepared>
+ <docno></docno>
+ <date></date>
+ <rev></rev>
+ <file>deprecations.xml</file>
+ </header>
+ <section>
+ <title>Introduction</title>
+ <p>This document aim to list all deprecated functionality in Erlang/OTP. It
+ was introduced as of OTP 22, and have not yet been updated with all old
+ deprecations. Deprecations made in other parts of the documentation are of
+ course still valid. For more information regarding the strategy regarding
+ deprecations see the documentation of
+ <seealso marker="../system_principles/misc#deprecation">Support, Compatibility,
+ Deprecations, and Removal</seealso>.</p>
+ </section>
+ <section>
+ <marker id="OTP-22"/>
+ <title>OTP 22</title>
+ <section>
+ <title>VxWorks Support</title>
+ <p>Some parts of OTP has had limited VxWorks support, such as for
+ example <seealso marker="erl_interface:index"><c>erl_interface</c></seealso>.
+ This support is now deprecated and has also been
+ <seealso marker="scheduled_for_removal#OTP-23">scheduled for removal</seealso>.</p>
+ </section>
+ <section>
+ <title>Legacy parts of erl_interface</title>
+ <p>The old legacy <seealso marker="erl_interface:index"><c>erl_interface</c></seealso>
+ library (functions with prefix <c>erl_</c>) is deprecated as of OTP 22. These
+ parts of <c>erl_interface</c> has been informally deprecated
+ for a very long time. You typically want to replace the usage of
+ the <c>erl_interface</c> library with the use of the <c>ei</c> library
+ which also is part of the <c>erl_interface</c> application. The old legacy
+ <seealso marker="erl_interface:index"><c>erl_interface</c></seealso>
+ library has also been <seealso marker="scheduled_for_removal#OTP-23">scheduled
+ for removal</seealso>.</p>
+ </section>
+ <section>
+ <title>System Events</title>
+ <p>
+ The format of "System Events" as defined in the man page for
+ <seealso marker="stdlib:sys">sys</seealso>
+ has been clarified and cleaned up.
+ Due to this, code that relied on the internal badly
+ documented previous (before this change) format
+ of OTP's "System Events", needs to be changed.
+ </p>
+ <p>
+ In the wake of this the function
+ <seealso marker="stdlib:sys#get_debug/3">sys:get_debug/3</seealso>
+ that returns data with undocumented and internal format
+ (and therefore is practically useless) has been deprecated,
+ and a new function
+ <seealso marker="stdlib:sys#get_log/1">sys:get_log/1</seealso>
+ has been added,
+ that hopefully does what the deprecated function was intended for.
+ </p>
+ </section>
+ </section>
+ <section>
+ <marker id="OTP-18"/>
+ <title>OTP 18</title>
+ <section>
+ <title>erlang:now()</title>
+ <p>New time functionality and a new time API was introduced. For more information
+ see the <seealso marker="erts:time_correction">Time and Time Correction</seealso>
+ chapter in the ERTS User's guide and specifically the
+ <seealso marker="erts:time_correction#Dos_and_Donts">Dos and Donts</seealso>
+ section on how to replace usage of <c>erlang:now()</c>.</p>
+ </section>
+ </section>
+</chapter>
diff --git a/system/doc/general_info/part.xml b/system/doc/general_info/part.xml
new file mode 100644
index 0000000000..fead7d58e7
--- /dev/null
+++ b/system/doc/general_info/part.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<!DOCTYPE part SYSTEM "part.dtd">
+
+<part xmlns:xi="http://www.w3.org/2001/XInclude">
+ <header>
+ <copyright>
+ <year>2019</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>General Information</title>
+ <prepared>OTP Team</prepared>
+ <docno></docno>
+ <date>2019-02-23</date>
+ <rev></rev>
+ <file>part.xml</file>
+ </header>
+ <xi:include href="deprecations.xml"/>
+ <xi:include href="scheduled_for_removal.xml"/>
+</part>
diff --git a/system/doc/general_info/scheduled_for_removal.xml b/system/doc/general_info/scheduled_for_removal.xml
new file mode 100644
index 0000000000..a9421df385
--- /dev/null
+++ b/system/doc/general_info/scheduled_for_removal.xml
@@ -0,0 +1,61 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<!DOCTYPE chapter SYSTEM "chapter.dtd">
+
+<chapter>
+ <header>
+ <copyright>
+ <year>2019</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>Scheduled for Removal</title>
+ <prepared></prepared>
+ <docno></docno>
+ <date></date>
+ <rev></rev>
+ <file>scheduled_for_removal.xml</file>
+ </header>
+ <section>
+ <title>Introduction</title>
+ <p>This document list all functionality in Erlang/OTP that currently are
+ scheduled for removal. For more information regarding the strategy regarding
+ removal of functionality see the documentation of
+ <seealso marker="../system_principles/misc#removal">Support, Compatibility,
+ Deprecations, and Removal</seealso>.</p>
+ </section>
+ <section>
+ <marker id="OTP-23"/>
+ <title>OTP 23</title>
+ <section>
+ <title>VxWorks Support</title>
+ <p>Some parts of OTP has had limited VxWorks support, such as for
+ example <seealso marker="erl_interface:index"><c>erl_interface</c></seealso>.
+ This support will be removed as of OTP 23. This limited support
+ was formally deprecated as of OTP 22</p>
+ </section>
+ <section>
+ <title>Legacy parts of erl_interface</title>
+ <p>The old legacy <seealso marker="erl_interface:index"><c>erl_interface</c></seealso>
+ library (functions with prefix <c>erl_</c>) will be removed as of
+ OTP 23. These parts of <c>erl_interface</c> has been informally deprecated
+ for a very long time, and was formally deprecated in OTP 22. You typically
+ want to replace the usage of the <c>erl_interface</c> library with the use
+ of the <c>ei</c> library which also is part of the <c>erl_interface</c>
+ application.</p>
+ </section>
+ </section>
+</chapter>
diff --git a/system/doc/general_info/xmlfiles.mk b/system/doc/general_info/xmlfiles.mk
new file mode 100644
index 0000000000..eab1632a4f
--- /dev/null
+++ b/system/doc/general_info/xmlfiles.mk
@@ -0,0 +1,22 @@
+#
+# %CopyrightBegin%
+#
+# Copyright Ericsson AB 2009-2018. All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# %CopyrightEnd%
+#
+GENERAL_INFO_CHAPTER_FILES = \
+ deprecations.xml \
+ scheduled_for_removal.xml
diff --git a/system/doc/getting_started/Makefile b/system/doc/getting_started/Makefile
index 1fe3d39e4e..1c917895d5 100644
--- a/system/doc/getting_started/Makefile
+++ b/system/doc/getting_started/Makefile
@@ -1,7 +1,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 1996-2016. All Rights Reserved.
+# Copyright Ericsson AB 1996-2018. 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.
@@ -28,6 +28,7 @@ include $(ERL_TOP)/erts/vsn.mk
#VSN=$(SYSTEM_VSN)
APPLICATION=otp-system-documentation
+XMLDIR := $(XMLDIR)/getting_started
# ----------------------------------------------------
# Release directory specification
# ----------------------------------------------------
@@ -73,7 +74,6 @@ DVIPS_FLAGS +=
# ----------------------------------------------------
# Targets
# ----------------------------------------------------
-_create_dirs := $(shell mkdir -p $(HTMLDIR))
docs: html
@@ -84,7 +84,8 @@ html: $(GIF_FILES) $(HTML_UG_FILE)
debug opt:
clean clean_docs:
- rm -rf $(HTMLDIR)
+ rm -f $(XMLDIR)/*.xml
+ rm -f $(HTMLDIR)/*.gif $(HTMLDIR)/*.html
rm -f $(TOP_PDF_FILE) $(TOP_PDF_FILE:%.pdf=%.fo)
rm -f errs core *~
diff --git a/system/doc/getting_started/conc_prog.xml b/system/doc/getting_started/conc_prog.xml
index 7936e0d484..4374a59e04 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>2017</year>
+ <year>2003</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -627,7 +627,7 @@ ping finished</pre>
%%% Change the function below to return the name of the node where the
%%% messenger server runs
server_node() ->
- messenger@bill.
+ messenger@super.
%%% This is the server process for the "messenger"
%%% the user list has the format [{ClientPid1, Name1},{ClientPid22, Name2},...]
diff --git a/system/doc/getting_started/seq_prog.xml b/system/doc/getting_started/seq_prog.xml
index 6b7e1cd24f..2b0750ff80 100644
--- a/system/doc/getting_started/seq_prog.xml
+++ b/system/doc/getting_started/seq_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>
@@ -271,11 +271,12 @@ convert(N, centimeter) ->
{'EXIT',{function_clause,[{tut2,convert,
[3,miles],
[{file,"tut2.erl"},{line,4}]},
- {erl_eval,do_apply,5,[{file,"erl_eval.erl"},{line,482}]},
- {shell,exprs,7,[{file,"shell.erl"},{line,666}]},
- {shell,eval_exprs,7,[{file,"shell.erl"},{line,621}]},
- {shell,eval_loop,3,[{file,"shell.erl"},{line,606}]}]}}</pre>
-
+ {erl_eval,do_apply,6,
+ [{file,"erl_eval.erl"},{line,677}]},
+ {shell,exprs,7,[{file,"shell.erl"},{line,687}]},
+ {shell,eval_exprs,7,[{file,"shell.erl"},{line,642}]},
+ {shell,eval_loop,3,
+ [{file,"shell.erl"},{line,627}]}]}}</pre>
</section>
<section>
diff --git a/system/doc/html/design_principles/.gitignore b/system/doc/html/design_principles/.gitignore
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/system/doc/html/design_principles/.gitignore
diff --git a/system/doc/html/efficiency_guide/.gitignore b/system/doc/html/efficiency_guide/.gitignore
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/system/doc/html/efficiency_guide/.gitignore
diff --git a/system/doc/html/embedded/.gitignore b/system/doc/html/embedded/.gitignore
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/system/doc/html/embedded/.gitignore
diff --git a/system/doc/html/general_info/.gitignore b/system/doc/html/general_info/.gitignore
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/system/doc/html/general_info/.gitignore
diff --git a/system/doc/html/getting_started/.gitignore b/system/doc/html/getting_started/.gitignore
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/system/doc/html/getting_started/.gitignore
diff --git a/system/doc/html/installation_guide/.gitignore b/system/doc/html/installation_guide/.gitignore
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/system/doc/html/installation_guide/.gitignore
diff --git a/system/doc/html/installation_guide/source/.gitignore b/system/doc/html/installation_guide/source/.gitignore
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/system/doc/html/installation_guide/source/.gitignore
diff --git a/system/doc/html/js/.gitignore b/system/doc/html/js/.gitignore
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/system/doc/html/js/.gitignore
diff --git a/system/doc/html/oam/.gitignore b/system/doc/html/oam/.gitignore
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/system/doc/html/oam/.gitignore
diff --git a/system/doc/html/programming_examples/.gitignore b/system/doc/html/programming_examples/.gitignore
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/system/doc/html/programming_examples/.gitignore
diff --git a/system/doc/html/reference_manual/.gitignore b/system/doc/html/reference_manual/.gitignore
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/system/doc/html/reference_manual/.gitignore
diff --git a/system/doc/html/system_architecture_intro/.gitignore b/system/doc/html/system_architecture_intro/.gitignore
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/system/doc/html/system_architecture_intro/.gitignore
diff --git a/system/doc/html/system_principles/.gitignore b/system/doc/html/system_principles/.gitignore
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/system/doc/html/system_principles/.gitignore
diff --git a/system/doc/html/tutorial/.gitignore b/system/doc/html/tutorial/.gitignore
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/system/doc/html/tutorial/.gitignore
diff --git a/system/doc/installation_guide/Makefile b/system/doc/installation_guide/Makefile
index 673c203422..c5234c1c9a 100644
--- a/system/doc/installation_guide/Makefile
+++ b/system/doc/installation_guide/Makefile
@@ -1,7 +1,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 1996-2016. All Rights Reserved.
+# Copyright Ericsson AB 1996-2018. 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.
@@ -28,6 +28,8 @@ include $(ERL_TOP)/erts/vsn.mk
#VSN=$(SYSTEM_VSN)
APPLICATION=otp-system-documentation
+XMLDIR := $(XMLDIR)/installation_guide
+
# ----------------------------------------------------
# Release directory specification
# ----------------------------------------------------
@@ -43,6 +45,8 @@ include xmlfiles.mk
XML_CHAPTER_FILES=$(INST_GUIDE_CHAPTER_FILES)
+# ----------------------------------------------------
+
TOPDOCDIR=..
BOOK_FILES = book.xml
@@ -55,12 +59,7 @@ XML_FILES = \
$(BOOK_FILES) $(XML_CHAPTER_FILES) \
$(XML_PART_FILES)
-# ----------------------------------------------------
-GENERATED_XML_FILES = \
- INSTALL.xml \
- INSTALL-CROSS.xml \
- INSTALL-WIN32.xml \
- OTP-PATCH-APPLY.xml
+XML_GEN_FILES = $(INST_GUIDE_CHAPTER_GEN_FILES:%=$(XMLDIR)/%)
# ----------------------------------------------------
@@ -88,11 +87,10 @@ DVIPS_FLAGS +=
# Targets
# ----------------------------------------------------
-%.xml: $(ERL_TOP)/HOWTO/%.md $(ERL_TOP)/make/emd2exml
+$(XMLDIR)/%.xml: $(ERL_TOP)/HOWTO/%.md $(ERL_TOP)/make/emd2exml
$(ERL_TOP)/make/emd2exml $< $@
$(REDIRECT_HTML_DIR)/%.html: Makefile
- test -d $(REDIRECT_HTML_DIR) || $(INSTALL_DIR) $(REDIRECT_HTML_DIR)
echo "<html><head><meta HTTP-EQUIV=\"REFRESH\"" > $@
echo " content=\"5; url=../"$(notdir $@)"\">" >> $@
echo "<title>This page has moved</title></head><body>" >> $@
@@ -102,17 +100,20 @@ $(REDIRECT_HTML_DIR)/%.html: Makefile
echo "This <a href=\"../"$(notdir $@)"\">link</a> will" >> $@
echo "take you there immediately.</p></body></html>" >> $@
-docs: $(GENERATED_XML_FILES) html
+docs: $(XML_GEN_FILES) html
local_docs: PDFDIR=../../pdf
-local_docs: $(GENERATED_XML_FILES)
+local_docs: $(XML_GEN_FILES)
-html: $(REDIRECT_HTML_FILES) $(GENERATED_XML_FILES) $(GIF_FILES) $(HTML_UG_FILE)
+html: $(REDIRECT_HTML_FILES) $(XML_GEN_FILES) $(GIF_FILES) $(HTML_UG_FILE)
debug opt:
clean clean_docs:
rm -f $(GENERATED_XML_FILES)
+ rm -f $(XMLDIR)/*.xml
+ rm -f $(HTMLDIR)/*.gif $(HTMLDIR)/*.html
+ rm -f $(XML_GEN_FILES)
rm -rf $(HTMLDIR)
rm -f $(TOP_PDF_FILE) $(TOP_PDF_FILE:%.pdf=%.fo)
rm -f errs core *~
diff --git a/system/doc/installation_guide/xmlfiles.mk b/system/doc/installation_guide/xmlfiles.mk
index 3f720e1ee5..f005c8404b 100644
--- a/system/doc/installation_guide/xmlfiles.mk
+++ b/system/doc/installation_guide/xmlfiles.mk
@@ -1,7 +1,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 2009-2016. All Rights Reserved.
+# Copyright Ericsson AB 2009-2018. 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.
@@ -18,7 +18,9 @@
# %CopyrightEnd%
#
INST_GUIDE_CHAPTER_FILES = \
- install-binary.xml \
+ install-binary.xml
+
+INST_GUIDE_CHAPTER_GEN_FILES = \
INSTALL.xml \
INSTALL-CROSS.xml \
INSTALL-WIN32.xml \
diff --git a/system/doc/oam/Makefile b/system/doc/oam/Makefile
index 9095744423..2eb429e04d 100644
--- a/system/doc/oam/Makefile
+++ b/system/doc/oam/Makefile
@@ -1,7 +1,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 1997-2016. All Rights Reserved.
+# Copyright Ericsson AB 1997-2018. 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.
@@ -27,6 +27,7 @@ include $(ERL_TOP)/erts/vsn.mk
#VSN=$(SYSTEM_VSN)
APPLICATION=otp-system-documentation
+XMLDIR := $(XMLDIR)/oam
# ----------------------------------------------------
# Release directory specification
# ----------------------------------------------------
@@ -70,10 +71,9 @@ DVIPS_FLAGS +=
# ----------------------------------------------------
# Targets
# ----------------------------------------------------
-_create_dirs := $(shell mkdir -p $(HTMLDIR))
$(HTMLDIR)/%.gif: %.gif
- $(INSTALL_DATA) $< $@
+ $(CP) $< $@
docs: html
@@ -86,7 +86,8 @@ gifs: $(GIF_FILES:%=$(HTMLDIR)/%)
debug opt:
clean clean_docs:
- rm -rf $(HTMLDIR)
+ rm -f $(XMLDIR)/*.xml
+ rm -f $(HTMLDIR)/*.gif $(HTMLDIR)/*.html
rm -f $(TOP_PDF_FILE) $(TOP_PDF_FILE:%.pdf=%.fo)
rm -f errs core *~
diff --git a/system/doc/oam/oam_intro.xml b/system/doc/oam/oam_intro.xml
index ead8c026b9..3d08a5f3b1 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>2017</year>
+ <year>1997</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -178,7 +178,7 @@
<section>
<title>MIB Structure</title>
<p>The top-level OTP MIB is called <c>OTP-REG</c> and it is
- included in the SASL application. All other OTP MIBs
+ included in the SNMP application. All other OTP MIBs
import some objects from this MIB.</p>
<p>Each MIB is contained in one application. The MIB text
@@ -186,67 +186,44 @@
the application directory. The generated <c>.hrl</c> files
with constant declarations are stored under
<c><![CDATA[include/<MIB>.hrl]]></c>, and the compiled MIBs
- are stored under <c><![CDATA[priv/mibs/<MIB>.bin]]></c>.
- For example, the <c>OTP-MIB</c> is included in the
- SASL application:</p>
+ are stored under <c><![CDATA[priv/mibs/<MIB>.bin]]></c>. </p>
- <code type="none">
-sasl-1.3/mibs/OTP-MIB.mib
-include/OTP-MIB.hrl
-priv/mibs/OTP-MIB.bin</code>
-
- <p>An application that needs to import this MIB into another
+ <p>An application that needs to import an MIB into another
MIB is to use the <c>il</c> option to the SNMP MIB compiler:</p>
<code type="none">
-snmp:c("MY-MIB", [{il, ["sasl/priv/mibs"]}]).</code>
+snmp:c("MY-MIB", [{il, ["snmp/priv/mibs"]}]).</code>
- <p>If the application needs to include the generated
+ <p>If the application needs to include a generated
<c>.hrl</c> file, it is to use the <c>-include_lib</c>
directive to the Erlang compiler:</p>
<code type="none">
-module(my_mib).
--include_lib("sasl/include/OTP-MIB.hrl").</code>
+-include_lib("snmp/include/OTP-REG.hrl").</code>
- <p>The following MIBs are defined in the OTP system:</p>
+ <p>Here is a list of some of the MIBs 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 SNMP) 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
+ <item><p><c>OTP-TC</c> (in SNMP) contains the general
Textual Conventions, which can be used by any other MIB.</p></item>
- <item><p><c>OTP-MIB</c> (in SASL) contains objects for
- instrumentation of the Erlang nodes, the Erlang machines,
- and the applications in the system.</p></item>
- <item><p><c>OTP-OS-MON-MIB</c> (in <c>oc_mon</c>) contains
- objects for instrumentation of disk, memory, and CPU use
- of the nodes in the system.</p></item>
<item><p><c>OTP-SNMPEA-MIB</c> (in <c>snmp</c>)
contains objects for instrumentation and control of the extensible
SNMP agent itself. The agent also implements the standard SNMPv2-MIB
(or v1 part of MIB-II, if SNMPv1 is used).</p></item>
- <item><p><c>OTP-EVA-MIB</c> (in <c>eva</c>) contains objects
- for instrumentation and control of the events and alarms in
- the system.</p></item>
- <item><p><c>OTP-LOG-MIB</c> (in <c>eva</c>) contains objects
- for instrumentation and control of the logs and FTP transfer of
- logs.</p></item>
- <item><p><c>OTP-EVA-LOG-MIB</c> (in <c>eva</c>) contains objects
- for instrumentation and control of the events and alarm logs
- in the system.</p></item>
- <item><p><c>OTP-SNMPEA-LOG-MIB</c> (in <c>eva</c>) contains
- objects for instrumentation and control of the SNMP audit
- trail log in the system.</p></item>
</list>
<p>The different applications use different strategies for
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: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>
+ function such as
+ <c>snmpa:unload_mibs(Agent, [Mib])</c>
+ to load the MIB, and
+ <c>snmpa:unload_mibs(Agent, [Mib])</c>
+ to unload the MIB. See the manual page for each application for
+ a description of how to load each MIB.</p>
</section>
</section>
</chapter>
diff --git a/system/doc/programming_examples/Makefile b/system/doc/programming_examples/Makefile
index 237076d770..9c67c24b64 100644
--- a/system/doc/programming_examples/Makefile
+++ b/system/doc/programming_examples/Makefile
@@ -1,7 +1,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 2003-2016. All Rights Reserved.
+# Copyright Ericsson AB 2003-2018. 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.
@@ -28,6 +28,7 @@ include $(ERL_TOP)/erts/vsn.mk
#VSN=$(SYSTEM_VSN)
APPLICATION=otp-system-documentation
+XMLDIR := $(XMLDIR)/programming_examples
# ----------------------------------------------------
# Release directory specification
# ----------------------------------------------------
@@ -52,7 +53,9 @@ PS_FILES =
XML_FILES = \
$(BOOK_FILES) $(XML_CHAPTER_FILES) \
- $(XML_PART_FILES)
+ $(XML_PART_FILES)
+
+XML_GEN_FILES = $(PROG_EX_CHAPTER_GEN_FILES:%=$(XMLDIR)/%)
# ----------------------------------------------------
HTML_FILES = \
@@ -71,7 +74,6 @@ DVIPS_FLAGS +=
# ----------------------------------------------------
# Targets
# ----------------------------------------------------
-_create_dirs := $(shell mkdir -p $(HTMLDIR))
docs: html
local_docs: PDFDIR=../../pdf
@@ -81,7 +83,8 @@ html: $(GIF_FILES) $(HTML_UG_FILE)
debug opt:
clean clean_docs:
- rm -rf $(HTMLDIR)
+ rm -f $(XMLDIR)/*.xml
+ rm -f $(HTMLDIR)/*.gif $(HTMLDIR)/*.html
rm -f $(TOP_PDF_FILE) $(TOP_PDF_FILE:%.pdf=%.fo)
rm -f errs core *~
diff --git a/system/doc/programming_examples/xmlfiles.mk b/system/doc/programming_examples/xmlfiles.mk
index 5129e488f4..e457ca0cce 100644
--- a/system/doc/programming_examples/xmlfiles.mk
+++ b/system/doc/programming_examples/xmlfiles.mk
@@ -1,7 +1,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 2009-2016. All Rights Reserved.
+# Copyright Ericsson AB 2009-2018. 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.
@@ -19,6 +19,8 @@
#
PROG_EX_CHAPTER_FILES = \
bit_syntax.xml \
- funs.xml \
list_comprehensions.xml \
records.xml
+
+PROG_EX_CHAPTER_GEN_FILES = \
+ funs.xml
diff --git a/system/doc/reference_manual/Makefile b/system/doc/reference_manual/Makefile
index e14a056979..809eb2c979 100644
--- a/system/doc/reference_manual/Makefile
+++ b/system/doc/reference_manual/Makefile
@@ -1,7 +1,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 2003-2016. All Rights Reserved.
+# Copyright Ericsson AB 2003-2018. 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.
@@ -28,6 +28,7 @@ include $(ERL_TOP)/erts/vsn.mk
#VSN=$(SYSTEM_VSN)
APPLICATION=otp-system-documentation
+XMLDIR := $(XMLDIR)/reference_manual
# ----------------------------------------------------
# Release directory specification
# ----------------------------------------------------
@@ -83,7 +84,6 @@ DVIPS_FLAGS +=
# ----------------------------------------------------
# Targets
# ----------------------------------------------------
-_create_dirs := $(shell mkdir -p $(HTMLDIR))
docs: html
@@ -94,7 +94,8 @@ html: $(GIF_FILES) $(HTML_UG_FILE)
debug opt:
clean clean_docs:
- rm -rf $(HTMLDIR)
+ rm -f $(XMLDIR)/*.xml
+ rm -f $(HTMLDIR)/*.gif $(HTMLDIR)/*.html
rm -f $(TOP_PDF_FILE) $(TOP_PDF_FILE:%.pdf=%.fo)
rm -f errs core *~
diff --git a/system/doc/reference_manual/errors.xml b/system/doc/reference_manual/errors.xml
index b16c5da6eb..16d3e7590e 100644
--- a/system/doc/reference_manual/errors.xml
+++ b/system/doc/reference_manual/errors.xml
@@ -108,14 +108,55 @@
(see <seealso marker="#exit_reasons">Exit Reason</seealso>),
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>
- from within a <c>try</c> expression, and is returned for
+ <p>The stack trace can be be bound to a variable 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
error.</p>
+
+ <section>
+ <title>The call-stack back trace (stacktrace)</title>
+ <p>The stack back-trace (<em>stacktrace</em>) is a list of
+ <c>{Module,Function,Arity,Location}</c>
+ tuples. The field <c>Arity</c> in the first tuple can be the
+ argument list of that function call instead of an arity integer,
+ depending on the exception.</p>
+
+ <p><c>Location</c> is a (possibly empty) list of two-tuples
+ that can indicate the location in the source code of the
+ function. The first element is an atom describing the type of
+ information in the second element. The following items can
+ occur:</p>
+ <taglist>
+ <tag><c>file</c></tag>
+ <item>The second element of the tuple is a string (list of
+ characters) representing the filename of the source file
+ of the function.
+ </item>
+ <tag><c>line</c></tag>
+ <item>The second element of the tuple is the line number
+ (an integer &gt; 0) in the source file
+ where the exception occurred or the function was called.
+ </item>
+ </taglist>
+ <warning><p>Developers should rely on stacktrace entries only for
+ debugging purposes.</p>
+ <p>The VM performs tail call optimization, which
+ does not add new entries to the stacktrace, and also limits stacktraces
+ to a certain depth. Furthermore, compiler options, optimizations and
+ future changes may add or remove stacktrace entries, causing any code
+ that expects the stacktrace to be in a certain order or contain specific
+ items to fail.</p>
+ <p>The only exception to this rule is the class <c>error</c> with the
+ reason <c>undef</c> which is guaranteed to include the <c>Module</c>,
+ <c>Function</c> and <c>Arity</c> of the attempted
+ function as the first stacktrace entry.</p>
+ </warning>
+ </section>
+
</section>
+
<section>
<title>Handling of Run-time Errors in Erlang</title>
diff --git a/system/doc/reference_manual/expressions.xml b/system/doc/reference_manual/expressions.xml
index cf2d5034aa..ea3b2159fc 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>2017</year>
+ <year>2003</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -567,6 +567,10 @@ Expr1 <input>op</input> Expr2</pre>
order is defined:</p>
<pre>
number &lt; atom &lt; reference &lt; fun &lt; port &lt; pid &lt; tuple &lt; map &lt; nil &lt; list &lt; bit string</pre>
+ <p><c>nil</c> in the previous expression represents the empty list
+ (<c>[]</c>), which is regarded as a separate type from
+ <c>list/0</c>. That is why <c>nil &lt; list</c>.
+ </p>
<p>Lists are compared element by element. Tuples are ordered by
size, two tuples with the same size are compared element by
element.</p>
@@ -574,6 +578,7 @@ number &lt; atom &lt; reference &lt; fun &lt; port &lt; pid &lt; tuple &lt; map
ascending term order and then by values in key order.
In maps key order integers types are considered less than floats types.
</p>
+ <p>Atoms are compared using their string value, codepoint by codepoint.</p>
<p>When comparing an integer to a float, the term with the lesser
precision is converted into the type of the other term, unless the
operator is one of <c>=:=</c> or <c>=/=</c>. A float is more precise than
@@ -1216,10 +1221,10 @@ Ei = Value |
&lt;&lt;1,17,0,42&gt;&gt;
10> <input>H.</input>
&lt;&lt;17,0,42&gt;&gt;
-11> <input>&lt;&lt;G,H/bitstring&gt;&gt; = &lt;&lt;1,17,42:12&gt;&gt;.</input>
-&lt;&lt;1,17,1,10:4&gt;&gt;
-12> <input>H.</input>
-&lt;&lt;17,1,10:4&gt;&gt;
+11> <input>&lt;&lt;G,J/bitstring&gt;&gt; = &lt;&lt;1,17,42:12&gt;&gt;.</input>
+&lt;&lt;1,17,2,10:4&gt;&gt;
+12> <input>J.</input>
+&lt;&lt;17,2,10:4&gt;&gt;
13> <input>&lt;&lt;1024/utf8&gt;&gt;.</input>
&lt;&lt;208,128&gt;&gt;
</pre>
@@ -1340,9 +1345,9 @@ hello</pre>
<code type="none">
try Exprs
catch
- [Class1:]ExceptionPattern1 [when ExceptionGuardSeq1] ->
+ Class1:ExceptionPattern1[:Stacktrace] [when ExceptionGuardSeq1] ->
ExceptionBody1;
- [ClassN:]ExceptionPatternN [when ExceptionGuardSeqN] ->
+ ClassN:ExceptionPatternN[:Stacktrace] [when ExceptionGuardSeqN] ->
ExceptionBodyN
end</code>
<p>This is an enhancement of
@@ -1362,10 +1367,12 @@ end</code>
the evaluation. In that case the exception is caught and
the patterns <c>ExceptionPattern</c> with the right exception
class <c>Class</c> are sequentially matched against the caught
- exception. An omitted <c>Class</c> is shorthand for <c>throw</c>.
- If a match succeeds and the optional guard sequence
+ exception. If a match succeeds and the optional guard sequence
<c>ExceptionGuardSeq</c> is true, the corresponding
<c>ExceptionBody</c> is evaluated to become the return value.</p>
+ <p><c>Stacktrace</c>, if specified, must be the name of a variable
+ (not a pattern). The stack trace is bound to the variable when
+ the corresponding <c>ExceptionPattern</c> matches.</p>
<p>If an exception occurs during evaluation of <c>Exprs</c> but
there is no matching <c>ExceptionPattern</c> of the right
<c>Class</c> with a true guard sequence, the exception is passed
@@ -1373,6 +1380,18 @@ end</code>
expression.</p>
<p>If an exception occurs during evaluation of <c>ExceptionBody</c>,
it is not caught.</p>
+ <p>It is allowed to omit <c>Class</c> and <c>Stacktrace</c>.
+ An omitted <c>Class</c> is shorthand for <c>throw</c>:</p>
+
+ <code type="none">
+try Exprs
+catch
+ ExceptionPattern1 [when ExceptionGuardSeq1] ->
+ ExceptionBody1;
+ ExceptionPatternN [when ExceptionGuardSeqN] ->
+ ExceptionBodyN
+end</code>
+
<p>The <c>try</c> expression can have an <c>of</c>
section:
</p>
@@ -1384,10 +1403,10 @@ try Exprs of
PatternN [when GuardSeqN] ->
BodyN
catch
- [Class1:]ExceptionPattern1 [when ExceptionGuardSeq1] ->
+ Class1:ExceptionPattern1[:Stacktrace] [when ExceptionGuardSeq1] ->
ExceptionBody1;
...;
- [ClassN:]ExceptionPatternN [when ExceptionGuardSeqN] ->
+ ClassN:ExceptionPatternN[:Stacktrace] [when ExceptionGuardSeqN] ->
ExceptionBodyN
end</code>
<p>If the evaluation of <c>Exprs</c> succeeds without an exception,
@@ -1408,10 +1427,10 @@ try Exprs of
PatternN [when GuardSeqN] ->
BodyN
catch
- [Class1:]ExceptionPattern1 [when ExceptionGuardSeq1] ->
+ Class1:ExceptionPattern1[:Stacktrace] [when ExceptionGuardSeq1] ->
ExceptionBody1;
...;
- [ClassN:]ExceptionPatternN [when ExceptionGuardSeqN] ->
+ ClassN:ExceptionPatternN[:Stacktrace] [when ExceptionGuardSeqN] ->
ExceptionBodyN
after
AfterBody
@@ -1470,7 +1489,7 @@ try Expr
catch
throw:Term -> Term;
exit:Reason -> {'EXIT',Reason}
- error:Reason -> {'EXIT',{Reason,erlang:get_stacktrace()}}
+ error:Reason:Stk -> {'EXIT',{Reason,Stk}}
end</code>
</section>
diff --git a/system/doc/reference_manual/introduction.xml b/system/doc/reference_manual/introduction.xml
index afbdfa7434..69e52e0b37 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>2017</year>
+ <year>2003</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -48,7 +48,7 @@
System Principles</seealso></p>
<p>Starting and stopping, boot scripts, code loading,
<seealso marker="doc/system_principles:error_logging">
- error logging</seealso>,
+ logging</seealso>,
<seealso marker="doc/system_principles:create_target">
creating target systems</seealso></p>
</item>
diff --git a/system/doc/reference_manual/macros.xml b/system/doc/reference_manual/macros.xml
index a341307ab7..8a8d5f3a4c 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>2017</year>
+ <year>2003</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -150,6 +150,11 @@ bar(X) ->
<item>The name of the current function.</item>
<tag><c>?FUNCTION_ARITY</c></tag>
<item>The arity (number of arguments) for the current function.</item>
+ <tag><c>?OTP_RELEASE</c></tag>
+ <item>The OTP release that the currently executing ERTS
+ application is part of, as an integer. For details, see
+ <seealso marker="erts:erlang#system_info/1"><c>erlang:system_info(otp_release)</c></seealso>.
+ This macro was introduced in OTP release 21.</item>
</taglist>
</section>
@@ -202,8 +207,16 @@ f() ->
directive. If that condition is false, the lines following
<c>else</c> are evaluated instead.</item>
<tag><c>-endif.</c></tag>
- <item>Specifies the end of an <c>ifdef</c> or <c>ifndef</c>
- directive.</item>
+ <item>Specifies the end of an <c>ifdef</c>, an <c>ifndef</c>
+ directive, or the end of an <c>if</c> or <c>elif</c> directive.</item>
+ <tag><c>-if(Condition).</c></tag>
+ <item>Evaluates the following lines only if <c>Condition</c>
+ evaluates to true.</item>
+ <tag><c>-elif(Condition).</c></tag>
+ <item>Only allowed after an <c>if</c> or another <c>elif</c> directive.
+ If the preceding <c>if</c> or <c>elif</c> directives do not
+ evaluate to true, and the <c>Condition</c> evaluates to true,
+ the lines following the <c>elif</c> are evaluated instead.</item>
</taglist>
<note>
<p>The macro directives cannot be used inside functions.</p>
@@ -231,6 +244,24 @@ or
{ok,m}</pre>
<p><c>?LOG(Arg)</c> is then expanded to a call to <c>io:format/2</c>
and provide the user with some simple trace output.</p>
+
+ <p><em>Example:</em></p>
+ <code type="none">
+-module(m)
+...
+-ifdef(OTP_RELEASE).
+ %% OTP 21 or higher
+ -if(?OTP_RELEASE >= 22).
+ %% Code that will work in OTP 22 or higher
+ -elif(?OTP_RELEASE >= 21).
+ %% Code that will work in OTP 21 or higher
+ -endif.
+-else.
+ %% OTP 20 or lower.
+-endif.
+...</code>
+ <p>The code uses the <c>OTP_RELEASE</c> macro to conditionally
+ select code depending on release.</p>
</section>
<section>
diff --git a/system/doc/reference_manual/modules.xml b/system/doc/reference_manual/modules.xml
index 4a97bfeb7b..6f93198ec1 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>2017</year>
+ <year>2003</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -307,6 +307,12 @@ behaviour_info(callbacks) -> Callbacks.</pre>
all functions in the module.</p>
</item>
+ <tag><c>nifs</c></tag>
+ <item>
+ <p>Returns a list of <c>{Name,Arity}</c> tuples with
+ all NIF functions in the module.</p>
+ </item>
+
<tag><c>native</c></tag>
<item>
<p>Return <c>true</c> if the module has native compiled code.
diff --git a/system/doc/reference_manual/typespec.xml b/system/doc/reference_manual/typespec.xml
index f6a19397c3..27cd0ba83d 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>2017</year>
+ <year>2003</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -113,8 +113,8 @@
| Erlang_Atom %% 'foo', 'bar', ...
Bitstring :: <<>>
- | <<_:M>> %% M is a positive integer
- | <<_:_*N>> %% N is a positive integer
+ | <<_:M>> %% M is an Integer_Value that evaluates to a positive integer
+ | <<_:_*N>> %% N is an Integer_Value that evaluates to a positive integer
| <<_:M, _:_*N>>
Fun :: fun() %% any function
@@ -123,8 +123,17 @@
| fun((TList) -> Type)
Integer :: integer()
- | Erlang_Integer %% ..., -1, 0, 1, ... 42 ...
- | Erlang_Integer..Erlang_Integer %% specifies an integer range
+ | Integer_Value
+ | Integer_Value..Integer_Value %% specifies an integer range
+
+ Integer_Value :: Erlang_Integer %% ..., -1, 0, 1, ... 42 ...
+ | Erlang_Character %% $a, $b ...
+ | Integer_Value BinaryOp Integer_Value
+ | UnaryOp Integer_Value
+
+ BinaryOp :: '*' | 'div' | 'rem' | 'band' | '+' | '-' | 'bor' | 'bxor' | 'bsl' | 'bsr'
+
+ UnaryOp :: '+' | '-' | 'bnot'
List :: list(Type) %% Proper list ([]-terminated)
| maybe_improper_list(Type1, Type2) %% Type1=contents, Type2=termination
@@ -151,8 +160,13 @@
Union :: Type1 | Type2
]]></pre>
<p>
+ Integer values are either integer or character literals or expressions
+ consisting of possibily nested unary or binary operations that evaluate to
+ an integer. Such expressions can also be used in bit strings and ranges.
+ </p>
+ <p>
The general form of bit strings is <c>&lt;&lt;_:M, _:_*N&gt;&gt;</c>,
- where <c>M</c> and <c>N</c> are positive integers. It denotes a
+ where <c>M</c> and <c>N</c> must evaluate to positive integers. It denotes a
bit string that is <c>M + (k*N)</c> bits long (that is, a bit string that
starts with <c>M</c> bits and continues with <c>k</c> segments of
<c>N</c> bits each, where <c>k</c> is also a positive integer).
diff --git a/system/doc/reference_manual/xmlfiles.mk b/system/doc/reference_manual/xmlfiles.mk
index fffcbdd911..92d232b628 100644
--- a/system/doc/reference_manual/xmlfiles.mk
+++ b/system/doc/reference_manual/xmlfiles.mk
@@ -1,7 +1,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 2009-2016. All Rights Reserved.
+# Copyright Ericsson AB 2009-2018. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
diff --git a/system/doc/system_architecture_intro/Makefile b/system/doc/system_architecture_intro/Makefile
index 446e66205c..ea9ee85105 100644
--- a/system/doc/system_architecture_intro/Makefile
+++ b/system/doc/system_architecture_intro/Makefile
@@ -1,7 +1,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 1997-2016. All Rights Reserved.
+# Copyright Ericsson AB 1997-2018. 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.
@@ -28,6 +28,7 @@ include $(ERL_TOP)/erts/vsn.mk
#VSN=$(SYSTEM_VSN)
APPLICATION=otp-system-documentation
+XMLDIR := $(XMLDIR)/system_architecture_intro
# ----------------------------------------------------
# Release directory specification
# ----------------------------------------------------
@@ -68,7 +69,6 @@ DVIPS_FLAGS +=
# ----------------------------------------------------
# Targets
# ----------------------------------------------------
-_create_dirs := $(shell mkdir -p $(HTMLDIR))
docs: html
@@ -79,7 +79,8 @@ html: $(GIF_FILES) $(HTML_UG_FILE)
debug opt:
clean clean_docs:
- rm -rf $(HTMLDIR)
+ rm -f $(XMLDIR)/*.xml
+ rm -f $(HTMLDIR)/*.gif $(HTMLDIR)/*.html
rm -f $(TOP_PDF_FILE) $(TOP_PDF_FILE:%.pdf=%.fo)
rm -f errs core *~
diff --git a/system/doc/system_architecture_intro/sys_arch_intro.xml b/system/doc/system_architecture_intro/sys_arch_intro.xml
index cf75e1f100..e8ada6427b 100644
--- a/system/doc/system_architecture_intro/sys_arch_intro.xml
+++ b/system/doc/system_architecture_intro/sys_arch_intro.xml
@@ -4,7 +4,7 @@
<chapter>
<header>
<copyright>
- <year>2000</year><year>2016</year>
+ <year>2000</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -98,20 +98,6 @@
</list>
</item>
<item>
- <p>CORBA services and IDL compiler.</p>
- <list type="bulleted">
- <item><em>cosEvent</em> Orber OMG Event Service.</item>
- <item><em>cosNotification</em> Orber OMG Notification
- Service.</item>
- <item><em>cosTime</em> Orber OMG Timer and TimerEvent
- Services.</item>
- <item><em>cosTransactions</em> Orber OMG Transaction
- Service.</item>
- <item><em>IC</em> IDL compiler</item>
- <item><em>Orber</em> A CORBA object request broker.</item>
- </list>
- </item>
- <item>
<p>Tools.</p>
<list type="bulleted">
<item><em>Appmon</em> A utility used to view OTP applications.</item>
diff --git a/system/doc/system_principles/Makefile b/system/doc/system_principles/Makefile
index 77edea8f58..5110b73373 100644
--- a/system/doc/system_principles/Makefile
+++ b/system/doc/system_principles/Makefile
@@ -1,7 +1,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 1996-2016. All Rights Reserved.
+# Copyright Ericsson AB 1996-2018. 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.
@@ -28,6 +28,7 @@ include $(ERL_TOP)/erts/vsn.mk
#VSN=$(SYSTEM_VSN)
APPLICATION=otp-system-documentation
+XMLDIR := $(XMLDIR)/system_principles
# ----------------------------------------------------
# Release directory specification
# ----------------------------------------------------
@@ -52,6 +53,8 @@ XML_FILES = \
$(BOOK_FILES) $(XML_CHAPTER_FILES) \
$(XML_PART_FILES)
+XML_GEN_FILES = $(SYSTEM_PRINCIPLES_CHAPTER_GEN_FILES:%=$(XMLDIR)/%)
+
# ----------------------------------------------------
HTMLDIR = ../html/system_principles
@@ -67,7 +70,6 @@ DVIPS_FLAGS +=
# ----------------------------------------------------
# Targets
# ----------------------------------------------------
-_create_dirs := $(shell mkdir -p $(HTMLDIR))
docs: html
@@ -78,7 +80,8 @@ html: $(GIF_FILES) $(HTML_UG_FILE)
debug opt:
clean clean_docs:
- rm -rf $(HTMLDIR)
+ rm -f $(XMLDIR)/*.xml
+ rm -f $(HTMLDIR)/*.gif $(HTMLDIR)/*.html
rm -f $(TOP_PDF_FILE) $(TOP_PDF_FILE:%.pdf=%.fo)
rm -f errs core *~
diff --git a/system/doc/system_principles/create_target.xmlsrc b/system/doc/system_principles/create_target.xmlsrc
index f9b27ffc35..ea0d938936 100644
--- a/system/doc/system_principles/create_target.xmlsrc
+++ b/system/doc/system_principles/create_target.xmlsrc
@@ -4,7 +4,7 @@
<chapter>
<header>
<copyright>
- <year>2002</year><year>2016</year>
+ <year>2002</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -263,6 +263,14 @@ os> <input>/usr/local/erl-target/bin/erl -boot /usr/local/erl-target/releases/FI
current directory create not only the file <c>mysystem.rel</c>,
but also file <c>sys.config</c>, the latter file is tacitly
put in the appropriate directory.</p>
+ <p>However, it can also be convenient to replace variables in
+ within a <c>sys.config</c> on the target after unpacking but
+ before running the release. If you have a <c>sys.config.src</c>
+ it will be included and is not required to be a valid Erlang term
+ file like <c>sys.config</c>. Before running the release you must
+ have a valid <c>sys.config</c> in the same directory, so using
+ <c>sys.config.src</c> requires having some tool to populate what is
+ needed and write <c>sys.config</c> to disk before booting the release.</p>
</section>
<section>
@@ -344,7 +352,7 @@ fi
START_ERL_DATA=${1:-$RELDIR/start_erl.data}
$ROOTDIR/bin/run_erl -daemon /tmp/ $ROOTDIR/log "exec $ROOTDIR/bin/start_erl $ROOTDIR\
-$RELDIR $START_ERL_DATA -heart</code>
+$RELDIR $START_ERL_DATA -heart"</code>
<p>We use the simplest possible <c>sys.config</c>, which we
store in <c>releases/FIRST</c>:</p>
<code type="none">
diff --git a/system/doc/system_principles/error_logging.xml b/system/doc/system_principles/error_logging.xml
index c99d59ddb7..9cbf7a2e94 100644
--- a/system/doc/system_principles/error_logging.xml
+++ b/system/doc/system_principles/error_logging.xml
@@ -4,7 +4,7 @@
<chapter>
<header>
<copyright>
- <year>2003</year><year>2016</year>
+ <year>2003</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -39,80 +39,71 @@
<code type="none"><![CDATA[
=ERROR REPORT==== 9-Dec-2003::13:25:02 ===
Error in process <0.27.0> with exit value: {{badmatch,[1,2,3]},[{m,f,1},{shell,eval_loop,2}]}]]></code>
- <p>The error information is handled by the <em>error logger</em>, a
- system process registered as <c>error_logger</c>. This process
- receives all error messages from the Erlang runtime system as
- well as from the standard behaviours and different Erlang/OTP
- applications.</p>
+ <p>The error information is handled by Logger, which is part of
+ the Kernel application.</p>
<p>The exit reasons (such as <c>badarg</c>) used by
the runtime system are described in
<seealso marker="doc/reference_manual:errors#exit_reasons">
Errors and Error Handling</seealso>.</p>
- <p>For information about the process <c>error_logger</c> and its user
- interface (with the same name), see the
- <seealso marker="kernel:error_logger">error_logger(3)</seealso>
- manual page in Kernel. The system can be configured so that
- error information
- is written to file or to tty, or both. In addition, user-defined
- applications can send and format error information using
- <c>error_logger</c>.</p>
+ <p>For information about Logger and its user
+ interface, see the
+ <seealso marker="kernel:logger">logger(3)</seealso>
+ manual page and
+ the <seealso marker="kernel:logger_chapter">Logging</seealso>
+ section in the Kernel User's Guide. The system can be configured so that
+ log events are
+ written to file or to tty, or both. In addition, user-defined
+ applications can send and format log events using
+ Logger.</p>
</section>
<section>
- <title>SASL Error Logging</title>
+ <title>Log events from OTP behaviours</title>
<p>The standard behaviours (<c>supervisor</c>, <c>gen_server</c>,
- and so on) send progress and error information to <c>error_logger</c>.
- If the SASL application is started, this information is
- written to tty as well. For more information, see
+ and so on) send progress and error information to
+ Logger. Progress reports are by default not logged, but can be
+ enabled by setting the primary log level to <c>info</c>, for
+ example by using the Kernel configuration
+ parameter <c>logger_level</c>. Supervisor reports, crash reports
+ and other error and information reports are by default logged
+ through the log handler which is set up when the Kernel
+ application is started.</p>
+ <p>Prior to Erlang/OTP 21.0, supervisor, crash, and progress
+ reports were only logged when the SASL application was
+ running. This behaviour can, for backwards compatibility, be
+ enabled by setting the Kernel configuration
+ parameter <seealso marker="kernel:kernel_app#logger_sasl_compatible">
+ <c>logger_sasl_compatible</c></seealso>
+ to <c>true</c>. For more information, see
<seealso marker="sasl:error_logging">SASL Error Logging</seealso>
in the SASL User's Guide.</p>
<pre>
-% <input>erl -boot start_sasl</input>
-Erlang (BEAM) emulator version 5.4.13 [hipe] [threads:0] [kernel-poll]
+% <input>erl -kernel logger_level info</input>
+Erlang/OTP 21 [erts-10.0] [source-13c50db] [64-bit] [smp:4:4] [ds:4:4:10] [async-threads:1] [hipe]
-
-=PROGRESS REPORT==== 31-Mar-2006::12:45:58 ===
- supervisor: {local,sasl_safe_sup}
- started: [{pid,&lt;0.33.0>},
- {name,alarm_handler},
- {mfa,{alarm_handler,start_link,[]}},
- {restart_type,permanent},
- {shutdown,2000},
- {child_type,worker}]
-
-=PROGRESS REPORT==== 31-Mar-2006::12:45:58 ===
- supervisor: {local,sasl_safe_sup}
- started: [{pid,&lt;0.34.0>},
- {name,overload},
- {mfa,{overload,start_link,[]}},
- {restart_type,permanent},
- {shutdown,2000},
- {child_type,worker}]
-
-=PROGRESS REPORT==== 31-Mar-2006::12:45:58 ===
- supervisor: {local,sasl_sup}
- started: [{pid,&lt;0.32.0>},
- {name,sasl_safe_sup},
- {mfa,{supervisor,
- start_link,
- [{local,sasl_safe_sup},sasl,safe]}},
- {restart_type,permanent},
- {shutdown,infinity},
- {child_type,supervisor}]
-
-=PROGRESS REPORT==== 31-Mar-2006::12:45:58 ===
- supervisor: {local,sasl_sup}
- started: [{pid,&lt;0.35.0>},
- {name,release_handler},
- {mfa,{release_handler,start_link,[]}},
- {restart_type,permanent},
- {shutdown,2000},
- {child_type,worker}]
-
-=PROGRESS REPORT==== 31-Mar-2006::12:45:58 ===
- application: sasl
- started_at: nonode@nohost
-Eshell V5.4.13 (abort with ^G)
+=PROGRESS REPORT==== 8-Jun-2018::16:54:19.916404 ===
+ application: kernel
+ started_at: nonode@nohost
+=PROGRESS REPORT==== 8-Jun-2018::16:54:19.922908 ===
+ application: stdlib
+ started_at: nonode@nohost
+=PROGRESS REPORT==== 8-Jun-2018::16:54:19.925755 ===
+ supervisor: {local,kernel_safe_sup}
+ started: [{pid,&lt;0.74.0>},
+ {id,disk_log_sup},
+ {mfargs,{disk_log_sup,start_link,[]}},
+ {restart_type,permanent},
+ {shutdown,1000},
+ {child_type,supervisor}]
+=PROGRESS REPORT==== 8-Jun-2018::16:54:19.926056 ===
+ supervisor: {local,kernel_safe_sup}
+ started: [{pid,&lt;0.75.0>},
+ {id,disk_log_server},
+ {mfargs,{disk_log_server,start_link,[]}},
+ {restart_type,permanent},
+ {shutdown,2000},
+ {child_type,worker}]
+Eshell V10.0 (abort with ^G)
1> </pre>
</section>
</chapter>
diff --git a/system/doc/system_principles/misc.xml b/system/doc/system_principles/misc.xml
new file mode 100644
index 0000000000..ed3675d180
--- /dev/null
+++ b/system/doc/system_principles/misc.xml
@@ -0,0 +1,206 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<!DOCTYPE chapter SYSTEM "chapter.dtd">
+
+<chapter>
+ <header>
+ <copyright>
+ <year>2018</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>Support, Compatibility, Deprecations, and Removal</title>
+ <prepared></prepared>
+ <responsible></responsible>
+ <docno></docno>
+ <approved></approved>
+ <checked></checked>
+ <date>2018-05-21</date>
+ <rev></rev>
+ <file>misc.xml</file>
+ </header>
+
+ <section>
+ <title>Introduction</title>
+ <p>This document describes strategy regarding supported Releases,
+ compatibility, deprecations and removal of functionality. This
+ document was introduced in OTP 21. Actions taken regarding these
+ issues before OTP 21 did not adhere this document.</p>
+ </section>
+
+ <section>
+ <marker id="supported_releases"/>
+ <title>Supported Releases</title>
+ <p>
+ In general, bugs are only fixed on the latest
+ <seealso marker="versions#releases_and_patches">release</seealso>,
+ and new features are introduced in the upcoming release that is
+ under development. However, when we, due to internal reasons, fix
+ bugs on older releases, these will be available and announced as well.
+ </p>
+ <p>
+ Due to the above, pull requests are only accepted on the
+ <c>maint</c> and the <c>master</c> branches in our
+ <url href="https://github.com/erlang/otp">git repository</url>.
+ The <c>maint</c> branch contains changes planned for the next
+ <seealso marker="versions#releases_and_patches">maintenance patch package</seealso>
+ on the latest OTP release and the <c>master</c> branch contain
+ changes planned for the upcoming OTP release.
+ </p>
+ </section>
+
+ <section>
+ <marker id="compatibility"/>
+ <title>Compatibility</title>
+ <p>
+ We always strive to remain as compatible as possible
+ even in the cases where we give no compatibility guarantees.
+ </p>
+ <p>
+ Different parts of the system will be handled differently
+ regarding compatibility. The following items describe how
+ different parts of the system are handled.
+ </p>
+ <taglist>
+ <tag>Erlang Distribution</tag>
+ <item>
+ <p>
+ Erlang nodes can communicate across at least
+ two preceding and two subsequent releases.
+ </p>
+ </item>
+ <tag>Compiled BEAM Code, NIF Libraries and Drivers</tag>
+ <item>
+ <p>
+ Compiled code can be loaded on at least two
+ subsequent releases.
+ </p>
+ <p>
+ Loading on previous releases is <em>not</em> supported.
+ </p>
+ </item>
+ <tag>Compiled HiPE Code</tag>
+ <item>
+ <p>
+ Compiled HiPE code can be loaded on the exact same build
+ of ERTS that was used when compiling the code. It might
+ however work on other builds, the emulator verifies
+ checksums in order to determine if it can load the code
+ or not. Note that HiPE has some limitations. For more
+ information see the documentation of the
+ <seealso marker="hipe:HiPE_app">HiPE</seealso> application.
+ </p>
+ </item>
+ <tag>APIs</tag>
+ <item>
+ <p>Compatible between releases.</p>
+ </item>
+ <tag>Compiler Warnings</tag>
+ <item>
+ <p>New warnings may be issued between releases.</p>
+ </item>
+ <tag>Command Line Arguments</tag>
+ <item>
+ <p>Incompatible changes may occur between releases.</p>
+ </item>
+ <tag>OTP Build Procedures</tag>
+ <item><p>Incompatible changes may occur between releases.</p></item>
+ </taglist>
+ <p>
+ Under certain circumstances incompatible changes might be
+ introduced even in parts of the system that should be compatible
+ between releases. Things that might trigger incompatible changes
+ like this are:
+ </p>
+ <taglist>
+ <tag>Security Issues</tag>
+ <item>
+ <p>
+ It might be necessary to introduce incompatible changes
+ in order to solve a security issue. This kind of
+ incompatibility might occur in a patch.
+ </p>
+ </item>
+ <tag>Bug Fixes</tag>
+ <item>
+ <p>
+ We will not be bug-compatible. A bug fix might introduce
+ incompatible changes. This kind of incompatibility
+ might occur in a patch.
+ </p>
+ </item>
+ <tag>Severe Previous Design Issues</tag>
+ <item>
+ <p>
+ Some parts of OTP were designed a very long time ago and
+ did not necessarily take today's computing environments into
+ account. In some cases the consequences of those design
+ decisions are too severe. This may be performance wise,
+ scalability wise, etc. If we deem the consequences too
+ severe, we might introduce incompatible changes. This kind
+ of incompatibility will not be introduced in a patch, but
+ instead in the next release.
+ </p>
+ </item>
+ </taglist>
+ <p>
+ Peripheral, trace, and debug functionality is at greater
+ risk of being changed in an incompatible way than functionality
+ in the language itself and core libraries used during operation.
+ </p>
+ </section>
+
+ <section>
+ <marker id="deprecation"/>
+ <title>Deprecation</title>
+ <p>
+ Functionality is deprecated when new functionality is
+ introduced that is preferred to be used instead of the
+ old functionality that is being deprecated. The deprecation
+ does <em>not</em> imply removal of the functionality unless
+ an upcoming removal is explicitly stated in the deprecation.
+ </p>
+ <p>
+ Deprecated functionality will be documented as deprecated, and
+ compiler warnings will be issued, when appropriate, as
+ early as possible. That is, the new preferred functionality
+ will appear at the same time as the deprecation is issued.
+ A new deprecation will at least be announced in a release
+ note and the documentation.
+ </p>
+ </section>
+
+ <section>
+ <marker id="removal"/>
+ <title>Removal</title>
+ <p>
+ Legacy solutions may eventually need to be removed. In such
+ cases, they will be phased out on a long enough time period
+ to give users the time to adapt. Before removal of
+ functionality it will be deprecated at least during one
+ release with an explicit announcement about
+ the upcoming removal. A new deprecation will at least be
+ announced in a release note and the documentation.
+ </p>
+ <p>
+ Peripheral, trace, and debug functionality is at greater
+ risk of removal than functionality in the language itself
+ and core libraries used during operation.
+ </p>
+ </section>
+
+</chapter>
+
diff --git a/system/doc/system_principles/part.xml b/system/doc/system_principles/part.xml
index 1b87ecd350..6699389eec 100644
--- a/system/doc/system_principles/part.xml
+++ b/system/doc/system_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>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -34,4 +34,5 @@
<xi:include href="create_target.xml"/>
<xi:include href="upgrade.xml"/>
<xi:include href="versions.xml"/>
+ <xi:include href="misc.xml"/>
</part>
diff --git a/system/doc/system_principles/system_principles.xml b/system/doc/system_principles/system_principles.xml
index 3605df3ade..500522d778 100644
--- a/system/doc/system_principles/system_principles.xml
+++ b/system/doc/system_principles/system_principles.xml
@@ -4,7 +4,7 @@
<chapter>
<header>
<copyright>
- <year>1996</year><year>2015</year>
+ <year>1996</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -93,7 +93,7 @@ init:stop()</pre>
{progress,kernel_load_completed}
{progress,modules_loaded}
{start,heart}
-{start,error_logger}
+{start,logger}
...</pre>
<p>For a detailed description of the syntax and contents of the
boot script, see the <c>script(4)</c> manual page in SASL.</p>
diff --git a/system/doc/system_principles/versions.xml b/system/doc/system_principles/versions.xml
index b9f7fa4bf6..fbdcc6b2b0 100644
--- a/system/doc/system_principles/versions.xml
+++ b/system/doc/system_principles/versions.xml
@@ -4,7 +4,7 @@
<chapter>
<header>
<copyright>
- <year>2014</year><year>2016</year>
+ <year>2014</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -32,9 +32,9 @@
<rev></rev>
<file>versions.xml</file>
</header>
- <marker id="versions section"></marker>
<section>
+ <marker id="versions section"></marker>
<title>OTP Version</title>
<p>As of OTP release 17, the OTP release number corresponds to
the major part of the OTP version. The OTP version as a concept was
@@ -136,8 +136,8 @@
</section>
<section>
- <title>Version Scheme</title>
<marker id="version_scheme"/>
+ <title>Version Scheme</title>
<note><p>The version scheme was changed as of OTP 17.0. This implies
that application versions used prior to OTP 17.0 do not adhere to this
version scheme. <seealso marker="#otp_17_0_app_versions">A list of
@@ -181,7 +181,7 @@
goes for application versions.</p>
<p>In general, versions can have more than three parts.
The versions are then only partially ordered. Such
- versions are only used in exceptional cases. When an extra
+ versions are only used when branching off from another branch. When an extra
part (out of the normal three parts) is added to a version number,
a new branch of versions is made. The new branch has a linear
order against the base version. However, versions on different
@@ -207,8 +207,68 @@
</section>
<section>
- <title>OTP 17.0 Application Versions</title>
+ <marker id="releases_and_patches"/>
+ <title>Releases and Patches</title>
+ <p>
+ When a new OTP release is released it will have an OTP
+ version on the form <c>&lt;Major&gt;.0</c> where the
+ major OTP version number equals the release number.
+ The major version number is increased one step since the
+ last major version. All other OTP versions with the same
+ major OTP version number are patches on that OTP release.
+ </p>
+ <p>
+ Patches are either released as maintenance patch packages
+ or emergency patch packages. The only difference is that
+ maintenance patch packages are planned and usually contain
+ more changes than emergency patch packages. Emergency patch
+ packages are released to solve one or more specific issues
+ when such are discovered.
+ </p>
+ <p>
+ The release of a maintenance patch package usually imply
+ an increase of the OTP <c>&lt;Minor&gt;</c> version while
+ the release of an emergency patch package usually imply an
+ increase of the OTP <c>&lt;Patch&gt;</c> version. This is
+ however not necessarily always the case since changes of
+ OTP versions are based on the actual changes in the code
+ and not based on whether the patch was planned or not.
+ For more information see the
+ <seealso marker="#version_scheme">Version Scheme</seealso>
+ section above.
+ </p>
+ </section>
+
+ <section>
+ <marker id="otp_versions_tree"/>
+ <title>OTP Versions Tree</title>
+ <p>
+ All released OTP versions can be found in the
+ <url href="http://www.erlang.org/download/otp_versions_tree.html">OTP
+ Versions Tree</url> which is automatically updated whenever
+ we release a new OTP version. Note that every version number as
+ such explicitly define its position in the version tree. Nothing
+ more than the version numbers are needed in order to construct
+ the tree. The root of the tree is OTP version 17.0 which is when
+ we introduced the new
+ <seealso marker="#version_scheme">version scheme</seealso>. The
+ green versions are normal versions released on the main track.
+ Old <seealso marker="#releases_and_patches">OTP releases</seealso>
+ will be maintained for a while on <c>maint</c> branches that have
+ branched off from the main track. Old <c>maint</c> branches always
+ branch off from the main track when the next OTP release is
+ introduced into the main track. Versions on these old <c>maint</c>
+ branches are marked blue. Besides the green and blue versions,
+ there are also gray versions. These are versions on branches
+ introduced in order to fix a specific problem for a specific
+ customer on a specific base version. Branches with gray versions
+ will typically become dead ends very quickly if not immediately.
+ </p>
+ </section>
+
+ <section>
<marker id="otp_17_0_app_versions"/>
+ <title>OTP 17.0 Application Versions</title>
<p>The following list details the application versions that
were part of OTP 17.0. If
the normal part of an application version number compares
diff --git a/system/doc/system_principles/xmlfiles.mk b/system/doc/system_principles/xmlfiles.mk
index c3c3bb4731..353c2c7f7f 100644
--- a/system/doc/system_principles/xmlfiles.mk
+++ b/system/doc/system_principles/xmlfiles.mk
@@ -1,7 +1,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 2009-2016. All Rights Reserved.
+# Copyright Ericsson AB 2009-2018. 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.
@@ -20,6 +20,9 @@
SYSTEM_PRINCIPLES_CHAPTER_FILES = \
system_principles.xml \
error_logging.xml \
- create_target.xml \
upgrade.xml \
- versions.xml
+ versions.xml \
+ misc.xml
+
+SYSTEM_PRINCIPLES_CHAPTER_GEN_FILES = \
+ create_target.xml
diff --git a/system/doc/top/Makefile b/system/doc/top/Makefile
index b6a80aadf5..e3f9c4710a 100644
--- a/system/doc/top/Makefile
+++ b/system/doc/top/Makefile
@@ -1,7 +1,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 1999-2016. All Rights Reserved.
+# Copyright Ericsson AB 1999-2018. 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.
@@ -39,6 +39,7 @@ INFO_FILES = ../../../README.md ../../COPYRIGHT PR.template
TOPDOCDIR=.
+include ../general_info/xmlfiles.mk
include ../installation_guide/xmlfiles.mk
include ../system_principles/xmlfiles.mk
include ../embedded/xmlfiles.mk
@@ -53,36 +54,72 @@ include ../oam/xmlfiles.mk
BOOK_FILES = book.xml
XML_FILES = \
- $(INST_GUIDE_CHAPTER_FILES:%=../installation_guide/%) \
- $(SYSTEM_PRINCIPLES_CHAPTER_FILES:%=../system_principles/%) \
- $(EMBEDDED_CHAPTER_FILES:%=../embedded/%) \
- $(GETTING_STARTED_CHAPTER_FILES:%=../getting_started/%) \
- $(REF_MAN_CHAPTER_FILES:%=../reference_manual/%) \
- $(PROG_EX_CHAPTER_FILES:%=../programming_examples/%) \
- $(EFF_GUIDE_CHAPTER_FILES:%=../efficiency_guide/%) \
- $(TUTORIAL_CHAPTER_FILES:%=../tutorial/%) \
- $(DESIGN_PRINCIPLES_CHAPTER_FILES:%=../design_principles/%) \
- $(OAM_CHAPTER_FILES:%=../oam/%) \
- ../installation_guide/part.xml \
- ../system_principles/part.xml \
- ../embedded/part.xml \
- ../getting_started/part.xml \
- ../reference_manual/part.xml \
- ../programming_examples/part.xml \
- ../efficiency_guide/part.xml \
- ../tutorial/part.xml \
- ../design_principles/part.xml \
- ../oam/part.xml \
$(BOOK_FILES)
-
-XMLLINT_SRCDIRS= ../installation_guide:../system_principles:../embedded:../getting_started:../reference_manual:../programming_examples:../efficiency_guide:../tutorial:../design_principles:../oam
+XML_GUIDE_FILES = \
+ $(GENERAL_INFO_CHAPTER_FILES:%=general_info/%) \
+ $(INST_GUIDE_CHAPTER_FILES:%=installation_guide/%) \
+ $(INST_GUIDE_CHAPTER_GEN_FILES:%=installation_guide/%) \
+ $(SYSTEM_PRINCIPLES_CHAPTER_FILES:%=system_principles/%) \
+ $(SYSTEM_PRINCIPLES_CHAPTER_GEN_FILES:%=system_principles/%) \
+ $(EMBEDDED_CHAPTER_FILES:%=embedded/%) \
+ $(EMBEDDED_CHAPTER_GEN_FILES:%=embedded/%) \
+ $(GETTING_STARTED_CHAPTER_FILES:%=getting_started/%) \
+ $(GETTING_STARTED_CHAPTER_GEN_FILES:%=getting_started/%) \
+ $(REF_MAN_CHAPTER_FILES:%=reference_manual/%) \
+ $(REF_MAN_CHAPTER_GEN_FILES:%=reference_manual/%) \
+ $(PROG_EX_CHAPTER_FILES:%=programming_examples/%) \
+ $(PROG_EX_CHAPTER_GEN_FILES:%=programming_examples/%) \
+ $(EFF_GUIDE_CHAPTER_FILES:%=efficiency_guide/%) \
+ $(EFF_GUIDE_CHAPTER_GEN_FILES:%=efficiency_guide/%) \
+ $(TUTORIAL_CHAPTER_FILES:%=tutorial/%) \
+ $(TUTORIAL_CHAPTER_GEN_FILES:%=tutorial/%) \
+ $(DESIGN_PRINCIPLES_CHAPTER_FILES:%=design_principles/%) \
+ $(DESIGN_PRINCIPLES_CHAPTER_GEN_FILES:%=design_principles/%) \
+ $(OAM_CHAPTER_FILES:%=oam/%) \
+ $(OAM_CHAPTER_GEN_FILES:%=oam/%)
+
+XML_GEN_FILES = \
+ $(XML_GUIDE_FILES:%=$(XMLDIR)/%) \
+ $(XMLDIR)/general_info/part.xml \
+ $(XMLDIR)/installation_guide/part.xml \
+ $(XMLDIR)/system_principles/part.xml \
+ $(XMLDIR)/embedded/part.xml \
+ $(XMLDIR)/getting_started/part.xml \
+ $(XMLDIR)/reference_manual/part.xml \
+ $(XMLDIR)/programming_examples/part.xml \
+ $(XMLDIR)/efficiency_guide/part.xml \
+ $(XMLDIR)/tutorial/part.xml \
+ $(XMLDIR)/design_principles/part.xml \
+ $(XMLDIR)/oam/part.xml
+
+
+XMLLINT_SRCDIRS= $(XMLDIR)/general_info:$(XMLDIR)/installation_guide:$(XMLDIR)/system_principles:$(XMLDIR)/embedded:$(XMLDIR)/getting_started:$(XMLDIR)/reference_manual:$(XMLDIR)/programming_examples:$(XMLDIR)/efficiency_guide:$(XMLDIR)/tutorial:$(XMLDIR)/design_principles:$(XMLDIR)/oam
HTMLDIR= ../html
PDFREFDIR= pdf
TOP_PDF_FILE = $(PDFDIR)/$(APPLICATION)-$(VSN).pdf
TOPDOC=true
+ifdef RELEASE_PATH
+INST_TYPE=rel
+INST_TYPE_SRC_DIR=$(RELEASE_PATH)
+# We build to the 'temporary' dir in order to be able to install
+# results using INSTALL_DATA (in order to get correct access
+# rights on installed files)
+INST_TYPE_DEST_DIR=$(RELSYSDIR)/temporary
+INST_TYPE_DEST_DIR_DEP=$(INST_TYPE_DEST_DIR)
+INST_TYPE_JS_DEST_DIR=$(INST_TYPE_DEST_DIR)
+INST_TYPE_VSN_FILE=$(INST_TYPE_DEST_DIR)/OTP_VERSION
+else
+INST_TYPE=src
+INST_TYPE_SRC_DIR=$(ERL_TOP)
+INST_TYPE_DEST_DIR=$(HTMLDIR)
+INST_TYPE_DEST_DIR_DEP=
+INST_TYPE_JS_DEST_DIR=$(INST_TYPE_DEST_DIR)/js
+INST_TYPE_VSN_FILE=$(ERL_TOP)/OTP_VERSION
+endif
+
#--------------------------------------------------------------------------
# We generate the index page from the installed system. This make
# it important that this is done last. The file index.html.src
@@ -92,17 +129,18 @@ EBIN = ebin
INDEX_SCRIPT = $(EBIN)/erl_html_tools.$(EMULATOR)
INDEX_SRC = src/erl_html_tools.erl
-INDEX_FILES = \
- $(HTMLDIR)/index.html \
- $(HTMLDIR)/applications.html
-JAVASCRIPT = $(HTMLDIR)/js/erlresolvelinks.js
+INDEX_HTML=$(INST_TYPE_DEST_DIR)/index.html
+APPLICATIONS_HTML=$(INST_TYPE_DEST_DIR)/applications.html
+INDEX_FILES = $(INDEX_HTML) $(APPLICATIONS_HTML)
+
+JAVASCRIPT = $(INST_TYPE_JS_DEST_DIR)/erlresolvelinks.js
JAVASCRIPT_BUILD_SCRIPT = $(EBIN)/erlresolvelinks.$(EMULATOR)
JAVASCRIPT_BUILD_SCRIPT_SRC = src/erlresolvelinks.erl
MAN_INDEX_SCRIPT = $(EBIN)/otp_man_index.$(EMULATOR)
MAN_INDEX_SRC = src/otp_man_index.erl
-MAN_INDEX = $(HTMLDIR)/man_index.html
+MAN_INDEX = $(INST_TYPE_DEST_DIR)/man_index.html
GLOSSARY = $(HTMLDIR)/glossary.html
GLOSSARY_SRC = $(ERL_TOP)/system/internal_tools/doctools/src/glossary.erl
@@ -117,45 +155,38 @@ TEMPLATES = \
$(INDEX_SCRIPT): $(INDEX_SRC)
$(ERLC) -o$(EBIN) +warn_unused_vars $<
-# We don't list toc_*.html as targets because we don't know
-$(HTMLDIR)/index.html + $(HTMLDIR)/applications.html: $(INDEX_SCRIPT) $(TEMPLATES)
- echo "Generating index $@"
-# Check if we are building the index from source or an installed release
- if test "$$RELEASE_ROOT" = "" ; then \
- $(ERL) -noshell -pa $(EBIN) -s erl_html_tools top_index src $(ERL_TOP) \
- $(HTMLDIR) `cat "$(ERL_TOP)/OTP_VERSION"` -s erlang halt ;\
+$(INST_TYPE_DEST_DIR)/OTP_VERSION: $(INST_TYPE_DEST_DIR_DEP)
+ if test -f "$(RELEASE_PATH)/releases/$(SYSTEM_VSN)/OTP_VERSION"; then \
+ $(CP) "$(RELEASE_PATH)/releases/$(SYSTEM_VSN)/OTP_VERSION" $@; \
else \
- $(ERL) -noshell -pa $(EBIN) -s erl_html_tools top_index rel $(RELEASE_ROOT) \
- $(HTMLDIR) `cat "$(RELEASE_ROOT)/releases/$(SYSTEM_VSN)/OTP_VERSION"` \
- -s erlang halt ;\
+ $(CP) $(ERL_TOP)/OTP_VERSION $@; \
fi
+# We don't list toc_*.html as targets because we don't know
+$(INDEX_HTML) + $(APPLICATIONS_HTML): $(INST_TYPE_DEST_DIR_DEP) $(INDEX_SCRIPT) $(TEMPLATES) $(INST_TYPE_VSN_FILE)
+ echo "Generating index $@"
+ $(ERL) -noshell -pa $(EBIN) -s erl_html_tools top_index $(INST_TYPE) \
+ $(INST_TYPE_SRC_DIR) $(INST_TYPE_DEST_DIR) \
+ `cat "$(INST_TYPE_VSN_FILE)"` -s erlang halt
+
#--------------------------------------------------------------------------
$(JAVASCRIPT_BUILD_SCRIPT): $(JAVASCRIPT_BUILD_SCRIPT_SRC)
$(ERLC) -o$(EBIN) +warn_unused_vars $<
-$(JAVASCRIPT): $(JAVASCRIPT_BUILD_SCRIPT)
- erl -noshell -pa $(EBIN) -s erlresolvelinks make -s erlang halt
- $(INSTALL_DIR) $(HTMLDIR)/js
- $(INSTALL_DATA) erlresolvelinks.js $(JAVASCRIPT)
+$(JAVASCRIPT): $(INST_TYPE_DEST_DIR_DEP) $(JAVASCRIPT_BUILD_SCRIPT)
+ erl -noshell -pa $(EBIN) -run erlresolvelinks make $(ERL_TOP) \
+ $(INST_TYPE_SRC_DIR) $(INST_TYPE_JS_DEST_DIR) -s erlang halt
#--------------------------------------------------------------------------
$(MAN_INDEX_SCRIPT): $(MAN_INDEX_SRC)
$(ERLC) -o$(EBIN) +warn_unused_vars $<
-$(MAN_INDEX): $(MAN_INDEX_SCRIPT)
-# Check if we are building the index from source or an installed release
- if test "$$RELEASE_ROOT" = "" ; then \
- $(ERL) -noshell -pa $(EBIN) -s otp_man_index gen src $(ERL_TOP) $@ \
- -s erlang halt ;\
- else \
- $(ERL) -noshell -pa $(EBIN) -s otp_man_index gen rel $(RELEASE_ROOT) $@ \
- -s erlang halt ;\
- fi
-
+$(MAN_INDEX): $(INST_TYPE_DEST_DIR_DEP) $(MAN_INDEX_SCRIPT)
+ $(ERL) -noshell -pa $(EBIN) -s otp_man_index gen $(INST_TYPE) \
+ $(INST_TYPE_SRC_DIR) $@ -s erlang halt
#--------------------------------------------------------------------------
@@ -233,19 +264,21 @@ html: $(INDEX_FILES) \
debug opt:
clean:
- rm -rf ../html/js
- rm -f PR.template
- rm -f $(INDEX_FILES) $(MAN_INDEX)
- rm -f $(TOP_PDF_FILE) $(TOP_PDF_FILE:%.pdf=%.fo)
- rm -f $(INDEX_SCRIPT) $(GLOSSARY_SCRIPT) \
- $(JAVASCRIPT_BUILD_SCRIPT)
- rm -f erl_crash.dump errs core *~
+ $(RM) ../html/js/*.js
+ $(RM) PR.template
+ $(RM) $(XMLDIR)/*.xml
+ $(RM) $(INDEX_FILES) $(MAN_INDEX)
+ $(RM) $(TOP_PDF_FILE) $(TOP_PDF_FILE:%.pdf=%.fo)
+ $(RM) $(INDEX_SCRIPT) $(GLOSSARY_SCRIPT) $(JAVASCRIPT_BUILD_SCRIPT)
+ $(RM) erl_crash.dump errs core *~
# ----------------------------------------------------
# Release Target
# ----------------------------------------------------
include $(ERL_TOP)/make/otp_release_targets.mk
+$(RELSYSDIR)/temporary:
+ $(INSTALL_DIR) $(RELSYSDIR)/temporary
release_docs_spec: docs
$(INSTALL_DIR) "$(RELEASE_PATH)"
@@ -255,13 +288,13 @@ release_docs_spec: docs
$(INSTALL_DATA) \
$(TOP_PDF_FILE) $(RELSYSDIR)/pdf
$(INSTALL_DIR) $(RELSYSDIR)/js
- $(INSTALL_DATA) \
- $(JAVASCRIPT) $(RELSYSDIR)/js
+ $(INSTALL_DATA) $(JAVASCRIPT) $(RELSYSDIR)/js
$(INSTALL_DATA) $(INDEX_FILES) $(MAN_INDEX) $(RELSYSDIR)
$(INSTALL_DIR) $(RELSYSDIR)/docbuild
$(INSTALL_DATA) $(INDEX_SCRIPT) $(MAN_INDEX_SCRIPT) $(JAVASCRIPT_BUILD_SCRIPT) \
$(INDEX_SRC) $(MAN_INDEX_SRC) $(JAVASCRIPT_BUILD_SCRIPT_SRC) \
$(TEMPLATES) $(RELSYSDIR)/docbuild
+ $(RM) -r $(RELSYSDIR)/temporary
release_spec:
diff --git a/system/doc/top/book.xml b/system/doc/top/book.xml
index c94b0f24d6..64c1e4caf6 100644
--- a/system/doc/top/book.xml
+++ b/system/doc/top/book.xml
@@ -4,7 +4,7 @@
<book xmlns:xi="http://www.w3.org/2001/XInclude">
<header titlestyle="normal">
<copyright>
- <year>1997</year><year>2016</year>
+ <year>1997</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -36,16 +36,17 @@
<contents level="2"></contents>
</preamble>
<parts lift="no">
- <xi:include href="../installation_guide/part.xml"/>
- <xi:include href="../system_principles/part.xml"/>
- <xi:include href="../embedded/part.xml"/>
- <xi:include href="../getting_started/part.xml"/>
- <xi:include href="../reference_manual/part.xml"/>
- <xi:include href="../programming_examples/part.xml"/>
- <xi:include href="../efficiency_guide/part.xml"/>
- <xi:include href="../tutorial/part.xml"/>
- <xi:include href="../design_principles/part.xml"/>
- <xi:include href="../oam/part.xml"/>
+ <xi:include href="../xml/general_info/part.xml"/>
+ <xi:include href="../xml/installation_guide/part.xml"/>
+ <xi:include href="../xml/system_principles/part.xml"/>
+ <xi:include href="../xml/embedded/part.xml"/>
+ <xi:include href="../xml/getting_started/part.xml"/>
+ <xi:include href="../xml/reference_manual/part.xml"/>
+ <xi:include href="../xml/programming_examples/part.xml"/>
+ <xi:include href="../xml/efficiency_guide/part.xml"/>
+ <xi:include href="../xml/tutorial/part.xml"/>
+ <xi:include href="../xml/design_principles/part.xml"/>
+ <xi:include href="../xml/oam/part.xml"/>
</parts>
<listofterms></listofterms>
<index></index>
diff --git a/system/doc/top/src/erl_html_tools.erl b/system/doc/top/src/erl_html_tools.erl
index 28a0649658..dee1871342 100644
--- a/system/doc/top/src/erl_html_tools.erl
+++ b/system/doc/top/src/erl_html_tools.erl
@@ -508,7 +508,7 @@ subst_app(App, [{VSN,_Path,Link,Text} | VerInfos]) ->
" <a href=\"",Link,"\" target=\"_top\">",uc(App),
"</a>\n",
" <a href=\"",Link,"\" target=\"_top\">",VSN,"</a>\n",
- " <td class=appnums>\n",
+ " <br/>\n",
subst_vsn(VerInfos),
" </td>\n",
" <td>\n",
@@ -522,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/erlresolvelinks.erl b/system/doc/top/src/erlresolvelinks.erl
index cfe8d0fa0b..c1285fa1c3 100644
--- a/system/doc/top/src/erlresolvelinks.erl
+++ b/system/doc/top/src/erlresolvelinks.erl
@@ -27,40 +27,28 @@
%%-----------------------------------------------------------------
-module(erlresolvelinks).
--export([make/0, make/1]).
+-export([make/1]).
-include_lib("kernel/include/file.hrl").
-define(JAVASCRIPT_NAME, "erlresolvelinks.js").
-make() ->
- case os:getenv("ERL_TOP") of
- false ->
- io:format("Variable ERL_TOP is required\n",[]);
- Value ->
- make_from_src(Value, ".")
- end.
-
-make([RootDir, DestDir]) ->
- do_make(RootDir, DestDir);
-make(RootDir) when is_atom(RootDir) ->
- DestDir = filename:join(RootDir, "doc"),
- do_make(RootDir, DestDir).
-
-do_make(_RootDir, _DestDir) ->
- ok.
+make([ErlTop, RootDir, DestDir]) ->
+ make(ErlTop, RootDir, DestDir).
-make_from_src(RootDir, DestDir) ->
+make(ErlTop, RootDir, DestDir) ->
%% doc/Dir
%% erts-Vsn
%% lib/App-Vsn
Name = ?JAVASCRIPT_NAME,
- DocDirs0 = get_dirs(filename:join([RootDir, "system/doc"])),
+ DocDirs0 = get_dirs(filename:join([ErlTop, "system/doc"])),
DocDirs = lists:map(fun({Dir, _DirPath}) ->
D = filename:join(["doc", Dir]),
{D, D} end, DocDirs0),
- ErtsDirs = latest_app_dirs(RootDir, ""),
- AppDirs = latest_app_dirs(RootDir, "lib"),
+ Released = ErlTop /= RootDir,
+
+ ErtsDirs = latest_app_dirs(Released, RootDir, ""),
+ AppDirs = latest_app_dirs(Released, RootDir, "lib"),
AllAppDirs =
lists:map(
@@ -106,30 +94,46 @@ is_dir({File, AFile}) ->
false
end.
-latest_app_dirs(RootDir, Dir) ->
+released_app_vsns([]) ->
+ [];
+released_app_vsns([{AppVsn, Dir} | AVDirs]) ->
+ try
+ {ok, _} = file:read_file_info(filename:join([Dir, "doc", "html"])),
+ [App, Vsn] = string:tokens(AppVsn, "-"),
+ VsnNumList = vsnstr_to_numlist(Vsn),
+ [_Maj, _Min | _] = VsnNumList,
+ [{{App, VsnNumList}, AppVsn} | released_app_vsns(AVDirs)]
+ catch
+ _:_ -> released_app_vsns(AVDirs)
+ end.
+
+latest_app_dirs(Release, RootDir, Dir) ->
ADir = filename:join(RootDir, Dir),
RDirs0 = get_dirs(ADir),
- RDirs1 = lists:filter(fun is_app_dir/1, RDirs0),
-
- SDirs0 =
- lists:map(fun({App, Dir1}) ->
- File = filename:join(Dir1, "vsn.mk"),
- case file:read_file(File) of
- {ok, Bin} ->
- case re:run(Bin, ".*VSN\s*=\s*([0-9\.]+).*",[{capture,[1],list}]) of
- {match, [VsnStr]} ->
- VsnNumList = vsnstr_to_numlist(VsnStr),
- {{App, VsnNumList}, App++"-"++VsnStr};
- nomatch ->
- io:format("No VSN variable found in ~s\n", [File]),
- error
- end;
- {error, Reason} ->
- io:format("~p : ~s\n", [Reason, File]),
- error
- end
- end,
- RDirs1),
+ SDirs0 = case Release of
+ true ->
+ released_app_vsns(RDirs0);
+ false ->
+ lists:map(fun({App, Dir1}) ->
+ File = filename:join(Dir1, "vsn.mk"),
+ case file:read_file(File) of
+ {ok, Bin} ->
+ case re:run(Bin, ".*VSN\s*=\s*([0-9\.]+).*",[{capture,[1],list}]) of
+ {match, [VsnStr]} ->
+ VsnNumList = vsnstr_to_numlist(VsnStr),
+ {{App, VsnNumList}, App++"-"++VsnStr};
+ nomatch ->
+ io:format("No VSN variable found in ~s\n", [File]),
+ error
+ end;
+ {error, Reason} ->
+ io:format("~p : ~s\n", [Reason, File]),
+ error
+ end
+ end,
+ lists:filter(fun is_app_dir/1, RDirs0))
+ end,
+
SDirs1 = lists:keysort(1, SDirs0),
App2Dirs = lists:foldr(fun({{App, _VsnNumList}, AppVsn}, Acc) ->
case lists:keymember(App, 1, Acc) of
diff --git a/system/doc/top/templates/index.html.src b/system/doc/top/templates/index.html.src
index 747d19cf7e..3b61052b99 100644
--- a/system/doc/top/templates/index.html.src
+++ b/system/doc/top/templates/index.html.src
@@ -41,6 +41,8 @@ limitations under the License.
<ul class="section-links">
<li><a href="applications.html">Applications</a></li>
<li><a href="man_index.html" class="modules">Modules</a></li>
+ <li><a href="general_info/deprecations.html" class="modules">Deprecations</a></li>
+ <li><a href="general_info/scheduled_for_removal.html" class="modules">Scheduled for Removal</a></li>
</ul>
<ul class="expand-collapse-items">
diff --git a/system/doc/tutorial/Makefile b/system/doc/tutorial/Makefile
index 5deea41f0a..4c62deeffd 100644
--- a/system/doc/tutorial/Makefile
+++ b/system/doc/tutorial/Makefile
@@ -1,7 +1,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 2000-2016. All Rights Reserved.
+# Copyright Ericsson AB 2000-2018. 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.
@@ -28,6 +28,7 @@ include $(ERL_TOP)/erts/vsn.mk
#VSN=$(SYSTEM_VSN)
APPLICATION=otp-system-documentation
+XMLDIR := $(XMLDIR)/tutorial
# ----------------------------------------------------
# Release directory specification
# ----------------------------------------------------
@@ -53,6 +54,9 @@ XML_FILES = \
$(BOOK_FILES) $(XML_CHAPTER_FILES) \
$(XML_PART_FILES)
+XML_GEN_FILES = \
+ $(TUTORIAL_CHAPTER_GEN_FILES:%=$(XMLDIR)/%)
+
# ----------------------------------------------------
C_FILES = \
@@ -89,10 +93,9 @@ DVIPS_FLAGS +=
# ----------------------------------------------------
# Targets
# ----------------------------------------------------
-_create_dirs := $(shell mkdir -p $(HTMLDIR))
$(HTMLDIR)/%.gif: %.gif
- $(INSTALL_DATA) $< $@
+ $(CP) $< $@
docs: html
@@ -105,7 +108,8 @@ gifs: $(GIF_FILES:%=$(HTMLDIR)/%)
debug opt:
clean clean_docs:
- rm -rf $(HTMLDIR)
+ rm -f $(XMLDIR)/*.xml
+ rm -f $(HTMLDIR)/*.gif $(HTMLDIR)/*.html
rm -f $(TOP_PDF_FILE) $(TOP_PDF_FILE:%.pdf=%.fo)
rm -f errs core *~
diff --git a/system/doc/tutorial/overview.xml b/system/doc/tutorial/overview.xml
index 255c22f2c1..bd652b1e4b 100644
--- a/system/doc/tutorial/overview.xml
+++ b/system/doc/tutorial/overview.xml
@@ -245,13 +245,13 @@ Term = binary_to_term(Binary)</pre>
</section>
<section>
- <title>IC</title>
+ <title>IC and CORBA</title>
<p>IC (Erlang IDL Compiler) is an interface generator that, given
an IDL interface specification, automatically generates stub
code in Erlang, C, or Java. See the IC User's Guide and IC
Reference Manual.</p>
- <p>For details, see the <seealso marker="ic:ic">ic</seealso>
- manual page in IC.</p>
+ <p>For details, see the
+ <url href="https://github.com/erlang/corba">corba repository</url>.</p>
</section>
<section>
diff --git a/system/doc/tutorial/port_driver.c b/system/doc/tutorial/port_driver.c
index 37de67310f..8b441733ed 100644
--- a/system/doc/tutorial/port_driver.c
+++ b/system/doc/tutorial/port_driver.c
@@ -51,8 +51,7 @@ ErlDrvEntry example_driver_entry = {
queue */
NULL, /* F_PTR call, much like control, sync call
to driver */
- NULL, /* F_PTR event, called when an event selected
- by driver_event() occurs. */
+ NULL, /* unused */
ERL_DRV_EXTENDED_MARKER, /* int extended marker, Should always be
set to indicate driver versioning */
ERL_DRV_EXTENDED_MAJOR_VERSION, /* int major_version, should always be
diff --git a/system/doc/tutorial/xmlfiles.mk b/system/doc/tutorial/xmlfiles.mk
index f8ed7be064..74e174f6d4 100644
--- a/system/doc/tutorial/xmlfiles.mk
+++ b/system/doc/tutorial/xmlfiles.mk
@@ -1,7 +1,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 2009-2016. All Rights Reserved.
+# Copyright Ericsson AB 2009-2018. 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.
@@ -19,13 +19,16 @@
#
TUTORIAL_CHAPTER_FILES = \
introduction.xml\
+ overview.xml
+
+TUTORIAL_CHAPTER_GEN_FILES = \
cnode.xml\
c_port.xml\
erl_interface.xml \
c_portdriver.xml \
example.xml\
- overview.xml\
nif.xml
+
# appendix.xml
# distribution.xml (to be part of tutorial later)
diff --git a/system/doc/xml/design_principles/.gitignore b/system/doc/xml/design_principles/.gitignore
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/system/doc/xml/design_principles/.gitignore
diff --git a/system/doc/xml/efficiency_guide/.gitignore b/system/doc/xml/efficiency_guide/.gitignore
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/system/doc/xml/efficiency_guide/.gitignore
diff --git a/system/doc/xml/embedded/.gitignore b/system/doc/xml/embedded/.gitignore
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/system/doc/xml/embedded/.gitignore
diff --git a/system/doc/xml/general_info/.gitignore b/system/doc/xml/general_info/.gitignore
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/system/doc/xml/general_info/.gitignore
diff --git a/system/doc/xml/getting_started/.gitignore b/system/doc/xml/getting_started/.gitignore
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/system/doc/xml/getting_started/.gitignore
diff --git a/system/doc/xml/installation_guide/.gitignore b/system/doc/xml/installation_guide/.gitignore
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/system/doc/xml/installation_guide/.gitignore
diff --git a/system/doc/xml/oam/.gitignore b/system/doc/xml/oam/.gitignore
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/system/doc/xml/oam/.gitignore
diff --git a/system/doc/xml/programming_examples/.gitignore b/system/doc/xml/programming_examples/.gitignore
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/system/doc/xml/programming_examples/.gitignore
diff --git a/system/doc/xml/reference_manual/.gitignore b/system/doc/xml/reference_manual/.gitignore
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/system/doc/xml/reference_manual/.gitignore
diff --git a/system/doc/xml/system_architecture_intro/.gitignore b/system/doc/xml/system_architecture_intro/.gitignore
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/system/doc/xml/system_architecture_intro/.gitignore
diff --git a/system/doc/xml/system_principles/.gitignore b/system/doc/xml/system_principles/.gitignore
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/system/doc/xml/system_principles/.gitignore
diff --git a/system/doc/xml/tutorial/.gitignore b/system/doc/xml/tutorial/.gitignore
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/system/doc/xml/tutorial/.gitignore