diff options
Diffstat (limited to 'system')
35 files changed, 1098 insertions, 110 deletions
diff --git a/system/doc/design_principles/events.xml b/system/doc/design_principles/events.xml index acd051d411..4d7b34bc70 100644 --- a/system/doc/design_principles/events.xml +++ b/system/doc/design_principles/events.xml @@ -227,7 +227,8 @@ ok</pre> <c>handle_info(Info, State)</c> must be implemented to handle them. Examples of other messages are exit messages, if the <c>gen_event</c> is linked to - other processes (than the supervisor) and trapping exit signals.</p> + other processes (than the supervisor, for example via + <c>add_sup_handler</c>) and trapping exit signals.</p> <code type="none"> handle_info({'EXIT', Pid, Reason}, State) -> ..code to handle exits here.. diff --git a/system/doc/design_principles/release_handling.xml b/system/doc/design_principles/release_handling.xml index d23e9732fc..167d92d52f 100644 --- a/system/doc/design_principles/release_handling.xml +++ b/system/doc/design_principles/release_handling.xml @@ -4,7 +4,7 @@ <chapter> <header> <copyright> - <year>2003</year><year>2020</year> + <year>2003</year><year>2021</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> @@ -311,7 +311,7 @@ the following instruction is used:</p> <code type="none"> {apply, {M, F, A}}</code> - <p>The release handler evalutes <c>apply(M, F, A)</c>.</p> + <p>The release handler evaluates <c>apply(M, F, A)</c>.</p> </section> <section> diff --git a/system/doc/design_principles/spec_proc.xml b/system/doc/design_principles/spec_proc.xml index 0610a15a8a..51a1228183 100644 --- a/system/doc/design_principles/spec_proc.xml +++ b/system/doc/design_principles/spec_proc.xml @@ -274,7 +274,7 @@ init(Parent) -> <section> <marker id="debug"></marker> <title>Debugging</title> - <p>To support the debug facilites in <c>sys</c>, a + <p>To support the debug facilities in <c>sys</c>, a <em>debug structure</em> is needed. The <c>Deb</c> term is initialized using <c>sys:debug_options/1</c>:</p> <code type="none"> diff --git a/system/doc/design_principles/statem.xml b/system/doc/design_principles/statem.xml index 2d6ea27635..c53d569c99 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>2020</year> + <year>2016</year><year>2021</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> @@ -1947,7 +1947,7 @@ do_unlock() -> <p> Say you have a state machine specification that uses state enter actions. - Allthough you can code this using inserted events + Although you can code this using inserted events (described in the next section), especially if just one or a few states has got state enter actions, this is a perfect use case for the built in diff --git a/system/doc/design_principles/sup_princ.xml b/system/doc/design_principles/sup_princ.xml index 4d1b593c92..c9aa52669b 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>2021</year> + <year>1997</year><year>2022</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> @@ -69,7 +69,7 @@ init(_Args) -> restart => permanent, shutdown => brutal_kill, type => worker, - modules => [cg3]}], + modules => [ch3]}], {ok, {SupFlags, ChildSpecs}}.</code> <p>The <c>SupFlags</c> variable in the return value from <c>init/1</c> represents @@ -374,7 +374,7 @@ child_spec() = #{id => child_id(), % mandatory <p>Note that this identifier occasionally has been called "name". As far as possible, the terms "identifier" or "id" are now used but in order to keep backwards compatibility, - some occurences of "name" can still be found, for example + some occurrences of "name" can still be found, for example in error messages.</p> </item> <item> diff --git a/system/doc/efficiency_guide/advanced.xml b/system/doc/efficiency_guide/advanced.xml index c545d22a8a..25899f6821 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>2021</year> + <year>2001</year><year>2022</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> @@ -39,7 +39,9 @@ <p>The unit of measurement is memory words. There exists both a 32-bit and a 64-bit implementation. A word is therefore 4 bytes or - 8 bytes, respectively.</p> + 8 bytes, respectively. The value for a running system can be + determined by calling <seeerl marker="erts:erlang#system_info_wordsize"> + <c>erlang:system_info(wordsize)</c></seeerl>.</p> <table> <row> <cell><em>Data Type</em></cell> diff --git a/system/doc/efficiency_guide/bench.erl b/system/doc/efficiency_guide/bench.erl index a1be24b051..a1e9a71084 100644 --- a/system/doc/efficiency_guide/bench.erl +++ b/system/doc/efficiency_guide/bench.erl @@ -424,7 +424,7 @@ create_html_table(File, {Bm, Res}) -> create_html_row(File, Name, ResultDict) end, Order), - %% Tabel end-tags + %% Table end-tags io:put_chars(File, "</table></td></tr></table>\n"), %% Create link to benchmark source code @@ -435,7 +435,7 @@ create_html_table(File, {Bm, Res}) -> %% create_html_row(File, Name, Dict) -> _ %% File = file() - html file to write data to. %% Name = atom() - Name of benchmark test -%% Dict = dict() - Dictonary where the relative time measures for +%% Dict = dict() - Dictionary where the relative time measures for %% the test can be found. %% %% Creates an actual html table-row. diff --git a/system/doc/efficiency_guide/commoncaveats.xmlsrc b/system/doc/efficiency_guide/commoncaveats.xmlsrc index 47ce3a014f..6ea8599e94 100644 --- a/system/doc/efficiency_guide/commoncaveats.xmlsrc +++ b/system/doc/efficiency_guide/commoncaveats.xmlsrc @@ -39,11 +39,16 @@ marker="erts:erlang#send_after/3">erlang:send_after/3</seemfa> and <seemfa marker="erts:erlang#start_timer/3">erlang:start_timer/3</seemfa>, - is much more efficient than using the timers provided by the - <seeerl marker="stdlib:timer">timer</seeerl> module in STDLIB. - The <c>timer</c> module uses a separate process to manage the timers. - That process can easily become overloaded if many processes - create and cancel timers frequently.</p> + is more efficient than using the timers provided by the + <seeerl marker="stdlib:timer">timer</seeerl> module in STDLIB.</p> + <p>The <c>timer</c> module uses a separate process to manage the timers. + Before OTP 25, this management overhead was substantial and increasing + with the number of timers, especially when they were short-lived, so the + timer server process could easily become overloaded and unresponsive. + In OTP 25, the timer module was improved by removing most of the management + overhead and the resulting performance penalty. Still, the timer server + remains a single process, and it may at some point become a bottleneck + of an application.</p> <p>The functions in the <c>timer</c> module that do not manage timers (such as <c>timer:tc/3</c> or <c>timer:sleep/1</c>), do not call the @@ -85,7 +90,7 @@ <p>a list with 10000 elements (or about 20000 heap words) will be copied to the newly created process.</p> - <p>An unncessary copy of 10000 element list can be bad enough, but it + <p>An unnecessary copy of 10000 element list can be bad enough, but it can get even worse if the <c>state</c> record contains <em>shared subterms</em>. Here is a simple example of a term with a shared subterm:</p> @@ -192,7 +197,7 @@ multiple_setelement(T0) -> <p>The two following <c>setelement/3</c> calls modify the tuple in place.</p> - <p>For the optimization to be applied, <em>all</em> the followings conditions + <p>For the optimization to be applied, <em>all</em> the following conditions must be true:</p> <list type="bulleted"> diff --git a/system/doc/efficiency_guide/functions.xml b/system/doc/efficiency_guide/functions.xml index 0a8ee7eb34..f3d6b59e49 100644 --- a/system/doc/efficiency_guide/functions.xml +++ b/system/doc/efficiency_guide/functions.xml @@ -4,7 +4,7 @@ <chapter> <header> <copyright> - <year>2001</year><year>2017</year> + <year>2001</year><year>2022</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> @@ -158,22 +158,23 @@ explicit_map_pairs(Map, Xs0, Ys0) -> <section> <title>Function Calls</title> - <p>This is an intentionally rough guide to the relative costs of - different calls. It is based on benchmark figures run on - Solaris/Sparc:</p> + <p>This is a rough hierarchy of the performance of the + different types of function calls:</p> <list type="bulleted"> <item>Calls to local or external functions (<c>foo()</c>, <c>m:foo()</c>) are the fastest calls.</item> <item>Calling or applying a fun (<c>Fun()</c>, <c>apply(Fun, [])</c>) - is about <em>three times</em> as expensive as calling a local - function.</item> + is just a little slower than external calls.</item> <item>Applying an exported function (<c>Mod:Name()</c>, - <c>apply(Mod, Name, [])</c>) is about twice as expensive as calling - a fun or about <em>six times</em> as expensive as calling a local - function.</item> + <c>apply(Mod, Name, [])</c>) where the number of arguments is known + at compile time is next.</item> + + <item>Applying an exported function (<c>apply(Mod, Name, Args)</c>) + where the number of arguments is not known at compile time is the + least efficient.</item> </list> <section> @@ -187,25 +188,8 @@ explicit_map_pairs(Map, Xs0, Ys0) -> in a hash table. It is therefore always slower than a direct call or a fun call.</p> - <p>It no longer matters (from a performance point of view) - whether you write:</p> - - <code type="erl"> -Module:Function(Arg1, Arg2)</code> - - <p>or:</p> - - <code type="erl"> -apply(Module, Function, [Arg1,Arg2])</code> - - <p>The compiler internally rewrites the latter code into the - former.</p> - - <p>The following code is slightly slower because the shape of the - list of arguments is unknown at compile time.</p> - - <code type="erl"> -apply(Module, Function, Arguments)</code> + <p>Caching callback functions into funs may be more efficient + in the long run than apply calls for frequently-used callbacks.</p> </section> </section> diff --git a/system/doc/efficiency_guide/retired_myths.xml b/system/doc/efficiency_guide/retired_myths.xml index a763770e5a..593e8f5492 100644 --- a/system/doc/efficiency_guide/retired_myths.xml +++ b/system/doc/efficiency_guide/retired_myths.xml @@ -5,7 +5,7 @@ <header> <copyright> <year>2016</year> - <year>2020</year> + <year>2021</year> <holder>Ericsson AB, All Rights Reserved</holder> </copyright> <legalnotice> @@ -31,7 +31,7 @@ <file>retired_myths.xml</file> </header> - <p>We belive that the truth finally has caught with the following, + <p>We believe that the truth finally has caught with the following, retired myths.</p> <section> diff --git a/system/doc/efficiency_guide/tablesDatabases.xml b/system/doc/efficiency_guide/tablesDatabases.xml index 3f77151e55..ba0d5e2e40 100644 --- a/system/doc/efficiency_guide/tablesDatabases.xml +++ b/system/doc/efficiency_guide/tablesDatabases.xml @@ -4,7 +4,7 @@ <chapter> <header> <copyright> - <year>2001</year><year>2016</year> + <year>2001</year><year>2021</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> @@ -137,7 +137,7 @@ print_person(PersonId) -> io:format("No person with ID = ~p~n", [PersonID]) end. -%%% Internal functionss +%%% Internal functions print_name(PersonID) -> [Person] = ets:lookup(person, PersonId), io:format("No person ~p~n", [Person#person.name]). diff --git a/system/doc/embedded/intro.xml b/system/doc/embedded/intro.xml index 2b9d35d24c..cec3212481 100644 --- a/system/doc/embedded/intro.xml +++ b/system/doc/embedded/intro.xml @@ -5,7 +5,7 @@ <header> <copyright> <year>1997</year> - <year>2016</year> + <year>2021</year> <holder>Ericsson AB, All Rights Reserved</holder> </copyright> <legalnotice> @@ -37,7 +37,7 @@ <p>This manual is a complement to the other manuals and describes how to install, run and maintain Erlang on an embedded system. </p> - <p>For more informaton about how to install and start Erlang read + <p>For more information about how to install and start Erlang read XXXXXXXX. </p> diff --git a/system/doc/general_info/DEPRECATIONS b/system/doc/general_info/DEPRECATIONS index ab304db2a8..2f83cbb9d3 100644 --- a/system/doc/general_info/DEPRECATIONS +++ b/system/doc/general_info/DEPRECATIONS @@ -18,13 +18,25 @@ # # +# Added in OTP 25. +# +slave:_/_ since=25 remove=27 +ct_slave:_/_ since=25 remove=27 +httpd_util:encode_hex/1 since=25 remove=26 +httpd_util:decode_hex/1 since=25 remove=26 + +crypto:crypto_dyn_iv_init/3 since=25 remove=27 +crypto:crypto_dyn_iv_update/3 since=25 remove=27 +erts_alloc_config:_/_ since=25 remove=26 + +# # Added in OTP 24. # -public_key:ssh_hostkey_fingerprint/1 since=24 remove=26 -public_key:ssh_hostkey_fingerprint/2 since=24 remove=26 -public_key:ssh_decode/2 since=24 remove=26 -public_key:ssh_encode/2 since=24 remove=26 +public_key:ssh_hostkey_fingerprint/1 since=24 remove=25 +public_key:ssh_hostkey_fingerprint/2 since=24 remove=25 +public_key:ssh_decode/2 since=24 remove=25 +public_key:ssh_encode/2 since=24 remove=25 ftp:start_service/1 since=24 remove=26 ftp:stop_service/1 since=24 remove=26 httpd_util:flatlength/1 since=24 remove=26 @@ -57,8 +69,8 @@ ssl:cipher_suites/0 since=21 remove=24 http_uri:parse/1 since=23 remove=25 http_uri:parse/2 since=23 remove=25 -http_uri:encode/1 since=23 remove=25 -http_uri:decode/1 since=23 remove=25 +http_uri:encode/1 since=23 remove=26 +http_uri:decode/1 since=23 remove=26 http_uri:scheme_defaults/0 since=23 remove=25 httpd:parse_query/1 since=23 pg2:_/_ since=23 remove=24 diff --git a/system/doc/general_info/deprecations_23.inc b/system/doc/general_info/deprecations_23.inc index ef1c6ff12f..1eb8f3dd5e 100644 --- a/system/doc/general_info/deprecations_23.inc +++ b/system/doc/general_info/deprecations_23.inc @@ -18,12 +18,12 @@ <section> <title>ssh</title> <p>The public key algorithm <c>'ssh-rsa</c> is regarded as insecure due - to its usage of SHA1, and is therfore deprecated. + to its usage of SHA1, and is therefore deprecated. It will not be available by default from OTP-24. </p> <p>The public key algorithm <c>'ssh-dss</c> is regarded as insecure due - to its usage of SHA1 and its short key length, and is therfore deprecated. + to its usage of SHA1 and its short key length, and is therefore deprecated. It is not available by default from OTP-23. </p> </section> diff --git a/system/doc/general_info/upcoming_incompatibilities.xml b/system/doc/general_info/upcoming_incompatibilities.xml index 69a0f6de16..59003d2243 100644 --- a/system/doc/general_info/upcoming_incompatibilities.xml +++ b/system/doc/general_info/upcoming_incompatibilities.xml @@ -4,7 +4,7 @@ <chapter> <header> <copyright> - <year>2021</year> + <year>2021</year><year>2022</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> @@ -132,5 +132,18 @@ </list> </section> + <section> + <title>The default timewarp mode will change to multi-time warp mode</title> + <p> + The default <seeguide marker="erts:time_correction#Time_Warp_Modes"> + Time Warp Mode</seeguide> will be changed from + <seeguide marker="erts:time_correction#No_Time_Warp_Mode"> + no time warp mode</seeguide> to <seeguide marker="erts:time_correction#Multi_Time_Warp_Mode"> + multi-time warp mode</seeguide>. See <seeguide marker="erts:time_correction"> + Time and Time Correction in Erlang</seeguide> for details on how this will + effect your system. + </p> + </section> + </section> </chapter> diff --git a/system/doc/programming_examples/bit_syntax.xml b/system/doc/programming_examples/bit_syntax.xml index cc89f3a469..08587ccff3 100644 --- a/system/doc/programming_examples/bit_syntax.xml +++ b/system/doc/programming_examples/bit_syntax.xml @@ -4,7 +4,7 @@ <chapter> <header> <copyright> - <year>2003</year><year>2020</year> + <year>2003</year><year>2022</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> @@ -206,7 +206,7 @@ X:4/little-signed-integer-unit:8</code> matching, this default value is only valid for the last element. All other binary elements in matching must have a size specification.</p> - <p>The default unit depends on the the type. For <c>integer</c>, + <p>The default unit depends on the type. For <c>integer</c>, <c>float</c>, and <c>bitstring</c> it is 1. For binary it is 8.</p> <p>The default signedness is <c>unsigned</c>.</p> <p>The default endianness is <c>big</c>.</p> @@ -311,8 +311,8 @@ foo(N, Bin) -> <section> <title>Binding and Using a Size Variable</title> <p>There is one exception to the rule that a variable that is - as size must be previously bound. It is possible to match and - bind a variable, and use it as a size within the the same + used as size must be previously bound. It is possible to match and + bind a variable, and use it as a size within the same binary pattern. For example:</p> <code type="none"><![CDATA[ diff --git a/system/doc/reference_manual/data_types.xml b/system/doc/reference_manual/data_types.xml index 15983ebbf9..1a4bdc5680 100644 --- a/system/doc/reference_manual/data_types.xml +++ b/system/doc/reference_manual/data_types.xml @@ -4,7 +4,7 @@ <chapter> <header> <copyright> - <year>2003</year><year>2021</year> + <year>2003</year><year>2022</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> @@ -30,7 +30,15 @@ <file>data_types.xml</file> </header> <p>Erlang provides a number of data types, which are listed in - this section.</p> + this section.</p> + + <marker id="no_user_types" /> + <p>Note that Erlang has no user defined types, only composite + types (data structures) made of Erlang terms. This means that any + function testing for a composite type, typically named + <c>is_type/1</c>, might return <c>true</c> for a term + that coincides with the chosen representation. The corresponding + functions for built in types do not suffer from this.</p> <section> <title>Terms</title> @@ -85,8 +93,8 @@ <p>When working with floats you may not see what you expect when printing or doing arithmetic operations. This is because floats are represented by a fixed number of bits in a base-2 system while - printed floats are represented with a base-10 system. Here are - examples of this phenomenon: + printed floats are represented with a base-10 system. Erlang + uses 64-bit floats. Here are examples of this phenomenon: </p> <pre> > <input>0.1+0.2.</input> diff --git a/system/doc/reference_manual/distributed.xml b/system/doc/reference_manual/distributed.xml index cc4746825b..f8fb159be3 100644 --- a/system/doc/reference_manual/distributed.xml +++ b/system/doc/reference_manual/distributed.xml @@ -4,7 +4,7 @@ <chapter> <header> <copyright> - <year>2003</year><year>2021</year> + <year>2003</year><year>2022</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> @@ -155,7 +155,7 @@ dilbert@uab</pre> name from the first node it connects to. In addition these distribution settings will be set: </p> - <pre><seeapp marker="kernel:kernel_app#dist_listen">-dist_listen false</seeapp> <seecom marker="erts:erl#hidden">-hidden</seecom> <seeapp marker="kernel:kernel_app#dist_auto_connect">-dist_auto_connect never</seeapp></pre> + <pre><seecom marker="erts:erl#dist_listen">-dist_listen false</seecom> <seecom marker="erts:erl#hidden">-hidden</seecom> <seeapp marker="kernel:kernel_app#dist_auto_connect">-kernel dist_auto_connect never</seeapp></pre> <p> As <c>-dist_auto_connect</c> is set to <c>never</c>, <seemfa marker="kernel:net_kernel#connect_node/1"><c>net_kernel:connect_node/1</c></seemfa> @@ -212,7 +212,7 @@ dilbert@uab</pre> in the following text is not very unpredictable. A better one can be generated using primitives in the <c>crypto</c> module, though this still does not make - the inital handshake cryptographically secure. + the initial handshake cryptographically secure. And inter-node communication is still in clear text. </p> </note> @@ -230,9 +230,14 @@ dilbert@uab</pre> <p>At start-up, a node has a random atom assigned as its default magic cookie and the cookie of other nodes is assumed to be <c>nocookie</c>. The first action of the Erlang network - authentication server (<c>auth</c>) is then to read a file named - <c>$HOME/.erlang.cookie</c>. If the file does not exist, it is - created. The UNIX permissions mode of the file is set to octal + authentication server (<c>auth</c>) is then to search for a file named + <c>.erlang.cookie</c> in the <seeerl marker="erts:init#home"> + user's home directory</seeerl> and then in + <seeerl marker="stdlib:filename#user_config"> + <c>filename:basedir(user_config, "erlang")</c></seeerl>. + If none of the files exist, a <c>.erlang.cooke</c> file is created + in the user's home directory. + The UNIX permissions mode of the file is set to octal 400 (read-only by user) and its content is a random string. An atom <c>Cookie</c> is created from the contents of the file and the cookie of the local node is set to this using diff --git a/system/doc/reference_manual/expressions.xml b/system/doc/reference_manual/expressions.xml index 8dbc620bd0..af143ad4d5 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>2021</year> + <year>2003</year><year>2023</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> @@ -395,6 +395,139 @@ is_valid_signal(Signal) -> </section> <section> + <marker id="maybe"></marker> + <title>Maybe</title> + <note><p><c>maybe</c> is an experimental new <seeguide + marker="system/reference_manual:features#features">feature</seeguide> + introduced in OTP 25. By default, it is disabled. To enable + <c>maybe</c>, either use the <c>-feature(maybe_expr,enable)</c> + directive (from within source code), or the compiler option + <c>{feature,maybe_expr,enable}</c>. The feature must also be enabled + in runtime using the <c>-enable-feature</c> option to <c>erl</c>.</p> + </note> + + <code type="erl"><![CDATA[ +maybe + Expr1, + ..., + ExprN +end]]></code> + + <p>The expressions in a <c>maybe</c> block are evaluated sequentially. If all + expressions are evaluated successfully, the return value of the <c>maybe</c> + block is <c>ExprN</c>. However, execution can be short-circuited by a + conditional match expression:</p> + + <code type="erl"><![CDATA[ +Expr1 ?= Expr2]]></code> + + <p><c>?=</c> is called the conditional match operator. It is only + allowed to be used at the top-level of a <c>maybe</c> block. It + matches the pattern <c>Expr1</c> against <c>Expr2</c>. If the + matching succeeds, any unbound variable in the pattern becomes + bound. If the expression is the last expression in the + <c>maybe</c> block, it also returns the value of <c>Expr2</c>. If the + matching is unsuccessful, the rest of the expressions in the <c>maybe</c> + block are skipped and the return value of the <c>maybe</c> + block is <c>Expr2</c>.</p> + + <p>None of the variables bound in a <c>maybe</c> block must be + used in the code that follows the block.</p> + + <p>Here is an example:</p> + + <code type="erl"><![CDATA[ +maybe + {ok, A} ?= a(), + true = A >= 0, + {ok, B} ?= b(), + A + B +end]]></code> + + <p>Let us first assume that <c>a()</c> returns <c>{ok,42}</c> and + <c>b()</c> returns <c>{ok,58}</c>. With those return values, all + of the match operators will succeed, and the return value of the + <c>maybe</c> block is <c>A + B</c>, which is equal to <c>42 + + 58 = 100</c>.</p> + + <p>Now let us assume that <c>a()</c> returns <c>error</c>. The + conditional match operator in <c>{ok, A} ?= a()</c> fails to + match, and the return value of the <c>maybe</c> block is the + value of the expression that failed to match, namely <c>error</c>. + Similarly, if <c>b()</c> returns <c>wrong</c>, the return value of + the <c>maybe</c> block is <c>wrong</c>.</p> + + <p>Finally, let us assume that <c>a()</c> returns + <c>-1</c>. Because <c>true = A >= 0</c> uses the match operator + `=`, a <c>{badmatch,false}</c> run-time error occurs when the + expression fails to match the pattern.</p> + + <p>The example can be written in a less succient way using nested + case expressions:</p> + + <code type="erl"><![CDATA[ +case a() of + {ok, A} -> + true = A >= 0, + case b() of + {ok, B} -> + A + B; + Other1 -> + Other1 + end; + Other2 -> + Other2 +end]]></code> + + <p>The <c>maybe</c> block can be augmented with <c>else</c> clauses:</p> + + <code type="erl"><![CDATA[ +maybe + Expr1, + ..., + ExprN +else + Pattern1 [when GuardSeq1] -> + Body1; + ...; + PatternN [when GuardSeqN] -> + BodyN +end]]></code> + + <p>If a conditional match operator fails, the failed expression is + matched against the patterns in all clauses between the + <c>else</c> and <c>end</c> keywords. If a match succeeds and the + optional guard sequence <c>GuardSeq</c> is true, the corresponding + <c>Body</c> is evaluated. The value returned from the body is the + return value of the <c>maybe</c> block.</p> + + <p>If there is no matching pattern with a true guard sequence, + an <c>else_clause</c> run-time error occurs.</p> + + <p>None of the variables bound in a <c>maybe</c> block must be used in + the <c>else</c> clauses. None of the variables bound in the <c>else</c> clauses + must be used in the code that follows the <c>maybe</c> block.</p> + + <p>Here is the previous example augmented with a <c>else</c> clauses:</p> + + <code type="erl"><![CDATA[ +maybe + {ok, A} ?= a(), + true = A >= 0, + {ok, B} ?= b(), + A + B +else + error -> error; + wrong -> error +end]]></code> + + <p>The <c>else</c> clauses translate the failing value from + the conditional match operators to the value <c>error</c>. If the + failing value is not one of the recognized values, a + <c>else_clause</c> run-time error occurs.</p> + </section> + + <section> <marker id="send"></marker> <title>Send</title> <pre> @@ -824,7 +957,7 @@ Expr1 -- Expr2</pre> <p>The list concatenation operator <c>++</c> appends its second argument to its first and returns the resulting list.</p> <p>The list subtraction operator <c>--</c> produces a list that - is a copy of the first argument. The procedure is a follows: + is a copy of the first argument. The procedure is as follows: for each element in the second argument, the first occurrence of this element (if any) is removed.</p> <p><em>Example:</em></p> @@ -1014,7 +1147,7 @@ M4 = M3#{a := 2, b := 3}. % 'a' and 'b' was added in `M1` and `M2`.</code> <p> Here keys <c>K1 .. Kn</c> are any expressions with literals or bound variables. If all key expressions - evalute successfully and all keys exist in map + evaluate successfully and all keys exist in map <c>M</c>, all variables in <c>V1 .. Vn</c> is matched to the associated values of their respective keys. @@ -1575,7 +1708,11 @@ end</pre> <c>BitStringExpr</c> must be an expression, which evaluates to a bitstring.</item> <item>A <em>filter</em> is an expression, which evaluates to - <c>true</c> or <c>false</c>.</item> + <c>true</c> or <c>false</c>, or a + <seeguide marker="#guard_expressions">guard expression</seeguide>. + If the filter is not a guard expression and evaluates + to a non-Boolean value <c>Val</c>, an exception + <c>{bad_filter, Val}</c> is triggered at runtime.</item> </list> <p>The variables in the generator patterns shadow previously bound variables, including variables bound in a previous generator pattern.</p> @@ -1612,7 +1749,7 @@ end</pre> the following syntax:</p> <pre> << BitStringExpr || Qualifier1,...,QualifierN >></pre> - <p><c>BitStringExpr</c> is an expression that evalutes to a bit + <p><c>BitStringExpr</c> is an expression that evaluates to a bit string. If <c>BitStringExpr</c> is a function call, it must be enclosed in parentheses. Each <c>Qualifier</c> is either a generator, a bit string generator or a filter.</p> @@ -1626,8 +1763,12 @@ end</pre> <c><![CDATA[BitstringPattern <= BitStringExpr]]></c>. <br></br> <c>BitStringExpr</c> must be an expression that evaluates to a bitstring.</item> - <item>A <em>filter</em> is an expression that evaluates to - <c>true</c> or <c>false</c>.</item> + <item>A <em>filter</em> is an expression, which evaluates to + <c>true</c> or <c>false</c>, or a + <seeguide marker="#guard_expressions">guard expression</seeguide>. + If the filter is not a guard expression and evaluates + to a non-Boolean value <c>Val</c>, an exception + <c>{bad_filter, Val}</c> is triggered at runtime.</item> </list> <p>The variables in the generator patterns shadow previously bound variables, including variables bound in a previous generator pattern.</p> @@ -1675,7 +1816,7 @@ end</pre> <item>Expressions that construct atoms, integer, floats, lists, tuples, records, binaries, and maps</item> <item>Expressions that update a map</item> - <item>The record epxressions <c>Expr#Name.Field</c> and <c>#Name.Field</c></item> + <item>The record expressions <c>Expr#Name.Field</c> and <c>#Name.Field</c></item> <item>Calls to the BIFs specified in tables <em>Type Test BIFs</em> and <em>Other BIFs Allowed in Guard Expressions</em></item> <item>Term comparisons</item> @@ -1854,6 +1995,10 @@ end</pre> <cell align="left" valign="middle">Right associative</cell> </row> <row> + <cell align="left" valign="middle">?=</cell> + <cell align="left" valign="middle"> </cell> + </row> + <row> <cell align="left" valign="middle">catch</cell> <cell align="left" valign="middle"> </cell> </row> diff --git a/system/doc/reference_manual/features.xml b/system/doc/reference_manual/features.xml new file mode 100644 index 0000000000..882cdd2582 --- /dev/null +++ b/system/doc/reference_manual/features.xml @@ -0,0 +1,217 @@ +<?xml version="1.0" encoding="utf-8" ?> +<!DOCTYPE chapter SYSTEM "chapter.dtd"> + +<chapter> + <header> + <copyright> + <year>2022</year><year>2022</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>Features</title> + <prepared></prepared> + <docno></docno> + <date></date> + <rev></rev> + <file>features.xml</file> + </header> + <p> + <marker id="features"/> + Introduced in OTP 25, Erlang has the concept of selectable features. + A feature can change, add or remove behaviour of the language and/or + runtime system. Examples can include + </p> + <list> + <item>Adding new syntactical constructs to the language</item> + <item>Change the semantics of an existing construct</item> + <item>Change the behaviour of some runtime aspect</item> + </list> + <p> + A feature will start out with a status of experimental part of OTP, + making it possible to try out for users and give feedback. The + possibility to try out features is enabled by options to the + compiler, directives in a module and options to the runtime system. + Even when a feature is not experimental it will still be possible to + enable or disable it. This makes it possible to adapt a code base + at a suitable pace instead of being forced when changing to a new + release. + </p> + <p> + The status of a feature will eventually end up as being either a + permanent part of OTP or rejected, being removed and no longer + selectable. + </p> + + <section> + <title>Life cycle of features</title> + <p>A feature is in one of four possible states:</p> + <taglist> + <tag>Experimental</tag> + <item>The initial state, is meant for trying out and collecting + feedback. The feature can be enabled but is disabled by + default.</item> + <tag>Approved</tag> + <item>The feature has been finalised and is now part of OTP. By + default it is enabled, but can be disabled.</item> + <tag>Permanent</tag> + <item>The feature is now a permanent part of OTP. It can no + longer be disabled.</item> + <tag>Rejected</tag> + <item>The feature never reached the approved state and will not + be part of OTP. It cannot be enabled.</item> + </taglist> + <p> + After leaving the experimental state, a feature can enter any of + the other three states, and if the next state is approved, the + feature will eventually end up in the permanent state. A feature + can change state only in connection with a release. + </p> + <p> + A feature may be in the approved state for several releases. + </p> + <table> + <row> + <cell>State</cell> + <cell>Default</cell> + <cell>Configurable</cell> + <cell>Available</cell> + </row> + <row> + <cell>Experimental</cell> + <cell>disabled</cell> + <cell>yes</cell> + <cell>yes</cell> + </row> + <row> + <cell>Approved</cell> + <cell>enabled</cell> + <cell>yes</cell> + <cell>yes</cell> + </row> + <row> + <cell>Permanent</cell> + <cell>enabled</cell> + <cell>no</cell> + <cell>yes</cell> + </row> + <row> + <cell>Rejected</cell> + <cell>disabled</cell> + <cell>no</cell> + <cell>no</cell> + </row> + <tcaption>Feature States</tcaption> + </table> + <list> + <item>Being configurable means the possibility to enable or + disable the feature by means of compiler options and directives + in the file being compiled.</item> + <item>Being available can be seen using the + <c>FEATURE_AVAILABLE</c> macro.</item> + </list> + </section> + + <section> + <title>Enabling and Disabling Features</title> + <p>To use a feature that is in the experimental state, it has to + be enabled during compilation. This can be done in a number of + different ways: + </p> + <taglist> + <tag>Options to <c>erlc</c></tag> + <item>Options <seecom + marker="erts:erlc#enable-feature"><c>-enable-feature</c></seecom> + and <seecom + marker="erts:erlc#disable-feature"><c>-disable-feature</c></seecom> + can be used to enable or disable individal features.</item> + <tag>Compiler options</tag> + <item>The compiler option <seeerl + marker="compiler:compile#feature-option"><c>{feature, + <feature>, enable|disable}</c></seeerl> can be used either + as a <c>+<term></c> option to <c>erlc</c> or in the options + argument to functions in the <c>compile</c> module.</item> + <tag>The feature directive</tag> + <item>Inside a prefix of a module, one can use a <seeguide + marker="macros#feature-directive"><c>-feature(<feature>, + enable|disable)</c></seeguide> directive. This is the preferred + method of enabling and disabling features.</item> + </taglist> + <p> + Note that to load a module compiled with features enabled, the + corresponding features must be enabled in the runtime. This + is done using options <seecom + marker="erts:erl#enable-feature"><c>-enable-feature</c></seecom> + and <seecom + marker="erts:erl#disable-feature"><c>-disable-feature</c></seecom> + to <c>erl</c>. This is to allow the possibility to prevent + the use of experimental features in, e.g., production. This + will catch experimental features used in both own and third + party components. An active choice to use experimental + features must be done. + </p> + </section> + + <section> + <title>Preprocessor Additions</title> + <p> + To allow for conditional compilation during transitioning of a + code base and/or trying out experimental features <seeguide + marker="system/reference_manual:macros#predefined-macros">feature</seeguide> + <c>predefined macros</c> <c>?FEATURE_AVAILABLE(Feature)</c> and + <c>?FEATURE_ENABLED(Feature)</c> are available. + </p> + </section> + + <section> + <title>Information about Existing Features</title> + <p> + The module <c>erl_features</c> <seeerl + marker="stdlib:erl_features"><c>erl_features</c></seeerl> exports + a number of functions that can be used to obtain information about + current features as well as the features used when compiling a + module. + </p> + <p>One can also use the <c>erlc</c> options <seecom + marker="erts:erlc#list-features"><c>-list-features</c></seecom> + and <seecom + marker="erts:erlc#describe-feature"><c>-describe-feature + <feature></c></seecom> to get information about existing + features. + </p> + <p> + Additionally, there is the compiler option + <seeerl + marker="compiler:compile#warn-keywords"><c>warn_keywords</c></seeerl> + that can be used to find atoms in the code base that might + collide with keywords in features not yet enabled. + </p> + </section> + + <section> + <title>Existing Features</title> + <p> + The following configurable features exist: + </p> + <taglist> + <tag><c>maybe_expr</c> (experimental)</tag> + <item> + Implementation of the <seeguide + marker="expressions#maybe"><c>maybe</c></seeguide> expression + proposed in <url href="https://www.erlang.org/eeps/eep-0049">EEP 49</url>.</item> + </taglist> + </section> +</chapter> diff --git a/system/doc/reference_manual/macros.xml b/system/doc/reference_manual/macros.xml index 0943dbd56d..e54e0e1d30 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>2021</year> + <year>2003</year><year>2022</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> @@ -134,7 +134,8 @@ bar(X) -> <section> <title>Predefined Macros</title> - <p>The following macros are predefined:</p> + <p> + The following macros are predefined:</p> <taglist> <tag><c>?MODULE</c></tag> <item>The name of the current module.</item> @@ -155,6 +156,17 @@ bar(X) -> application is part of, as an integer. For details, see <seemfa marker="erts:erlang#system_info/1"><c>erlang:system_info(otp_release)</c></seemfa>. This macro was introduced in OTP release 21.</item> + <tag><c>?FEATURE_AVAILABLE(Feature)</c></tag> + <item>Expands to <c>true</c> if the <seeguide + marker="system/reference_manual:features#features">feature</seeguide> + <c>Feature</c> is available. The feature might or might not + be enabled. This macro was introduced with OTP release + 25.</item> + <tag><c>?FEATURE_ENABLED(Feature)</c></tag> + <item>Expands to <c>true</c> if the <seeguide + marker="system/reference_manual:features#features">feature</seeguide> + <c>Feature</c> is enabled. This macro was introduced with OTP + release 25.</item> </taglist> </section> @@ -265,6 +277,27 @@ or </section> <section> + <title> + The -feature() directive + </title> + <marker id="feature-directive"/> + + <p> + The directive <c>-feature(FeatureName, enable | disable)</c> can + be used to enable or disable the <seeguide + marker="system/reference_manual:features#features">feature</seeguide> + <c>FeatureName</c>. This is the preferred way of enabling + (disabling) features, although it is possible to do it with + options to the compiler as well. + </p> + <p> + Note that the <c>-feature(..)</c> directive may only appear + before any syntax is used. In practice this means it should + appear before any <c>-export(..)</c> or record definitions. + </p> + </section> + + <section> <title>-error() and -warning() directives</title> <p>The directive <c>-error(Term)</c> causes a compilation error.</p> diff --git a/system/doc/reference_manual/modules.xml b/system/doc/reference_manual/modules.xml index f5ea7d1580..b373e2506b 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>2021</year> + <year>2003</year><year>2022</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> @@ -129,6 +129,36 @@ fact(0) -> % | <seeguide marker="code_loading#on_load"> Running a Function When a Module is Loaded</seeguide>.</p> </item> + <tag><marker id="nifs_attribute"/><c>-nifs(Functions).</c></tag> + <item> + <p> + Specifies which of the functions, defined within the module, that + may be loaded as NIFs with <seemfa marker="erts:erlang#load_nif/2"> + <c>erlang:load_nif/2</c></seemfa>. + </p> + <p> + <c>Functions</c> is a list + <c>[Name1/Arity1, ..., NameN/ArityN]</c>, where each + <c>NameI</c> is an atom and <c>ArityI</c> an integer. + </p> + <note> + <p> + The <c>-nifs()</c> attribute was introduced in OTP 25.0. For older + Erlang source code without it, any functions in the module may be + loaded as NIFs. However, it is recommended to declare the NIFs with + the <c>-nifs</c> attribute. This allows the compiler to make better + decisions regarding optimizations for example. + </p> + <p> + There is no need to add <c>-nifs([])</c> in modules that do not + load NIFs. The lack of any call to + <seemfa marker="erts:erlang#load_nif/2"><c>erlang:load_nif/2</c></seemfa>, + from within the module, is enough for the compiler to draw the + same conclusion. + </p> + </note> + </item> + </taglist> </section> @@ -221,6 +251,30 @@ behaviour_info(callbacks) -> Callbacks.</pre> </section> <section> + <title> + The feature directive + </title> + + <p> + While not a module attribute, but rather a directive (since it + might affect syntax), there is the <c>-feature(..)</c> + directive used for enabling and disabling <seeguide + marker="system/reference_manual:features#features">features</seeguide>. + </p> + <p> + The syntax is similar to that of an attribute, but has two + arguments: + </p> + <pre> +-feature(FeatureName, enable | disable).</pre> + <p> + Note that the <seeguide + marker="macros#feature-directive">feature directive</seeguide> + can only appear in a prefix of the module. + </p> + </section> + + <section> <title>Comments</title> <p>Comments can be placed anywhere in a module except within strings and quoted atoms. A comment begins with the character "%", diff --git a/system/doc/reference_manual/opaques.xml b/system/doc/reference_manual/opaques.xml new file mode 100644 index 0000000000..8fa3bae3e5 --- /dev/null +++ b/system/doc/reference_manual/opaques.xml @@ -0,0 +1,141 @@ +<?xml version="1.0" encoding="utf-8"?> +<!DOCTYPE chapter SYSTEM "chapter.dtd"> + +<chapter> + <header> + <copyright> + <year>2021</year> + <year>2022</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>Opaques</title> + <prepared>Max Heiber</prepared> + <docno></docno> + <date></date> + <rev></rev> + <file>opaques.xml</file> + </header> + + <section> + <title>Opaque Type Aliases</title> + <p>The main use case for opacity in Erlang is to hide the implementation of a data type, enabling evolving the API while minimizing the risk of breaking consumers. The runtime does not check opacity. Dialyzer provides some opacity-checking, but the rest is up to convention. + </p> + <p> + This document explains what Erlang opacity is (and the trade-offs involved) via the example of OTP's + <c>sets:set()</c> + data type. This type + <em>was</em> + defined in `sets` module like this: + </p> + <code type="erl">-opaque set(Element) :: #set{segs :: segs(Element)}.</code> + <p>OTP 24 changed the definition to the following, in + <url href="https://github.com/erlang/otp/commit/e66941e8d7c47b973dff94c0308ea85a6be1958e">this commit</url> + </p> + <code type="erl">-opaque set(Element) :: #set{segs :: segs(Element)} | #{Element => ?VALUE}.</code> + <p> + And this change was safer and more backwards-compatible than if the type had been defined with + <c>-type</c> + instead of + <c>-opaque</c> + . Here's why: when a module defines an + <c>-opaque</c> + , the contract is that only the defining module should rely on the definition of the type: no other modules should rely on the definition. + </p> + <p> + This means that code that pattern-matched on + <c>set</c> + as a record/tuple technically broke the contract, and opted in to being potentially broken when the definition of + <c>set()</c> + changed. Before OTP 24, this code printed + <c>ok</c> + . In OTP 24 it may error: + </p> + <code type="erl"> +case sets:new() of + Set when is_tuple(Set) -> + io:format("ok") +end. + </code> + <p> + <strong>When working with an opaque defined in another module, here are some recommendations:</strong> + </p> + + <list type="bulleted"> + <item> + Don't examine the underlying type using pattern-matching, guards, or functions that reveal the type, such as + <c>tuple_size/1</c> + . + </item> + <item> + Instead, use functions provided by the module for working with the type. For example, + <c>sets</c> + module provides + <c>sets:new/0</c> + , + <c>sets:add/2</c> + , + <c>sets:is_element/2</c> + , etc. + </item> + <item> + <c>sets:set(a)</c> + is a subtype of + <c>sets:set(a | b)</c> + and not the other way around. Generally, you can rely on the property that + <c>the_opaque(T)</c> + is a subtype of + <c>the_opaque(U)</c> + when T is a subtype of U. + </item> + </list> + <p> + <strong>When defining your own opaques, here are some recommendations:</strong> + </p> + <list type="bulleted"> + <item> + Since consumers are expected to not rely on the definition of the opaque type, you must provide functions for constructing and querying/deconstructing intances of your opaque type. For example, sets can be constructed with + <c>sets:new/0</c>, <c>sets:from_list/1</c>, <c>sets:add/2</c>, queried with <c>sets:is_element/2</c>, and deconstructed with<c>sets:to_list/1</c>. + </item> + <item> + Don't define an opaque with a type variable in parameter position. This breaks the normal and expected behavior that (for example) + <c>my_type(a)</c> is a subtype of <c>my_type(a | b)</c> + </item> + <item> + Add <seeguide marker="typespec">specs</seeguide> to exported functions that use the opaque type + </item> + </list> + <p>Note that opaques can be harder to work with for consumers, since the consumer is expected not to pattern-match and must instead use functions that the author of the opaque type provides to use instances of the type.</p> + <p> + Also, opacity in Erlang is skin-deep: the runtime does not enforce opacity-checking. So now that sets are implemented in terms of maps, an + <c>is_map</c> + check on a set + <em>will</em> + pass. The opacity rules are only enforced by convention and by additional tooling such as Dialyzer. And this enforcement is not total: For example, determined consumer of + <c>sets</c> + can still do things that reveal the structure of the set, such as by printing, serializing, or using a set as + <c>term()</c> + and then inspecting via functions like + <c>is_map</c> + or + <c>maps:get/2</c> + . And Dialyzer must make some + <url href="https://github.com/erlang/otp/issues/5118">approximations</url> + . Opacity checking has limitations, but is still a vital tool in scalable Erlang development. + </p> + </section> +</chapter> diff --git a/system/doc/reference_manual/part.xml b/system/doc/reference_manual/part.xml index 3d31157973..ec2e3e0306 100644 --- a/system/doc/reference_manual/part.xml +++ b/system/doc/reference_manual/part.xml @@ -4,7 +4,7 @@ <part xmlns:xi="http://www.w3.org/2001/XInclude"> <header> <copyright> - <year>2003</year><year>2016</year> + <year>2003</year><year>2022</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> @@ -35,10 +35,12 @@ <xi:include href="modules.xml"/> <xi:include href="functions.xml"/> <xi:include href="typespec.xml"/> + <xi:include href="opaques.xml"/> <xi:include href="expressions.xml"/> <xi:include href="macros.xml"/> <xi:include href="records.xml"/> <xi:include href="errors.xml"/> + <xi:include href="features.xml"/> <xi:include href="processes.xml"/> <xi:include href="distributed.xml"/> <xi:include href="code_loading.xml"/> diff --git a/system/doc/reference_manual/processes.xml b/system/doc/reference_manual/processes.xml index 4c8c5f7e3f..92be5b60d3 100644 --- a/system/doc/reference_manual/processes.xml +++ b/system/doc/reference_manual/processes.xml @@ -4,7 +4,7 @@ <chapter> <header> <copyright> - <year>2003</year><year>2021</year> + <year>2003</year><year>2023</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> @@ -700,7 +700,12 @@ spawn(Module, Name, Args) -> pid() <seecom marker="erts:erl#+zdbbl"><c>+zdbbl</c></seecom>. Note that if you do raise the limit like this, you need to take care of flow control yourself to ensure that you do not get into a - situation with excessive memory usage. + situation with excessive memory usage. As of OTP 25.3 it is + also possible to enable <i>fully asynchronous distributed + signaling</i> on a per process level using + <seeerl marker="erts:erlang#process_flag_async_dist"> + <c>process_flag(async_dist, Bool)</c></seeerl>. Also in this case + you need to take care of flow control yourself. </p> </item> </taglist> @@ -798,7 +803,7 @@ spawn(Module, Name, Args) -> pid() <list> <item><p> <c>noproc</c> in case no process or port was - found when setting up a link in a preceeding + found when setting up a link in a preceding call to the <seemfa marker="erts:erlang#link/1"><c>link(PidOrPort)</c></seemfa> BIF. The process or port identified as sender diff --git a/system/doc/reference_manual/typespec.xml b/system/doc/reference_manual/typespec.xml index 0e3d909099..75482e5be1 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>2021</year> + <year>2003</year><year>2022</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> @@ -160,7 +160,7 @@ ]]></pre> <p> Integer values are either integer or character literals or expressions - consisting of possibily nested unary or binary operations that evaluate to + consisting of possibly nested unary or binary operations that evaluate to an integer. Such expressions can also be used in bit strings and ranges. </p> <p> @@ -411,6 +411,7 @@ types are not accessible by other modules anyway - and is always to be exported. </p> + <p>Read more on <seeguide marker="opaques">Opaques</seeguide></p> </section> <section> @@ -537,8 +538,7 @@ ; (T4, T5) -> T6.</pre> <p> A current restriction, which currently results in a warning - (not an error) by the compiler, is that the domains of - the argument types cannot overlap. + by Dialyzer, is that the domains of the argument types cannot overlap. For example, the following specification results in a warning: </p> <pre> @@ -607,5 +607,13 @@ of the following form: </p> <pre> -spec my_error(term()) -> no_return().</pre> + + <note> + <p>Erlang uses the shorthand version <c>_</c> as an anonymous type variable + equivalent to <c>term()</c> or <c>any()</c>. For example, the following function</p> + <pre> -spec Function(string(), _) -> string().</pre> + <p>is equivalent to:</p> + <pre> -spec Function(string(), any()) -> string().</pre> + </note> </section> </chapter> diff --git a/system/doc/reference_manual/xmlfiles.mk b/system/doc/reference_manual/xmlfiles.mk index 92d232b628..8e2af09699 100644 --- a/system/doc/reference_manual/xmlfiles.mk +++ b/system/doc/reference_manual/xmlfiles.mk @@ -1,7 +1,7 @@ # # %CopyrightBegin% # -# Copyright Ericsson AB 2009-2018. All Rights Reserved. +# Copyright Ericsson AB 2009-2022. 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,9 +27,11 @@ REF_MAN_CHAPTER_FILES = \ macros.xml \ records.xml \ errors.xml \ + features.xml \ processes.xml \ distributed.xml \ code_loading.xml \ ports.xml \ character_set.xml \ - typespec.xml + typespec.xml \ + opaques.xml diff --git a/system/doc/system_principles/system_principles.xml b/system/doc/system_principles/system_principles.xml index d0c6f59807..c731e7fb66 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>2020</year> + <year>1996</year><year>2023</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> @@ -107,7 +107,7 @@ init:stop()</pre> the applications Kernel and STDLIB.</item> <item><c>start_sasl.boot</c> - Loads the code for and starts the applications Kernel, STDLIB, and - SASL).</item> + SASL.</item> <item><c>no_dot_erlang.boot</c> - Loads the code for and starts the applications Kernel and STDLIB. Skips loading the file <c>.erlang</c>. Useful for scripts and diff --git a/system/doc/top/src/erl_html_tools.erl b/system/doc/top/src/erl_html_tools.erl index 5942861f0f..d609f35380 100644 --- a/system/doc/top/src/erl_html_tools.erl +++ b/system/doc/top/src/erl_html_tools.erl @@ -261,7 +261,7 @@ find_application_infos([{App, Vsn, AppPath, IndexURL} | Paths]) -> case lists:keysearch("group", 1, Db) of {value, {_, G0}} -> % This value may be in two parts, - % tag and desciption + % tag and description case string:str(G0, " ") of 0 -> {list_to_atom(G0), ""}; diff --git a/system/doc/tutorial/c_port.xmlsrc b/system/doc/tutorial/c_port.xmlsrc index d89c87eeac..6646f2298e 100644 --- a/system/doc/tutorial/c_port.xmlsrc +++ b/system/doc/tutorial/c_port.xmlsrc @@ -158,7 +158,7 @@ Eshell V4.9.1.2 (abort with ^G) {ok,complex1}</pre> <p><em>Step 3.</em> Run the example:</p> <pre> -2> <input>complex1:start("extprg").</input> +2> <input>complex1:start("./extprg").</input> <0.34.0> 3> <input>complex1:foo(3).</input> 4 diff --git a/system/doc/tutorial/complex6.erl b/system/doc/tutorial/complex6.erl index a5f51886c8..05aa8e68f1 100644 --- a/system/doc/tutorial/complex6.erl +++ b/system/doc/tutorial/complex6.erl @@ -1,5 +1,6 @@ -module(complex6). -export([foo/1, bar/1]). +-nifs([foo/1, bar/1]). -on_load(init/0). init() -> diff --git a/system/doc/tutorial/debugging.xml b/system/doc/tutorial/debugging.xml new file mode 100644 index 0000000000..4439bc6d19 --- /dev/null +++ b/system/doc/tutorial/debugging.xml @@ -0,0 +1,348 @@ +<?xml version="1.0" encoding="utf-8"?> +<!DOCTYPE chapter SYSTEM "chapter.dtd"> +<chapter> + <header> + <copyright> + <year>2022</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>Debugging NIFs and Port Drivers</title> + <prepared/> + <docno/> + <date/> + <rev/> + <file>debugging.xml</file> + </header> + + <section> + <title>With great power comes great responsibilty</title> + <p> + NIFs and port driver code run inside the Erlang VM OS process (the + "Beam"). To maximize performance the code is called directly by the same + threads executing Erlang beam code and has full access to all the memory + of the OS process. A buggy NIF/driver can thus make severe damage by + corrupting memory. + </p> + <p> + In a best case scenario such memory corruption is detected immediately + causing the Beam to crash generating a core dump file which can be + analyzed to find the bug. However, it is very common for memory corruption + bugs to not be immediately detected when the faulty write happens, but + instead much later, for example when the calling Erlang process is garbage + collected. When that happens it can be very hard to find the root cause of + the memory corruption by analysing the core dump. All traces that could + have indicated which specific buggy NIF/driver that caused the corruption + may be long gone. + </p> + </section> + <section> + <title>The debug emulator</title> + <p> + One way to make debugging easier is to run an emulator built with target + <c>debug</c>. It will + </p> + <list type="bulleted"> + <item> + <p> + <em>Increase probability of detecting bugs earlier</em>. It contains a + lot more runtime checks to ensure correct use of internal interfaces + and data structures. + </p> + </item> + <item> + <p> + <em>Generate a core dump that is easier to analyze</em>. Compiler + optimizations are turned off, which stops the compiler from + "optimizing away" variables, thus making it easier/possible to inspect + their state. + </p> + </item> + <item> + <p> + <em>Detect lock order violations</em>. A runtime lock checker will + verify that the locks in the + <seecref marker="erts:erl_nif"><c>erl_nif</c></seecref> and + <seecref marker="erts:erl_driver"><c>erl_driver</c></seecref> + APIs are seized in a consistent order that cannot result in deadlock + bugs. + </p> + </item> + </list> + <p> + In fact, we recommend to use the debug emulator as default during + development of NIFs and drivers, regardless if you are troubleshooting + bugs or not. Some subtle bugs may not be detected by the normal emulator + and just happen to work anyway by chance. However, another version of the + emulator, or even different circumstances within the same emulator, may + cause the bug to later provoke all kinds of problems. + </p> + <p> + The main disadvantage of the <c>debug</c> emulator is its reduced + performance. The extra runtime checks and lack of compiler optimizations + may result in a slowdown with a factor of two or more depending on + load. The memory footprint should be about the same. + </p> + <p> + If the <c>debug</c> emulator is part of the Erlang/OTP installation, it can be + started with the <seecom marker="erts:erl#emu_type"><c>-emu_type</c></seecom> + option. + </p> + <pre> +> <input>erl -emu_type debug</input> +Erlang/OTP 25 [erts-13.0.2] ... <em>[type-assertions] [debug-compiled] [lock-checking]</em> + +Eshell V13.0.2 (abort with ^G) +1> +</pre> + <p> + If the <c>debug</c> emulator is not part of the installation, you need to + <seeguide marker="system/installation_guide:INSTALL#Advanced-configuration-and-build-of-ErlangOTP_Building_How-to-Build-a-Debug-Enabled-Erlang-RunTime-System"> + build it from the Erlang/OTP source code</seeguide>. After building from source + either make an Erlang/OTP installation or you can run the debug emulator + directly in the source tree with the <c>cerl</c> script: + </p> + <pre> +> <input>$ERL_TOP/bin/cerl -debug</input> +Erlang/OTP 25 [erts-13.0.2] ... <em>[type-assertions] [debug-compiled] [lock-checking]</em> + +Eshell V13.0.2 (abort with ^G) +1> +</pre> + <p> + The <c>cerl</c> script can also be used as a convenient way to start + the debugger <c>gdb</c> for core dump analysis: + </p> + <pre> +> <input>$ERL_TOP/bin/cerl -debug -core core.12345</input> +or +> <input>$ERL_TOP/bin/cerl -debug -rcore core.12345</input> +</pre> + <p> + The first variant starts Emacs and runs <c>gdb</c> within, while + the other <c>-rcore</c> runs <c>gdb</c> directly in the terminal. Apart + from starting <c>gdb</c> with the correct <c>beam.debug.smp</c> executable + file it will also read the file <c>$ERL_TOP/erts/etc/unix/etp-commands</c> + which contains a lot of <c>gdb</c> command for inspecting a beam core + dump. For example, the command <c>etp</c> that will print the content of + an Erlang term (<c>Eterm</c>) in plain Erlang syntax. + </p> + </section> + <section> + <title>Address Sanitizer</title> + <p> + <url href="https://clang.llvm.org/docs/AddressSanitizer.html"> + AddressSanitizer</url> (asan) is an open source programming tool that + detects memory corruption bugs such as buffer overflows, use-after-free + and memory leaks. AddressSanitizer is based on compiler instrumentation + and is supported by both gcc and clang. + </p> + <p> + Similar to the <c>debug</c> emulator, the <c>asan</c> emulator runs slower + than normal, about 2-3 times slower. However, it also has a larger memory + footprint, about 3 times more memory than normal. + </p> + <p> + To get full effect you should compile both your own NIF/driver code as + well as the Erlang emulator with AddressSanitizer instrumentation. Compile + your own code by passing option <c>-fsanitize=address</c> to gcc or + clang. Other recommended options that will improve the fault + identification are <c>-fno-common</c> and <c>-fno-omit-frame-pointer</c>. + </p> + <p> + Build and run the emulator with AddressSanitizer support by using the same + procedure as for the debug emulator, except use the <c>asan</c> build + target instead of <c>debug</c>. + </p> + <taglist> + <tag>Run in source tree</tag> + <item> + <p> + If you run the <c>asan</c> emulator directly in the source tree with the + <c>cerl</c> script you only need to set environment variable + <c>ASAN_LOG_DIR</c> to the directory where the error log files will be + generated. + </p> + <pre> +> <input>export ASAN_LOG_DIR=/my/asan/log/dir</input> +> <input>$ERL_TOP/bin/cerl -asan</input> +Erlang/OTP 25 [erts-13.0.2] ... <em>[address-sanitizer]</em> + +Eshell V13.0.2 (abort with ^G) +1> +</pre> + <p> + You may however also want to set <c>ASAN_OPTIONS="halt_on_error=true"</c> + if you want the emulator to crash when an error is detected. + </p> + </item> + <tag>Run installed Erlang/OTP</tag> + <item> + <p> + If you run the <c>asan</c> emulator in an installed Erlang/OTP with <c>erl + -emu_type asan</c> you need to set the path to the error log + <em>file</em> with + </p> + <pre> +> <input>export ASAN_OPTIONS="log_path=/my/asan/log/file"</input></pre> + <p> + To avoid false positive memory leak reports from the emulator + itself set <c>LSAN_OPTIONS</c> (LSAN=LeakSanitizer): + </p> + <pre> +> <input>export LSAN_OPTIONS="suppressions=$ERL_TOP/erts/emulator/asan/suppress"</input></pre> + <p> + The <c>suppress</c> file is currently not installed but can be copied + manually from the source tree to wherever you want it. + </p> + </item> + </taglist> + <p> + Memory corruption errors are reported by AddressSanitizer when they + happen, but memory leaks are only checked and reported by default then the + emulator terminates. + </p> + </section> + <section> + <title>Valgrind</title> + <p> + An even more heavy weight debugging tool is <url + href="https://valgrind.org">Valgrind</url>. It can also find memory + corruption bugs and memory leaks similar to <c>asan</c>. Valgrind is not + as good at buffer overflow bugs, but it will find use of undefined data, + which is a type of error that <c>asan</c> cannot detect. + </p> + <p> + Valgrind is much slower than <c>asan</c> and it is incapable at + exploiting CPU multicore processing. We therefore recommend <c>asan</c> as + the first choice before trying valgrind. + </p> + <p> + Valgrind runs as a virtual machine itself, emulating execution of hardware + machine instructions. This means you can run almost any program unchanged + on valgrind. However, we have found that the beam executable benefits from + being compiled with special adaptions for running on valgrind. + </p> + <p> + Build the emulator with <c>valgrind</c> target the same as is done for + <c>debug</c> and <c>asan</c>. Note that <c>valgrind</c> needs to be + installed on the machine before the build starts. + </p> + <p> + Run the <c>valgrind</c> emulator directly in the source tree with the + <c>cerl</c> script. Set environment variable <c>VALGRIND_LOG_DIR</c> to + the directory where the error log files will be generated. + </p> + <pre> +> <input>export VALGRIND_LOG_DIR=/my/valgrind/log/dir</input> +> <input>$ERL_TOP/bin/cerl -valgrind</input> +Erlang/OTP 25 [erts-13.0.2] ... <em>[valgrind-compiled]</em> + +Eshell V13.0.2 (abort with ^G) +1> +</pre> + </section> + <section> + <title>rr - Record and Replay</title> + <p> + Last but not least, the fantastic interactive debugging tool <url + href="https://rr-project.org/">rr</url>, developed by Mozilla as + open source. <c>rr</c> stands for Record and Replay. While a core dump + represents only a static snapshot of the OS process when it crashed, with + <c>rr</c> you instead record the entire session, from start of the OS + process to the end (the crash). You can then replay that session from + within <c>gdb</c>. Single step, set breakpoints and watchpoints, and even + <em>execute backwards</em>. + </p> + <p> + Considering its powerful utility, <c>rr</c> is remarkably light weight. + It runs on Linux with any reasonably modern x86 CPU. You may get a two + times slowdown when executing in recording mode. The big weakness is its + inability to exploite CPU multicore processing. If the bug is a race + condition between concurrently running threads, it may be hard to + reproduce with <c>rr</c>. + </p> + <p> + <c>rr</c> does not require any special instrumented compilation. However, + if possible, run it together with the <c>debug</c> emulator, as that will + result in a much nicer debugging experience. You run <c>rr</c> in the + source tree using the <c>cerl</c> script. + </p> + <p> + Here is an example of a typical session. First we catch the crash in an rr + recording session: + </p> + <pre> +> <input>$ERL_TOP/bin/cerl -debug -rr</input> +rr: Saving execution to trace directory /home/foobar/.local/share/rr/beam.debug.smp-1. +Erlang/OTP 25 [erts-13.0.2] + +Eshell V13.0.2 (abort with ^G) +1> <input>mymod:buggy_nif().</input> +Segmentation fault</pre> + <p> + Now we can replay that session with <c>rr replay</c>: + </p> + <pre> +> <input>rr replay</input> +GNU gdb (Ubuntu 9.2-0ubuntu1~20.04.1) 9.2 +: +(rr) <input>continue</input> +: +Thread 2 received signal SIGSEGV, Segmentation fault. +(rr) <input>backtrace</input></pre> + <p> + You get the call stack at the moment of the crash. Bad luck, it is + somewhere deep down in the garbage collection of the beam. But you manage + to figure out that variable <c>hp</c> points to a broken Erlang term. + </p> + <p> + Set a watch point on that memory position and resume execution + <em>backwards</em>. The debugger will then stop at the exact position when + that memory position <c>*hp</c> was written. + </p> + <pre> +(rr) <input>watch -l *hp</input> +Hardware watchpoint 1: -location *hp +(rr) <input>reverse-continue</input> +Continuing. + +Thread 2 received signal SIGSEGV, Segmentation fault.</pre> + <p> + This is a quirk to be aware about. We started by executing forward until + it crashed with SIGSEGV. We are now executing backwards from that point, + so we are hitting the same SIGSEGV again but from the other + direction. Just continue backwards once more to move past it. + </p> + <pre> +(rr) <input>reverse-continue</input> +Continuing. + +Thread 2 hit Hardware watchpoint 1: -location *hp + +Old value = 42 +New value = 0</pre> + <p> + And here we are at the position when someone wrote a broken term on the + process heap. Note that "Old value" and "New value" are reversed when we + execute backwards. In this case the value 42 was written on the heap. + Let's see who the guilty one is: + </p> + <pre> +(rr) <input>backtrace</input></pre> + </section> +</chapter> diff --git a/system/doc/tutorial/nif.xmlsrc b/system/doc/tutorial/nif.xmlsrc index 5fd94a7946..5f932cd5ba 100644 --- a/system/doc/tutorial/nif.xmlsrc +++ b/system/doc/tutorial/nif.xmlsrc @@ -4,7 +4,7 @@ <chapter> <header> <copyright> - <year>2000</year><year>2021</year> + <year>2000</year><year>2022</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> @@ -32,8 +32,7 @@ <p>This section outlines an example of how to solve the example problem in <seeguide marker="example">Problem Example</seeguide> by using Native Implemented Functions (NIFs).</p> - <p>NIFs were introduced in Erlang/OTP R13B03 as an experimental - feature. It is a simpler and more efficient way of calling C-code + <p>NIFs are a simpler and more efficient way of calling C-code than using port drivers. NIFs are most suitable for synchronous functions, such as <c>foo</c> and <c>bar</c> in the example, that do some relatively short calculations without side effects and @@ -62,7 +61,7 @@ </list> <p>Normally these are minimal stub implementations that throw an exception. But they can also be used as fallback implementations - for functions that do not have native implemenations on some + for functions that do not have native implementations on some architectures.</p> <p>NIF libraries are loaded by calling <c>erlang:load_nif/2</c>, with the name of the shared library as argument. The second @@ -99,7 +98,7 @@ <codeinclude file="complex6_nif.c" tag="" type="none"></codeinclude> - <p>Here,<c>ERL_NIF_INIT</c> has the following arguments:</p> + <p>Here, <c>ERL_NIF_INIT</c> has the following arguments:</p> <list type="bulleted"> <item><p>The first argument must be the name of the Erlang module as a C-identifier. It will be stringified by the diff --git a/system/doc/tutorial/part.xml b/system/doc/tutorial/part.xml index 4a66f0cb22..f546890e79 100644 --- a/system/doc/tutorial/part.xml +++ b/system/doc/tutorial/part.xml @@ -4,7 +4,7 @@ <part xmlns:xi="http://www.w3.org/2001/XInclude"> <header> <copyright> - <year>2000</year><year>2016</year> + <year>2000</year><year>2022</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> @@ -36,5 +36,6 @@ <xi:include href="c_portdriver.xml"/> <xi:include href="cnode.xml"/> <xi:include href="nif.xml"/> + <xi:include href="debugging.xml"/> </part> diff --git a/system/doc/tutorial/xmlfiles.mk b/system/doc/tutorial/xmlfiles.mk index 74e174f6d4..a2c024d2dd 100644 --- a/system/doc/tutorial/xmlfiles.mk +++ b/system/doc/tutorial/xmlfiles.mk @@ -1,7 +1,8 @@ + # # %CopyrightBegin% # -# Copyright Ericsson AB 2009-2018. All Rights Reserved. +# Copyright Ericsson AB 2009-2022. 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,7 +20,8 @@ # TUTORIAL_CHAPTER_FILES = \ introduction.xml\ - overview.xml + overview.xml\ + debugging.xml TUTORIAL_CHAPTER_GEN_FILES = \ cnode.xml\ |