aboutsummaryrefslogtreecommitdiffstats
path: root/lib/kernel
diff options
context:
space:
mode:
Diffstat (limited to 'lib/kernel')
-rw-r--r--lib/kernel/doc/src/app.xml4
-rw-r--r--lib/kernel/doc/src/application.xml5
-rw-r--r--lib/kernel/doc/src/auth.xml8
-rw-r--r--lib/kernel/doc/src/code.xml71
-rw-r--r--lib/kernel/doc/src/disk_log.xml12
-rw-r--r--lib/kernel/doc/src/erl_ddll.xml22
-rw-r--r--lib/kernel/doc/src/error_logger.xml2
-rw-r--r--lib/kernel/doc/src/file.xml29
-rw-r--r--lib/kernel/doc/src/gen_sctp.xml14
-rw-r--r--lib/kernel/doc/src/gen_tcp.xml5
-rw-r--r--lib/kernel/doc/src/gen_udp.xml4
-rw-r--r--lib/kernel/doc/src/heart.xml63
-rw-r--r--lib/kernel/doc/src/inet.xml35
-rw-r--r--lib/kernel/doc/src/inet_res.xml31
-rw-r--r--lib/kernel/doc/src/kernel_app.xml37
-rw-r--r--lib/kernel/doc/src/net_adm.xml4
-rw-r--r--lib/kernel/doc/src/net_kernel.xml13
-rw-r--r--lib/kernel/doc/src/notes.xml207
-rw-r--r--lib/kernel/doc/src/os.xml4
-rw-r--r--lib/kernel/doc/src/seq_trace.xml29
-rw-r--r--lib/kernel/examples/uds_dist/c_src/uds_drv.c12
-rw-r--r--lib/kernel/src/code.erl9
-rw-r--r--lib/kernel/src/code_server.erl9
-rw-r--r--lib/kernel/src/disk_log_1.erl6
-rw-r--r--lib/kernel/src/erl_epmd.erl18
-rw-r--r--lib/kernel/src/file_io_server.erl122
-rw-r--r--lib/kernel/src/gen_tcp.erl3
-rw-r--r--lib/kernel/src/heart.erl185
-rw-r--r--lib/kernel/src/inet.erl22
-rw-r--r--lib/kernel/src/inet6_tcp.erl19
-rw-r--r--lib/kernel/src/inet6_tcp_dist.erl365
-rw-r--r--lib/kernel/src/inet_db.erl38
-rw-r--r--lib/kernel/src/inet_dns_record_adts.pl6
-rw-r--r--lib/kernel/src/inet_int.hrl1
-rw-r--r--lib/kernel/src/inet_tcp.erl16
-rw-r--r--lib/kernel/src/inet_tcp_dist.erl157
-rw-r--r--lib/kernel/src/kernel.app.src4
-rw-r--r--lib/kernel/src/kernel.appup.src6
-rw-r--r--lib/kernel/src/seq_trace.erl14
-rw-r--r--lib/kernel/src/user_drv.erl3
-rw-r--r--lib/kernel/test/bif_SUITE.erl10
-rw-r--r--lib/kernel/test/code_SUITE.erl28
-rw-r--r--lib/kernel/test/code_SUITE_data/on_load_errors/simple_on_load_error.erl5
-rw-r--r--lib/kernel/test/file_SUITE.erl64
-rw-r--r--lib/kernel/test/gen_tcp_api_SUITE.erl19
-rw-r--r--lib/kernel/test/heart_SUITE.erl67
-rw-r--r--lib/kernel/test/inet_sockopt_SUITE.erl82
-rw-r--r--lib/kernel/test/seq_trace_SUITE.erl166
-rw-r--r--lib/kernel/test/standard_error_SUITE.erl31
-rw-r--r--lib/kernel/vsn.mk2
50 files changed, 1367 insertions, 721 deletions
diff --git a/lib/kernel/doc/src/app.xml b/lib/kernel/doc/src/app.xml
index 1591d589af..35feec144e 100644
--- a/lib/kernel/doc/src/app.xml
+++ b/lib/kernel/doc/src/app.xml
@@ -191,7 +191,7 @@ RTDeps [ApplicationVersion] []
start phases must be a subset of the set of phases defined
for the primary application. Refer to <em>OTP Design Principles</em> for more information.</p>
</item>
- <tag><marker id="runtime_dependencies"><c>runtime_dependencies</c></marker></tag>
+ <tag><marker id="runtime_dependencies"></marker><c>runtime_dependencies</c></tag>
<item><p>A list of application versions that the application
depends on. An example of such an application version is
<c>"kernel-3.0"</c>. Application versions specified as runtime
@@ -201,7 +201,7 @@ RTDeps [ApplicationVersion] []
how to compare application versions see
<seealso marker="doc/system_principles:versions">the
documentation of versions in the system principles
- guide</seealso>. Note that that the application version
+ guide</seealso>. Note that the application version
specifies a source code version. An additional indirect
requirement is that installed binary application of
the specified version has been built so that it is
diff --git a/lib/kernel/doc/src/application.xml b/lib/kernel/doc/src/application.xml
index 0fe774a73f..4d8e6ce94b 100644
--- a/lib/kernel/doc/src/application.xml
+++ b/lib/kernel/doc/src/application.xml
@@ -60,8 +60,9 @@
</datatype>
<datatype>
<!-- Parameterized opaque types are NYI: -->
- <name><marker id="type-tuple_of">tuple_of(T)</marker></name>
- <desc><p>A tuple where the elements are of type <c>T</c>.</p></desc>
+ <name>tuple_of(T)</name>
+ <desc><p><marker id="type-tuple_of"/>
+ A tuple where the elements are of type <c>T</c>.</p></desc>
</datatype>
</datatypes>
<funcs>
diff --git a/lib/kernel/doc/src/auth.xml b/lib/kernel/doc/src/auth.xml
index 9ebc6f8f1a..71b1863e96 100644
--- a/lib/kernel/doc/src/auth.xml
+++ b/lib/kernel/doc/src/auth.xml
@@ -50,7 +50,7 @@
be established in this case. Returns <c>no</c> if <c><anno>Node</anno></c>
does not exist or communication is not authorized (it has
another cookie than <c>auth</c> thinks it has).</p>
- <p>Use <seealso marker="net_adm#ping/1">net_adm:ping(<anno>Node</anno>)</seealso>
+ <p>Use <seealso marker="net_adm#ping/1">net_adm:ping(<c><anno>Node</anno></c>)</seealso>
instead.</p>
</desc>
</func>
@@ -71,7 +71,7 @@
</type_desc>
<desc>
<p>Use
- <seealso marker="erts:erlang#erlang:set_cookie/2">erlang:set_cookie(node(), <anno>Cookie</anno>)</seealso>
+ <seealso marker="erts:erlang#erlang:set_cookie/2">erlang:set_cookie(node(), <c><anno>Cookie</anno></c>)</seealso>
instead.</p>
</desc>
</func>
@@ -94,8 +94,8 @@
<p>Sets the magic cookie of <c><anno>Node</anno></c> to <c><anno>Cookie</anno></c>, and
verifies the status of the authorization.
Equivalent to calling
- <seealso marker="erts:erlang#erlang:set_cookie/2">erlang:set_cookie(<anno>Node</anno>, <anno>Cookie</anno>)</seealso>, followed by
- <seealso marker="#is_auth/1">auth:is_auth(<anno>Node</anno>)</seealso>.</p>
+ <seealso marker="erts:erlang#erlang:set_cookie/2">erlang:set_cookie(<c><anno>Node</anno></c>, <c><anno>Cookie</anno>)</c></seealso>, followed by
+ <seealso marker="#is_auth/1">auth:is_auth(<c><anno>Node</anno></c>)</seealso>.</p>
</desc>
</func>
</funcs>
diff --git a/lib/kernel/doc/src/code.xml b/lib/kernel/doc/src/code.xml
index 7cdedfa0ba..1bd52040a0 100644
--- a/lib/kernel/doc/src/code.xml
+++ b/lib/kernel/doc/src/code.xml
@@ -180,7 +180,7 @@
example, the call
<c>erl_prim_loader:list_dir( "/otp/root/lib/mnesia-4.4.7.ez/mnesia-4.4.7/examples/bench)"</c>
would list the contents of a directory inside an archive.
- See <seealso marker="erts:erl_prim_loader">erl_prim_loader(3)</seealso></p>.
+ See <seealso marker="erts:erl_prim_loader">erl_prim_loader(3)</seealso>.</p>
<p>An application archive file and a regular application directory
may coexist. This may be useful when there is a need of having
@@ -230,7 +230,7 @@
<c>-code_path_choice Choice</c>. If the flag is set to <c>relaxed</c>,
the code server will instead choose a suitable directory
depending on the actual file structure. If there exists a regular
- application ebin directory,situation it will be chosen. But if it does
+ application ebin directory, it will be chosen. But if it does
not exist, the ebin directory in the archive is chosen if it
exists. If neither of them exists the original directory will be
chosen.</p>
@@ -242,7 +242,7 @@
particular useful to set the flag to <c>relaxed</c> when you want
to elaborate with code loading from archives without editing the
<c>boot script</c>. The default is <c>relaxed</c>. See <seealso
- marker="erts:init">init(3)</seealso></p> </section>
+ marker="erts:init">init(3)</seealso></p></section>
<section>
@@ -282,11 +282,51 @@
<p>From the R12B release, functions in this module will generally fail with an
exception if they are passed an incorrect type (for instance, an integer or a tuple
- where an atom was expected). An error tuple will be returned if type of argument
+ where an atom was expected). An error tuple will be returned if the type of the argument
was correct, but there was some other error (for instance, a non-existing directory
- given to <c>set_path/1</c>.</p>
+ was given to <c>set_path/1</c>).</p>
</section>
+ <section>
+ <marker id="error_reasons"></marker>
+ <title>Error Reasons for Code-Loading Functions</title>
+
+ <p>Functions that load code (such as <c>load_file/1</c>) will
+ return <c>{error,Reason}</c> if the load operation fails.
+ Here follows a description of the common reasons.</p>
+
+ <taglist>
+ <tag><c>badfile</c></tag>
+ <item>
+ <p>The object code has an incorrect format or the module
+ name in the object code is not the expected module name.</p>
+ </item>
+
+ <tag><c>nofile</c></tag>
+ <item>
+ <p>No file with object code was found.</p>
+ </item>
+
+ <tag><c>not_purged</c></tag>
+ <item>
+ <p>The object code could not be loaded because an old version
+ of the code already existed.</p>
+ </item>
+
+ <tag><c>on_load_failure</c></tag>
+ <item>
+ <p>The module has an
+ <seealso marker="doc/reference_manual:code_loading#on_load">-on_load function</seealso>
+ that failed when it was called.</p>
+ </item>
+
+ <tag><c>sticky_directory</c></tag>
+ <item>
+ <p>The object code resides in a sticky directory.</p>
+ </item>
+
+ </taglist>
+ </section>
<datatypes>
<datatype>
<name name="load_ret"/>
@@ -411,12 +451,8 @@
be used to load object code with a module name that is
different from the file name.</p>
<p>Returns <c>{module, <anno>Module</anno>}</c> if successful, or
- <c>{error, nofile}</c> if no object code is found, or
- <c>{error, sticky_directory}</c> if the object code resides in
- a sticky directory. Also if the loading fails, an error tuple is
- returned. See
- <seealso marker="erts:erlang#load_module/2">erlang:load_module/2</seealso>
- for possible values of <c><anno>What</anno></c>.</p>
+ <c>{error, Reason}</c> if loading fails.
+ See <seealso marker="#error_reasons">Error Reasons for Code-Loading Functions</seealso> for a description of the possible error reasons.</p>
</desc>
</func>
<func>
@@ -428,7 +464,7 @@
<desc>
<p>Does the same as <c>load_file(<anno>Module</anno>)</c>, but
<c><anno>Filename</anno></c> is either an absolute file name, or a
- relative file name. The code path is not searched. It returns
+ relative file name. The code path is not searched. It returns
a value in the same way as
<seealso marker="#load_file/1">load_file/1</seealso>. Note
that <c><anno>Filename</anno></c> should not contain the extension (for
@@ -444,7 +480,8 @@
<seealso marker="#load_file/1">load_file/1</seealso>,
unless the module is already loaded.
In embedded mode, however, it does not load a module which is not
- already loaded, but returns <c>{error, embedded}</c> instead.</p>
+ already loaded, but returns <c>{error, embedded}</c> instead.
+ See <seealso marker="#error_reasons">Error Reasons for Code-Loading Functions</seealso> for a description of other possible error reasons.</p>
</desc>
</func>
<func>
@@ -461,12 +498,8 @@
comes. Accordingly, <c><anno>Filename</anno></c> is not opened and read by
the code server.</p>
<p>Returns <c>{module, <anno>Module</anno>}</c> if successful, or
- <c>{error, sticky_directory}</c> if the object code resides in
- a sticky directory, or <c>{error, badarg}</c> if any argument
- is invalid. Also if the loading fails, an error tuple is
- returned. See
- <seealso marker="erts:erlang#load_module/2">erlang:load_module/2</seealso>
- for possible values of <c><anno>What</anno></c>.</p>
+ <c>{error, Reason}</c> if loading fails.
+ See <seealso marker="#error_reasons">Error Reasons for Code-Loading Functions</seealso> for a description of the possible error reasons.</p>
</desc>
</func>
<func>
diff --git a/lib/kernel/doc/src/disk_log.xml b/lib/kernel/doc/src/disk_log.xml
index 32488a9f01..7d4a9687ea 100644
--- a/lib/kernel/doc/src/disk_log.xml
+++ b/lib/kernel/doc/src/disk_log.xml
@@ -233,11 +233,11 @@
<func>
<name name="alog" arity="2"/>
<name name="balog" arity="2"/>
+ <fsummary>Asynchronously log an item onto a disk log.</fsummary>
<type variable="Log"/>
<type variable="Term" name_i="1"/>
<type variable="Bytes"/>
<type name="notify_ret"/>
- <fsummary>Asynchronously log an item onto a disk log.</fsummary>
<desc>
<p>The <c>alog/2</c> and <c>balog/2</c> functions asynchronously
append an item to a disk log. The function <c>alog/2</c> is
@@ -288,8 +288,8 @@
<func>
<name name="block" arity="1"/>
<name name="block" arity="2"/>
- <type name="block_error_rsn"/>
<fsummary>Block a disk log.</fsummary>
+ <type name="block_error_rsn"/>
<desc>
<p>With a call to <c>block/1,2</c> a process can block a log.
If the blocking process is not an owner of the log, a temporary
@@ -663,8 +663,8 @@
<func>
<name name="lclose" arity="1"/>
<name name="lclose" arity="2"/>
- <type name="lclose_error_rsn"/>
<fsummary>Close a disk log on one node.</fsummary>
+ <type name="lclose_error_rsn"/>
<desc>
<p>The function <c>lclose/1</c> closes a local log or an
individual distributed log on the current node.
@@ -744,6 +744,7 @@
</func>
<func>
<name name="open" arity="1"/>
+ <fsummary>Open a disk log file.</fsummary>
<type name="dlog_options"/>
<type name="dlog_option"/>
<type name="open_ret"/>
@@ -753,7 +754,6 @@
<type name="open_error_rsn"/>
<type name="dlog_optattr"/>
<type name="dlog_size"/>
- <fsummary>Open a disk log file.</fsummary>
<desc>
<p>The <c><anno>ArgL</anno></c> parameter is a list of options which have
the following meanings:</p>
@@ -1043,8 +1043,8 @@ If
</func>
<func>
<name name="sync" arity="1"/>
- <type name="sync_error_rsn"/>
<fsummary>Flush the contents of a disk log to the disk.</fsummary>
+ <type name="sync_error_rsn"/>
<desc>
<p>The <c>sync/1</c> function ensures that the contents of the
log are actually written to the disk.
@@ -1086,8 +1086,8 @@ If
</func>
<func>
<name name="unblock" arity="1"/>
- <type name="unblock_error_rsn"/>
<fsummary>Unblock a disk log.</fsummary>
+ <type name="unblock_error_rsn"/>
<desc>
<p>The <c>unblock/1</c> function unblocks a log.
A log can only be unblocked by the blocking process.
diff --git a/lib/kernel/doc/src/erl_ddll.xml b/lib/kernel/doc/src/erl_ddll.xml
index d622725ba0..8d71883cf4 100644
--- a/lib/kernel/doc/src/erl_ddll.xml
+++ b/lib/kernel/doc/src/erl_ddll.xml
@@ -388,14 +388,14 @@
remove a monitor.</p>
<p>The function accepts the following parameters:</p>
<taglist>
- <tag><em><anno>Tag</anno></em></tag>
+ <tag><em><c><anno>Tag</anno></c></em></tag>
<item>
<p>The monitor tag is always <c>driver</c> as this function
can only be used to create driver monitors. In the future,
driver monitors will be integrated with process monitors,
why this parameter has to be given for consistence.</p>
</item>
- <tag><em><anno>Item</anno></em></tag>
+ <tag><em><c><anno>Item</anno></c></em></tag>
<item>
<p>The <c><anno>Item</anno></c> parameter specifies which driver one
wants to monitor (the name of the driver) as well as
@@ -642,7 +642,7 @@
</note>
<p>The function accepts the following parameters:</p>
<taglist>
- <tag><em><anno>Path</anno></em></tag>
+ <tag><em><c><anno>Path</anno></c></em></tag>
<item>
<p>The filesystem path to the directory where the driver
object file is situated. The filename of the object file
@@ -665,7 +665,7 @@
to have <em>only one loader</em> of a driver one wants to
upgrade in a running system! </p>
</item>
- <tag><em><anno>Name</anno></em></tag>
+ <tag><em><c><anno>Name</anno></c></em></tag>
<item>
<p>The name parameter is the name of the driver to be used
in subsequent calls to <seealso marker="erts:erlang#open_port/2">open_port</seealso>. The
@@ -678,14 +678,14 @@
with this <c><anno>Name</anno></c> parameter, much as a beam-file's
module name much correspond to its filename.</p>
</item>
- <tag><em><anno>OptionList</anno></em></tag>
+ <tag><em><c><anno>OptionList</anno></c></em></tag>
<item>
<p>A number of options can be specified to control the
loading operation. The options are given as a list of
two-tuples, the tuples having the following values and
meanings:</p>
<taglist>
- <tag><em>{driver_options, <anno>DriverOptionList</anno>}</em></tag>
+ <tag><em>{driver_options, <c><anno>DriverOptionList</anno></c>}</em></tag>
<item>
<p>This option is to provide options that will change
its general behavior and will "stick" to the driver
@@ -701,7 +701,7 @@
when the last <seealso marker="#users">user</seealso> calls <seealso marker="#try_unload/2">try_unload/2</seealso>, or
the last process having loaded the driver exits.</p>
</item>
- <tag><em>{monitor, <anno>MonitorOption</anno>}</em></tag>
+ <tag><em>{monitor, <c><anno>MonitorOption</anno></c>}</em></tag>
<item>
<p>A <c><anno>MonitorOption</anno></c> tells <c>try_load/3</c> to
trigger a driver monitor under certain
@@ -732,7 +732,7 @@
<c>{monitor, pending_driver}</c> in production
code (see the monitor discussion above). </p>
</item>
- <tag><em>{reload,<anno>ReloadOption</anno>}</em></tag>
+ <tag><em>{reload, <c><anno>ReloadOption</anno></c>}</em></tag>
<item>
<p>This option is used when one wants to
<em>reload</em> a driver from disk, most often in a
@@ -910,13 +910,13 @@
</taglist>
<p>The function accepts the following parameters:</p>
<taglist>
- <tag><em><anno>Name</anno></em></tag>
+ <tag><em><c><anno>Name</anno></c></em></tag>
<item>
<p>The name parameter is the name of the driver to be
unloaded. The name can be specified either as an
<c>iolist()</c> or as an <c>atom()</c>. </p>
</item>
- <tag><em><anno>OptionList</anno></em></tag>
+ <tag><em><c><anno>OptionList</anno></c></em></tag>
<item>
<p>The <c><anno>OptionList</anno></c> argument can be used to specify
certain behavior regarding ports as well as triggering
@@ -934,7 +934,7 @@
unloads, one should use the driver option
<c>kill_ports</c> when loading the driver instead.</p>
</item>
- <tag><em>{monitor, <anno>MonitorOption</anno>}</em></tag>
+ <tag><em>{monitor, <c><anno>MonitorOption</anno></c>}</em></tag>
<item>
<p>This option creates a driver monitor if the condition
given in <c><anno>MonitorOption</anno></c> is true. The valid
diff --git a/lib/kernel/doc/src/error_logger.xml b/lib/kernel/doc/src/error_logger.xml
index f83fe53084..92e14c2bef 100644
--- a/lib/kernel/doc/src/error_logger.xml
+++ b/lib/kernel/doc/src/error_logger.xml
@@ -299,12 +299,12 @@ ok</pre>
<name name="logfile" arity="1" clause_i="1"/>
<name name="logfile" arity="1" clause_i="2"/>
<name name="logfile" arity="1" clause_i="3"/>
+ <fsummary>Enable or disable error printouts to a file</fsummary>
<type variable="Filename"/>
<type variable="OpenReason" name_i="1"/>
<type variable="CloseReason" name_i="2"/>
<type variable="FilenameReason" name_i="3"/>
<type name="open_error"/>
- <fsummary>Enable or disable error printouts to a file</fsummary>
<desc>
<p>Enables or disables printout of standard events to a file.</p>
<p>This is done by adding or deleting the standard event handler
diff --git a/lib/kernel/doc/src/file.xml b/lib/kernel/doc/src/file.xml
index 4954568086..831ef1c22a 100644
--- a/lib/kernel/doc/src/file.xml
+++ b/lib/kernel/doc/src/file.xml
@@ -87,9 +87,10 @@
<name name="deep_list"/>
</datatype>
<datatype>
- <name><marker id="type-fd">fd()</marker></name>
+ <name>fd()</name>
<desc>
- <p>A file descriptor representing a file opened in <seealso
+ <p><marker id="type-fd"/>
+ A file descriptor representing a file opened in <seealso
marker="#raw">raw</seealso> mode.</p>
</desc>
</datatype>
@@ -491,7 +492,7 @@
<name name="list_dir" arity="1"/>
<fsummary>List files in a directory</fsummary>
<desc>
- <p>Lists all files in a directory, <b>except</b> files
+ <p>Lists all files in a directory, <em>except</em> files
with "raw" names. Returns
<c>{ok, <anno>Filenames</anno>}</c> if successful.
Otherwise, it returns <c>{error, <anno>Reason</anno>}</c>.
@@ -1193,8 +1194,8 @@
and <c>read_line/1</c> are the only ways to read from a file
opened in raw mode (although they work for normally opened
files, too).</p>
- <p>For files where <c>encoding</c> is set to something else than <c>latin1</c>, one character might be represented by more than one byte on the file. The parameter <c>Number</c> always denotes the number of <em>characters</em> read from the file, why the position in the file might be moved a lot more than this number when reading a Unicode file.</p>
- <p>Also if <c>encoding</c> is set to something else than <c>latin1</c>, the <c>read/3</c> call will fail if the data contains characters larger than 255, why the <seealso marker="stdlib:io">io(3)</seealso> module is to be preferred when reading such a file.</p>
+ <p>For files where <c>encoding</c> is set to something else than <c>latin1</c>, one character might be represented by more than one byte on the file. The parameter <c>Number</c> always denotes the number of <em>characters</em> read from the file, while the position in the file might be moved much more than this number when reading a Unicode file.</p>
+ <p>Also, if <c>encoding</c> is set to something else than <c>latin1</c>, the <c>read/3</c> call will fail if the data contains characters larger than 255, which is why the <seealso marker="stdlib:io">io(3)</seealso> module is to be preferred when reading such a file.</p>
<p>The function returns:</p>
<taglist>
<tag><c>{ok, <anno>Data</anno>}</c></tag>
@@ -1307,15 +1308,15 @@
<item>
<p>The current system access to the file.</p>
</item>
- <tag><c>atime = <seealso marker="#type-date_time">date_time()</seealso> | integer() >= 0</c></tag>
+ <tag><c>atime = </c><seealso marker="#type-date_time">date_time()</seealso><c> | integer() >= 0</c></tag>
<item>
<p>The last time the file was read.</p>
</item>
- <tag><c>mtime = <seealso marker="#type-date_time">date_time()</seealso> | integer() >= 0</c></tag>
+ <tag><c>mtime = </c><seealso marker="#type-date_time">date_time()</seealso><c> | integer() >= 0</c></tag>
<item>
<p>The last time the file was written.</p>
</item>
- <tag><c>ctime = <seealso marker="#type-date_time">date_time()</seealso> | integer() >=0</c></tag>
+ <tag><c>ctime = </c><seealso marker="#type-date_time">date_time()</seealso><c> | integer() >=0</c></tag>
<item>
<p>The interpretation of this time field depends on
the operating system. On Unix, it is the last time
@@ -1745,7 +1746,7 @@
See <seealso marker="gen_tcp#controlling_process-2">gen_tcp:controlling_process/2</seealso></p>
<p>If the OS used does not support sendfile, an Erlang fallback
using file:read and gen_tcp:send is used.</p>
- <p>The option list can contain the following options:
+ <p>The option list can contain the following options:</p>
<taglist>
<tag><c>chunk_size</c></tag>
<item>The chunk size used by the erlang fallback to send
@@ -1760,7 +1761,6 @@
the sendfile call will return <c>{error,einval}</c>.
Introduced in Erlang/OTP 17.0. Default is false.</item>
</taglist>
- </p>
</desc>
</func>
<func>
@@ -1851,22 +1851,21 @@
Type <c>local</c> will interpret the time set as local, <c>universal</c> will
interpret it as universal time and <c>posix</c> must be seconds since
or before unix time epoch which is 1970-01-01 00:00 UTC.
- Default is <c>{time, local}</c>.
+ Default is <c>{time, local}</c>.</p>
<p>If the <c>raw</c> option is set, the file server will not be called
and only informations about local files will be returned.</p>
- </p>
<p>The following fields are used from the record, if they are
given.</p>
<taglist>
- <tag><c>atime = <seealso marker="#type-date_time">date_time()</seealso> | integer() >= 0</c></tag>
+ <tag><c>atime = </c><seealso marker="#type-date_time">date_time()</seealso><c> | integer() >= 0</c></tag>
<item>
<p>The last time the file was read.</p>
</item>
- <tag><c>mtime = <seealso marker="#type-date_time">date_time()</seealso> | integer() >= 0</c></tag>
+ <tag><c>mtime = </c><seealso marker="#type-date_time">date_time()</seealso><c> | integer() >= 0</c></tag>
<item>
<p>The last time the file was written.</p>
</item>
- <tag><c>ctime = <seealso marker="#type-date_time">date_time()</seealso> | integer() >= 0</c></tag>
+ <tag><c>ctime = </c><seealso marker="#type-date_time">date_time()</seealso><c> | integer() >= 0</c></tag>
<item>
<p>On Unix, any value give for this field will be ignored
(the "ctime" for the file will be set to the current
diff --git a/lib/kernel/doc/src/gen_sctp.xml b/lib/kernel/doc/src/gen_sctp.xml
index b704d90613..456108a2fe 100644
--- a/lib/kernel/doc/src/gen_sctp.xml
+++ b/lib/kernel/doc/src/gen_sctp.xml
@@ -77,9 +77,10 @@
<datatypes>
<datatype>
- <name><marker id="type-assoc_id">assoc_id()</marker></name>
+ <name>assoc_id()</name>
<desc>
- <p>An opaque term returned in for example #sctp_paddr_change{}
+ <p><marker id="type-assoc_id"/>
+ An opaque term returned in for example #sctp_paddr_change{}
that identifies an association for an SCTP socket. The term
is opaque except for the special value <c>0</c> that has a
meaning such as "the whole endpoint" or "all future associations".
@@ -98,9 +99,10 @@
<desc><marker id="type-sctp_socket"></marker></desc>
</datatype>
<datatype>
- <name><marker id="type-sctp_socket">sctp_socket()</marker></name>
+ <name>sctp_socket()</name>
<desc>
- <p>Socket identifier returned from <c>open/*</c>.</p>
+ <p><marker id="type-sctp_socket"/>
+ Socket identifier returned from <c>open/*</c>.</p>
<marker id="exports"></marker>
</desc>
</datatype>
@@ -146,7 +148,7 @@
<c><anno>Addr</anno></c> and <c><anno>Port</anno></c>. The <c><anno>Timeout</anno></c>,
is expressed in milliseconds. A socket can be associated with multiple peers.</p>
- <p><b>WARNING:</b>Using a value of <c><anno>Timeout</anno></c> less than
+ <p><em>WARNING:</em>Using a value of <c><anno>Timeout</anno></c> less than
the maximum time taken by the OS to establish an association (around 4.5 minutes
if the default values from RFC 4960 are used) can result in
inconsistent or incorrect return values. This is especially
@@ -170,7 +172,7 @@
<p>The number of outbound and inbound streams can be set by
giving an <c>sctp_initmsg</c> option to <c>connect</c>
as in:</p>
-<pre> connect(<anno>Socket</anno>, Ip, <anno>Port</anno>,
+<pre> connect(Socket, Ip, Port>,
[{sctp_initmsg,#sctp_initmsg{num_ostreams=OutStreams,
max_instreams=MaxInStreams}}]) </pre>
<p>All options <c><anno>Opt</anno></c> are set on the socket before the
diff --git a/lib/kernel/doc/src/gen_tcp.xml b/lib/kernel/doc/src/gen_tcp.xml
index 8d9f09cea7..6a19e76c4f 100644
--- a/lib/kernel/doc/src/gen_tcp.xml
+++ b/lib/kernel/doc/src/gen_tcp.xml
@@ -78,9 +78,10 @@ do_recv(Sock, Bs) ->
<name name="listen_option"/>
</datatype>
<datatype>
- <name><marker id="type-socket">socket()</marker></name>
+ <name>socket()</name>
<desc>
- <p>As returned by accept/1,2 and connect/3,4.</p>
+ <p><marker id="type-socket"/>
+ As returned by accept/1,2 and connect/3,4.</p>
<marker id="connect"></marker>
</desc>
</datatype>
diff --git a/lib/kernel/doc/src/gen_udp.xml b/lib/kernel/doc/src/gen_udp.xml
index 6f34aba43c..79cd87dcef 100644
--- a/lib/kernel/doc/src/gen_udp.xml
+++ b/lib/kernel/doc/src/gen_udp.xml
@@ -43,9 +43,9 @@
<name name="option_name"/>
</datatype>
<datatype>
- <name><marker id="type-socket">socket()</marker></name>
+ <name>socket()</name>
<desc>
- <p>As returned by open/1,2.</p>
+ <p><marker id="type-socket"/>As returned by open/1,2.</p>
</desc>
</datatype>
</datatypes>
diff --git a/lib/kernel/doc/src/heart.xml b/lib/kernel/doc/src/heart.xml
index b9fad17ce1..9da4773f2d 100644
--- a/lib/kernel/doc/src/heart.xml
+++ b/lib/kernel/doc/src/heart.xml
@@ -118,6 +118,13 @@
<p>In the following descriptions, all function fails with reason
<c>badarg</c> if <c>heart</c> is not started.</p>
</description>
+
+ <datatypes>
+ <datatype>
+ <name name="heart_option"/>
+ </datatype>
+ </datatypes>
+
<funcs>
<func>
<name name="set_cmd" arity="1"/>
@@ -154,6 +161,62 @@
the empty string will be returned.</p>
</desc>
</func>
+
+ <func>
+ <name name="set_callback" arity="2"/>
+ <fsummary>Set a validation callback</fsummary>
+ <desc>
+ <p> This validation callback will be executed before any heartbeat sent
+ to the port program. For the validation to succeed it needs to return
+ with the value <c>ok</c>.
+ </p>
+ <p> An exception within the callback will be treated as a validation failure. </p>
+ <p> The callback will be removed if the system reboots. </p>
+ </desc>
+ </func>
+ <func>
+ <name name="clear_callback" arity="0"/>
+ <fsummary>Clear the validation callback</fsummary>
+ <desc>
+ <p>Removes the validation callback call before heartbeats.</p>
+ </desc>
+ </func>
+ <func>
+ <name name="get_callback" arity="0"/>
+ <fsummary>Get the validation callback</fsummary>
+ <desc>
+ <p>Get the validation callback. If the callback is cleared, <c>none</c> will be returned.</p>
+ </desc>
+ </func>
+
+ <func>
+ <name name="set_options" arity="1"/>
+ <fsummary>Set a list of options</fsummary>
+ <desc>
+ <p> Valid options <c>set_options</c> are: </p>
+ <taglist>
+ <tag><c>check_schedulers</c></tag>
+ <item>
+ <p>If enabled, a signal will be sent to each scheduler to check its
+ responsiveness. The system check occurs before any heartbeat sent
+ to the port program. If any scheduler is not responsive enough the
+ heart program will not receive its heartbeat and thus eventually terminate the node.
+ </p>
+ </item>
+ </taglist>
+ <p> Returns with the value <c>ok</c> if the options are valid.</p>
+ </desc>
+ </func>
+ <func>
+ <name name="get_options" arity="0"/>
+ <fsummary>Get the temporary reboot command</fsummary>
+ <desc>
+ <p>Returns <c>{ok, Options}</c> where <c>Options</c> is a list of current options enabled for heart.
+ If the callback is cleared, <c>none</c> will be returned.</p>
+ </desc>
+ </func>
+
+
</funcs>
</erlref>
diff --git a/lib/kernel/doc/src/inet.xml b/lib/kernel/doc/src/inet.xml
index e5d7ce048a..088d78c1d6 100644
--- a/lib/kernel/doc/src/inet.xml
+++ b/lib/kernel/doc/src/inet.xml
@@ -4,7 +4,7 @@
<erlref>
<header>
<copyright>
- <year>1997</year><year>2013</year>
+ <year>1997</year><year>2015</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -117,8 +117,9 @@ fe80::204:acff:fe17:bf38
</desc>
</datatype>
<datatype>
- <name><marker id="type-socket">socket()</marker></name>
- <desc><p>See <seealso marker="gen_tcp#type-socket">gen_tcp(3)</seealso>
+ <name>socket()</name>
+ <desc><p><marker id="type-socket"></marker>
+ See <seealso marker="gen_tcp#type-socket">gen_tcp(3)</seealso>
and <seealso marker="gen_udp#type-socket">gen_udp(3)</seealso>.</p>
</desc>
</datatype>
@@ -222,7 +223,7 @@ fe80::204:acff:fe17:bf38
</p>
<p>
Do not rely too much on the order of <c><anno>Flag</anno></c> atoms or
- <c><anno>Ifopt</anno></c> tuples. There are some rules, though:
+ <c><anno>Ifopt</anno></c> tuples. There are some rules, though:</p>
<list>
<item>
Immediately after <c>{addr,_}</c> follows <c>{netmask,_}</c>
@@ -238,7 +239,6 @@ fe80::204:acff:fe17:bf38
tuple concerns that address.
</item>
</list>
- </p>
<p>
The <c>{hwaddr,_}</c> tuple is not returned on Solaris since the
hardware address historically belongs to the link layer and only
@@ -379,14 +379,14 @@ fe80::204:acff:fe17:bf38
<name name="ntoa" arity="1" />
<fsummary>Convert IPv6 / IPV4 adress to ascii</fsummary>
<desc>
- <p>Parses an <a href="#type-ip_address">ip_address()</a> and returns an IPv4 or IPv6 address string.</p>
+ <p>Parses an <seealso marker="#type-ip_address">ip_address()</seealso> and returns an IPv4 or IPv6 address string.</p>
</desc>
</func>
<func>
<name name="parse_ipv4_address" arity="1" />
<fsummary>Parse an IPv4 address</fsummary>
<desc>
- <p>Parses an IPv4 address string and returns an <a href="#type-ip4_address">ip4_address()</a>.
+ <p>Parses an IPv4 address string and returns an <seealso marker="#type-ip4_address">ip4_address()</seealso>.
Accepts a shortened IPv4 shortened address string.</p>
</desc>
</func>
@@ -394,14 +394,14 @@ fe80::204:acff:fe17:bf38
<name name="parse_ipv4strict_address" arity="1" />
<fsummary>Parse an IPv4 address strict.</fsummary>
<desc>
- <p>Parses an IPv4 address string containing four fields, i.e <b>not</b> shortened, and returns an <a href="#type-ip4_adress">ip4_address()</a>.</p>
+ <p>Parses an IPv4 address string containing four fields, i.e <em>not</em> shortened, and returns an <seealso marker="#type-ip4_address">ip4_address()</seealso>.</p>
</desc>
</func>
<func>
<name name="parse_ipv6_address" arity="1" />
<fsummary>Parse an IPv6 address</fsummary>
<desc>
- <p>Parses an IPv6 address string and returns an <a href="#type-ip6_address">ip6_address()</a>.
+ <p>Parses an IPv6 address string and returns an <seealso marker="#type-ip6_address">ip6_address()</seealso>.
If an IPv4 address string is passed, an IPv4-mapped IPv6 address is returned.</p>
</desc>
</func>
@@ -409,22 +409,22 @@ fe80::204:acff:fe17:bf38
<name name="parse_ipv6strict_address" arity="1" />
<fsummary>Parse an IPv6 address strict.</fsummary>
<desc>
- <p>Parses an IPv6 address string and returns an <a href="#type-ip6_address">ip6_address()</a>.
- Does <b>not</b> accept IPv4 adresses.</p>
+ <p>Parses an IPv6 address string and returns an <seealso marker="#type-ip6_address">ip6_address()</seealso>.
+ Does <em>not</em> accept IPv4 adresses.</p>
</desc>
</func>
<func>
<name name="parse_address" arity="1" />
<fsummary>Parse an IPv4 or IPv6 address.</fsummary>
<desc>
- <p>Parses an IPv4 or IPv6 address string and returns an <a href="#type-ip4_address">ip4_address()</a> or <a href="#type-ip6_address">ip6_address()</a>. Accepts a shortened IPv4 address string.</p>
+ <p>Parses an IPv4 or IPv6 address string and returns an <seealso marker="#type-ip4_address">ip4_address()</seealso> or <seealso marker="#type-ip6_address">ip6_address()</seealso>. Accepts a shortened IPv4 address string.</p>
</desc>
</func>
<func>
<name name="parse_strict_address" arity="1" />
<fsummary>Parse an IPv4 or IPv6 address strict.</fsummary>
<desc>
- <p>Parses an IPv4 or IPv6 address string and returns an <a href="#type-ip4_address">ip4_address()</a> or <a href="#type-ip6_adress">ip6_address()</a>. Does <b>not</b> accept a shortened IPv4 address string.</p>
+ <p>Parses an IPv4 or IPv6 address string and returns an <seealso marker="#type-ip4_address">ip4_address()</seealso> or <seealso marker="#type-ip6_address">ip6_address()</seealso>. Does <em>not</em> accept a shortened IPv4 address string.</p>
</desc>
</func>
<func>
@@ -862,10 +862,10 @@ fe80::204:acff:fe17:bf38
<c>CAP_SYS_ADMIN</c> according to the documentation for setns(2).
However, during testing also <c>CAP_SYS_PTRACE</c>
and <c>CAP_DAC_READ_SEARCH</c> has proven to be necessary.
- Example:<code>
+ Example:</p><code>
setcap cap_sys_admin,cap_sys_ptrace,cap_dac_read_search+epi beam.smp
</code>
- Note also that the filesystem containing the virtual machine
+ <p>Note also that the filesystem containing the virtual machine
executable (<c>beam.smp</c> in the example above) has to be local,
mounted without the <c>nosetuid</c> flag,
support extended attributes and that
@@ -981,6 +981,11 @@ setcap cap_sys_admin,cap_sys_ptrace,cap_dac_read_search+epi beam.smp
indicated length are accepted and not considered invalid due
to internal buffer limitations.</p>
</item>
+ <tag><c>{line_delimiter, Char}</c>(TCP/IP sockets)</tag>
+ <item>
+ <p>Sets the line delimiting character for line oriented protocols
+ (<c>line</c>). Default value is <c>$\n</c>.</p>
+ </item>
<tag><c>{priority, Priority}</c></tag>
<item> <p>Set the protocol-defined priority for all packets to be sent
diff --git a/lib/kernel/doc/src/inet_res.xml b/lib/kernel/doc/src/inet_res.xml
index 6a2c9b1955..851a36aba9 100644
--- a/lib/kernel/doc/src/inet_res.xml
+++ b/lib/kernel/doc/src/inet_res.xml
@@ -4,7 +4,7 @@
<erlref>
<header>
<copyright>
- <year>2009</year><year>2013</year>
+ <year>2009</year><year>2015</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -77,8 +77,11 @@
query is tried for the <c>alt_nameservers</c>.</p>
</section>
+ <section>
+ <title>Resolver Types</title>
+ <p>The following data types concern the resolver:</p>
+ </section>
<datatypes>
- <p>Resolver types:</p>
<datatype>
<name name="res_option"/>
</datatype>
@@ -88,8 +91,13 @@
<datatype>
<name name="res_error"/>
</datatype>
-
- <p><marker id="dns_types"/>DNS types:</p>
+ </datatypes>
+ <section>
+ <title>DNS Types</title>
+ <p><marker id="dns_types"/>
+ The following data types concern the DNS client:</p>
+ </section>
+ <datatypes>
<datatype>
<name name="dns_name"/>
<desc><p>A string with no adjacent dots.</p></desc>
@@ -106,7 +114,7 @@
<p>This is the start of a hiearchy of opaque data structures
that can be examined with access functions in inet_dns that
return lists of {Field,Value} tuples. The arity 2 functions
- just return the value for a given field.
+ just return the value for a given field.</p>
<pre>
dns_msg() = DnsMsg
inet_dns:msg(DnsMsg) ->
@@ -154,18 +162,19 @@ dns_rr() = DnsRr
| {version, integer()}
| {z, integer()}
| {data, dns_data()} ]
- inet_dns:rr(DnsRr, Field) -> Value
+ inet_dns:rr(DnsRr, Field) -> Value</pre>
-There is an info function for the types above:
+<p>There is an info function for the types above:</p>
+<pre>
inet_dns:record_type(dns_msg()) -> msg;
inet_dns:record_type(dns_header()) -> header;
inet_dns:record_type(dns_query()) -> dns_query;
inet_dns:record_type(dns_rr()) -> rr;
-inet_dns:record_type(_) -> undefined.
+inet_dns:record_type(_) -> undefined.</pre>
-So; inet_dns:(inet_dns:record_type(X))(X) will convert
-any of these data structures into a {Field,Value} list.</pre></p>
+<p>So; inet_dns:(inet_dns:record_type(X))(X) will convert
+any of these data structures into a {Field,Value} list.</p>
</desc>
</datatype>
<datatype>
@@ -272,7 +281,7 @@ any of these data structures into a {Field,Value} list.</pre></p>
<p>Resolve a DNS record of the given type and class for the given name.
The returned <c>dns_msg()</c> can be examined using
access functions in <c>inet_db</c> as described
- in <seealso marker="#dns_types">DNS types</seealso>.
+ in <seealso marker="#dns_types">DNS Types</seealso>.
</p><p>
If <c><anno>Name</anno></c> is an <c>ip_address()</c>, the domain name
to query for is generated as the standard reverse
diff --git a/lib/kernel/doc/src/kernel_app.xml b/lib/kernel/doc/src/kernel_app.xml
index 2cea38bae9..956c57f7c1 100644
--- a/lib/kernel/doc/src/kernel_app.xml
+++ b/lib/kernel/doc/src/kernel_app.xml
@@ -43,6 +43,7 @@
<item><c>erl_boot_server</c></item>
<item><c>erl_ddll</c></item>
<item><c>error_logger</c></item>
+ <item><c>error_logger_format_depth</c></item>
<item><c>file</c></item>
<item><c>global</c></item>
<item><c>global_group</c></item>
@@ -152,6 +153,42 @@
</item>
</taglist>
</item>
+ <tag><c>error_logger_format_depth = Depth</c></tag>
+ <item>
+ <marker id="error_logger_format_depth"></marker>
+ <p>This parameter can be used to limit the size of the
+ formatted output from the error logger event handlers.</p>
+
+ <note><p>This configuration parameter was introduced in OTP 18.1.
+ It is currently experimental. Based on user feedback it
+ may be changed or improved in future releases, for example
+ to gain better control over how to limit the size of the
+ formatted output. We have no plans to entirely remove this
+ new feature, unless it turns out to be completely
+ useless. In OTP 19, the default may be changed to limit the
+ formatted output.</p></note>
+
+ <p><c>Depth</c> is a positive integer that is the maximum
+ depth to which terms are printed by the error logger event
+ handlers included in OTP. Specifically, the two event handlers
+ defined by the <c>Kernel</c> application and the two event
+ handlers in the <c>SASL</c> application will use this
+ configuration parameter. (If you have implemented you own
+ error handlers, this configuration parameter will have no
+ effect on them.)</p>
+
+ <p>The way <c>Depth</c> is used, is that format strings
+ string passed to the event handlers will be rewritten.
+ The "~p" and "~w" format controls will be replaced with
+ "~P" and "~W", respectively, and <c>Depth</c> will be
+ used as the depth parameter. See
+ <seealso marker="stdlib:io#format/2">io:format/2</seealso>.</p>
+
+ <note><p>A reasonable starting value for <c>Depth</c> is
+ <c>30</c>. You should test crashing various processes in your
+ application and examine the logs from the crashes, and then
+ either increase or decrease the value.</p></note>
+ </item>
<tag><c>global_groups = [GroupTuple]</c></tag>
<item>
<p>Defines global groups, see
diff --git a/lib/kernel/doc/src/net_adm.xml b/lib/kernel/doc/src/net_adm.xml
index 1072be44a5..4ef9d361f6 100644
--- a/lib/kernel/doc/src/net_adm.xml
+++ b/lib/kernel/doc/src/net_adm.xml
@@ -89,8 +89,8 @@
<func>
<name name="world" arity="0"/>
<name name="world" arity="1"/>
- <type name="verbosity"/>
<fsummary>Lookup and connect to all nodes at all hosts in <c>.hosts.erlang</c></fsummary>
+ <type name="verbosity"/>
<desc>
<p>This function calls <c>names(Host)</c> for all hosts which
are specified in the Erlang host file <c>.hosts.erlang</c>,
@@ -110,8 +110,8 @@
<func>
<name name="world_list" arity="1"/>
<name name="world_list" arity="2"/>
- <type name="verbosity"/>
<fsummary>Lookup and connect to all nodes at specified hosts</fsummary>
+ <type name="verbosity"/>
<desc>
<p>As <c>world/0,1</c>, but the hosts are given as argument
instead of being read from <c>.hosts.erlang</c>.</p>
diff --git a/lib/kernel/doc/src/net_kernel.xml b/lib/kernel/doc/src/net_kernel.xml
index a0132db8db..311e0d8ea4 100644
--- a/lib/kernel/doc/src/net_kernel.xml
+++ b/lib/kernel/doc/src/net_kernel.xml
@@ -63,11 +63,16 @@
<funcs>
<func>
<name name="allow" arity="1"/>
- <fsummary>Limit access to a specified set of nodes</fsummary>
+ <fsummary>Permit access to a specified set of nodes</fsummary>
<desc>
- <p>Limits access to the specified set of nodes. Any access
- attempts made from (or to) nodes not in <c><anno>Nodes</anno></c> will be
- rejected.</p>
+ <p>Permits access to the specified set of nodes.</p>
+ <p>Before the first call to <c>allow/1</c>, any node with the correct
+ cookie can be connected. When <c>allow/1</c> is called, a list
+ of allowed nodes is established. Any access attempts made from (or to)
+ nodes not in that list will be rejected.</p>
+ <p>Subsequent calls to <c>allow/1</c> will add the specified nodes
+ to the list of allowed nodes. It is not possible to remove nodes
+ from the list.</p>
<p>Returns <c>error</c> if any element in <c><anno>Nodes</anno></c> is not
an atom.</p>
</desc>
diff --git a/lib/kernel/doc/src/notes.xml b/lib/kernel/doc/src/notes.xml
index b8db22aba7..cf5777d4be 100644
--- a/lib/kernel/doc/src/notes.xml
+++ b/lib/kernel/doc/src/notes.xml
@@ -31,6 +31,190 @@
</header>
<p>This document describes the changes made to the Kernel application.</p>
+<section><title>Kernel 4.2</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p><c>code:load_abs([10100])</c> would bring down the
+ entire runtime system and create a crash dump. Corrected
+ to generate an error exception in the calling
+ process.</p>
+ <p>Also corrected specs for code loading functions and
+ added more information in the documentation about the
+ error reasons returned by code-loading functions.</p>
+ <p>
+ Own Id: OTP-9375</p>
+ </item>
+ <item>
+ <p>
+ <seealso
+ marker="kernel:gen_tcp#accept/2"><c>gen_tcp:accept/2</c></seealso>
+ was not <seealso
+ marker="erts:time_correction#Time_Warp_Safe_Code">time
+ warp safe</seealso>. This since it used the same time as
+ returned by <seealso
+ marker="erts:erlang#now/0"><c>erlang:now/0</c></seealso>
+ when calculating timeout. This has now been fixed.</p>
+ <p>
+ Own Id: OTP-13254 Aux Id: OTP-11997, OTP-13222 </p>
+ </item>
+ <item>
+ <p> Correct the contract for <c>inet:getifaddrs/1</c>.
+ </p>
+ <p>
+ Own Id: OTP-13335 Aux Id: ERL-95 </p>
+ </item>
+ </list>
+ </section>
+
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p>
+ Time warp safety improvements.</p>
+ <p>
+ Introduced the options <c>monotonic_timestamp</c>, and
+ <c>strict_monotonic_timestamp</c> to the trace,
+ sequential trace, and system profile functionality. This
+ since the already existing <c>timestamp</c> option is not
+ time warp safe.</p>
+ <p>
+ Introduced the option <c>safe_fixed_monotonic_time</c> to
+ <c>ets:info/2</c> and <c>dets:info/2</c>. This since the
+ already existing <c>safe_fixed</c> option is not time
+ warp safe.</p>
+ <p>
+ Own Id: OTP-13222 Aux Id: OTP-11997 </p>
+ </item>
+ <item>
+ <p>
+ Add validation callback for heart</p>
+ <p>
+ The erlang heart process may now have a validation
+ callback installed. The validation callback will be
+ executed, if present, before any heartbeat to heart port
+ program. If the validation fails, or stalls, no heartbeat
+ will be sent and the node will go down.</p>
+ <p>
+ With the option <c>'check_schedulers'</c> heart executes
+ a responsiveness check of the schedulers before a
+ heartbeat is sent to the port program. If the
+ responsiveness check fails, the heartbeat will not be
+ performed (as intended).</p>
+ <p>
+ Own Id: OTP-13250</p>
+ </item>
+ <item>
+ <p>
+ Clarify documentation of <c>net_kernel:allow/1</c></p>
+ <p>
+ Own Id: OTP-13299</p>
+ </item>
+ <item>
+ <p>
+ EPMD supports both IPv4 and IPv6</p>
+ <p>
+ Also affects oldest supported windows version.</p>
+ <p>
+ Own Id: OTP-13364</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Kernel 4.1.1</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Host name lookups though inet_res, the Erlang DNS
+ resolver, are now done case insensitively according to
+ RFC 4343. Patch by Holger Weiß.</p>
+ <p>
+ Own Id: OTP-12836</p>
+ </item>
+ <item>
+ <p>
+ IPv6 distribution handler has been updated to share code
+ with IPv4 so that all features are supported in IPv6 as
+ well. A bug when using an IPv4 address as hostname has
+ been fixed.</p>
+ <p>
+ Own Id: OTP-13040</p>
+ </item>
+ <item>
+ <p>
+ Caching of host names in the internal DNS resolver
+ inet_res has been made character case insensitive for
+ host names according to RFC 4343.</p>
+ <p>
+ Own Id: OTP-13083</p>
+ </item>
+ <item>
+ <p>Cooked file mode buffering has been fixed so
+ file:position/2 now works according to Posix on Posix
+ systems i.e. when file:position/2 returns an error the
+ file pointer is unaffected.</p> <p>The Windows system
+ documentation, however, is unclear on this point so the
+ documentation of file:position/2 still does not promise
+ anything.</p> <p>Cooked file mode file:pread/2,3 and
+ file:pwrite/2,3 have been corrected to honor character
+ encoding like the combination of file:position/2 and
+ file:read/2 or file:write/2 already does. This is
+ probably not very useful since the character
+ representation on the caller's side is latin1,
+ period.</p>
+ <p>
+ Own Id: OTP-13155 Aux Id: PR#646 </p>
+ </item>
+ </list>
+ </section>
+
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p>
+ Add {line_delim, byte()} option to inet:setopts/2 and
+ decode_packet/3</p>
+ <p>
+ Own Id: OTP-12837</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Kernel 4.1</title>
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p>A mechanism for limiting the amount of text that the
+ built-in error logger events will produce has been
+ introduced. It is useful for limiting both the size of
+ log files and the CPU time used to produce them.</p>
+ <p>This mechanism is experimental in the sense that it
+ may be changed if it turns out that it does not solve the
+ problem it is supposed to solve. In that case, there may
+ be backward incompatible improvements to this
+ mechanism.</p>
+ <p>See the documentation for the config parameter
+ <c>error_logger_format_depth</c> in the Kernel
+ application for information about how to turn on this
+ feature.</p>
+ <p>
+ Own Id: OTP-12864</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>Kernel 4.0</title>
<section><title>Fixed Bugs and Malfunctions</title>
@@ -159,6 +343,22 @@
</section>
+<section><title>Kernel 3.2.0.1</title>
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>The 'raw' socket option could not be used multiple times
+ in one call to any e.g gen_tcp function because only one
+ of the occurrences were used. This bug has been fixed,
+ and also a small bug concerning propagating error codes
+ from within inet:setopts/2.</p>
+ <p>Own Id: OTP-11482 Aux Id: seq12872 </p>
+ </item>
+ </list>
+ </section>
+ </section>
+
+
<section><title>Kernel 3.2</title>
<section><title>Fixed Bugs and Malfunctions</title>
@@ -1192,7 +1392,7 @@
</item>
<item>
<p> Fix returned error from gen_tcp:accept/1,2 when
- running out of ports
+ running out of ports.</p>
<p>
The {error, enfile} return value is badly misleading and
confusing for this case, since the Posix ENFILE errno
@@ -1201,7 +1401,7 @@
{error, system_limit}, which is consistent with e.g.
various file(3) functions. inet:format_error/1 has also
been updated to support system_limit in the same manner
- as file:format_error/1. (Thanks to Per Hedeland)</p></p>
+ as file:format_error/1. (Thanks to Per Hedeland)</p>
<p>
Own Id: OTP-9990</p>
</item>
@@ -1396,7 +1596,6 @@
Own Id: OTP-9764</p>
</item>
<item>
- <p>
<list> <item><p>Correct callback spec in application
module</p></item> <item><p>Refine warning about callback
specs with extra ranges</p></item> <item><p>Cleanup
@@ -1407,7 +1606,7 @@
analysis</p></item> <item><p>Fix crash in
Dialyzer</p></item> <item><p>Variable substitution was
not generalizing any unknown variables.</p></item>
- </list></p>
+ </list>
<p>
Own Id: OTP-9776</p>
</item>
diff --git a/lib/kernel/doc/src/os.xml b/lib/kernel/doc/src/os.xml
index 2d2a690fea..682d4a2eac 100644
--- a/lib/kernel/doc/src/os.xml
+++ b/lib/kernel/doc/src/os.xml
@@ -171,8 +171,8 @@ DirOut = os:cmd("dir"), % on Win32 platform</code>
</func>
<func>
<name name="timestamp" arity="0"/>
- <type_desc variable="Timestamp">Timestamp = {MegaSecs, Secs, MicroSecs}</type_desc>
<fsummary>Current OS system time on the erlang:timestamp/0 format</fsummary>
+ <type_desc variable="Timestamp">Timestamp = {MegaSecs, Secs, MicroSecs}</type_desc>
<desc>
<p>Returns current
<seealso marker="erts:time_correction#OS_System_Time">OS system time</seealso>
@@ -205,7 +205,7 @@ format_utc_timestamp() ->
29 Apr 2009 9:55:30.051711
</pre>
<p>OS system time can also be retreived by
- <c><seealso marker="#system_time/0"><c>os:system_time/0</c></seealso></c>,
+ <seealso marker="#system_time/0"><c>os:system_time/0</c></seealso>,
and <seealso marker="#system_time/1"><c>os:system_time/1</c></seealso>.</p>
</desc>
</func>
diff --git a/lib/kernel/doc/src/seq_trace.xml b/lib/kernel/doc/src/seq_trace.xml
index 3439111035..f4fcd222ec 100644
--- a/lib/kernel/doc/src/seq_trace.xml
+++ b/lib/kernel/doc/src/seq_trace.xml
@@ -127,6 +127,35 @@ seq_trace:set_token(OldToken), % activate the trace token again
enables/disables a timestamp to be generated for each
traced event. Default is <c>false</c>.</p>
</item>
+ <tag><c>set_token(strict_monotonic_timestamp, <anno>Bool</anno>)</c></tag>
+ <item>
+ <p>A trace token flag (<c>true | false</c>) which
+ enables/disables a strict monotonic timestamp to be generated
+ for each traced event. Default is <c>false</c>. Timestamps will
+ consist of
+ <seealso marker="erts:time_correction#Erlang_Monotonic_Time">Erlang
+ monotonic time</seealso> and a monotonically increasing
+ integer. The time-stamp has the same format and value
+ as produced by <c>{erlang:monotonic_time(nano_seconds),
+ erlang:unique_integer([monotonic])}</c>.</p>
+ </item>
+ <tag><c>set_token(monotonic_timestamp, <anno>Bool</anno>)</c></tag>
+ <item>
+ <p>A trace token flag (<c>true | false</c>) which
+ enables/disables a strict monotonic timestamp to be generated
+ for each traced event. Default is <c>false</c>. Timestamps
+ will use
+ <seealso marker="erts:time_correction#Erlang_Monotonic_Time">Erlang
+ monotonic time</seealso>. The time-stamp has the same
+ format and value as produced by
+ <c>erlang:monotonic_time(nano_seconds)</c>.</p>
+ </item>
+ <p>If multiple timestamp flags are passed, <c>timestamp</c> has
+ precedence over <c>strict_monotonic_timestamp</c> which
+ in turn has precedence over <c>monotonic_timestamp</c>. All
+ timestamp flags are remembered, so if two are passed
+ and the one with highest precedence later is disabled
+ the other one will become active.</p>
</taglist>
</desc>
</func>
diff --git a/lib/kernel/examples/uds_dist/c_src/uds_drv.c b/lib/kernel/examples/uds_dist/c_src/uds_drv.c
index e32ad69adf..8c028ba910 100644
--- a/lib/kernel/examples/uds_dist/c_src/uds_drv.c
+++ b/lib/kernel/examples/uds_dist/c_src/uds_drv.c
@@ -957,28 +957,24 @@ static void put_packet_length(char *b, int len)
/*
** Malloc wrappers
-** Note!
-** The function erl_exit is actually not a pert of the
-** driver interface, but it is very nice to use if one wants to halt
-** with a core and an erlang crash dump.
*/
static void *my_malloc(size_t size)
{
- void erl_exit(int, char *, ...);
void *ptr;
if ((ptr = driver_alloc(size)) == NULL) {
- erl_exit(1,"Could not allocate %lu bytes of memory",(unsigned long) size);
+ fprintf(stderr, "Could not allocate %lu bytes of memory",(unsigned long) size);
+ abort();
}
return ptr;
}
static void *my_realloc(void *ptr, size_t size)
{
- void erl_exit(int, char *, ...);
void *nptr;
if ((nptr = driver_realloc(ptr, size)) == NULL) {
- erl_exit(1,"Could not reallocate %lu bytes of memory",(unsigned long) size);
+ fprintf(stderr, "Could not reallocate %lu bytes of memory",(unsigned long) size);
+ abort();
}
return nptr;
}
diff --git a/lib/kernel/src/code.erl b/lib/kernel/src/code.erl
index 352c02562b..7237550786 100644
--- a/lib/kernel/src/code.erl
+++ b/lib/kernel/src/code.erl
@@ -77,10 +77,9 @@
%%----------------------------------------------------------------------------
-type load_error_rsn() :: 'badfile'
- | 'native_code'
| 'nofile'
| 'not_purged'
- | 'on_load'
+ | 'on_load_failure'
| 'sticky_directory'.
-type load_ret() :: {'error', What :: load_error_rsn()}
| {'module', Module :: module()}.
@@ -135,14 +134,16 @@ load_file(Mod) when is_atom(Mod) ->
-spec ensure_loaded(Module) -> {module, Module} | {error, What} when
Module :: module(),
- What :: embedded | badfile | native_code | nofile | on_load.
+ What :: embedded | badfile | nofile | on_load_failure.
ensure_loaded(Mod) when is_atom(Mod) ->
call({ensure_loaded,Mod}).
%% XXX File as an atom is allowed only for backwards compatibility.
-spec load_abs(Filename) -> load_ret() when
Filename :: file:filename().
-load_abs(File) when is_list(File); is_atom(File) -> call({load_abs,File,[]}).
+load_abs(File) when is_list(File); is_atom(File) ->
+ Mod = list_to_atom(filename:basename(File)),
+ call({load_abs,File,Mod}).
%% XXX Filename is also an atom(), e.g. 'cover_compiled'
-spec load_abs(Filename :: loaded_filename(), Module :: module()) -> load_ret().
diff --git a/lib/kernel/src/code_server.erl b/lib/kernel/src/code_server.erl
index e461c95d19..614219794c 100644
--- a/lib/kernel/src/code_server.erl
+++ b/lib/kernel/src/code_server.erl
@@ -313,7 +313,7 @@ handle_call(get_path, {_From,_Tag}, S) ->
{reply,S#state.path,S};
%% Messages to load, delete and purge modules/files.
-handle_call({load_abs,File,Mod}, Caller, S) ->
+handle_call({load_abs,File,Mod}, Caller, S) when is_atom(Mod) ->
case modp(File) of
false ->
{reply,{error,badarg},S};
@@ -1222,15 +1222,10 @@ modp(Atom) when is_atom(Atom) -> true;
modp(List) when is_list(List) -> int_list(List);
modp(_) -> false.
-load_abs(File, Mod0, Caller, St) ->
+load_abs(File, Mod, Caller, St) ->
Ext = objfile_extension(),
FileName0 = lists:concat([File, Ext]),
FileName = absname(FileName0),
- Mod = if Mod0 =:= [] ->
- list_to_atom(filename:basename(FileName0, Ext));
- true ->
- Mod0
- end,
case erl_prim_loader:get_file(FileName) of
{ok,Bin,_} ->
try_load_module(FileName, Mod, Bin, Caller, St);
diff --git a/lib/kernel/src/disk_log_1.erl b/lib/kernel/src/disk_log_1.erl
index 9b9fd086f1..2e61363aa6 100644
--- a/lib/kernel/src/disk_log_1.erl
+++ b/lib/kernel/src/disk_log_1.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2013. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2016. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -79,6 +79,7 @@ log(FdC, FileName, X) ->
logl(X) ->
logl(X, [], 0).
+-dialyzer({no_improper_lists, logl/3}).
logl([X | T], Bs, Size) ->
Sz = byte_size(X),
BSz = <<Sz:?SIZESZ/unit:8>>,
@@ -1142,6 +1143,7 @@ write_index_file(read_write, FName, NewFile, OldFile, OldCnt) ->
file_error(FileName, E)
end.
+-dialyzer({no_improper_lists, to_8_bytes/4}).
to_8_bytes(<<N:32,T/binary>>, NT, FileName, Fd) ->
to_8_bytes(T, [NT | <<N:64>>], FileName, Fd);
to_8_bytes(B, NT, _FileName, _Fd) when byte_size(B) =:= 0 ->
@@ -1276,6 +1278,7 @@ ext_split_bins(CurB, MaxB, FirstPos, Bins) ->
MaxBs = MaxB - CurB, IsFirst = CurB =:= FirstPos,
ext_split_bins(MaxBs, IsFirst, [], Bins, 0, 0).
+-dialyzer({no_improper_lists, ext_split_bins/6}).
ext_split_bins(MaxBs, IsFirst, First, [X | Last], Bs, N) ->
NBs = Bs + byte_size(X),
if
@@ -1296,6 +1299,7 @@ int_split_bins(CurB, MaxB, FirstPos, Bins) ->
MaxBs = MaxB - CurB, IsFirst = CurB =:= FirstPos,
int_split_bins(MaxBs, IsFirst, [], Bins, 0, 0).
+-dialyzer({no_improper_lists, int_split_bins/6}).
int_split_bins(MaxBs, IsFirst, First, [X | Last], Bs, N) ->
Sz = byte_size(X),
NBs = Bs + Sz + ?HEADERSZ,
diff --git a/lib/kernel/src/erl_epmd.erl b/lib/kernel/src/erl_epmd.erl
index 55ce9a7e64..c6202dd796 100644
--- a/lib/kernel/src/erl_epmd.erl
+++ b/lib/kernel/src/erl_epmd.erl
@@ -32,7 +32,7 @@
%% External exports
-export([start/0, start_link/0, stop/0, port_please/2,
port_please/3, names/0, names/1,
- register_node/2, open/0, open/1, open/2]).
+ register_node/2, register_node/3, open/0, open/1, open/2]).
%% gen_server callbacks
-export([init/1, handle_call/3, handle_cast/2, handle_info/2,
@@ -102,7 +102,9 @@ names(EpmdAddr) ->
register_node(Name, PortNo) ->
- gen_server:call(erl_epmd, {register, Name, PortNo}, infinity).
+ register_node(Name, PortNo, inet).
+register_node(Name, PortNo, Family) ->
+ gen_server:call(erl_epmd, {register, Name, PortNo, Family}, infinity).
%%%----------------------------------------------------------------------
%%% Callback functions from gen_server
@@ -120,10 +122,10 @@ init(_) ->
-spec handle_call(calls(), term(), state()) ->
{'reply', term(), state()} | {'stop', 'shutdown', 'ok', state()}.
-handle_call({register, Name, PortNo}, _From, State) ->
+handle_call({register, Name, PortNo, Family}, _From, State) ->
case State#state.socket of
P when P < 0 ->
- case do_register_node(Name, PortNo) of
+ case do_register_node(Name, PortNo, Family) of
{alive, Socket, Creation} ->
S = State#state{socket = Socket,
port_no = PortNo,
@@ -206,8 +208,12 @@ open({A,B,C,D,E,F,G,H}=EpmdAddr, Timeout) when ?ip6(A,B,C,D,E,F,G,H) ->
close(Socket) ->
gen_tcp:close(Socket).
-do_register_node(NodeName, TcpPort) ->
- case open() of
+do_register_node(NodeName, TcpPort, Family) ->
+ Localhost = case Family of
+ inet -> open({127,0,0,1});
+ inet6 -> open({0,0,0,0,0,0,0,1})
+ end,
+ case Localhost of
{ok, Socket} ->
Name = to_string(NodeName),
Extra = "",
diff --git a/lib/kernel/src/file_io_server.erl b/lib/kernel/src/file_io_server.erl
index bf8b9e2747..deb7b315b1 100644
--- a/lib/kernel/src/file_io_server.erl
+++ b/lib/kernel/src/file_io_server.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2000-2013. All Rights Reserved.
+%% Copyright Ericsson AB 2000-2015. 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.
@@ -206,8 +206,8 @@ io_reply(From, ReplyAs, Reply) ->
file_request({advise,Offset,Length,Advise},
#state{handle=Handle}=State) ->
case ?PRIM_FILE:advise(Handle, Offset, Length, Advise) of
- {error,_}=Reply ->
- {stop,normal,Reply,State};
+ {error,Reason}=Reply ->
+ {stop,Reason,Reply,State};
Reply ->
{reply,Reply,State}
end;
@@ -215,62 +215,91 @@ file_request({allocate, Offset, Length},
#state{handle = Handle} = State) ->
Reply = ?PRIM_FILE:allocate(Handle, Offset, Length),
{reply, Reply, State};
+file_request({pread,At,Sz}, State)
+ when At =:= cur;
+ At =:= {cur,0} ->
+ case get_chars(Sz, latin1, State) of
+ {reply,Reply,NewState}
+ when is_list(Reply);
+ is_binary(Reply) ->
+ {reply,{ok,Reply},NewState};
+ Other ->
+ Other
+ end;
file_request({pread,At,Sz},
- #state{handle=Handle,buf=Buf,read_mode=ReadMode}=State) ->
+ #state{handle=Handle,buf=Buf}=State) ->
case position(Handle, At, Buf) of
- {ok,_Offs} ->
- case ?PRIM_FILE:read(Handle, Sz) of
- {ok,Bin} when ReadMode =:= list ->
- std_reply({ok,binary_to_list(Bin)}, State);
- Reply ->
- std_reply(Reply, State)
- end;
- Reply ->
- std_reply(Reply, State)
+ {error,_} = Reply ->
+ {error,Reply,State};
+ _ ->
+ case get_chars(Sz, latin1, State#state{buf= <<>>}) of
+ {reply,Reply,NewState}
+ when is_list(Reply);
+ is_binary(Reply) ->
+ {reply,{ok,Reply},NewState};
+ Other ->
+ Other
+ end
end;
+file_request({pwrite,At,Data},
+ #state{buf= <<>>}=State)
+ when At =:= cur;
+ At =:= {cur,0} ->
+ put_chars(Data, latin1, State);
file_request({pwrite,At,Data},
#state{handle=Handle,buf=Buf}=State) ->
case position(Handle, At, Buf) of
- {ok,_Offs} ->
- std_reply(?PRIM_FILE:write(Handle, Data), State);
- Reply ->
- std_reply(Reply, State)
+ {error,_} = Reply ->
+ {error,Reply,State};
+ _ ->
+ put_chars(Data, latin1, State)
end;
file_request(datasync,
#state{handle=Handle}=State) ->
case ?PRIM_FILE:datasync(Handle) of
- {error,_}=Reply ->
- {stop,normal,Reply,State};
+ {error,Reason}=Reply ->
+ {stop,Reason,Reply,State};
Reply ->
{reply,Reply,State}
end;
file_request(sync,
#state{handle=Handle}=State) ->
case ?PRIM_FILE:sync(Handle) of
- {error,_}=Reply ->
- {stop,normal,Reply,State};
+ {error,Reason}=Reply ->
+ {stop,Reason,Reply,State};
Reply ->
{reply,Reply,State}
end;
file_request(close,
#state{handle=Handle}=State) ->
- {stop,normal,?PRIM_FILE:close(Handle),State#state{buf= <<>>}};
+ case ?PRIM_FILE:close(Handle) of
+ {error,Reason}=Reply ->
+ {stop,Reason,Reply,State#state{buf= <<>>}};
+ Reply ->
+ {stop,normal,Reply,State#state{buf= <<>>}}
+ end;
file_request({position,At},
#state{handle=Handle,buf=Buf}=State) ->
- std_reply(position(Handle, At, Buf), State);
+ case position(Handle, At, Buf) of
+ {error,_} = Reply ->
+ {error,Reply,State};
+ Reply ->
+ std_reply(Reply, State)
+ end;
file_request(truncate,
#state{handle=Handle}=State) ->
case ?PRIM_FILE:truncate(Handle) of
- {error,_Reason}=Reply ->
- {stop,normal,Reply,State#state{buf= <<>>}};
+ {error,Reason}=Reply ->
+ {stop,Reason,Reply,State#state{buf= <<>>}};
Reply ->
- {reply,Reply,State}
+ std_reply(Reply, State)
end;
file_request(Unknown,
#state{}=State) ->
Reason = {request, Unknown},
{error,{error,Reason},State}.
+%% Standard reply and clear buffer
std_reply({error,_}=Reply, State) ->
{error,Reply,State#state{buf= <<>>}};
std_reply(Reply, State) ->
@@ -286,8 +315,8 @@ io_request({put_chars, Enc, Chars},
io_request({put_chars, Enc, Chars},
#state{handle=Handle,buf=Buf}=State) ->
case position(Handle, cur, Buf) of
- {error,_}=Reply ->
- {stop,normal,Reply,State#state{buf= <<>>}};
+ {error,Reason}=Reply ->
+ {stop,Reason,Reply,State};
_ ->
put_chars(Chars, Enc, State#state{buf= <<>>})
end;
@@ -368,23 +397,27 @@ io_request_loop([Request|Tail],
%% I/O request put_chars
%%
put_chars(Chars, latin1, #state{handle=Handle, unic=latin1}=State) ->
+ NewState = State#state{buf = <<>>},
case ?PRIM_FILE:write(Handle, Chars) of
- {error,_}=Reply ->
- {stop,normal,Reply,State};
+ {error,Reason}=Reply ->
+ {stop,Reason,Reply,NewState};
Reply ->
- {reply,Reply,State}
+ {reply,Reply,NewState}
end;
put_chars(Chars, InEncoding, #state{handle=Handle, unic=OutEncoding}=State) ->
+ NewState = State#state{buf = <<>>},
case unicode:characters_to_binary(Chars,InEncoding,OutEncoding) of
Bin when is_binary(Bin) ->
case ?PRIM_FILE:write(Handle, Bin) of
- {error,_}=Reply ->
- {stop,normal,Reply,State};
+ {error,Reason}=Reply ->
+ {stop,Reason,Reply,NewState};
Reply ->
- {reply,Reply,State}
+ {reply,Reply,NewState}
end;
{error,_,_} ->
- {stop,normal,{error,{no_translation, InEncoding, OutEncoding}},State}
+ {stop,no_translation,
+ {error,{no_translation, InEncoding, OutEncoding}},
+ NewState}
end.
get_line(S, {<<>>, Cont}, OutEnc,
@@ -884,11 +917,14 @@ cbv({utf32,little},_) ->
%% Compensates ?PRIM_FILE:position/2 for the number of bytes
%% we have buffered
-
-position(Handle, cur, Buf) ->
- position(Handle, {cur, 0}, Buf);
-position(Handle, {cur, Offs}, Buf) when is_binary(Buf) ->
- ?PRIM_FILE:position(Handle, {cur, Offs-byte_size(Buf)});
-position(Handle, At, _Buf) ->
- ?PRIM_FILE:position(Handle, At).
-
+position(Handle, At, Buf) ->
+ ?PRIM_FILE:position(
+ Handle,
+ case At of
+ cur ->
+ {cur, -byte_size(Buf)};
+ {cur, Offs} ->
+ {cur, Offs-byte_size(Buf)};
+ _ ->
+ At
+ end).
diff --git a/lib/kernel/src/gen_tcp.erl b/lib/kernel/src/gen_tcp.erl
index d7dba4ac80..8cb2a725e8 100644
--- a/lib/kernel/src/gen_tcp.erl
+++ b/lib/kernel/src/gen_tcp.erl
@@ -114,7 +114,8 @@
option().
-type socket() :: port().
--export_type([option/0, option_name/0, connect_option/0, listen_option/0]).
+-export_type([option/0, option_name/0, connect_option/0, listen_option/0,
+ socket/0]).
%%
%% Connect a socket
diff --git a/lib/kernel/src/heart.erl b/lib/kernel/src/heart.erl
index 464b6919f1..eea78aabdf 100644
--- a/lib/kernel/src/heart.erl
+++ b/lib/kernel/src/heart.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2013. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2016. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -34,7 +34,11 @@
%%%
%%% It recognizes the flag '-heart'
%%%--------------------------------------------------------------------
--export([start/0, init/2, set_cmd/1, clear_cmd/0, get_cmd/0, cycle/0]).
+-export([start/0, init/2,
+ set_cmd/1, clear_cmd/0, get_cmd/0,
+ set_callback/2, clear_callback/0, get_callback/0,
+ set_options/1, get_options/0,
+ cycle/0]).
-define(START_ACK, 1).
-define(HEART_BEAT, 2).
@@ -49,6 +53,16 @@
-define(CYCLE_TIMEOUT, 10000).
-define(HEART_PORT_NAME, heart_port).
+%% valid heart options
+-define(SCHEDULER_CHECK_OPT, check_schedulers).
+
+-type heart_option() :: ?SCHEDULER_CHECK_OPT.
+
+-record(state,{port :: port(),
+ cmd :: [] | binary(),
+ options :: [heart_option()],
+ callback :: 'undefined' | {atom(), atom()}}).
+
%%---------------------------------------------------------------------
-spec start() -> 'ignore' | {'error', term()} | {'ok', pid()}.
@@ -81,11 +95,11 @@ wait_for_init_ack(From) ->
init(Starter, Parent) ->
process_flag(trap_exit, true),
process_flag(priority, max),
- register(heart, self()),
+ register(?MODULE, self()),
case catch start_portprogram() of
{ok, Port} ->
Starter ! {ok, self()},
- loop(Parent, Port, "");
+ loop(Parent, #state{port=Port, cmd=[], options=[]});
no_heart ->
Starter ! {no_heart, self()};
error ->
@@ -96,33 +110,68 @@ init(Starter, Parent) ->
Cmd :: string().
set_cmd(Cmd) ->
- heart ! {self(), set_cmd, Cmd},
+ ?MODULE ! {self(), set_cmd, Cmd},
wait().
-spec get_cmd() -> {ok, Cmd} when
Cmd :: string().
get_cmd() ->
- heart ! {self(), get_cmd},
+ ?MODULE ! {self(), get_cmd},
wait().
-spec clear_cmd() -> ok.
clear_cmd() ->
- heart ! {self(), clear_cmd},
+ ?MODULE ! {self(), clear_cmd},
+ wait().
+
+-spec set_callback(Module,Function) -> 'ok' | {'error', {'bad_callback', {Module, Function}}} when
+ Module :: atom(),
+ Function :: atom().
+
+set_callback(Module, Function) ->
+ ?MODULE ! {self(), set_callback, {Module,Function}},
+ wait().
+
+-spec get_callback() -> {'ok', {Module, Function}} | 'none' when
+ Module :: atom(),
+ Function :: atom().
+
+get_callback() ->
+ ?MODULE ! {self(), get_callback},
+ wait().
+
+-spec clear_callback() -> ok.
+
+clear_callback() ->
+ ?MODULE ! {self(), clear_callback},
+ wait().
+
+-spec set_options(Options) -> 'ok' | {'error', {'bad_options', Options}} when
+ Options :: [heart_option()].
+
+set_options(Options) ->
+ ?MODULE ! {self(), set_options, Options},
wait().
+-spec get_options() -> {'ok', Options} | 'none' when
+ Options :: [atom()].
+
+get_options() ->
+ ?MODULE ! {self(), get_options},
+ wait().
%%% Should be used solely by the release handler!!!!!!!
-spec cycle() -> 'ok' | {'error', term()}.
cycle() ->
- heart ! {self(), cycle},
+ ?MODULE ! {self(), cycle},
wait().
wait() ->
receive
- {heart, Res} ->
+ {?MODULE, Res} ->
Res
end.
@@ -182,8 +231,8 @@ wait_ack(Port) ->
{error, Reason}
end.
-loop(Parent, Port, Cmd) ->
- _ = send_heart_beat(Port),
+loop(Parent, #state{port=Port}=S) ->
+ _ = send_heart_beat(S),
receive
{From, set_cmd, NewCmd0} ->
Enc = file:native_name_encoding(),
@@ -191,37 +240,72 @@ loop(Parent, Port, Cmd) ->
NewCmd when is_binary(NewCmd), byte_size(NewCmd) < 2047 ->
_ = send_heart_cmd(Port, NewCmd),
_ = wait_ack(Port),
- From ! {heart, ok},
- loop(Parent, Port, NewCmd);
+ From ! {?MODULE, ok},
+ loop(Parent, S#state{cmd=NewCmd});
_ ->
- From ! {heart, {error, {bad_cmd, NewCmd0}}},
- loop(Parent, Port, Cmd)
+ From ! {?MODULE, {error, {bad_cmd, NewCmd0}}},
+ loop(Parent, S)
end;
{From, clear_cmd} ->
- From ! {heart, ok},
- _ = send_heart_cmd(Port, ""),
+ From ! {?MODULE, ok},
+ _ = send_heart_cmd(Port, []),
_ = wait_ack(Port),
- loop(Parent, Port, "");
+ loop(Parent, S#state{cmd = []});
{From, get_cmd} ->
- From ! {heart, get_heart_cmd(Port)},
- loop(Parent, Port, Cmd);
+ From ! {?MODULE, get_heart_cmd(Port)},
+ loop(Parent, S);
+ {From, set_callback, Callback} ->
+ case Callback of
+ {M,F} when is_atom(M), is_atom(F) ->
+ From ! {?MODULE, ok},
+ loop(Parent, S#state{callback=Callback});
+ _ ->
+ From ! {?MODULE, {error, {bad_callback, Callback}}},
+ loop(Parent, S)
+ end;
+ {From, get_callback} ->
+ Res = case S#state.callback of
+ undefined -> none;
+ Cb -> {ok, Cb}
+ end,
+ From ! {?MODULE, Res},
+ loop(Parent, S);
+ {From, clear_callback} ->
+ From ! {?MODULE, ok},
+ loop(Parent, S#state{callback=undefined});
+ {From, set_options, Options} ->
+ case validate_options(Options) of
+ Validated when is_list(Validated) ->
+ From ! {?MODULE, ok},
+ loop(Parent, S#state{options=Validated});
+ _ ->
+ From ! {?MODULE, {error, {bad_options, Options}}},
+ loop(Parent, S)
+ end;
+ {From, get_options} ->
+ Res = case S#state.options of
+ [] -> none;
+ Cb -> {ok, Cb}
+ end,
+ From ! {?MODULE, Res},
+ loop(Parent, S);
{From, cycle} ->
%% Calls back to loop
- do_cycle_port_program(From, Parent, Port, Cmd);
+ do_cycle_port_program(From, Parent, S);
{'EXIT', Parent, shutdown} ->
no_reboot_shutdown(Port);
{'EXIT', Parent, Reason} ->
exit(Port, Reason),
exit(Reason);
{'EXIT', Port, badsig} -> % we can ignore badsig-messages!
- loop(Parent, Port, Cmd);
+ loop(Parent, S);
{'EXIT', Port, _Reason} ->
- exit({port_terminated, {heart, loop, [Parent, Port, Cmd]}});
+ exit({port_terminated, {?MODULE, loop, [Parent, S]}});
_ ->
- loop(Parent, Port, Cmd)
+ loop(Parent, S)
after
?TIMEOUT ->
- loop(Parent, Port, Cmd)
+ loop(Parent, S)
end.
-spec no_reboot_shutdown(port()) -> no_return().
@@ -233,38 +317,47 @@ no_reboot_shutdown(Port) ->
exit(normal)
end.
-do_cycle_port_program(Caller, Parent, Port, Cmd) ->
+validate_options(Opts) -> validate_options(Opts,[]).
+validate_options([],Res) -> Res;
+validate_options([?SCHEDULER_CHECK_OPT=Opt|Opts],Res) -> validate_options(Opts,[Opt|Res]);
+validate_options(_,_) -> error.
+
+do_cycle_port_program(Caller, Parent, #state{port=Port} = S) ->
unregister(?HEART_PORT_NAME),
case catch start_portprogram() of
{ok, NewPort} ->
_ = send_shutdown(Port),
receive
{'EXIT', Port, _Reason} ->
- _ = send_heart_cmd(NewPort, Cmd),
- Caller ! {heart, ok},
- loop(Parent, NewPort, Cmd)
+ _ = send_heart_cmd(NewPort, S#state.cmd),
+ Caller ! {?MODULE, ok},
+ loop(Parent, S#state{port=NewPort})
after
?CYCLE_TIMEOUT ->
%% Huh! Two heart port programs running...
%% well, the old one has to be sick not to respond
%% so we'll settle for the new one...
- _ = send_heart_cmd(NewPort, Cmd),
- Caller ! {heart, {error, stop_error}},
- loop(Parent, NewPort, Cmd)
+ _ = send_heart_cmd(NewPort, S#state.cmd),
+ Caller ! {?MODULE, {error, stop_error}},
+ loop(Parent, S#state{port=NewPort})
end;
no_heart ->
- Caller ! {heart, {error, no_heart}},
- loop(Parent, Port, Cmd);
+ Caller ! {?MODULE, {error, no_heart}},
+ loop(Parent, S);
error ->
- Caller ! {heart, {error, start_error}},
- loop(Parent, Port, Cmd)
+ Caller ! {?MODULE, {error, start_error}},
+ loop(Parent, S)
end.
%% "Beates" the heart once.
-send_heart_beat(Port) -> Port ! {self(), {command, [?HEART_BEAT]}}.
+send_heart_beat(#state{port=Port, callback=Cb, options=Opts}) ->
+ ok = check_system(Opts),
+ ok = check_callback(Cb),
+ Port ! {self(), {command, [?HEART_BEAT]}}.
%% Set a new HEART_COMMAND.
+-dialyzer({no_improper_lists, send_heart_cmd/2}).
send_heart_cmd(Port, []) ->
Port ! {self(), {command, [?CLEAR_CMD]}};
send_heart_cmd(Port, Cmd) ->
@@ -277,6 +370,24 @@ get_heart_cmd(Port) ->
{ok, Cmd}
end.
+check_system([]) -> ok;
+check_system([?SCHEDULER_CHECK_OPT|Opts]) ->
+ ok = erts_internal:system_check(schedulers),
+ check_system(Opts).
+
+%% validate system by performing a check before the heartbeat
+%% return 'ok' if everything is alright.
+%% Terminate if with reason if something is a miss.
+%% It is fine to timeout in the callback, in fact that is the intention
+%% if something goes wront -> no heartbeat.
+
+check_callback(Callback) ->
+ case Callback of
+ undefined -> ok;
+ {M,F} ->
+ erlang:apply(M,F,[])
+ end.
+
%% Sends shutdown command to the port.
send_shutdown(Port) -> Port ! {self(), {command, [?SHUT_DOWN]}}.
diff --git a/lib/kernel/src/inet.erl b/lib/kernel/src/inet.erl
index da7f04089d..c1ae99ea24 100644
--- a/lib/kernel/src/inet.erl
+++ b/lib/kernel/src/inet.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2015. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2016. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -289,7 +289,7 @@ getifaddrs(Socket) ->
-spec getifaddrs() -> {ok, Iflist} | {error, posix()} when
Iflist :: [{Ifname,[Ifopt]}],
Ifname :: string(),
- Ifopt :: {flag,[Flag]} | {addr,Addr} | {netmask,Netmask}
+ Ifopt :: {flags,[Flag]} | {addr,Addr} | {netmask,Netmask}
| {broadaddr,Broadaddr} | {dstaddr,Dstaddr}
| {hwaddr,Hwaddr},
Flag :: up | broadcast | loopback | pointtopoint
@@ -671,7 +671,7 @@ stats() ->
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
connect_options() ->
[tos, priority, reuseaddr, keepalive, linger, sndbuf, recbuf, nodelay,
- header, active, packet, packet_size, buffer, mode, deliver,
+ header, active, packet, packet_size, buffer, mode, deliver, line_delimiter,
exit_on_close, high_watermark, low_watermark, high_msgq_watermark,
low_msgq_watermark, send_timeout, send_timeout_close, delay_send, raw,
show_econnreset].
@@ -692,6 +692,7 @@ connect_options(Opts, Family) ->
case con_opt(Opts, BaseOpts, connect_options()) of
{ok, R} ->
{ok, R#connect_opts {
+ opts = lists:reverse(R#connect_opts.opts),
ifaddr = translate_ip(R#connect_opts.ifaddr, Family)
}};
Error -> Error
@@ -721,6 +722,8 @@ con_opt([Opt | Opts], #connect_opts{} = R, As) ->
{active,N} when is_integer(N), N < 32768, N >= -32768 ->
NOpts = lists:keydelete(active, 1, R#connect_opts.opts),
con_opt(Opts, R#connect_opts { opts = [{active,N}|NOpts] }, As);
+ {line_delimiter,C} when is_integer(C), C >= 0, C =< 255 ->
+ con_add(line_delimiter, C, R, Opts, As);
{Name,Val} when is_atom(Name) -> con_add(Name, Val, R, Opts, As);
_ -> {error, badarg}
end;
@@ -760,6 +763,7 @@ listen_options(Opts, Family) ->
case list_opt(Opts, BaseOpts, listen_options()) of
{ok, R} ->
{ok, R#listen_opts {
+ opts = lists:reverse(R#listen_opts.opts),
ifaddr = translate_ip(R#listen_opts.ifaddr, Family)
}};
Error -> Error
@@ -818,6 +822,7 @@ udp_options(Opts, Family) ->
case udp_opt(Opts, #udp_opts { }, udp_options()) of
{ok, R} ->
{ok, R#udp_opts {
+ opts = lists:reverse(R#udp_opts.opts),
ifaddr = translate_ip(R#udp_opts.ifaddr, Family)
}};
Error -> Error
@@ -891,9 +896,12 @@ sctp_options() ->
sctp_options(Opts, Mod) ->
case sctp_opt(Opts, Mod, #sctp_opts{}, sctp_options()) of
{ok,#sctp_opts{ifaddr=undefined}=SO} ->
- {ok,SO#sctp_opts{ifaddr=Mod:translate_ip(?SCTP_DEF_IFADDR)}};
- {ok,_}=OK ->
- OK;
+ {ok,
+ SO#sctp_opts{
+ opts=lists:reverse(SO#sctp_opts.opts),
+ ifaddr=Mod:translate_ip(?SCTP_DEF_IFADDR)}};
+ {ok,SO} ->
+ {ok,SO#sctp_opts{opts=lists:reverse(SO#sctp_opts.opts)}};
Error -> Error
end.
@@ -965,6 +973,8 @@ add_opt(Name, Val, Opts, As) ->
case lists:member(Name, As) of
true ->
case prim_inet:is_sockopt_val(Name, Val) of
+ true when Name =:= raw ->
+ {ok, [{Name,Val} | Opts]};
true ->
Opts1 = lists:keydelete(Name, 1, Opts),
{ok, [{Name,Val} | Opts1]};
diff --git a/lib/kernel/src/inet6_tcp.erl b/lib/kernel/src/inet6_tcp.erl
index 2ea017285c..1978307b3c 100644
--- a/lib/kernel/src/inet6_tcp.erl
+++ b/lib/kernel/src/inet6_tcp.erl
@@ -25,10 +25,29 @@
-export([controlling_process/2]).
-export([fdopen/2]).
+-export([family/0, mask/2, parse_address/1]).
-export([getserv/1, getaddr/1, getaddr/2, getaddrs/1, getaddrs/2]).
-include("inet_int.hrl").
+%% my address family
+family() -> inet6.
+
+%% Apply netmask on address
+mask({M1,M2,M3,M4,M5,M6,M7,M8}, {IP1,IP2,IP3,IP4,IP5,IP6,IP7,IP8}) ->
+ {M1 band IP1,
+ M2 band IP2,
+ M3 band IP3,
+ M4 band IP4,
+ M5 band IP5,
+ M6 band IP6,
+ M7 band IP7,
+ M8 band IP8 }.
+
+%% Parse address string
+parse_address(Host) ->
+ inet_parse:ipv6strict_address(Host).
+
%% inet_tcp port lookup
getserv(Port) when is_integer(Port) -> {ok, Port};
getserv(Name) when is_atom(Name) -> inet:getservbyname(Name,tcp).
diff --git a/lib/kernel/src/inet6_tcp_dist.erl b/lib/kernel/src/inet6_tcp_dist.erl
index a74a4916ba..3ab7f269bb 100644
--- a/lib/kernel/src/inet6_tcp_dist.erl
+++ b/lib/kernel/src/inet6_tcp_dist.erl
@@ -24,28 +24,6 @@
-export([listen/1, accept/1, accept_connection/5,
setup/5, close/1, select/1, is_node_name/1]).
-%% internal exports
-
--export([accept_loop/2,do_accept/6,do_setup/6, getstat/1,tick/1]).
-
--import(error_logger,[error_msg/2]).
-
--include("net_address.hrl").
-
-
-
--define(to_port(Socket, Data, Opts),
- case inet6_tcp:send(Socket, Data, Opts) of
- {error, closed} ->
- self() ! {tcp_closed, Socket},
- {error, closed};
- R ->
- R
- end).
-
-
--include("dist.hrl").
--include("dist_util.hrl").
%% ------------------------------------------------------------
%% Select this protocol based on node name
@@ -53,14 +31,7 @@
%% ------------------------------------------------------------
select(Node) ->
- case split_node(atom_to_list(Node), $@, []) of
- [_, Host] ->
- case inet:getaddr(Host,inet6) of
- {ok,_} -> true;
- _ -> false
- end;
- _ -> false
- end.
+ inet_tcp_dist:gen_select(inet6_tcp, Node).
%% ------------------------------------------------------------
%% Create the listen socket, i.e. the port that this erlang
@@ -68,59 +39,14 @@ select(Node) ->
%% ------------------------------------------------------------
listen(Name) ->
- case inet6_tcp:listen(0, [{active, false}, {packet,2}]) of
- {ok, Socket} ->
- TcpAddress = get_tcp_address(Socket),
- {_,Port} = TcpAddress#net_address.address,
- case erl_epmd:register_node(Name, Port) of
- {ok, Creation} ->
- {ok, {Socket, TcpAddress, Creation}};
- Error ->
- Error
- end;
- Error ->
- Error
- end.
+ inet_tcp_dist:gen_listen(inet6_tcp, Name).
%% ------------------------------------------------------------
%% Accepts new connection attempts from other Erlang nodes.
%% ------------------------------------------------------------
accept(Listen) ->
- spawn_opt(?MODULE, accept_loop, [self(), Listen], [link, {priority, max}]).
-
-accept_loop(Kernel, Listen) ->
- case inet6_tcp:accept(Listen) of
- {ok, Socket} ->
- Kernel ! {accept,self(),Socket,inet6,tcp},
- _ = controller(Kernel, Socket),
- accept_loop(Kernel, Listen);
- Error ->
- exit(Error)
- end.
-
-controller(Kernel, Socket) ->
- receive
- {Kernel, controller, Pid} ->
- flush_controller(Pid, Socket),
- inet6_tcp:controlling_process(Socket, Pid),
- flush_controller(Pid, Socket),
- Pid ! {self(), controller};
- {Kernel, unsupported_protocol} ->
- exit(unsupported_protocol)
- end.
-
-flush_controller(Pid, Socket) ->
- receive
- {tcp, Socket, Data} ->
- Pid ! {tcp, Socket, Data},
- flush_controller(Pid, Socket);
- {tcp_closed, Socket} ->
- Pid ! {tcp_closed, Socket},
- flush_controller(Pid, Socket)
- after 0 ->
- ok
- end.
+ inet_tcp_dist:gen_accept(inet6_tcp, Listen).
%% ------------------------------------------------------------
%% Accepts a new connection attempt from another Erlang node.
@@ -128,85 +54,7 @@ flush_controller(Pid, Socket) ->
%% ------------------------------------------------------------
accept_connection(AcceptPid, Socket, MyNode, Allowed, SetupTime) ->
- spawn_opt(?MODULE, do_accept,
- [self(), AcceptPid, Socket, MyNode, Allowed, SetupTime],
- [link, {priority, max}]).
-
-do_accept(Kernel, AcceptPid, Socket, MyNode, Allowed, SetupTime) ->
- receive
- {AcceptPid, controller} ->
- Timer = dist_util:start_timer(SetupTime),
- case check_ip(Socket) of
- true ->
- HSData = #hs_data{
- kernel_pid = Kernel,
- this_node = MyNode,
- socket = Socket,
- timer = Timer,
- this_flags = 0,
- allowed = Allowed,
- f_send = fun(S,D) -> inet6_tcp:send(S,D) end,
- f_recv = fun(S,N,T) -> inet6_tcp:recv(S,N,T)
- end,
- f_setopts_pre_nodeup =
- fun(S) ->
- inet:setopts(S,
- [{active, false},
- {packet, 4},
- nodelay()])
- end,
- f_setopts_post_nodeup =
- fun(S) ->
- inet:setopts(S,
- [{active, true},
- {deliver, port},
- {packet, 4},
- nodelay()])
- end,
- f_getll = fun(S) ->
- inet:getll(S)
- end,
- f_address = fun get_remote_id/2,
- mf_tick = fun ?MODULE:tick/1,
- mf_getstat = fun ?MODULE:getstat/1
- },
- dist_util:handshake_other_started(HSData);
- {false,IP} ->
- error_msg("** Connection attempt from "
- "disallowed IP ~w ** ~n", [IP]),
- ?shutdown(no_node)
- end
- end.
-
-
-%% we may not always want the nodelay behaviour
-%% for performance reasons
-
-nodelay() ->
- case application:get_env(kernel, dist_nodelay) of
- undefined ->
- {nodelay, true};
- {ok, true} ->
- {nodelay, true};
- {ok, false} ->
- {nodelay, false};
- _ ->
- {nodelay, true}
- end.
-
-
-%% ------------------------------------------------------------
-%% Get remote information about a Socket.
-%% ------------------------------------------------------------
-
-get_remote_id(Socket, Node) ->
- {ok, Address} = inet:peername(Socket),
- [_, Host] = split_node(atom_to_list(Node), $@, []),
- #net_address {
- address = Address,
- host = Host,
- protocol = tcp,
- family = inet6 }.
+ inet_tcp_dist:gen_accept_connection(inet6_tcp, AcceptPid, Socket, MyNode, Allowed, SetupTime).
%% ------------------------------------------------------------
%% Setup a new connection to another Erlang node.
@@ -214,214 +62,13 @@ get_remote_id(Socket, Node) ->
%% ------------------------------------------------------------
setup(Node, Type, MyNode, LongOrShortNames,SetupTime) ->
- spawn_opt(?MODULE, do_setup,
- [self(), Node, Type, MyNode, LongOrShortNames, SetupTime],
- [link, {priority, max}]).
-
-do_setup(Kernel, Node, Type, MyNode, LongOrShortNames,SetupTime) ->
- ?trace("~p~n",[{?MODULE,self(),setup,Node}]),
- [Name, Address] = splitnode(Node, LongOrShortNames),
- case inet:getaddr(Address, inet6) of
- {ok, Ip} ->
- Timer = dist_util:start_timer(SetupTime),
- case erl_epmd:port_please(Name, Ip) of
- {port, TcpPort, Version} ->
- ?trace("port_please(~p) -> version ~p~n",
- [Node,Version]),
- dist_util:reset_timer(Timer),
- case inet6_tcp:connect(Ip, TcpPort,
- [{active, false},
- {packet,2}]) of
- {ok, Socket} ->
- HSData = #hs_data{
- kernel_pid = Kernel,
- other_node = Node,
- this_node = MyNode,
- socket = Socket,
- timer = Timer,
- this_flags = 0,
- other_version = Version,
- f_send = fun inet6_tcp:send/2,
- f_recv = fun inet6_tcp:recv/3,
- f_setopts_pre_nodeup =
- fun(S) ->
- inet:setopts
- (S,
- [{active, false},
- {packet, 4},
- nodelay()])
- end,
- f_setopts_post_nodeup =
- fun(S) ->
- inet:setopts
- (S,
- [{active, true},
- {deliver, port},
- {packet, 4},
- nodelay()])
- end,
- f_getll = fun inet:getll/1,
- f_address =
- fun(_,_) ->
- #net_address {
- address = {Ip,TcpPort},
- host = Address,
- protocol = tcp,
- family = inet6}
- end,
- mf_tick = fun ?MODULE:tick/1,
- mf_getstat = fun ?MODULE:getstat/1,
- request_type = Type
- },
- dist_util:handshake_we_started(HSData);
- _ ->
- %% Other Node may have closed since
- %% port_please !
- ?trace("other node (~p) "
- "closed since port_please.~n",
- [Node]),
- ?shutdown(Node)
- end;
- _ ->
- ?trace("port_please (~p) "
- "failed.~n", [Node]),
- ?shutdown(Node)
- end;
- __Other ->
- ?trace("inet_getaddr(~p) "
- "failed (~p).~n", [Node,__Other]),
- ?shutdown(Node)
- end.
+ inet_tcp_dist:gen_setup(inet6_tcp, Node, Type, MyNode, LongOrShortNames, SetupTime).
%%
%% Close a socket.
%%
close(Socket) ->
inet6_tcp:close(Socket).
-
-
-%% If Node is illegal terminate the connection setup!!
-splitnode(Node, LongOrShortNames) ->
- case split_node(atom_to_list(Node), $@, []) of
- [Name|Tail] when Tail =/= [] ->
- Host = lists:append(Tail),
- case split_node(Host, $., []) of
- [_] when LongOrShortNames =:= longnames ->
- case inet_parse:ipv6strict_address(Host) of
- {ok, _} ->
- [Name, Host];
- _ ->
- error_msg("** System running to use "
- "fully qualified "
- "hostnames **~n"
- "** Hostname ~s is illegal **~n",
- [Host]),
- ?shutdown(Node)
- end;
- L when length(L) > 1, LongOrShortNames =:= shortnames ->
- error_msg("** System NOT running to use fully qualified "
- "hostnames **~n"
- "** Hostname ~s is illegal **~n",
- [Host]),
- ?shutdown(Node);
- _ ->
- [Name, Host]
- end;
- [_] ->
- error_msg("** Nodename ~p illegal, no '@' character **~n",
- [Node]),
- ?shutdown(Node);
- _ ->
- error_msg("** Nodename ~p illegal **~n", [Node]),
- ?shutdown(Node)
- end.
-
-split_node([Chr|T], Chr, Ack) -> [lists:reverse(Ack)|split_node(T, Chr, [])];
-split_node([H|T], Chr, Ack) -> split_node(T, Chr, [H|Ack]);
-split_node([], _, Ack) -> [lists:reverse(Ack)].
-
-%% ------------------------------------------------------------
-%% Fetch local information about a Socket.
-%% ------------------------------------------------------------
-get_tcp_address(Socket) ->
- {ok, Address} = inet:sockname(Socket),
- {ok, Host} = inet:gethostname(),
- #net_address {
- address = Address,
- host = Host,
- protocol = tcp,
- family = inet6
- }.
-
-%% ------------------------------------------------------------
-%% Do only accept new connection attempts from nodes at our
-%% own LAN, if the check_ip environment parameter is true.
-%% ------------------------------------------------------------
-check_ip(Socket) ->
- case application:get_env(check_ip) of
- {ok, true} ->
- case get_ifs(Socket) of
- {ok, IFs, IP} ->
- check_ip(IFs, IP);
- _ ->
- ?shutdown(no_node)
- end;
- _ ->
- true
- end.
-
-get_ifs(Socket) ->
- case inet:peername(Socket) of
- {ok, {IP, _}} ->
- case inet:getif(Socket) of
- {ok, IFs} -> {ok, IFs, IP};
- Error -> Error
- end;
- Error ->
- Error
- end.
-
-check_ip([{OwnIP, _, Netmask}|IFs], PeerIP) ->
- case {mask(Netmask, PeerIP), mask(Netmask, OwnIP)} of
- {M, M} -> true;
- _ -> check_ip(IFs, PeerIP)
- end;
-check_ip([], PeerIP) ->
- {false, PeerIP}.
-mask({M1,M2,M3,M4,M5,M6,M7,M8}, {IP1,IP2,IP3,IP4,IP5,IP6,IP7,IP8}) ->
- {M1 band IP1,
- M2 band IP2,
- M3 band IP3,
- M4 band IP4,
- M5 band IP5,
- M6 band IP6,
- M7 band IP7,
- M8 band IP8 }.
-
is_node_name(Node) when is_atom(Node) ->
- case split_node(atom_to_list(Node), $@, []) of
- [_,_Host] -> true;
- _ -> false
- end;
-is_node_name(_Node) ->
- false.
-tick(Sock) ->
- ?to_port(Sock,[],[force]).
-getstat(Socket) ->
- case inet:getstat(Socket, [recv_cnt, send_cnt, send_pend]) of
- {ok, Stat} ->
- split_stat(Stat,0,0,0);
- Error ->
- Error
- end.
-
-split_stat([{recv_cnt, R}|Stat], _, W, P) ->
- split_stat(Stat, R, W, P);
-split_stat([{send_cnt, W}|Stat], R, _, P) ->
- split_stat(Stat, R, W, P);
-split_stat([{send_pend, P}|Stat], R, W, _) ->
- split_stat(Stat, R, W, P);
-split_stat([], R, W, P) ->
- {ok, R, W, P}.
-
+ inet_tcp_dist:is_node_name(Node).
diff --git a/lib/kernel/src/inet_db.erl b/lib/kernel/src/inet_db.erl
index 1621efbfd7..108a803610 100644
--- a/lib/kernel/src/inet_db.erl
+++ b/lib/kernel/src/inet_db.erl
@@ -633,20 +633,22 @@ make_hostent(Name, Datas, Aliases, Type) ->
hostent_by_domain(Domain, Type) ->
?dbg("hostent_by_domain: ~p~n", [Domain]),
- hostent_by_domain(stripdot(Domain), [], Type).
+ hostent_by_domain(stripdot(Domain), [], [], Type).
-hostent_by_domain(Domain, Aliases, Type) ->
+hostent_by_domain(Domain, Aliases, LAliases, Type) ->
case lookup_type(Domain, Type) of
[] ->
case lookup_cname(Domain) of
[] ->
{error, nxdomain};
[CName | _] ->
- case lists:member(CName, [Domain | Aliases]) of
+ LDomain = tolower(Domain),
+ case lists:member(CName, [LDomain | LAliases]) of
true ->
{error, nxdomain};
false ->
- hostent_by_domain(CName, [Domain | Aliases], Type)
+ hostent_by_domain(CName, [Domain | Aliases],
+ [LDomain | LAliases], Type)
end
end;
Addrs ->
@@ -671,24 +673,26 @@ lookup_rr(Domain, Class, Type) ->
%% match data field directly and cache RRs.
%%
res_hostent_by_domain(Domain, Type, Rec) ->
- res_cache_answer(Rec),
- RRs = Rec#dns_rec.anlist,
+ RRs = lists:map(fun lower_rr/1, Rec#dns_rec.anlist),
+ res_cache_answer(Rec#dns_rec{anlist = RRs}),
?dbg("res_hostent_by_domain: ~p - ~p~n", [Domain, RRs]),
- res_hostent_by_domain(stripdot(Domain), [], Type, RRs).
+ res_hostent_by_domain(stripdot(Domain), [], [], Type, RRs).
-res_hostent_by_domain(Domain, Aliases, Type, RRs) ->
- case res_lookup_type(Domain, Type, RRs) of
+res_hostent_by_domain(Domain, Aliases, LAliases, Type, RRs) ->
+ LDomain = tolower(Domain),
+ case res_lookup_type(LDomain, Type, RRs) of
[] ->
- case res_lookup_type(Domain, ?S_CNAME, RRs) of
+ case res_lookup_type(LDomain, ?S_CNAME, RRs) of
[] ->
{error, nxdomain};
[CName | _] ->
- case lists:member(CName, [Domain | Aliases]) of
+ case lists:member(tolower(CName), [LDomain | LAliases]) of
true ->
{error, nxdomain};
false ->
res_hostent_by_domain(CName, [Domain | Aliases],
- Type, RRs)
+ [LDomain | LAliases], Type,
+ RRs)
end
end;
Addrs ->
@@ -721,7 +725,8 @@ gethostbyaddr(IP) ->
%%
res_gethostbyaddr(IP, Rec) ->
{ok, {IP1, HType, HLen}} = dnt(IP),
- res_cache_answer(Rec),
+ RRs = lists:map(fun lower_rr/1, Rec#dns_rec.anlist),
+ res_cache_answer(Rec#dns_rec{anlist = RRs}),
ent_gethostbyaddr(Rec#dns_rec.anlist, IP1, HType, HLen).
ent_gethostbyaddr(RRs, IP, AddrType, Length) ->
@@ -1378,7 +1383,7 @@ times() ->
%% lookup and remove old entries
do_lookup_rr(Domain, Class, Type) ->
- match_rr(#dns_rr{domain = Domain, class = Class,type = Type,
+ match_rr(#dns_rr{domain = tolower(Domain), class = Class,type = Type,
cnt = '_', tm = '_', ttl = '_',
bm = '_', func = '_', data = '_'}).
@@ -1400,6 +1405,11 @@ filter_rr([RR | RRs], Time) ->
[RR | filter_rr(RRs, Time)];
filter_rr([], _Time) -> [].
+%% Lower case the domain name before storage.
+%%
+lower_rr(#dns_rr{domain=Domain}=RR) when is_list(Domain) ->
+ RR#dns_rr { domain = tolower(Domain) };
+lower_rr(RR) -> RR.
%%
%% Case fold upper-case to lower-case according to RFC 4343
diff --git a/lib/kernel/src/inet_dns_record_adts.pl b/lib/kernel/src/inet_dns_record_adts.pl
index 657d2b9d35..6d719d836e 100644
--- a/lib/kernel/src/inet_dns_record_adts.pl
+++ b/lib/kernel/src/inet_dns_record_adts.pl
@@ -57,7 +57,8 @@ while(<DATA>) {
$" = ',';
$\ = "\n";
-while( my ($Name, $r) = each(%Names)) {
+foreach my $Name (sort keys %Names) {
+ my $r = $Names{$Name};
# Create substitutions for this Name
my ($Record, @Fields) = @{ $r };
my @FieldMatchValues;
@@ -110,7 +111,8 @@ while( my ($Name, $r) = each(%Names)) {
for my $i ( 0 .. $#INDEX ) {
my $line = $INDEX[$i];
if ($line =~ s/^[*]//) {
- while( my ($Name, $r) = each(%Names)) {
+ foreach my $Name (sort keys %Names) {
+ my $r = $Names{$Name};
my ($Record) = @{ $r };
$_ = $line;
s/Name\b/$Name/g;
diff --git a/lib/kernel/src/inet_int.hrl b/lib/kernel/src/inet_int.hrl
index bfe4c9ec8c..e7c6cf8ae2 100644
--- a/lib/kernel/src/inet_int.hrl
+++ b/lib/kernel/src/inet_int.hrl
@@ -149,6 +149,7 @@
-define(INET_LOPT_MSGQ_LOWTRMRK, 37).
-define(INET_LOPT_NETNS, 38).
-define(INET_LOPT_TCP_SHOW_ECONNRESET, 39).
+-define(INET_LOPT_LINE_DELIM, 40).
% Specific SCTP options: separate range:
-define(SCTP_OPT_RTOINFO, 100).
-define(SCTP_OPT_ASSOCINFO, 101).
diff --git a/lib/kernel/src/inet_tcp.erl b/lib/kernel/src/inet_tcp.erl
index b5c758c02c..f551af9709 100644
--- a/lib/kernel/src/inet_tcp.erl
+++ b/lib/kernel/src/inet_tcp.erl
@@ -27,11 +27,25 @@
-export([controlling_process/2]).
-export([fdopen/2]).
+-export([family/0, mask/2, parse_address/1]).
-export([getserv/1, getaddr/1, getaddr/2, getaddrs/1, getaddrs/2]).
-
-include("inet_int.hrl").
+%% my address family
+family() -> inet.
+
+%% Apply netmask on address
+mask({M1,M2,M3,M4}, {IP1,IP2,IP3,IP4}) ->
+ {M1 band IP1,
+ M2 band IP2,
+ M3 band IP3,
+ M4 band IP4}.
+
+%% Parse address string
+parse_address(Host) ->
+ inet_parse:ipv4strict_address(Host).
+
%% inet_tcp port lookup
getserv(Port) when is_integer(Port) -> {ok, Port};
getserv(Name) when is_atom(Name) -> inet:getservbyname(Name,tcp).
diff --git a/lib/kernel/src/inet_tcp_dist.erl b/lib/kernel/src/inet_tcp_dist.erl
index 1bdc1c9ed8..64b28bb49b 100644
--- a/lib/kernel/src/inet_tcp_dist.erl
+++ b/lib/kernel/src/inet_tcp_dist.erl
@@ -24,9 +24,13 @@
-export([listen/1, accept/1, accept_connection/5,
setup/5, close/1, select/1, is_node_name/1]).
+%% Generalized dist API
+-export([gen_listen/2, gen_accept/2, gen_accept_connection/6,
+ gen_setup/6, gen_select/2]).
+
%% internal exports
--export([accept_loop/2,do_accept/6,do_setup/6,getstat/1,tick/1]).
+-export([accept_loop/3,do_accept/7,do_setup/7,getstat/1]).
-import(error_logger,[error_msg/2]).
@@ -34,15 +38,6 @@
--define(to_port(Socket, Data, Opts),
- case inet_tcp:send(Socket, Data, Opts) of
- {error, closed} ->
- self() ! {tcp_closed, Socket},
- {error, closed};
- R ->
- R
- end).
-
-include("dist.hrl").
-include("dist_util.hrl").
@@ -53,8 +48,15 @@
%% ------------------------------------------------------------
select(Node) ->
+ gen_select(inet_tcp, Node).
+
+gen_select(Driver, Node) ->
case split_node(atom_to_list(Node), $@, []) of
- [_,_Host] -> true;
+ [_, Host] ->
+ case inet:getaddr(Host, Driver:family()) of
+ {ok,_} -> true;
+ _ -> false
+ end;
_ -> false
end.
@@ -64,9 +66,12 @@ select(Node) ->
%% ------------------------------------------------------------
listen(Name) ->
- case do_listen([{active, false}, {packet,2}, {reuseaddr, true}]) of
+ gen_listen(inet_tcp, Name).
+
+gen_listen(Driver, Name) ->
+ case do_listen(Driver, [{active, false}, {packet,2}, {reuseaddr, true}]) of
{ok, Socket} ->
- TcpAddress = get_tcp_address(Socket),
+ TcpAddress = get_tcp_address(Driver, Socket),
{_,Port} = TcpAddress#net_address.address,
case erl_epmd:register_node(Name, Port) of
{ok, Creation} ->
@@ -78,7 +83,7 @@ listen(Name) ->
Error
end.
-do_listen(Options) ->
+do_listen(Driver, Options) ->
{First,Last} = case application:get_env(kernel,inet_dist_listen_min) of
{ok,N} when is_integer(N) ->
case application:get_env(kernel,
@@ -91,14 +96,14 @@ do_listen(Options) ->
_ ->
{0,0}
end,
- do_listen(First, Last, listen_options([{backlog,128}|Options])).
+ do_listen(Driver, First, Last, listen_options([{backlog,128}|Options])).
-do_listen(First,Last,_) when First > Last ->
+do_listen(_Driver, First,Last,_) when First > Last ->
{error,eaddrinuse};
-do_listen(First,Last,Options) ->
- case inet_tcp:listen(First, Options) of
+do_listen(Driver, First,Last,Options) ->
+ case Driver:listen(First, Options) of
{error, eaddrinuse} ->
- do_listen(First+1,Last,Options);
+ do_listen(Driver, First+1,Last,Options);
Other ->
Other
end.
@@ -124,23 +129,26 @@ listen_options(Opts0) ->
%% ------------------------------------------------------------
accept(Listen) ->
- spawn_opt(?MODULE, accept_loop, [self(), Listen], [link, {priority, max}]).
+ gen_accept(inet_tcp, Listen).
-accept_loop(Kernel, Listen) ->
- case inet_tcp:accept(Listen) of
+gen_accept(Driver, Listen) ->
+ spawn_opt(?MODULE, accept_loop, [Driver, self(), Listen], [link, {priority, max}]).
+
+accept_loop(Driver, Kernel, Listen) ->
+ case Driver:accept(Listen) of
{ok, Socket} ->
- Kernel ! {accept,self(),Socket,inet,tcp},
- _ = controller(Kernel, Socket),
- accept_loop(Kernel, Listen);
+ Kernel ! {accept,self(),Socket,Driver:family(),tcp},
+ _ = controller(Driver, Kernel, Socket),
+ accept_loop(Driver, Kernel, Listen);
Error ->
exit(Error)
end.
-controller(Kernel, Socket) ->
+controller(Driver, Kernel, Socket) ->
receive
{Kernel, controller, Pid} ->
flush_controller(Pid, Socket),
- inet_tcp:controlling_process(Socket, Pid),
+ Driver:controlling_process(Socket, Pid),
flush_controller(Pid, Socket),
Pid ! {self(), controller};
{Kernel, unsupported_protocol} ->
@@ -165,15 +173,18 @@ flush_controller(Pid, Socket) ->
%% ------------------------------------------------------------
accept_connection(AcceptPid, Socket, MyNode, Allowed, SetupTime) ->
+ gen_accept_connection(inet_tcp, AcceptPid, Socket, MyNode, Allowed, SetupTime).
+
+gen_accept_connection(Driver, AcceptPid, Socket, MyNode, Allowed, SetupTime) ->
spawn_opt(?MODULE, do_accept,
- [self(), AcceptPid, Socket, MyNode, Allowed, SetupTime],
+ [Driver, self(), AcceptPid, Socket, MyNode, Allowed, SetupTime],
[link, {priority, max}]).
-do_accept(Kernel, AcceptPid, Socket, MyNode, Allowed, SetupTime) ->
+do_accept(Driver, Kernel, AcceptPid, Socket, MyNode, Allowed, SetupTime) ->
receive
{AcceptPid, controller} ->
Timer = dist_util:start_timer(SetupTime),
- case check_ip(Socket) of
+ case check_ip(Driver, Socket) of
true ->
HSData = #hs_data{
kernel_pid = Kernel,
@@ -182,9 +193,8 @@ do_accept(Kernel, AcceptPid, Socket, MyNode, Allowed, SetupTime) ->
timer = Timer,
this_flags = 0,
allowed = Allowed,
- f_send = fun(S,D) -> inet_tcp:send(S,D) end,
- f_recv = fun(S,N,T) -> inet_tcp:recv(S,N,T)
- end,
+ f_send = fun Driver:send/2,
+ f_recv = fun Driver:recv/3,
f_setopts_pre_nodeup =
fun(S) ->
inet:setopts(S,
@@ -203,8 +213,8 @@ do_accept(Kernel, AcceptPid, Socket, MyNode, Allowed, SetupTime) ->
f_getll = fun(S) ->
inet:getll(S)
end,
- f_address = fun get_remote_id/2,
- mf_tick = fun ?MODULE:tick/1,
+ f_address = fun(S, Node) -> get_remote_id(Driver, S, Node) end,
+ mf_tick = fun(S) -> tick(Driver, S) end,
mf_getstat = fun ?MODULE:getstat/1
},
dist_util:handshake_other_started(HSData);
@@ -235,13 +245,13 @@ nodelay() ->
%% ------------------------------------------------------------
%% Get remote information about a Socket.
%% ------------------------------------------------------------
-get_remote_id(Socket, Node) ->
+get_remote_id(Driver, Socket, Node) ->
case inet:peername(Socket) of
{ok,Address} ->
case split_node(atom_to_list(Node), $@, []) of
[_,Host] ->
#net_address{address=Address,host=Host,
- protocol=tcp,family=inet};
+ protocol=tcp,family=Driver:family()};
_ ->
%% No '@' or more than one '@' in node name.
?shutdown(no_node)
@@ -256,14 +266,18 @@ get_remote_id(Socket, Node) ->
%% ------------------------------------------------------------
setup(Node, Type, MyNode, LongOrShortNames,SetupTime) ->
+ gen_setup(inet_tcp, Node, Type, MyNode, LongOrShortNames, SetupTime).
+
+gen_setup(Driver, Node, Type, MyNode, LongOrShortNames, SetupTime) ->
spawn_opt(?MODULE, do_setup,
- [self(), Node, Type, MyNode, LongOrShortNames, SetupTime],
+ [Driver, self(), Node, Type, MyNode, LongOrShortNames, SetupTime],
[link, {priority, max}]).
-do_setup(Kernel, Node, Type, MyNode, LongOrShortNames,SetupTime) ->
+do_setup(Driver, Kernel, Node, Type, MyNode, LongOrShortNames, SetupTime) ->
?trace("~p~n",[{inet_tcp_dist,self(),setup,Node}]),
- [Name, Address] = splitnode(Node, LongOrShortNames),
- case inet:getaddr(Address, inet) of
+ [Name, Address] = splitnode(Driver, Node, LongOrShortNames),
+ AddressFamily = Driver:family(),
+ case inet:getaddr(Address, AddressFamily) of
{ok, Ip} ->
Timer = dist_util:start_timer(SetupTime),
case erl_epmd:port_please(Name, Ip) of
@@ -272,7 +286,7 @@ do_setup(Kernel, Node, Type, MyNode, LongOrShortNames,SetupTime) ->
[Node,Version]),
dist_util:reset_timer(Timer),
case
- inet_tcp:connect(
+ Driver:connect(
Ip, TcpPort,
connect_options([{active, false}, {packet, 2}]))
of
@@ -285,8 +299,8 @@ do_setup(Kernel, Node, Type, MyNode, LongOrShortNames,SetupTime) ->
timer = Timer,
this_flags = 0,
other_version = Version,
- f_send = fun inet_tcp:send/2,
- f_recv = fun inet_tcp:recv/3,
+ f_send = fun Driver:send/2,
+ f_recv = fun Driver:recv/3,
f_setopts_pre_nodeup =
fun(S) ->
inet:setopts
@@ -311,9 +325,9 @@ do_setup(Kernel, Node, Type, MyNode, LongOrShortNames,SetupTime) ->
address = {Ip,TcpPort},
host = Address,
protocol = tcp,
- family = inet}
+ family = AddressFamily}
end,
- mf_tick = fun ?MODULE:tick/1,
+ mf_tick = fun(S) -> tick(Driver, S) end,
mf_getstat = fun ?MODULE:getstat/1,
request_type = Type
},
@@ -353,18 +367,23 @@ close(Socket) ->
%% If Node is illegal terminate the connection setup!!
-splitnode(Node, LongOrShortNames) ->
+splitnode(Driver, Node, LongOrShortNames) ->
case split_node(atom_to_list(Node), $@, []) of
[Name|Tail] when Tail =/= [] ->
Host = lists:append(Tail),
case split_node(Host, $., []) of
[_] when LongOrShortNames =:= longnames ->
- error_msg("** System running to use "
- "fully qualified "
- "hostnames **~n"
- "** Hostname ~s is illegal **~n",
- [Host]),
- ?shutdown(Node);
+ case Driver:parse_address(Host) of
+ {ok, _} ->
+ [Name, Host];
+ _ ->
+ error_msg("** System running to use "
+ "fully qualified "
+ "hostnames **~n"
+ "** Hostname ~s is illegal **~n",
+ [Host]),
+ ?shutdown(Node)
+ end;
L when length(L) > 1, LongOrShortNames =:= shortnames ->
error_msg("** System NOT running to use fully qualified "
"hostnames **~n"
@@ -390,26 +409,26 @@ split_node([], _, Ack) -> [lists:reverse(Ack)].
%% ------------------------------------------------------------
%% Fetch local information about a Socket.
%% ------------------------------------------------------------
-get_tcp_address(Socket) ->
+get_tcp_address(Driver, Socket) ->
{ok, Address} = inet:sockname(Socket),
{ok, Host} = inet:gethostname(),
#net_address {
address = Address,
host = Host,
protocol = tcp,
- family = inet
+ family = Driver:family()
}.
%% ------------------------------------------------------------
%% Do only accept new connection attempts from nodes at our
%% own LAN, if the check_ip environment parameter is true.
%% ------------------------------------------------------------
-check_ip(Socket) ->
+check_ip(Driver, Socket) ->
case application:get_env(check_ip) of
{ok, true} ->
case get_ifs(Socket) of
{ok, IFs, IP} ->
- check_ip(IFs, IP);
+ check_ip(Driver, IFs, IP);
_ ->
?shutdown(no_node)
end;
@@ -428,20 +447,14 @@ get_ifs(Socket) ->
Error
end.
-check_ip([{OwnIP, _, Netmask}|IFs], PeerIP) ->
- case {mask(Netmask, PeerIP), mask(Netmask, OwnIP)} of
+check_ip(Driver, [{OwnIP, _, Netmask}|IFs], PeerIP) ->
+ case {Driver:mask(Netmask, PeerIP), Driver:mask(Netmask, OwnIP)} of
{M, M} -> true;
- _ -> check_ip(IFs, PeerIP)
+ _ -> check_ip(Driver, IFs, PeerIP)
end;
-check_ip([], PeerIP) ->
+check_ip(_Driver, [], PeerIP) ->
{false, PeerIP}.
-mask({M1,M2,M3,M4}, {IP1,IP2,IP3,IP4}) ->
- {M1 band IP1,
- M2 band IP2,
- M3 band IP3,
- M4 band IP4}.
-
is_node_name(Node) when is_atom(Node) ->
case split_node(atom_to_list(Node), $@, []) of
[_, _Host] -> true;
@@ -450,8 +463,14 @@ is_node_name(Node) when is_atom(Node) ->
is_node_name(_Node) ->
false.
-tick(Sock) ->
- ?to_port(Sock,[],[force]).
+tick(Driver, Socket) ->
+ case Driver:send(Socket, [], [force]) of
+ {error, closed} ->
+ self() ! {tcp_closed, Socket},
+ {error, closed};
+ R ->
+ R
+ end.
getstat(Socket) ->
case inet:getstat(Socket, [recv_cnt, send_cnt, send_pend]) of
diff --git a/lib/kernel/src/kernel.app.src b/lib/kernel/src/kernel.app.src
index c9327e4f31..419dc0a2fc 100644
--- a/lib/kernel/src/kernel.app.src
+++ b/lib/kernel/src/kernel.app.src
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2013. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2015. 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.
@@ -116,6 +116,6 @@
{applications, []},
{env, [{error_logger, tty}]},
{mod, {kernel, []}},
- {runtime_dependencies, ["erts-7.0", "stdlib-2.5", "sasl-2.4"]}
+ {runtime_dependencies, ["erts-7.3", "stdlib-2.6", "sasl-2.6"]}
]
}.
diff --git a/lib/kernel/src/kernel.appup.src b/lib/kernel/src/kernel.appup.src
index 701aafc717..cc9e6f771a 100644
--- a/lib/kernel/src/kernel.appup.src
+++ b/lib/kernel/src/kernel.appup.src
@@ -18,7 +18,9 @@
%% %CopyrightEnd%
{"%VSN%",
%% Up from - max one major revision back
- [{<<"3\\.[0-2](\\.[0-9]+)*">>,[restart_new_emulator]}], % OTP-17
+ [{<<"4\\.[0-2](\\.[0-9]+)*">>,[restart_new_emulator]}, % OTP-18.*
+ {<<"3\\.[0-2](\\.[0-9]+)*">>,[restart_new_emulator]}], % OTP-17
%% Down to - max one major revision back
- [{<<"3\\.[0-2](\\.[0-9]+)*">>,[restart_new_emulator]}] % OTP-17
+ [{<<"4\\.[0-2](\\.[0-9]+)*">>,[restart_new_emulator]}, % OTP-18.*
+ {<<"3\\.[0-2](\\.[0-9]+)*">>,[restart_new_emulator]}] % OTP-17
}.
diff --git a/lib/kernel/src/seq_trace.erl b/lib/kernel/src/seq_trace.erl
index 07ccd3e494..a7a782c29c 100644
--- a/lib/kernel/src/seq_trace.erl
+++ b/lib/kernel/src/seq_trace.erl
@@ -23,7 +23,9 @@
-define(SEQ_TRACE_SEND, 1). %(1 << 0)
-define(SEQ_TRACE_RECEIVE, 2). %(1 << 1)
-define(SEQ_TRACE_PRINT, 4). %(1 << 2)
--define(SEQ_TRACE_TIMESTAMP, 8). %(1 << 3)
+-define(SEQ_TRACE_NOW_TIMESTAMP, 8). %(1 << 3)
+-define(SEQ_TRACE_STRICT_MON_TIMESTAMP, 16). %(1 << 4)
+-define(SEQ_TRACE_MON_TIMESTAMP, 32). %(1 << 5)
-export([set_token/1,
set_token/2,
@@ -37,7 +39,7 @@
%%---------------------------------------------------------------------------
--type flag() :: 'send' | 'receive' | 'print' | 'timestamp'.
+-type flag() :: 'send' | 'receive' | 'print' | 'timestamp' | 'monotonic_timestamp' | 'strict_monotonic_timestamp'.
-type component() :: 'label' | 'serial' | flag().
-type value() :: (Integer :: non_neg_integer())
| {Previous :: non_neg_integer(),
@@ -135,5 +137,9 @@ decode_flags(Flags) ->
Print = (Flags band ?SEQ_TRACE_PRINT) > 0,
Send = (Flags band ?SEQ_TRACE_SEND) > 0,
Rec = (Flags band ?SEQ_TRACE_RECEIVE) > 0,
- Ts = (Flags band ?SEQ_TRACE_TIMESTAMP) > 0,
- [{print,Print},{send,Send},{'receive',Rec},{timestamp,Ts}].
+ NowTs = (Flags band ?SEQ_TRACE_NOW_TIMESTAMP) > 0,
+ StrictMonTs = (Flags band ?SEQ_TRACE_STRICT_MON_TIMESTAMP) > 0,
+ MonTs = (Flags band ?SEQ_TRACE_MON_TIMESTAMP) > 0,
+ [{print,Print},{send,Send},{'receive',Rec},{timestamp,NowTs},
+ {strict_monotonic_timestamp, StrictMonTs},
+ {monotonic_timestamp, MonTs}].
diff --git a/lib/kernel/src/user_drv.erl b/lib/kernel/src/user_drv.erl
index ca3c53ff93..b794d4f45e 100644
--- a/lib/kernel/src/user_drv.erl
+++ b/lib/kernel/src/user_drv.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2013. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2016. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -559,6 +559,7 @@ put_int16(N, Tail) ->
%% is sent back to the process sending the request. This command was added in
%% OTP 18 to make sure that data sent from io:format is actually printed
%% to the console before the vm stops when calling erlang:halt(integer()).
+-dialyzer({no_improper_lists, io_command/1}).
io_command({put_chars_sync, unicode,Cs,Reply}) ->
{{command,[?OP_PUTC_SYNC|unicode:characters_to_binary(Cs,utf8)]},Reply};
io_command({put_chars, unicode,Cs}) ->
diff --git a/lib/kernel/test/bif_SUITE.erl b/lib/kernel/test/bif_SUITE.erl
index c3840f3d16..dd3010567a 100644
--- a/lib/kernel/test/bif_SUITE.erl
+++ b/lib/kernel/test/bif_SUITE.erl
@@ -33,6 +33,7 @@
spawn_failures/1,
run_fun/1,
+ decode_packet_delim/1,
wilderness/1]).
-export([init_per_testcase/2, end_per_testcase/2]).
@@ -516,6 +517,15 @@ fetch_proc_vals(Pid) ->
{value,{heap_size,HS}} = lists:keysearch(heap_size, 1, PI),
?line {Ls, P, FA, HS}.
+decode_packet_delim(doc) ->
+ ["Test erlang:packet_delim/3 with {line_delimiter,0} option"];
+decode_packet_delim(suite) ->
+ [];
+decode_packet_delim(Config) when is_list(Config) ->
+ {ok,<<"abc",0>>,<<"efg",0>>} =
+ erlang:decode_packet(line, <<"abc",0,"efg",0>>, [{line_delimiter, 0}]),
+ {more, undefined} = erlang:decode_packet(line, <<"abc",0,"efg",0>>, []).
+
% This testcase should probably be moved somewhere else
wilderness(doc) ->
["Test that memory allocation command line options affecting the"
diff --git a/lib/kernel/test/code_SUITE.erl b/lib/kernel/test/code_SUITE.erl
index ef5303defd..73ade14fa1 100644
--- a/lib/kernel/test/code_SUITE.erl
+++ b/lib/kernel/test/code_SUITE.erl
@@ -323,6 +323,7 @@ load_abs(Config) when is_list(Config) ->
{error, nofile} = code:load_abs(TestDir ++ "/duuuumy_mod"),
{error, badfile} = code:load_abs(TestDir ++ "/code_a_test"),
{'EXIT', _} = (catch code:load_abs({})),
+ {'EXIT', _} = (catch code:load_abs("Non-latin-имя-файла")),
{module, code_b_test} = code:load_abs(TestDir ++ "/code_b_test"),
code:stick_dir(TestDir),
{error, sticky_directory} = code:load_abs(TestDir ++ "/code_b_test"),
@@ -1132,9 +1133,8 @@ mult_lib_roots(Config) when is_list(Config) ->
?t:start_node(mult_lib_roots, slave,
[{args,"-env ERL_LIBS "++ErlLibs}]),
- TSPath = filename:dirname(code:which(test_server)),
Path0 = rpc:call(Node, code, get_path, []),
- [TSPath,"."|Path1] = Path0,
+ ["."|Path1] = Path0,
[Kernel|Path2] = Path1,
[Stdlib|Path3] = Path2,
mult_lib_verify_lib(Kernel, "kernel"),
@@ -1178,16 +1178,19 @@ mult_lib_remove_prefix([$/|T], []) -> T.
bad_erl_libs(Config) when is_list(Config) ->
{ok,Node} =
- ?t:start_node(mult_lib_roots, slave,
- [{args,"-env ERL_LIBS "}]),
-
+ ?t:start_node(bad_erl_libs, slave, []),
+ Code = rpc:call(Node,code,get_path,[]),
?t:stop_node(Node),
{ok,Node2} =
- ?t:start_node(mult_lib_roots, slave,
+ ?t:start_node(bad_erl_libs, slave,
[{args,"-env ERL_LIBS /no/such/dir"}]),
-
+ Code2 = rpc:call(Node,code,get_path,[]),
?t:stop_node(Node2),
+
+ %% Test that code path is not affected by the faulty ERL_LIBS
+ Code = Code2,
+
ok.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@@ -1599,6 +1602,17 @@ on_load_errors(Config) when is_list(Config) ->
ok
end,
+ %% Make sure that the code loading functions return the correct
+ %% error code.
+ Simple = simple_on_load_error,
+ SimpleList = atom_to_list(Simple),
+ {error,on_load_failure} = code:load_file(Simple),
+ {error,on_load_failure} = code:ensure_loaded(Simple),
+ {ok,SimpleCode} = file:read_file("simple_on_load_error.beam"),
+ {error,on_load_failure} = code:load_binary(Simple, "", SimpleCode),
+ {error,on_load_failure} = code:load_abs(SimpleList),
+ {error,on_load_failure} = code:load_abs(SimpleList, Simple),
+
ok.
do_on_load_error(ReturnValue) ->
diff --git a/lib/kernel/test/code_SUITE_data/on_load_errors/simple_on_load_error.erl b/lib/kernel/test/code_SUITE_data/on_load_errors/simple_on_load_error.erl
new file mode 100644
index 0000000000..603c282257
--- /dev/null
+++ b/lib/kernel/test/code_SUITE_data/on_load_errors/simple_on_load_error.erl
@@ -0,0 +1,5 @@
+-module(simple_on_load_error).
+-on_load(on_load/0).
+
+on_load() ->
+ nope.
diff --git a/lib/kernel/test/file_SUITE.erl b/lib/kernel/test/file_SUITE.erl
index 8856be31c2..09d9a45197 100644
--- a/lib/kernel/test/file_SUITE.erl
+++ b/lib/kernel/test/file_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2013. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2015. 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.
@@ -48,7 +48,7 @@
-export([cur_dir_0/1, cur_dir_1/1, make_del_dir/1,
list_dir/1,list_dir_error/1,
untranslatable_names/1, untranslatable_names_error/1,
- pos1/1, pos2/1]).
+ pos1/1, pos2/1, pos3/1]).
-export([close/1, consult1/1, path_consult/1, delete/1]).
-export([ eval1/1, path_eval/1, script1/1, path_script/1,
open1/1,
@@ -80,6 +80,7 @@
-export([interleaved_read_write/1]).
+-export([unicode/1]).
-export([altname/1]).
-export([large_file/1, large_write/1]).
@@ -114,7 +115,7 @@
suite() -> [{ct_hooks,[ts_install_cth]}].
all() ->
- [altname, read_write_file, {group, dirs},
+ [unicode, altname, read_write_file, {group, dirs},
{group, files}, delete, rename, names, {group, errors},
{group, compression}, {group, links}, copy,
delayed_write, read_ahead, segment_read, segment_write,
@@ -136,7 +137,7 @@ groups() ->
[open1, old_modes, new_modes, path_open, close, access,
read_write, pread_write, append, open_errors,
exclusive]},
- {pos, [], [pos1, pos2]},
+ {pos, [], [pos1, pos2, pos3]},
{file_info, [],
[file_info_basic_file, file_info_basic_directory,
file_info_bad, file_info_times, file_write_file_info]},
@@ -1370,6 +1371,27 @@ pos2(Config) when is_list(Config) ->
?line test_server:timetrap_cancel(Dog),
ok.
+pos3(suite) -> [];
+pos3(doc) -> ["When it does not use raw mode, file:position had a bug."];
+pos3(Config) when is_list(Config) ->
+ ?line Dog = test_server:timetrap(test_server:seconds(5)),
+ ?line RootDir = ?config(data_dir, Config),
+ ?line Name = filename:join(RootDir, "realmen.html.gz"),
+
+ ?line {ok, Fd} = ?FILE_MODULE:open(Name, [read, binary]),
+ ?line {ok, _} = ?FILE_MODULE:read(Fd, 5),
+ ?line {error, einval} = ?FILE_MODULE:position(Fd, {bof, -1}),
+
+ %% Here ok had returned =(
+ ?line {error, einval} = ?FILE_MODULE:position(Fd, {cur, -10}),
+ %% That test is actually questionable since file:position/2
+ %% is documented to leave the file position undefined after
+ %% it has returned an error. But on Posix systems the position
+ %% is guaranteed to be unchanged after an error return. On e.g
+ %% Windows there is nothing stated about this in the documentation.
+
+ ?line test_server:timetrap_cancel(Dog),
+ ok.
file_info_basic_file(suite) -> [];
file_info_basic_file(doc) -> [];
@@ -2761,6 +2783,40 @@ compress_async_crash_loop(N, Path, ExpectedData) ->
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+unicode(Config) when is_list(Config) ->
+ Dir = ?config(priv_dir, Config),
+ Name = filename:join(Dir, "data-utf8.txt"),
+ Txt = lists:seq(128, 255),
+ D = unicode:characters_to_binary(Txt, latin1, latin1),
+ {ok,Fd1} =
+ ?FILE_MODULE:open(Name, [write,read,binary,{encoding,unicode}]),
+ ok = ?FILE_MODULE:truncate(Fd1),
+ ok = ?FILE_MODULE:write(Fd1, Txt),
+ {ok,0} = ?FILE_MODULE:position(Fd1, bof),
+ {ok,D} = ?FILE_MODULE:read(Fd1, 129),
+ {ok,0} = ?FILE_MODULE:position(Fd1, bof),
+ {ok,D1} = ?FILE_MODULE:read(Fd1, 64),
+ {ok,Pos} = ?FILE_MODULE:position(Fd1, cur),
+ {ok,D2} = ?FILE_MODULE:pread(Fd1, {cur,0}, 65),
+ D = <<D1/binary, D2/binary>>,
+ {ok,D1} = ?FILE_MODULE:pread(Fd1, bof, 64),
+ {ok,Pos} = ?FILE_MODULE:position(Fd1, Pos),
+ {ok,D2} = ?FILE_MODULE:read(Fd1, 64),
+ ok = ?FILE_MODULE:close(Fd1),
+ %%
+ RawD = unicode:characters_to_binary(Txt, latin1, unicode),
+ {ok,RawD} = ?FILE_MODULE:read_file(Name),
+ %%
+ {ok,Fd2} = ?FILE_MODULE:open(Name, [read,{encoding,unicode}]),
+ {ok,Txt} = ?FILE_MODULE:read(Fd2, 129),
+ {Txt1,Txt2} = lists:split(64, Txt),
+ {ok,Txt2} = ?FILE_MODULE:pread(Fd2, Pos, 65),
+ {ok,0} = ?FILE_MODULE:position(Fd2, bof),
+ {ok,Txt1} = ?FILE_MODULE:read(Fd2, 64),
+ ok = ?FILE_MODULE:close(Fd2).
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
altname(doc) ->
"Test the file:altname/1 function";
altname(suite) ->
diff --git a/lib/kernel/test/gen_tcp_api_SUITE.erl b/lib/kernel/test/gen_tcp_api_SUITE.erl
index a051d504b2..962471c20c 100644
--- a/lib/kernel/test/gen_tcp_api_SUITE.erl
+++ b/lib/kernel/test/gen_tcp_api_SUITE.erl
@@ -31,7 +31,7 @@
init_per_testcase/2, end_per_testcase/2,
t_connect_timeout/1, t_accept_timeout/1,
t_connect_bad/1,
- t_recv_timeout/1, t_recv_eof/1,
+ t_recv_timeout/1, t_recv_eof/1, t_recv_delim/1,
t_shutdown_write/1, t_shutdown_both/1, t_shutdown_error/1,
t_shutdown_async/1,
t_fdopen/1, t_fdconnect/1, t_implicit_inet6/1]).
@@ -48,7 +48,7 @@ all() ->
groups() ->
[{t_accept, [], [t_accept_timeout]},
{t_connect, [], [t_connect_timeout, t_connect_bad]},
- {t_recv, [], [t_recv_timeout, t_recv_eof]}].
+ {t_recv, [], [t_recv_timeout, t_recv_eof, t_recv_delim]}].
@@ -131,6 +131,21 @@ t_recv_eof(Config) when is_list(Config) ->
?line {error, closed} = gen_tcp:recv(Client, 0),
ok.
+t_recv_delim(doc) -> "Test using message delimiter $X";
+t_recv_delim(suite) -> [];
+t_recv_delim(Config) when is_list(Config) ->
+ {ok, L} = gen_tcp:listen(0, []),
+ {ok, Port} = inet:port(L),
+ Opts = [{active,false},{packet,line},{line_delimiter,$X}],
+ {ok, Client} = gen_tcp:connect(localhost, Port, Opts),
+ {ok, A} = gen_tcp:accept(L),
+ ok = gen_tcp:send(A, "abcXefgX"),
+ {ok, "abcX"} = gen_tcp:recv(Client, 0, 0),
+ {ok, "efgX"} = gen_tcp:recv(Client, 0, 0),
+ ok = gen_tcp:close(Client),
+ ok = gen_tcp:close(A),
+ ok.
+
%%% gen_tcp:shutdown/2
t_shutdown_write(Config) when is_list(Config) ->
diff --git a/lib/kernel/test/heart_SUITE.erl b/lib/kernel/test/heart_SUITE.erl
index 83efbb4c35..39cd29cea0 100644
--- a/lib/kernel/test/heart_SUITE.erl
+++ b/lib/kernel/test/heart_SUITE.erl
@@ -27,6 +27,8 @@
node_start_immediately_after_crash/1,
node_start_soon_after_crash/1,
set_cmd/1, clear_cmd/1, get_cmd/1,
+ callback_api/1,
+ options_api/1,
dont_drop/1, kill_pid/1]).
-export([init_per_testcase/2, end_per_testcase/2]).
@@ -66,6 +68,8 @@ all() -> [
node_start_immediately_after_crash,
node_start_soon_after_crash,
set_cmd, clear_cmd, get_cmd,
+ callback_api,
+ options_api,
kill_pid
].
@@ -358,6 +362,69 @@ get_cmd(Config) when is_list(Config) ->
stop_node(Node),
ok.
+callback_api(Config) when is_list(Config) ->
+ {ok, Node} = start_check(slave, heart_test),
+ none = rpc:call(Node, heart, get_callback, []),
+ M0 = self(),
+ F0 = ok,
+ {error, {bad_callback, {M0,F0}}} = rpc:call(Node, heart, set_callback, [M0,F0]),
+ none = rpc:call(Node, heart, get_callback, []),
+ M1 = lists:duplicate(28, $a),
+ F1 = lists:duplicate(28, $b),
+ {error, {bad_callback, {M1,F1}}} = rpc:call(Node, heart, set_callback, [M1,F1]),
+ none = rpc:call(Node, heart, get_callback, []),
+
+ M2 = heart_check_module,
+ F2 = cb_ok,
+ F3 = cb_error,
+ Code0 = generate(M2, [], [
+ atom_to_list(F2) ++ "() -> ok.",
+ atom_to_list(F3) ++ "() -> exit(\"callback_error (as intended)\")."
+ ]),
+ {module, M2} = rpc:call(Node, erlang, load_module, [M2, Code0]),
+ ok = rpc:call(Node, M2, F2, []),
+ ok = rpc:call(Node, heart, set_callback, [M2,F2]),
+ {ok, {M2,F2}} = rpc:call(Node, heart, get_callback, []),
+ ok = rpc:call(Node, heart, clear_callback, []),
+ none = rpc:call(Node, heart, get_callback, []),
+ ok = rpc:call(Node, heart, set_callback, [M2,F2]),
+ {ok, {M2,F2}} = rpc:call(Node, heart, get_callback, []),
+ ok = rpc:call(Node, heart, set_callback, [M2,F3]),
+ receive {nodedown, Node} -> ok
+ after 5000 -> test_server:fail(node_not_killed)
+ end,
+ stop_node(Node),
+ ok.
+
+options_api(Config) when is_list(Config) ->
+ {ok, Node} = start_check(slave, heart_test),
+ none = rpc:call(Node, heart, get_options, []),
+ M0 = self(),
+ F0 = ok,
+ {error, {bad_options, {M0,F0}}} = rpc:call(Node, heart, set_options, [{M0,F0}]),
+ none = rpc:call(Node, heart, get_options, []),
+ Ls = lists:duplicate(28, $b),
+ {error, {bad_options, Ls}} = rpc:call(Node, heart, set_options, [Ls]),
+ none = rpc:call(Node, heart, get_options, []),
+
+ ok = rpc:call(Node, heart, set_options, [[check_schedulers]]),
+ {ok, [check_schedulers]} = rpc:call(Node, heart, get_options, []),
+ ok = rpc:call(Node, heart, set_options, [[]]),
+ none = rpc:call(Node, heart, get_options, []),
+
+ ok = rpc:call(Node, heart, set_options, [[check_schedulers]]),
+ {ok, [check_schedulers]} = rpc:call(Node, heart, get_options, []),
+ {error, {bad_options, Ls}} = rpc:call(Node, heart, set_options, [Ls]),
+ {ok, [check_schedulers]} = rpc:call(Node, heart, get_options, []),
+
+ receive after 3000 -> ok end, %% wait 3 secs
+
+ ok = rpc:call(Node, heart, set_options, [[]]),
+ none = rpc:call(Node, heart, get_options, []),
+ stop_node(Node),
+ ok.
+
+
dont_drop(suite) ->
%%% Removed as it may crash epmd/distribution in colourful
%%% ways. While we ARE finding out WHY, it would
diff --git a/lib/kernel/test/inet_sockopt_SUITE.erl b/lib/kernel/test/inet_sockopt_SUITE.erl
index 1262f36fae..cb522c8abe 100644
--- a/lib/kernel/test/inet_sockopt_SUITE.erl
+++ b/lib/kernel/test/inet_sockopt_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2007-2013. All Rights Reserved.
+%% Copyright Ericsson AB 2007-2015. 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.
@@ -52,6 +52,7 @@
-export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1,
init_per_group/2,end_per_group/2,
simple/1, loop_all/1, simple_raw/1, simple_raw_getbin/1,
+ multiple_raw/1, multiple_raw_getbin/1,
doc_examples_raw/1,doc_examples_raw_getbin/1,
large_raw/1,large_raw_getbin/1,combined/1,combined_getbin/1,
ipv6_v6only_udp/1, ipv6_v6only_tcp/1, ipv6_v6only_sctp/1,
@@ -65,6 +66,7 @@ suite() -> [{ct_hooks,[ts_install_cth]}].
all() ->
[simple, loop_all, simple_raw, simple_raw_getbin,
+ multiple_raw, multiple_raw_getbin,
doc_examples_raw, doc_examples_raw_getbin, large_raw,
large_raw_getbin, combined, combined_getbin,
ipv6_v6only_udp, ipv6_v6only_tcp, ipv6_v6only_sctp,
@@ -185,6 +187,84 @@ nintbin2int(<<Int:16/native>>) -> Int;
nintbin2int(<<Int:8/native>>) -> Int;
nintbin2int(<<>>) -> 0.
+
+
+multiple_raw(suite) -> [];
+multiple_raw(doc) -> "Test setopt/getopt of multiple raw options.";
+multiple_raw(Config) when is_list(Config) ->
+ do_multiple_raw(Config,false).
+multiple_raw_getbin(suite) -> [];
+multiple_raw_getbin(doc) -> "Test setopt/getopt of multiple raw options, "
+ "with binaries in getopt.";
+multiple_raw_getbin(Config) when is_list(Config) ->
+ do_multiple_raw(Config,true).
+
+do_multiple_raw(Config, Binary) ->
+ Port = start_helper(Config),
+ SolSocket = ask_helper(Port, ?C_GET_SOL_SOCKET),
+ SoKeepalive = ask_helper(Port, ?C_GET_SO_KEEPALIVE),
+ SoKeepaliveTrue = {raw,SolSocket,SoKeepalive,<<1:32/native>>},
+ SoKeepaliveFalse = {raw,SolSocket,SoKeepalive,<<0:32/native>>},
+ SoReuseaddr = ask_helper(Port, ?C_GET_SO_REUSEADDR),
+ SoReuseaddrTrue = {raw,SolSocket,SoReuseaddr,<<1:32/native>>},
+ SoReuseaddrFalse = {raw,SolSocket,SoReuseaddr,<<0:32/native>>},
+ {S1,S2} =
+ create_socketpair(
+ [SoReuseaddrFalse,SoKeepaliveTrue],
+ [SoKeepaliveFalse,SoReuseaddrTrue]),
+ {ok,[{reuseaddr,false},{keepalive,true}]} =
+ inet:getopts(S1, [reuseaddr,keepalive]),
+ {ok,
+ [{raw,SolSocket,SoReuseaddr,S1R1},
+ {raw,SolSocket,SoKeepalive,S1K1}]} =
+ inet:getopts(
+ S1,
+ [{raw,SolSocket,SoReuseaddr,binarify(4, Binary)},
+ {raw,SolSocket,SoKeepalive,binarify(4, Binary)}]),
+ true = nintbin2int(S1R1) =:= 0,
+ true = nintbin2int(S1K1) =/= 0,
+ {ok,[{keepalive,false},{reuseaddr,true}]} =
+ inet:getopts(S2, [keepalive,reuseaddr]),
+ {ok,
+ [{raw,SolSocket,SoKeepalive,S2K1},
+ {raw,SolSocket,SoReuseaddr,S2R1}]} =
+ inet:getopts(
+ S2,
+ [{raw,SolSocket,SoKeepalive,binarify(4, Binary)},
+ {raw,SolSocket,SoReuseaddr,binarify(4, Binary)}]),
+ true = nintbin2int(S2K1) =:= 0,
+ true = nintbin2int(S2R1) =/= 0,
+ %%
+ ok = inet:setopts(
+ S1, [SoReuseaddrTrue,SoKeepaliveFalse]),
+ ok = inet:setopts(
+ S2, [SoKeepaliveTrue,SoReuseaddrFalse]),
+ {ok,
+ [{raw,SolSocket,SoReuseaddr,S1R2},
+ {raw,SolSocket,SoKeepalive,S1K2}]} =
+ inet:getopts(
+ S1,
+ [{raw,SolSocket,SoReuseaddr,binarify(4, Binary)},
+ {raw,SolSocket,SoKeepalive,binarify(4, Binary)}]),
+ true = nintbin2int(S1R2) =/= 0,
+ true = nintbin2int(S1K2) =:= 0,
+ {ok,
+ [{raw,SolSocket,SoKeepalive,S2K2},
+ {raw,SolSocket,SoReuseaddr,S2R2}]} =
+ inet:getopts(
+ S2,
+ [{raw,SolSocket,SoKeepalive,binarify(4, Binary)},
+ {raw,SolSocket,SoReuseaddr,binarify(4, Binary)}]),
+ true = nintbin2int(S2K2) =/= 0,
+ true = nintbin2int(S2R2) =:= 0,
+ %%
+ gen_tcp:close(S1),
+ gen_tcp:close(S2),
+ stop_helper(Port),
+ ok.
+
+
+
doc_examples_raw(suite) -> [];
doc_examples_raw(doc) -> "Test that the example code from the documentation "
"works";
diff --git a/lib/kernel/test/seq_trace_SUITE.erl b/lib/kernel/test/seq_trace_SUITE.erl
index 7df0bc3d2f..6a63f7bc9c 100644
--- a/lib/kernel/test/seq_trace_SUITE.erl
+++ b/lib/kernel/test/seq_trace_SUITE.erl
@@ -35,6 +35,11 @@
%-define(line_trace, 1).
-include_lib("test_server/include/test_server.hrl").
+-define(TIMESTAMP_MODES, [no_timestamp,
+ timestamp,
+ monotonic_timestamp,
+ strict_monotonic_timestamp]).
+
-define(default_timeout, ?t:minutes(1)).
suite() -> [{ct_hooks,[ts_install_cth]}].
@@ -75,6 +80,17 @@ end_per_testcase(_Case, Config) ->
token_set_get(doc) -> [];
token_set_get(suite) -> [];
token_set_get(Config) when is_list(Config) ->
+ do_token_set_get(timestamp),
+ do_token_set_get(monotonic_timestamp),
+ do_token_set_get(strict_monotonic_timestamp).
+
+do_token_set_get(TsType) ->
+ io:format("Testing ~p~n", [TsType]),
+ Flags = case TsType of
+ timestamp -> 15;
+ strict_monotonic_timestamp -> 23;
+ monotonic_timestamp -> 39
+ end,
?line Self = self(),
?line seq_trace:reset_trace(),
%% Test that initial seq_trace is disabled
@@ -88,22 +104,22 @@ token_set_get(Config) when is_list(Config) ->
?line {send,true} = seq_trace:get_token(send),
?line false = seq_trace:set_token('receive',true),
?line {'receive',true} = seq_trace:get_token('receive'),
- ?line false = seq_trace:set_token(timestamp,true),
- ?line {timestamp,true} = seq_trace:get_token(timestamp),
+ ?line false = seq_trace:set_token(TsType,true),
+ ?line {TsType,true} = seq_trace:get_token(TsType),
%% Check the whole token
- ?line {15,17,0,Self,0} = seq_trace:get_token(), % all flags are set
+ ?line {Flags,17,0,Self,0} = seq_trace:get_token(), % all flags are set
%% Test setting and reading the 'serial' field
?line {0,0} = seq_trace:set_token(serial,{3,5}),
?line {serial,{3,5}} = seq_trace:get_token(serial),
%% Check the whole token, test that a whole token can be set and get
- ?line {15,17,5,Self,3} = seq_trace:get_token(),
- ?line seq_trace:set_token({15,19,7,Self,5}),
- ?line {15,19,7,Self,5} = seq_trace:get_token(),
+ ?line {Flags,17,5,Self,3} = seq_trace:get_token(),
+ ?line seq_trace:set_token({Flags,19,7,Self,5}),
+ ?line {Flags,19,7,Self,5} = seq_trace:get_token(),
%% Check that receive timeout does not reset token
?line receive after 0 -> ok end,
- ?line {15,19,7,Self,5} = seq_trace:get_token(),
+ ?line {Flags,19,7,Self,5} = seq_trace:get_token(),
%% Check that token can be unset
- ?line {15,19,7,Self,5} = seq_trace:set_token([]),
+ ?line {Flags,19,7,Self,5} = seq_trace:set_token([]),
?line [] = seq_trace:get_token(),
%% Check that Previous serial counter survived unset token
?line 0 = seq_trace:set_token(label, 17),
@@ -139,30 +155,42 @@ tracer_set_get(Config) when is_list(Config) ->
print(doc) -> [];
print(suite) -> [];
print(Config) when is_list(Config) ->
+ lists:foreach(fun do_print/1, ?TIMESTAMP_MODES).
+
+do_print(TsType) ->
?line start_tracer(),
- ?line seq_trace:set_token(print,true),
+ ?line set_token_flags([print, TsType]),
?line seq_trace:print(0,print1),
?line seq_trace:print(1,print2),
?line seq_trace:print(print3),
?line seq_trace:reset_trace(),
- ?line [{0,{print,_,_,[],print1}},
- {0,{print,_,_,[],print3}}] = stop_tracer(2).
+ ?line [{0,{print,_,_,[],print1}, Ts0},
+ {0,{print,_,_,[],print3}, Ts1}] = stop_tracer(2),
+ check_ts(TsType, Ts0),
+ check_ts(TsType, Ts1).
send(doc) -> [];
send(suite) -> [];
send(Config) when is_list(Config) ->
+ lists:foreach(fun do_send/1, ?TIMESTAMP_MODES).
+
+do_send(TsType) ->
?line seq_trace:reset_trace(),
?line start_tracer(),
?line Receiver = spawn(?MODULE,one_time_receiver,[]),
- ?line seq_trace:set_token(send,true),
+ ?line set_token_flags([send, TsType]),
?line Receiver ! send,
?line Self = self(),
?line seq_trace:reset_trace(),
- ?line [{0,{send,_,Self,Receiver,send}}] = stop_tracer(1).
+ ?line [{0,{send,_,Self,Receiver,send}, Ts}] = stop_tracer(1),
+ check_ts(TsType, Ts).
distributed_send(doc) -> [];
distributed_send(suite) -> [];
distributed_send(Config) when is_list(Config) ->
+ lists:foreach(fun do_distributed_send/1, ?TIMESTAMP_MODES).
+
+do_distributed_send(TsType) ->
?line {ok,Node} = start_node(seq_trace_other,[]),
?line {_,Dir} = code:is_loaded(?MODULE),
?line Mdir = filename:dirname(Dir),
@@ -170,30 +198,39 @@ distributed_send(Config) when is_list(Config) ->
?line seq_trace:reset_trace(),
?line start_tracer(),
?line Receiver = spawn(Node,?MODULE,one_time_receiver,[]),
- ?line seq_trace:set_token(send,true),
+ ?line set_token_flags([send,TsType]),
?line Receiver ! send,
?line Self = self(),
?line seq_trace:reset_trace(),
?line stop_node(Node),
- ?line [{0,{send,_,Self,Receiver,send}}] = stop_tracer(1).
+ ?line [{0,{send,_,Self,Receiver,send}, Ts}] = stop_tracer(1),
+ check_ts(TsType, Ts).
+
recv(doc) -> [];
recv(suite) -> [];
recv(Config) when is_list(Config) ->
+ lists:foreach(fun do_recv/1, ?TIMESTAMP_MODES).
+
+do_recv(TsType) ->
?line seq_trace:reset_trace(),
?line start_tracer(),
?line Receiver = spawn(?MODULE,one_time_receiver,[]),
- ?line seq_trace:set_token('receive',true),
+ ?line set_token_flags(['receive',TsType]),
?line Receiver ! 'receive',
%% let the other process receive the message:
?line receive after 1 -> ok end,
?line Self = self(),
?line seq_trace:reset_trace(),
- ?line [{0,{'receive',_,Self,Receiver,'receive'}}] = stop_tracer(1).
+ ?line [{0,{'receive',_,Self,Receiver,'receive'}, Ts}] = stop_tracer(1),
+ check_ts(TsType, Ts).
distributed_recv(doc) -> [];
distributed_recv(suite) -> [];
distributed_recv(Config) when is_list(Config) ->
+ lists:foreach(fun do_distributed_recv/1, ?TIMESTAMP_MODES).
+
+do_distributed_recv(TsType) ->
?line {ok,Node} = start_node(seq_trace_other,[]),
?line {_,Dir} = code:is_loaded(?MODULE),
?line Mdir = filename:dirname(Dir),
@@ -201,7 +238,7 @@ distributed_recv(Config) when is_list(Config) ->
?line seq_trace:reset_trace(),
?line rpc:call(Node,?MODULE,start_tracer,[]),
?line Receiver = spawn(Node,?MODULE,one_time_receiver,[]),
- ?line seq_trace:set_token('receive',true),
+ ?line set_token_flags(['receive',TsType]),
?line Receiver ! 'receive',
%% let the other process receive the message:
?line receive after 1 -> ok end,
@@ -210,16 +247,20 @@ distributed_recv(Config) when is_list(Config) ->
?line Result = rpc:call(Node,?MODULE,stop_tracer,[1]),
?line stop_node(Node),
?line ok = io:format("~p~n",[Result]),
- ?line [{0,{'receive',_,Self,Receiver,'receive'}}] = Result.
+ ?line [{0,{'receive',_,Self,Receiver,'receive'}, Ts}] = Result,
+ check_ts(TsType, Ts).
trace_exit(doc) -> [];
trace_exit(suite) -> [];
trace_exit(Config) when is_list(Config) ->
+ lists:foreach(fun do_trace_exit/1, ?TIMESTAMP_MODES).
+
+do_trace_exit(TsType) ->
?line seq_trace:reset_trace(),
?line start_tracer(),
?line Receiver = spawn_link(?MODULE, one_time_receiver, [exit]),
?line process_flag(trap_exit, true),
- ?line seq_trace:set_token(send,true),
+ ?line set_token_flags([send, TsType]),
?line Receiver ! {before, exit},
%% let the other process receive the message:
?line receive
@@ -233,13 +274,18 @@ trace_exit(Config) when is_list(Config) ->
?line Result = stop_tracer(2),
?line seq_trace:reset_trace(),
?line ok = io:format("~p~n", [Result]),
- ?line [{0, {send, {0,1}, Self, Receiver, {before, exit}}},
+ ?line [{0, {send, {0,1}, Self, Receiver, {before, exit}}, Ts0},
{0, {send, {1,2}, Receiver, Self,
- {'EXIT', Receiver, {exit, {before, exit}}}}}] = Result.
+ {'EXIT', Receiver, {exit, {before, exit}}}}, Ts1}] = Result,
+ check_ts(TsType, Ts0),
+ check_ts(TsType, Ts1).
distributed_exit(doc) -> [];
distributed_exit(suite) -> [];
distributed_exit(Config) when is_list(Config) ->
+ lists:foreach(fun do_distributed_exit/1, ?TIMESTAMP_MODES).
+
+do_distributed_exit(TsType) ->
?line {ok, Node} = start_node(seq_trace_other, []),
?line {_, Dir} = code:is_loaded(?MODULE),
?line Mdir = filename:dirname(Dir),
@@ -248,7 +294,7 @@ distributed_exit(Config) when is_list(Config) ->
?line rpc:call(Node, ?MODULE, start_tracer,[]),
?line Receiver = spawn_link(Node, ?MODULE, one_time_receiver, [exit]),
?line process_flag(trap_exit, true),
- ?line seq_trace:set_token(send, true),
+ ?line set_token_flags([send, TsType]),
?line Receiver ! {before, exit},
%% let the other process receive the message:
?line receive
@@ -264,7 +310,8 @@ distributed_exit(Config) when is_list(Config) ->
?line stop_node(Node),
?line ok = io:format("~p~n", [Result]),
?line [{0, {send, {1, 2}, Receiver, Self,
- {'EXIT', Receiver, {exit, {before, exit}}}}}] = Result.
+ {'EXIT', Receiver, {exit, {before, exit}}}}, Ts}] = Result,
+ check_ts(TsType, Ts).
call(doc) ->
"Tests special forms {is_seq_trace} and {get_seq_token} "
@@ -361,14 +408,22 @@ port(doc) ->
"Send trace messages to a port.";
port(suite) -> [];
port(Config) when is_list(Config) ->
+ lists:foreach(fun (TsType) -> do_port(TsType, Config) end,
+ ?TIMESTAMP_MODES).
+
+do_port(TsType, Config) ->
+ io:format("Testing ~p~n",[TsType]),
?line Port = load_tracer(Config),
?line seq_trace:set_system_tracer(Port),
- ?line seq_trace:set_token(print, true),
+ ?line set_token_flags([print, TsType]),
?line Small = [small,term],
?line seq_trace:print(0, Small),
?line case get_port_message(Port) of
- {seq_trace,0,{print,_,_,[],Small}} ->
+ {seq_trace,0,{print,_,_,[],Small}} when TsType == no_timestamp ->
+ ok;
+ {seq_trace,0,{print,_,_,[],Small},Ts0} when TsType /= no_timestamp ->
+ check_ts(TsType, Ts0),
ok;
Other ->
?line seq_trace:reset_trace(),
@@ -382,7 +437,10 @@ port(Config) when is_list(Config) ->
?line seq_trace:print(0, OtherSmall),
?line seq_trace:reset_trace(),
?line case get_port_message(Port) of
- {seq_trace,0,{print,_,_,[],OtherSmall}} ->
+ {seq_trace,0,{print,_,_,[],OtherSmall}} when TsType == no_timestamp ->
+ ok;
+ {seq_trace,0,{print,_,_,[],OtherSmall}, Ts1} when TsType /= no_timestamp ->
+ check_ts(TsType, Ts1),
ok;
Other1 ->
?line ?t:fail({unexpected,Other1})
@@ -399,6 +457,8 @@ port(Config) when is_list(Config) ->
Other2 ->
?line ?t:fail({unexpected,Other2})
end,
+ unlink(Port),
+ exit(Port,kill),
ok.
get_port_message(Port) ->
@@ -734,7 +794,7 @@ simple_tracer(Data, DN) ->
{seq_trace,Label,Info,Ts} ->
simple_tracer([{Label,Info,Ts}|Data], DN+1);
{seq_trace,Label,Info} ->
- simple_tracer([{Label,Info}|Data], DN+1);
+ simple_tracer([{Label,Info, no_timestamp}|Data], DN+1);
{stop,N,From} when DN >= N ->
From ! {tracerlog,lists:reverse(Data)}
end.
@@ -759,7 +819,55 @@ start_tracer() ->
seq_trace:set_system_tracer(Pid),
Pid.
-
+
+set_token_flags([]) ->
+ ok;
+set_token_flags([no_timestamp|Flags]) ->
+ seq_trace:set_token(timestamp, false),
+ seq_trace:set_token(monotonic_timestamp, false),
+ seq_trace:set_token(strict_monotonic_timestamp, false),
+ set_token_flags(Flags);
+set_token_flags([Flag|Flags]) ->
+ seq_trace:set_token(Flag, true),
+ set_token_flags(Flags).
+
+check_ts(no_timestamp, Ts) ->
+ try
+ no_timestamp = Ts
+ catch
+ _ : _ ->
+ ?t:fail({unexpected_timestamp, Ts})
+ end,
+ ok;
+check_ts(timestamp, Ts) ->
+ try
+ {Ms,S,Us} = Ts,
+ true = is_integer(Ms),
+ true = is_integer(S),
+ true = is_integer(Us)
+ catch
+ _ : _ ->
+ ?t:fail({unexpected_timestamp, Ts})
+ end,
+ ok;
+check_ts(monotonic_timestamp, Ts) ->
+ try
+ true = is_integer(Ts)
+ catch
+ _ : _ ->
+ ?t:fail({unexpected_timestamp, Ts})
+ end,
+ ok;
+check_ts(strict_monotonic_timestamp, Ts) ->
+ try
+ {MT, UMI} = Ts,
+ true = is_integer(MT),
+ true = is_integer(UMI)
+ catch
+ _ : _ ->
+ ?t:fail({unexpected_timestamp, Ts})
+ end,
+ ok.
start_node(Name, Param) ->
test_server:start_node(Name, slave, [{args, Param}]).
diff --git a/lib/kernel/test/standard_error_SUITE.erl b/lib/kernel/test/standard_error_SUITE.erl
index e8917bbd47..97ead9b9fd 100644
--- a/lib/kernel/test/standard_error_SUITE.erl
+++ b/lib/kernel/test/standard_error_SUITE.erl
@@ -21,13 +21,13 @@
-module(standard_error_SUITE).
-export([all/0,suite/0]).
--export([badarg/1,getopts/1]).
+-export([badarg/1,getopts/1,output/1]).
suite() ->
[{ct_hooks,[ts_install_cth]}].
all() ->
- [badarg,getopts].
+ [badarg,getopts,output].
badarg(Config) when is_list(Config) ->
{'EXIT',{badarg,_}} = (catch io:put_chars(standard_error, [oops])),
@@ -37,3 +37,30 @@ badarg(Config) when is_list(Config) ->
getopts(Config) when is_list(Config) ->
[{encoding,latin1}] = io:getopts(standard_error),
ok.
+
+%% Test that writing a lot of output to standard_error does not cause the
+%% processes handling it to terminate like this:
+%%
+%% =ERROR REPORT==== 9-Aug-2015::23:19:23 ===
+%% ** Generic server standard_error_sup terminating
+%% ** Last message in was {'EXIT',<0.28.0>,eagain}
+%% ** When Server state == {state,standard_error,undefined,<0.28.0>,
+%% {local,standard_error_sup}}
+%% ** Reason for termination ==
+%% ** eagain
+%%
+%% This problem, observed with Erlang 18.0.2, was fixed in fd_driver by
+%% properly handling EAGAIN if it arises on file descriptor writes.
+%%
+output(Config) when is_list(Config) ->
+ Ref = monitor(process, standard_error_sup),
+ Chars = [ [["1234567890" || _ <- lists:seq(1,10)], $\s,
+ integer_to_list(L), $\r, $\n] || L <- lists:seq(1, 100) ],
+ ok = io:put_chars(standard_error, Chars),
+ receive
+ {'DOWN', Ref, process, _, _} ->
+ error(standard_error_noproc)
+ after
+ 500 ->
+ ok
+ end.
diff --git a/lib/kernel/vsn.mk b/lib/kernel/vsn.mk
index c912da0091..c8917ebc3c 100644
--- a/lib/kernel/vsn.mk
+++ b/lib/kernel/vsn.mk
@@ -1 +1 @@
-KERNEL_VSN = 4.0
+KERNEL_VSN = 4.2