aboutsummaryrefslogtreecommitdiffstats
path: root/lib/kernel
diff options
context:
space:
mode:
Diffstat (limited to 'lib/kernel')
-rw-r--r--lib/kernel/doc/src/Makefile4
-rw-r--r--lib/kernel/doc/src/app.xml40
-rw-r--r--lib/kernel/doc/src/application.xml24
-rw-r--r--lib/kernel/doc/src/auth.xml4
-rw-r--r--lib/kernel/doc/src/book.xml4
-rw-r--r--lib/kernel/doc/src/code.xml2
-rw-r--r--lib/kernel/doc/src/config.xml4
-rw-r--r--lib/kernel/doc/src/disk_log.xml4
-rw-r--r--lib/kernel/doc/src/erl_boot_server.xml4
-rw-r--r--lib/kernel/doc/src/erl_ddll.xml4
-rw-r--r--lib/kernel/doc/src/erl_prim_loader_stub.xml4
-rw-r--r--lib/kernel/doc/src/erlang_stub.xml4
-rw-r--r--lib/kernel/doc/src/error_handler.xml2
-rw-r--r--lib/kernel/doc/src/error_logger.xml4
-rw-r--r--lib/kernel/doc/src/fascicules.xml2
-rw-r--r--lib/kernel/doc/src/file.xml146
-rw-r--r--lib/kernel/doc/src/gen_sctp.xml35
-rw-r--r--lib/kernel/doc/src/gen_tcp.xml10
-rw-r--r--lib/kernel/doc/src/gen_udp.xml21
-rw-r--r--lib/kernel/doc/src/global.xml2
-rw-r--r--lib/kernel/doc/src/global_group.xml4
-rw-r--r--lib/kernel/doc/src/heart.xml13
-rw-r--r--lib/kernel/doc/src/inet.xml55
-rw-r--r--lib/kernel/doc/src/inet_res.xml4
-rw-r--r--lib/kernel/doc/src/init_stub.xml4
-rw-r--r--lib/kernel/doc/src/kernel_app.xml45
-rw-r--r--lib/kernel/doc/src/net_adm.xml4
-rw-r--r--lib/kernel/doc/src/net_kernel.xml4
-rw-r--r--lib/kernel/doc/src/notes.xml197
-rw-r--r--lib/kernel/doc/src/notes_history.xml4
-rw-r--r--lib/kernel/doc/src/os.xml4
-rw-r--r--lib/kernel/doc/src/part_notes.xml4
-rw-r--r--lib/kernel/doc/src/part_notes_history.xml4
-rw-r--r--lib/kernel/doc/src/pg2.xml4
-rw-r--r--lib/kernel/doc/src/ref_man.xml7
-rw-r--r--lib/kernel/doc/src/ref_man.xml.src67
-rw-r--r--lib/kernel/doc/src/rpc.xml4
-rw-r--r--lib/kernel/doc/src/seq_trace.xml4
-rw-r--r--lib/kernel/doc/src/specs.xml2
-rw-r--r--lib/kernel/doc/src/user.xml4
-rw-r--r--lib/kernel/doc/src/wrap_log_reader.xml4
-rw-r--r--lib/kernel/doc/src/zlib_stub.xml4
-rw-r--r--lib/kernel/include/dist.hrl3
-rw-r--r--lib/kernel/src/application.erl29
-rw-r--r--lib/kernel/src/application_controller.erl83
-rw-r--r--lib/kernel/src/application_master.erl44
-rw-r--r--lib/kernel/src/auth.erl4
-rw-r--r--lib/kernel/src/code.erl2
-rw-r--r--lib/kernel/src/code_server.erl251
-rw-r--r--lib/kernel/src/disk_log.erl13
-rw-r--r--lib/kernel/src/disk_log_1.erl78
-rw-r--r--lib/kernel/src/disk_log_server.erl30
-rw-r--r--lib/kernel/src/dist_ac.erl68
-rw-r--r--lib/kernel/src/dist_util.erl5
-rw-r--r--lib/kernel/src/erl_boot_server.erl35
-rw-r--r--lib/kernel/src/erl_epmd.erl71
-rw-r--r--lib/kernel/src/erl_reply.erl4
-rw-r--r--lib/kernel/src/error_logger.erl20
-rw-r--r--lib/kernel/src/erts_debug.erl25
-rw-r--r--lib/kernel/src/file.erl60
-rw-r--r--lib/kernel/src/file_io_server.erl12
-rw-r--r--lib/kernel/src/file_server.erl3
-rw-r--r--lib/kernel/src/gen_sctp.erl4
-rw-r--r--lib/kernel/src/gen_tcp.erl4
-rw-r--r--lib/kernel/src/gen_udp.erl2
-rw-r--r--lib/kernel/src/global.erl23
-rw-r--r--lib/kernel/src/global_group.erl13
-rw-r--r--lib/kernel/src/group.erl8
-rw-r--r--lib/kernel/src/heart.erl36
-rw-r--r--lib/kernel/src/hipe_unified_loader.erl35
-rw-r--r--lib/kernel/src/inet.erl36
-rw-r--r--lib/kernel/src/inet6_tcp_dist.erl2
-rw-r--r--lib/kernel/src/inet_config.erl3
-rw-r--r--lib/kernel/src/inet_db.erl11
-rw-r--r--lib/kernel/src/inet_gethost_native.erl6
-rw-r--r--lib/kernel/src/inet_int.hrl1
-rw-r--r--lib/kernel/src/inet_parse.erl2
-rw-r--r--lib/kernel/src/inet_res.erl33
-rw-r--r--lib/kernel/src/inet_sctp.erl4
-rw-r--r--lib/kernel/src/inet_tcp_dist.erl2
-rw-r--r--lib/kernel/src/kernel.app.src3
-rw-r--r--lib/kernel/src/kernel.appup.src16
-rw-r--r--lib/kernel/src/kernel.erl11
-rw-r--r--lib/kernel/src/kernel_config.erl6
-rw-r--r--lib/kernel/src/net_adm.erl6
-rw-r--r--lib/kernel/src/net_kernel.erl19
-rw-r--r--lib/kernel/src/os.erl56
-rw-r--r--lib/kernel/src/pg2.erl20
-rw-r--r--lib/kernel/src/rpc.erl30
-rw-r--r--lib/kernel/src/seq_trace.erl4
-rw-r--r--lib/kernel/src/standard_error.erl6
-rw-r--r--lib/kernel/src/user.erl8
-rw-r--r--lib/kernel/src/user_drv.erl41
-rw-r--r--lib/kernel/src/wrap_log_reader.erl10
-rw-r--r--lib/kernel/test/application_SUITE.erl103
-rw-r--r--lib/kernel/test/application_SUITE_data/deadlock/deadlock.app2
-rw-r--r--lib/kernel/test/application_SUITE_data/deadlock/deadlock.erl12
-rw-r--r--lib/kernel/test/application_SUITE_data/t4.config1
-rw-r--r--lib/kernel/test/code_SUITE.erl48
-rw-r--r--lib/kernel/test/file_SUITE.erl175
-rw-r--r--lib/kernel/test/file_name_SUITE.erl1
-rw-r--r--lib/kernel/test/gen_sctp_SUITE.erl125
-rw-r--r--lib/kernel/test/gen_tcp_misc_SUITE.erl147
-rw-r--r--lib/kernel/test/gen_udp_SUITE.erl109
-rw-r--r--lib/kernel/test/global_SUITE_data/global_trace.erl1
-rw-r--r--lib/kernel/test/heart_SUITE.erl8
-rw-r--r--lib/kernel/test/kernel_SUITE.erl116
-rw-r--r--lib/kernel/test/os_SUITE.erl26
-rw-r--r--lib/kernel/test/os_SUITE_data/my_echo.c28
-rw-r--r--lib/kernel/test/prim_file_SUITE.erl175
-rw-r--r--lib/kernel/test/ram_file_SUITE.erl3
-rw-r--r--lib/kernel/test/sendfile_SUITE.erl95
-rw-r--r--lib/kernel/test/zlib_SUITE.erl3
-rw-r--r--lib/kernel/vsn.mk2
114 files changed, 2345 insertions, 906 deletions
diff --git a/lib/kernel/doc/src/Makefile b/lib/kernel/doc/src/Makefile
index de3ca1e176..ec5d1f09e4 100644
--- a/lib/kernel/doc/src/Makefile
+++ b/lib/kernel/doc/src/Makefile
@@ -76,8 +76,8 @@ BOOK_FILES = book.xml
XML_FILES = \
$(BOOK_FILES) $(XML_CHAPTER_FILES) \
- $(XML_PART_FILES) $(XML_REF3_FILES) $(XML_REF4_FILES) \
- $(XML_REF6_FILES) $(XML_APPLICATION_FILES)
+ $(XML_PART_FILES) $(XML_REF3_FILES) $(XML_REF4_FILES)\
+ $(XML_REF6_FILES) $(XML_APPLICATION_FILES)
# ----------------------------------------------------
diff --git a/lib/kernel/doc/src/app.xml b/lib/kernel/doc/src/app.xml
index 1914844b37..8575d94048 100644
--- a/lib/kernel/doc/src/app.xml
+++ b/lib/kernel/doc/src/app.xml
@@ -1,10 +1,10 @@
-<?xml version="1.0" encoding="latin1" ?>
+<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE fileref SYSTEM "fileref.dtd">
<fileref>
<header>
<copyright>
- <year>1997</year><year>2012</year>
+ <year>1997</year><year>2013</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -61,7 +61,8 @@
{applications, Apps},
{env, Env},
{mod, Start},
- {start_phases, Phases}]}.
+ {start_phases, Phases},
+ {runtime_dependencies, RTDeps}]}.
Value Default
----- -------
@@ -77,8 +78,10 @@ Apps [App] []
Env [{Par,Val}] []
Start {Module,StartArgs} []
Phases [{Phase,PhaseArgs}] undefined
+RTDeps [ApplicationVersion] []
Module = Name = App = Par = Phase = atom()
- Val = StartArgs = PhaseArgs = term()</code>
+ Val = StartArgs = PhaseArgs = term()
+ ApplicationVersion = string()</code>
<p><c>Application</c> is the name of the application.</p>
<p>For the application controller, all keys are optional.
The respective default values are used for any omitted keys.</p>
@@ -87,6 +90,8 @@ Phases [{Phase,PhaseArgs}] undefined
<c>description</c>, <c>vsn</c>, <c>modules</c>, <c>registered</c>
and <c>applications</c>. The other keys are ignored by
<c>systools</c>.</p>
+ <warning><p>The <c>RTDeps</c> type was introduced in OTP 17.0 and
+ might be subject to changes during the OTP 17 release.</p></warning>
<taglist>
<tag><c>description</c></tag>
<item>
@@ -185,6 +190,33 @@ Phases [{Phase,PhaseArgs}] undefined
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>
+ <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
+ dependencies are minimum requirements. That is, a larger
+ application version than the one specified in the
+ dependency satisfies the requirement. For information on
+ 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
+ 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
+ compatible with the rest of the system.</p>
+ <p>Some dependencies might only be required in specific runtime
+ scenarios. In the case such optional dependencies exist, these are
+ specified and documented in the corresponding "App" documentation
+ of the specific application.</p>
+ <warning><p>The <c>runtime_dependencies</c> key was introduced in
+ OTP 17.0. The type of its value might be subject to changes during
+ the OTP 17 release.</p></warning>
+ <warning><p>All runtime dependencies specified in OTP applications
+ during the OTP 17 release may not be completely correct. This
+ is actively being worked on. Declared runtime dependencies in OTP
+ applications are expected to be correct in OTP 18.</p></warning>
+ </item>
</taglist>
</section>
diff --git a/lib/kernel/doc/src/application.xml b/lib/kernel/doc/src/application.xml
index 3909b11e59..7664fda4db 100644
--- a/lib/kernel/doc/src/application.xml
+++ b/lib/kernel/doc/src/application.xml
@@ -1,10 +1,10 @@
-<?xml version="1.0" encoding="latin1" ?>
+<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE erlref SYSTEM "erlref.dtd">
<erlref>
<header>
<copyright>
- <year>1996</year><year>2013</year>
+ <year>1996</year><year>2014</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -239,10 +239,19 @@ Nodes = [cp1@cave, {cp2@cave, cp3@cave}]</code>
<desc>
<p>Sets the value of the configuration parameter <c><anno>Par</anno></c> for
<c><anno>Application</anno></c>.</p>
- <p><c>set_env/3</c> uses the standard <c>gen_server</c> timeout
- value (5000 ms). A <c><anno>Timeout</anno></c> argument can be provided
+ <p><c>set_env/4</c> uses the standard <c>gen_server</c> timeout
+ value (5000 ms). The <c>timeout</c> option can be provided
if another timeout value is useful, for example, in situations
where the application controller is heavily loaded.</p>
+ <p>If <c>set_env/4</c> is called before the application is loaded,
+ the application environment values specified in the <c>Application.app</c>
+ file will override the ones previously set. This is also true for application
+ reloads.</p>
+ <p>The <c>persistent</c> option can be set to <c>true</c>
+ when there is a need to guarantee parameters set with <c>set_env/4</c>
+ will not be overridden by the ones defined in the application resource
+ file on load. This means persistent values will stick after the application
+ is loaded and also on application reload.</p>
<warning>
<p>Use this function only if you know what you are doing,
that is, on your own applications. It is very application
@@ -406,9 +415,11 @@ Nodes = [cp1@cave, {cp2@cave, cp3@cave}]</code>
<p>Removes the configuration parameter <c><anno>Par</anno></c> and its value
for <c><anno>Application</anno></c>.</p>
<p><c>unset_env/2</c> uses the standard <c>gen_server</c>
- timeout value (5000 ms). A <c><anno>Timeout</anno></c> argument can be
+ timeout value (5000 ms). The <c>timeout</c> option can be
provided if another timeout value is useful, for example, in
situations where the application controller is heavily loaded.</p>
+ <p><c>unset_env/3</c> also allows the persistent option to be passed
+ (see <c>set_env/4</c> above).</p>
<warning>
<p>Use this function only if you know what you are doing,
that is, on your own applications. It is very application
@@ -448,8 +459,7 @@ Nodes = [cp1@cave, {cp2@cave, cp3@cave}]</code>
<name>Module:start(StartType, StartArgs) -> {ok, Pid} | {ok, Pid, State} | {error, Reason}</name>
<fsummary>Start an application</fsummary>
<type>
- <v>StartType = normal | {takeover,Node} | {failover,Node}</v>
- <v>&nbsp;Node = node()</v>
+ <v>StartType = <seealso marker="#type-start_type">start_type()</seealso></v>
<v>StartArgs = term()</v>
<v>Pid = pid()</v>
<v>State = term()</v>
diff --git a/lib/kernel/doc/src/auth.xml b/lib/kernel/doc/src/auth.xml
index 15d9ef0fe4..72beee46f5 100644
--- a/lib/kernel/doc/src/auth.xml
+++ b/lib/kernel/doc/src/auth.xml
@@ -1,10 +1,10 @@
-<?xml version="1.0" encoding="latin1" ?>
+<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE erlref SYSTEM "erlref.dtd">
<erlref>
<header>
<copyright>
- <year>1996</year><year>2011</year>
+ <year>1996</year><year>2013</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
diff --git a/lib/kernel/doc/src/book.xml b/lib/kernel/doc/src/book.xml
index caf13fd001..09123976cb 100644
--- a/lib/kernel/doc/src/book.xml
+++ b/lib/kernel/doc/src/book.xml
@@ -1,10 +1,10 @@
-<?xml version="1.0" encoding="latin1" ?>
+<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE book SYSTEM "book.dtd">
<book xmlns:xi="http://www.w3.org/2001/XInclude">
<header titlestyle="normal">
<copyright>
- <year>1997</year><year>2009</year>
+ <year>1997</year><year>2013</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
diff --git a/lib/kernel/doc/src/code.xml b/lib/kernel/doc/src/code.xml
index 6f04741f85..454ee9bcbb 100644
--- a/lib/kernel/doc/src/code.xml
+++ b/lib/kernel/doc/src/code.xml
@@ -1,4 +1,4 @@
-<?xml version="1.0" encoding="latin1" ?>
+<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE erlref SYSTEM "erlref.dtd">
<erlref>
diff --git a/lib/kernel/doc/src/config.xml b/lib/kernel/doc/src/config.xml
index 34398e90ac..005504dbd1 100644
--- a/lib/kernel/doc/src/config.xml
+++ b/lib/kernel/doc/src/config.xml
@@ -1,10 +1,10 @@
-<?xml version="1.0" encoding="latin1" ?>
+<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE fileref SYSTEM "fileref.dtd">
<fileref>
<header>
<copyright>
- <year>1997</year><year>2009</year>
+ <year>1997</year><year>2013</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
diff --git a/lib/kernel/doc/src/disk_log.xml b/lib/kernel/doc/src/disk_log.xml
index d278d54d93..27d8ab4fc1 100644
--- a/lib/kernel/doc/src/disk_log.xml
+++ b/lib/kernel/doc/src/disk_log.xml
@@ -1,11 +1,11 @@
-<?xml version="1.0" encoding="latin1" ?>
+<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE erlref SYSTEM "erlref.dtd">
<erlref>
<header>
<copyright>
<year>1997</year>
- <year>2011</year>
+ <year>2013</year>
<holder>Ericsson AB, All Rights Reserved</holder>
</copyright>
<legalnotice>
diff --git a/lib/kernel/doc/src/erl_boot_server.xml b/lib/kernel/doc/src/erl_boot_server.xml
index 472671a80e..abaea4f695 100644
--- a/lib/kernel/doc/src/erl_boot_server.xml
+++ b/lib/kernel/doc/src/erl_boot_server.xml
@@ -1,10 +1,10 @@
-<?xml version="1.0" encoding="latin1" ?>
+<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE erlref SYSTEM "erlref.dtd">
<erlref>
<header>
<copyright>
- <year>1996</year><year>2011</year>
+ <year>1996</year><year>2013</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
diff --git a/lib/kernel/doc/src/erl_ddll.xml b/lib/kernel/doc/src/erl_ddll.xml
index 26db11cfcd..7be54c8b95 100644
--- a/lib/kernel/doc/src/erl_ddll.xml
+++ b/lib/kernel/doc/src/erl_ddll.xml
@@ -1,10 +1,10 @@
-<?xml version="1.0" encoding="latin1" ?>
+<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE erlref SYSTEM "erlref.dtd">
<erlref>
<header>
<copyright>
- <year>1997</year><year>2012</year>
+ <year>1997</year><year>2013</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
diff --git a/lib/kernel/doc/src/erl_prim_loader_stub.xml b/lib/kernel/doc/src/erl_prim_loader_stub.xml
index e6324b8168..485b16b91f 100644
--- a/lib/kernel/doc/src/erl_prim_loader_stub.xml
+++ b/lib/kernel/doc/src/erl_prim_loader_stub.xml
@@ -1,11 +1,11 @@
-<?xml version="1.0" encoding="latin1" ?>
+<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE erlref SYSTEM "erlref.dtd">
<erlref>
<header>
<copyright>
<year>1997</year>
- <year>2009</year>
+ <year>2013</year>
<holder>Ericsson AB, All Rights Reserved</holder>
</copyright>
<legalnotice>
diff --git a/lib/kernel/doc/src/erlang_stub.xml b/lib/kernel/doc/src/erlang_stub.xml
index 333c4fedaf..79a041110a 100644
--- a/lib/kernel/doc/src/erlang_stub.xml
+++ b/lib/kernel/doc/src/erlang_stub.xml
@@ -1,11 +1,11 @@
-<?xml version="1.0" encoding="latin1" ?>
+<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE erlref SYSTEM "erlref.dtd">
<erlref>
<header>
<copyright>
<year>1997</year>
- <year>2009</year>
+ <year>2013</year>
<holder>Ericsson AB, All Rights Reserved</holder>
</copyright>
<legalnotice>
diff --git a/lib/kernel/doc/src/error_handler.xml b/lib/kernel/doc/src/error_handler.xml
index 84ec3927c8..2f8f09b984 100644
--- a/lib/kernel/doc/src/error_handler.xml
+++ b/lib/kernel/doc/src/error_handler.xml
@@ -1,4 +1,4 @@
-<?xml version="1.0" encoding="latin1" ?>
+<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE erlref SYSTEM "erlref.dtd">
<erlref>
diff --git a/lib/kernel/doc/src/error_logger.xml b/lib/kernel/doc/src/error_logger.xml
index cd86b364f6..3815b0877c 100644
--- a/lib/kernel/doc/src/error_logger.xml
+++ b/lib/kernel/doc/src/error_logger.xml
@@ -1,10 +1,10 @@
-<?xml version="1.0" encoding="latin1" ?>
+<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE erlref SYSTEM "erlref.dtd">
<erlref>
<header>
<copyright>
- <year>1996</year><year>2012</year>
+ <year>1996</year><year>2013</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
diff --git a/lib/kernel/doc/src/fascicules.xml b/lib/kernel/doc/src/fascicules.xml
index 43090b4aed..fadd37eefb 100644
--- a/lib/kernel/doc/src/fascicules.xml
+++ b/lib/kernel/doc/src/fascicules.xml
@@ -1,4 +1,4 @@
-<?xml version="1.0" encoding="latin1" ?>
+<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE fascicules SYSTEM "fascicules.dtd">
<fascicules>
diff --git a/lib/kernel/doc/src/file.xml b/lib/kernel/doc/src/file.xml
index 66ecba1bf2..8dae34431b 100644
--- a/lib/kernel/doc/src/file.xml
+++ b/lib/kernel/doc/src/file.xml
@@ -1,10 +1,10 @@
-<?xml version="1.0" encoding="latin1" ?>
+<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE erlref SYSTEM "erlref.dtd">
<erlref>
<header>
<copyright>
- <year>1996</year><year>2013</year>
+ <year>1996</year><year>2014</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -37,54 +37,48 @@
the file operations. See the command line flag
<c>+A</c> in <seealso marker="erts:erl">erl(1)</seealso>.</p>
- <p>The Erlang VM supports file names in Unicode to a limited
- extent. Depending on how the VM is started (with the parameter
- <c>+fnu</c> or <c>+fnl</c>), file names given can contain
- characters > 255 and the VM system will convert file names
- back and forth to the native file name encoding.</p>
+ <p>With regard to file name encoding, the Erlang VM can operate in
+ two modes. The current mode can be queried using the <seealso
+ marker="#native_name_encoding">native_name_encoding/0</seealso>
+ function. It returns either <c>latin1</c> or <c>utf8</c>.</p>
- <p>The default behavior for Unicode character translation depends
- on to what extent the underlying OS/filesystem enforces consistent
- naming. On OSes where all file names are ensured to be in one or
- another encoding, Unicode is the default (currently this holds for
- Windows and MacOSX). On OSes with completely transparent file
- naming (i.e. all Unixes except MacOSX), ISO-latin-1 file naming is
- the default. The reason for the ISO-latin-1 default is that
- file names are not guaranteed to be possible to interpret according to
- the Unicode encoding expected (i.e. UTF-8), and file names that
- cannot be decoded will only be accessible by using &quot;raw
- file names&quot;, in other word file names given as binaries.</p>
-
- <p>As file names are traditionally not binaries in Erlang,
- applications that need to handle raw file names need to be
- converted, why the Unicode mode for file names is not default on
- systems having completely transparent file naming.</p>
+ <p>In the <c>latin1</c> mode, the Erlang VM does not change the
+ encoding of file names. In the <c>utf8</c> mode, file names can
+ contain Unicode characters greater than 255 and the VM will
+ convert file names back and forth to the native file name encoding
+ (usually UTF-8, but UTF-16 on Windows).</p>
- <p>Raw file names is a new feature in OTP R14B01, which allows the
- user to supply completely uninterpreted file names to the
- underlying OS/filesystem. They are supplied as binaries, where it
- is up to the user to supply a correct encoding for the
- environment. The function <c>file:native_name_encoding()</c> can
- be used to check what encoding the VM is working in. If the
- function returns <c>latin1</c> file names are not in any way
- converted to Unicode, if it is <c>utf8</c>, raw file names should
- be encoded as UTF-8 if they are to follow the convention of the VM
- (and usually the convention of the OS as well). Using raw
- file names is useful if you have a filesystem with inconsistent
- file naming, where some files are named in UTF-8 encoding while
- others are not. A file:list_dir on such mixed file name systems
- when the VM is in Unicode file name mode might return file names as
- raw binaries as they cannot be interpreted as Unicode
- file names. Raw file names can also be used to give UTF-8 encoded
- file names even though the VM is not started in Unicode file name
- translation mode.</p>
+ <p>The default mode depends on the operating system. Windows and
+ MacOS X enforce consistent file name encoding and therefore the
+ VM uses the <c>utf8</c> mode.</p>
+
+ <p>On operating systems with transparent naming (i.e. all Unix
+ systems except MacOS X), the default will be <c>utf8</c> if the
+ terminal supports UTF-8, otherwise <c>latin1</c>. The default may
+ be overridden using the <c>+fnl</c> (to force <c>latin1</c> mode)
+ or <c>+fnu</c> (to force <c>utf8</c> mode) when starting <seealso
+ marker="erts:erl">erl</seealso>.</p>
+
+ <p>On operating systems with transparent naming, files could be
+ inconsistently named, i.e. some files are encoded in UTF-8 while
+ others are encoded in (for example) iso-latin1. To be able to
+ handle file systems with inconsistent naming when running in the
+ <c>utf8</c> mode, the concept of "raw file names" has been
+ introduced.</p>
+
+ <p>A raw file name is a file name given as a binary. The Erlang VM
+ will perform no translation of a file name given as a binary on
+ systems with transparent naming.</p>
+
+ <p>When running in the <c>utf8</c> mode, the
+ <c>file:list_dir/1</c> and <c>file:read_link/1</c> functions will
+ never return raw file names. Use the <seealso
+ marker="#list_dir_all">list_dir_all/1</seealso> and <seealso
+ marker="#read_link_all">read_link_all/1</seealso> functions to
+ return all file names including raw file names.</p>
+
+ <p>Also see <seealso marker="stdlib:unicode_usage#notes-about-raw-filenames">Notes about raw file names</seealso>.</p>
- <p>Note that on Windows, <c>file:native_name_encoding()</c>
- returns <c>utf8</c> per default, which is the format for raw
- file names even on Windows, although the underlying OS specific
- code works in a limited version of little endian UTF16. As far as
- the Erlang programmer is concerned, Windows native Unicode format
- is UTF-8...</p>
</description>
<datatypes>
@@ -535,8 +529,8 @@
<name name="list_dir_all" arity="1"/>
<fsummary>List all files in a directory</fsummary>
<desc>
- <p>Lists all the files in a directory, including files with
- "raw" names.
+ <p><marker id="list_dir_all"/>Lists all the files in a directory,
+ including files with "raw" names.
Returns <c>{ok, <anno>Filenames</anno>}</c> if successful.
Otherwise, it returns <c>{error, <anno>Reason</anno>}</c>.
<c><anno>Filenames</anno></c> is a list of
@@ -648,16 +642,24 @@
<item>
<p>Symbolic links are not supported on this platform.</p>
</item>
+ <tag><c>eperm</c></tag>
+ <item>
+ <p>User does not have privileges to create symbolic links
+ (<c>SeCreateSymbolicLinkPrivilege</c> on Windows).</p>
+ </item>
</taglist>
</desc>
</func>
<func>
<name name="native_name_encoding" arity="0"/>
- <fsummary>Return the VM's configured filename encoding.</fsummary>
+ <fsummary>Return the VM's configured filename encoding</fsummary>
<desc>
- <p>This function returns the configured default file name encoding to use for raw file names. Generally an application supplying file names raw (as binaries), should obey the character encoding returned by this function.</p>
- <p>By default, the VM uses ISO-latin-1 file name encoding on filesystems and/or OSes that use completely transparent file naming. This includes all Unix versions except MacOSX, where the vfs layer enforces UTF-8 file naming. By giving the experimental option <c>+fnu</c> when starting Erlang, UTF-8 translation of file names can be turned on even for those systems. If Unicode file name translation is in effect, the system behaves as usual as long as file names conform to the encoding, but will return file names that are not properly encoded in UTF-8 as raw file names (i.e. binaries).</p>
- <p>On Windows, this function also returns <c>utf8</c> by default. The OS uses a pure Unicode naming scheme and file names are always possible to interpret as valid Unicode. The fact that the underlying Windows OS actually encodes file names using little endian UTF-16 can be ignored by the Erlang programmer. Windows and MacOSX are the only operating systems where the VM operates in Unicode file name mode by default.</p>
+ <p><marker id="native_name_encoding"/>This function returns
+ the file name encoding mode. If it is <c>latin1</c>, the
+ system does no translation of file names. If it is
+ <c>utf8</c>, file names will be converted back and forth to
+ the native file name encoding (usually UTF-8, but UTF-16 on
+ Windows).</p>
</desc>
</func>
<func>
@@ -826,6 +828,16 @@
<item>
<p><c>File</c> must be <c>iodata()</c>. Returns an <c>fd()</c> which lets the <c>file</c> module operate on the data in-memory as if it is a file.</p>
</item>
+ <tag><c>sync</c></tag>
+ <item>
+ <p>On platforms that support it, enables the POSIX <c>O_SYNC</c> synchronous I/O flag or its platform-dependent
+ equivalent (e.g., <c>FILE_FLAG_WRITE_THROUGH</c> on Windows) so that writes to the file block until the data has
+ been physically written to disk. Be aware, though, that the exact semantics of this flag differ from platform to
+ platform; for example, neither Linux nor Windows guarantees that all file metadata are also written before the call
+ returns. For precise semantics, check the details of your platform's documentation. On platforms with no
+ support for POSIX <c>O_SYNC</c> or equivalent, use of the <c>sync</c> flag causes <c>open</c> to return
+ <c>{error, enotsup}</c>.</p>
+ </item>
</taglist>
<p>Returns:</p>
<taglist>
@@ -1440,7 +1452,8 @@
<name name="read_link" arity="1"/>
<fsummary>See what a link is pointing to</fsummary>
<desc>
- <p>This function returns <c>{ok, <anno>Filename</anno>}</c> if
+ <p><marker id="read_link_all"/>This function returns
+ <c>{ok, <anno>Filename</anno>}</c> if
<c><anno>Name</anno></c> refers to a symbolic link that is
not a "raw" file name, or <c>{error, <anno>Reason</anno>}</c>
otherwise.
@@ -1622,6 +1635,11 @@
<desc>
<p>Sets the current working directory of the file server to
<c><anno>Dir</anno></c>. Returns <c>ok</c> if successful.</p>
+ <p>The functions in the <c>file</c> module usually treat binaries
+ as raw filenames, i.e. they are passed as is even when the encoding
+ of the binary does not agree with <c>file:native_name_encoding()</c>.
+ This function however expects binaries to be encoded according to the
+ value returned by <c>file:native_name_encoding()</c>.</p>
<p>Typical error reasons are:</p>
<taglist>
<tag><c>enoent</c></tag>
@@ -1646,8 +1664,8 @@
<tag><c>no_translation</c></tag>
<item>
<p><c><anno>Dir</anno></c> is a <c>binary()</c> with
- characters coded in ISO-latin-1 and the VM was started
- with the parameter <c>+fnue</c>.</p>
+ characters coded in ISO-latin-1 and the VM is operating
+ with unicode file name encoding.</p>
</item>
</taglist>
<warning>
@@ -1736,16 +1754,16 @@
<item>The chunk size used by the erlang fallback to send
data. If using the fallback, this should be set to a value
which comfortably fits in the systems memory. Default is 20 MB.</item>
+ <tag><c>use_threads</c></tag>
+ <item>Instruct the emulator to use the async thread pool for the
+ sendfile system call. This could be usefull if the OS you are running
+ on does not properly support non-blocking sendfile calls. Do note that
+ using async threads potentially makes your system volnerable to slow
+ client attacks. If set to true and no async threads are available,
+ the sendfile call will return <c>{error,einval}</c>.
+ Introduced in Erlang/OTP 17.0. Default is false.</item>
</taglist>
</p>
- <p>On operating systems with thread support, it is recommended to use
- async threads. See the command line flag
- <c>+A</c> in <seealso marker="erts:erl">erl(1)</seealso>. If it is not
- possible to use async threads for sendfile, it is recommended to use
- a relatively small value for the send buffer on the socket. Otherwise
- the Erlang VM might loose some of its soft realtime guarantees.
- Which size to use depends on the OS/hardware and the requirements
- of the application.</p>
</desc>
</func>
<func>
diff --git a/lib/kernel/doc/src/gen_sctp.xml b/lib/kernel/doc/src/gen_sctp.xml
index 33f1c20608..dc9e4766a9 100644
--- a/lib/kernel/doc/src/gen_sctp.xml
+++ b/lib/kernel/doc/src/gen_sctp.xml
@@ -1,10 +1,10 @@
-<?xml version="1.0" encoding="latin1" ?>
+<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE erlref SYSTEM "erlref.dtd">
<erlref>
<header>
<copyright>
- <year>2007</year><year>2012</year>
+ <year>2007</year><year>2013</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -496,9 +496,11 @@
orthogonal to the sets of TCP, UDP and generic INET options:
only those options which are explicitly listed below are allowed
for SCTP sockets. Options can be set on the socket using
- <c>gen_sctp:open/1,2</c> or <c>inet:setopts/2</c>,
- retrieved using <c>inet:getopts/2</c>, and when calling
- <c>gen_sctp:connect/4,5</c> options can be changed.</p>
+ <seealso marker="#open/1"><c>gen_sctp:open/1,2</c></seealso>
+ or <seealso marker="inet#setopts/2"><c>inet:setopts/2</c></seealso>,
+ retrieved using <seealso marker="inet#getopts/2"><c>inet:getopts/2</c></seealso>,
+ and when calling <seealso marker="#connect/4"><c>gen_sctp:connect/4,5</c></seealso>
+ options can be changed.</p>
<marker id="option-binary"></marker>
<marker id="option-list"></marker>
<taglist>
@@ -507,7 +509,7 @@
<p>Determines the type of data returned from <c>gen_sctp:recv/1,2</c>.</p>
<marker id="option-active"></marker>
</item>
- <tag><c>{active, true|false|once}</c></tag>
+ <tag><c>{active, true|false|once|N}</c></tag>
<item>
<list type="bulleted">
<item>
@@ -524,11 +526,28 @@
</item>
<item>
<p>If <c>once</c>, only one message is automatically placed
- in the message queue, after that the mode is automatically
- re-set to passive. This provides flow control as well as
+ in the message queue, and after that the mode is automatically
+ reset to passive. This provides flow control as well as
the possibility for the receiver to listen for its incoming
SCTP data interleaved with other inter-process messages.</p>
</item>
+ <item>
+ <p>If <c>active</c> is specified as an integer <c>N</c> in the
+ range -32768 to 32767 (inclusive), then that number is added to
+ the socket's count of the number of data messages to be
+ delivered to the controlling process. If the result of the
+ addition would be negative, the count is set to 0. Once the
+ count reaches 0, either through the delivery of messages or by
+ being explicitly set with <seealso
+ marker="inet#setopts/2">inet:setopts/2</seealso>, the socket's
+ mode is automatically reset to passive (<c>{active,
+ false}</c>) mode. When a socket in this active mode transitions to
+ passive mode, the message <c>{sctp_passive, Socket}</c> is sent
+ to the controlling process to notify it that if it wants to
+ receive more data messages from the socket, it must call
+ <seealso marker="inet#setopts/2">inet:setopts/2</seealso> to set
+ the socket back into an active mode.</p>
+ </item>
</list>
</item>
<tag><c>{tos, integer()}</c></tag>
diff --git a/lib/kernel/doc/src/gen_tcp.xml b/lib/kernel/doc/src/gen_tcp.xml
index 11a0843c10..dbd0d3c815 100644
--- a/lib/kernel/doc/src/gen_tcp.xml
+++ b/lib/kernel/doc/src/gen_tcp.xml
@@ -1,10 +1,10 @@
-<?xml version="1.0" encoding="latin1" ?>
+<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE erlref SYSTEM "erlref.dtd">
<erlref>
<header>
<copyright>
- <year>1997</year><year>2012</year>
+ <year>1997</year><year>2013</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -148,6 +148,12 @@ do_recv(Sock, Bs) ->
as messages:</p>
<code type="none">
{tcp, Socket, Data}</code>
+ <p>If the socket is in <c>{active, N}</c> mode (see <seealso marker="inet#setopts/2">
+ inet:setopts/2</seealso> for details) and its message counter
+ drops to 0, the following message is delivered to indicate that the
+ socket has transitioned to passive (<c>{active, false}</c>) mode:</p>
+ <code type="none">
+{tcp_passive, Socket}</code>
<p>If the socket is closed, the following message is delivered:</p>
<code type="none">
{tcp_closed, Socket}</code>
diff --git a/lib/kernel/doc/src/gen_udp.xml b/lib/kernel/doc/src/gen_udp.xml
index 4850278a64..503725fe18 100644
--- a/lib/kernel/doc/src/gen_udp.xml
+++ b/lib/kernel/doc/src/gen_udp.xml
@@ -1,10 +1,10 @@
-<?xml version="1.0" encoding="latin1" ?>
+<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE erlref SYSTEM "erlref.dtd">
<erlref>
<header>
<copyright>
- <year>1997</year><year>2012</year>
+ <year>1997</year><year>2013</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -145,14 +145,23 @@
<seealso marker="inet#setopts/2">inet:setopts/2</seealso>.</p>
</item>
</taglist>
- <p>The returned socket <c><anno>Socket</anno></c> is used to send packets
- from this port with <c>send/4</c>. When UDP packets arrive at
- the opened port, they are delivered as messages:</p>
+ <p>The returned socket <c><anno>Socket</anno></c> is used to send
+ packets from this port with <c>send/4</c>. When UDP packets arrive
+ at the opened port, if the socket is in an active mode the packets
+ are delivered as messages to the controlling process:</p>
<code type="none">
{udp, Socket, IP, InPortNo, Packet}</code>
- <p>Note that arriving UDP packets that are longer than
+ <p>If the socket is not in an active mode, data can be
+ retrieved via the <seealso marker="#recv/2">recv/2,3</seealso> calls.
+ Note that arriving UDP packets that are longer than
the receive buffer option specifies, might be truncated
without warning.</p>
+ <p>When a socket in <c>{active, N}</c> mode (see <seealso marker="inet#setopts/2">
+ inet:setopts/2</seealso> for details) transitions to passive
+ (<c>{active, false}</c>) mode, the controlling process is notified by a
+ message of the following form:</p>
+ <code type="none">
+{udp_passive, Socket}</code>
<p><c>IP</c> and <c>InPortNo</c> define the address from which
<c>Packet</c> came. <c>Packet</c> is a list of bytes if
the option <c>list</c> was specified. <c>Packet</c> is a
diff --git a/lib/kernel/doc/src/global.xml b/lib/kernel/doc/src/global.xml
index 53958c47c2..691b243443 100644
--- a/lib/kernel/doc/src/global.xml
+++ b/lib/kernel/doc/src/global.xml
@@ -1,4 +1,4 @@
-<?xml version="1.0" encoding="latin1" ?>
+<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE erlref SYSTEM "erlref.dtd">
<erlref>
diff --git a/lib/kernel/doc/src/global_group.xml b/lib/kernel/doc/src/global_group.xml
index abf6178fc4..2c181da83a 100644
--- a/lib/kernel/doc/src/global_group.xml
+++ b/lib/kernel/doc/src/global_group.xml
@@ -1,10 +1,10 @@
-<?xml version="1.0" encoding="latin1" ?>
+<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE erlref SYSTEM "erlref.dtd">
<erlref>
<header>
<copyright>
- <year>1998</year><year>2011</year>
+ <year>1998</year><year>2013</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
diff --git a/lib/kernel/doc/src/heart.xml b/lib/kernel/doc/src/heart.xml
index 2856d84dcf..3ec33d2f18 100644
--- a/lib/kernel/doc/src/heart.xml
+++ b/lib/kernel/doc/src/heart.xml
@@ -1,10 +1,10 @@
-<?xml version="1.0" encoding="latin1" ?>
+<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE erlref SYSTEM "erlref.dtd">
<erlref>
<header>
<copyright>
- <year>1996</year><year>2012</year>
+ <year>1996</year><year>2013</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -118,8 +118,13 @@
the system. The new Erlang runtime system will (if it
misbehaves) use the environment variable
<c>HEART_COMMAND</c> to reboot.</p>
- <p>Limitations: The length of the <c><anno>Cmd</anno></c> command string
- must be less than 2047 characters.</p>
+
+ <p>Limitations: The <c><anno>Cmd</anno></c> command string
+ will be sent to the heart program as a ISO-latin-1 or UTF-8
+ encoded binary depending on the file name encoding mode of the
+ emulator (see
+ <seealso marker="kernel:file#native_name_encoding/0"><c>file:native_name_encoding/0</c></seealso>).
+ The size of the encoded binary must be less than 2047 bytes.</p>
</desc>
</func>
<func>
diff --git a/lib/kernel/doc/src/inet.xml b/lib/kernel/doc/src/inet.xml
index bc4c68230e..50e1cc290c 100644
--- a/lib/kernel/doc/src/inet.xml
+++ b/lib/kernel/doc/src/inet.xml
@@ -1,4 +1,4 @@
-<?xml version="1.0" encoding="latin1" ?>
+<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE erlref SYSTEM "erlref.dtd">
<erlref>
@@ -361,7 +361,7 @@ fe80::204:acff:fe17:bf38
</item>
<tag><c>send_dvi</c></tag>
<item>
- <p>Average packet size deviation in bytes received sent from the socket.</p>
+ <p>Average packet size deviation in bytes sent from the socket.</p>
</item>
<tag><c>send_max</c></tag>
<item>
@@ -544,47 +544,66 @@ fe80::204:acff:fe17:bf38
<p>Sets one or more options for a socket. The following options
are available:</p>
<taglist>
- <tag><c>{active, true | false | once}</c></tag>
+ <tag><c>{active, true | false | once | N}</c></tag>
<item>
<p>If the value is <c>true</c>, which is the default,
everything received from the socket will be sent as
messages to the receiving process. If the value is
<c>false</c> (passive mode), the process must explicitly
- receive incoming data by calling <c>gen_tcp:recv/2,3</c>
- or <c>gen_udp:recv/2,3</c> (depending on the type of
- socket).</p>
+ receive incoming data by calling
+ <seealso marker="gen_tcp#recv/2"><c>gen_tcp:recv/2,3</c></seealso>,
+ <seealso marker="gen_udp#recv/2"><c>gen_udp:recv/2,3</c></seealso>
+ or <seealso marker="gen_sctp#recv/1"><c>gen_sctp:recv/1,2</c></seealso>
+ (depending on the type of socket).</p>
<p>If the value is <c>once</c> (<c>{active, once}</c>),
<em>one</em> data message from the socket will be sent
to the process. To receive one more message,
<c>setopts/2</c> must be called again with the
<c>{active, once}</c> option.</p>
- <p>When using <c>{active, once}</c>, the socket changes
- behaviour automatically when data is received. This can
- sometimes be confusing in combination with connection
- oriented sockets (i.e. <c>gen_tcp</c>) as a socket with
- <c>{active, false}</c> behaviour reports closing
+ <p>If the value is an integer <c>N</c> in the range -32768 to 32767
+ (inclusive), the value is added to the socket's count of data
+ messages sent to the controlling process. A socket's default
+ message count is 0. If a negative value is specified and its
+ magnitude is equal to or greater than the socket's current
+ message count, the socket's message count is set to 0. Once
+ the socket's message count reaches 0, either due to sending
+ received data messages to the process or by being explicitly set,
+ the process is then notified by a special message, specific to
+ the type of socket, that the socket has entered passive
+ mode. Once the socket enters passive mode, to receive more
+ messages <c>setopts/2</c> must be called again to set the
+ socket back into an active mode.</p>
+ <p>When using <c>{active, once}</c> or <c>{active, N}</c>, the
+ socket changes behaviour automatically when data is received.
+ This can sometimes be confusing in combination with
+ connection-oriented sockets (i.e. <c>gen_tcp</c>) as a socket
+ with <c>{active, false}</c> behaviour reports closing
differently than a socket with <c>{active, true}</c>
behaviour. To make programming easier, a socket where
the peer closed and this was detected while in
<c>{active, false}</c> mode, will still generate the
message
- <c>{tcp_closed,Socket}</c> when set to <c>{active, once}</c> or <c>{active, true}</c> mode. It is therefore
+ <c>{tcp_closed,Socket}</c> when set to <c>{active, once}</c>,
+ <c>{active, true}</c> or <c>{active, N}</c> mode. It is therefore
safe to assume that the message
<c>{tcp_closed,Socket}</c>, possibly followed by socket
port termination (depending on the <c>exit_on_close</c>
option) will eventually appear when a socket changes
back and forth between <c>{active, true}</c> and
- <c>{active, false}</c> mode. However,
+ <c>{active, false}</c> mode. However,
<em>when</em> peer closing is detected is all up to the
underlying TCP/IP stack and protocol.</p>
- <p>Note that <c>{active,true}</c> mode provides no flow
+ <p>Note that <c>{active, true}</c> mode provides no flow
control; a fast sender could easily overflow the
- receiver with incoming messages. Use active mode only if
+ receiver with incoming messages. The same is true of
+ <c>{active, N}</c> mode while the message count is greater
+ than zero. Use active mode only if
your high-level protocol provides its own flow control
(for instance, acknowledging received messages) or the
- amount of data exchanged is small. <c>{active,false}</c>
- mode or use of the <c>{active, once}</c> mode provides
- flow control; the other side will not be able send
+ amount of data exchanged is small. <c>{active, false}</c>
+ mode, use of the <c>{active, once}</c> mode or <c>{active, N}</c>
+ mode with values of <c>N</c> appropriate for the application
+ provides flow control; the other side will not be able send
faster than the receiver can read.</p>
</item>
diff --git a/lib/kernel/doc/src/inet_res.xml b/lib/kernel/doc/src/inet_res.xml
index bf73ccf13d..7880ccda05 100644
--- a/lib/kernel/doc/src/inet_res.xml
+++ b/lib/kernel/doc/src/inet_res.xml
@@ -1,10 +1,10 @@
-<?xml version="1.0" encoding="latin1" ?>
+<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE erlref SYSTEM "erlref.dtd">
<erlref>
<header>
<copyright>
- <year>2009</year><year>2011</year>
+ <year>2009</year><year>2013</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
diff --git a/lib/kernel/doc/src/init_stub.xml b/lib/kernel/doc/src/init_stub.xml
index e8645458e4..5c57f8850e 100644
--- a/lib/kernel/doc/src/init_stub.xml
+++ b/lib/kernel/doc/src/init_stub.xml
@@ -1,11 +1,11 @@
-<?xml version="1.0" encoding="latin1" ?>
+<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE erlref SYSTEM "erlref.dtd">
<erlref>
<header>
<copyright>
<year>1997</year>
- <year>2009</year>
+ <year>2013</year>
<holder>Ericsson AB, All Rights Reserved</holder>
</copyright>
<legalnotice>
diff --git a/lib/kernel/doc/src/kernel_app.xml b/lib/kernel/doc/src/kernel_app.xml
index faa8f86dbd..00c6bc33d6 100644
--- a/lib/kernel/doc/src/kernel_app.xml
+++ b/lib/kernel/doc/src/kernel_app.xml
@@ -1,10 +1,10 @@
-<?xml version="1.0" encoding="latin1" ?>
+<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE appref SYSTEM "appref.dtd">
<appref>
<header>
<copyright>
- <year>1996</year><year>2012</year>
+ <year>1996</year><year>2014</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -35,7 +35,7 @@
Erlang/OTP consists of Kernel and STDLIB. The Kernel application
contains the following services:</p>
<list type="bulleted">
- <item>application controller, see <c>application(3)</c></item>
+ <item>application controller, see <seealso marker="application">application(3)</seealso></item>
<item><c>code</c></item>
<item><c>disk_log</c></item>
<item><c>dist_ac</c>, distributed application controller</item>
@@ -66,8 +66,8 @@
<section>
<title>Configuration</title>
<p>The following configuration parameters are defined for the Kernel
- application. See <c>app(3)</c> for more information about
- configuration parameters.</p>
+ application. See <seealso marker="app">app(4)</seealso> for more
+ information about configuration parameters.</p>
<taglist>
<tag><c>browser_cmd = string() | {M,F,A}</c></tag>
<item>
@@ -93,7 +93,8 @@
<item><c>Time = integer()>0</c></item>
<item><c>Nodes = [node() | {node(),...,node()}]</c></item>
</list>
- <p>The parameter is described in <c>application(3)</c>, function
+ <p>The parameter is described in
+ <seealso marker="application">application(3)</seealso>, function
<c>load/2</c>.</p>
</item>
<tag><c>dist_auto_connect = Value</c></tag>
@@ -105,11 +106,13 @@
<taglist>
<tag><c>never</c></tag>
<item>Connections are never automatically established, they
- must be explicitly connected. See <c>net_kernel(3)</c>.</item>
+ must be explicitly connected. See
+ <seealso marker="net_kernel">net_kernel(3)</seealso>.</item>
<tag><c>once</c></tag>
<item>Connections will be established automatically, but only
once per node. If a node goes down, it must thereafter be
- explicitly connected. See <c>net_kernel(3)</c>.</item>
+ explicitly connected. See
+ <seealso marker="net_kernel">net_kernel(3)</seealso>.</item>
</taglist>
</item>
<tag><c>permissions = [Perm]</c></tag>
@@ -121,7 +124,8 @@
<item><c>ApplName = atom()</c></item>
<item><c>Bool = boolean()</c></item>
</list>
- <p>Permissions are described in <c>application(3)</c>, function
+ <p>Permissions are described in
+ <seealso marker="application">application(3)</seealso>, function
<c>permit/2</c>.</p>
</item>
<tag><c>error_logger = Value</c></tag>
@@ -149,7 +153,8 @@
</item>
<tag><c>global_groups = [GroupTuple]</c></tag>
<item>
- <p>Defines global groups, see <c>global_group(3)</c>.</p>
+ <p>Defines global groups, see
+ <seealso marker="global_group">global_group(3)</seealso>.</p>
<list type="bulleted">
<item><c>GroupTuple = {GroupName, [Node]} | {GroupName, PublishType, [Node]}</c></item>
<item><c>GroupName = atom()</c></item>
@@ -160,18 +165,19 @@
<tag><c>inet_default_connect_options = [{Opt, Val}]</c></tag>
<item>
<p>Specifies default options for <c>connect</c> sockets,
- see <c>inet(3)</c>.</p>
+ see <seealso marker="inet">inet(3)</seealso>.</p>
</item>
<tag><c>inet_default_listen_options = [{Opt, Val}]</c></tag>
<item>
<p>Specifies default options for <c>listen</c> (and
- <c>accept</c>) sockets, see <c>inet(3)</c>.</p>
+ <c>accept</c>) sockets, see <seealso marker="inet">inet(3)</seealso>.</p>
</item>
<tag><c>{inet_dist_use_interface, ip_address()}</c></tag>
<item>
<p>If the host of an Erlang node has several network interfaces,
this parameter specifies which one to listen on. See
- <c>inet(3)</c> for the type definition of <c>ip_address()</c>.</p>
+ <seealso marker="inet">inet(3)</seealso> for the type definition
+ of <c>ip_address()</c>.</p>
</item>
<tag><c>{inet_dist_listen_min, First}</c></tag>
<item>
@@ -276,7 +282,8 @@ MaxT = TickTime + TickTime / 4</code>
<tag><c>start_boot_server = true | false</c></tag>
<item>
<p>Starts the <c>boot_server</c> if the parameter is <c>true</c>
- (see <c>erl_boot_server(3)</c>). This parameter should be
+ (see <seealso marker="erl_boot_server">erl_boot_server(3)</seealso>).
+ This parameter should be
set to <c>true</c> in an embedded system which uses this
service.</p>
<p>The default value is <c>false</c>.</p>
@@ -296,13 +303,15 @@ MaxT = TickTime + TickTime / 4</code>
<tag><c>start_disk_log = true | false</c></tag>
<item>
<p>Starts the <c>disk_log_server</c> if the parameter is
- <c>true</c> (see <c>disk_log(3)</c>). This parameter should be
+ <c>true</c> (see <seealso marker="disk_log">disk_log(3)</seealso>).
+ This parameter should be
set to true in an embedded system which uses this service.</p>
<p>The default value is <c>false</c>.</p>
</item>
<tag><c>start_pg2 = true | false</c></tag>
<item>
- <p>Starts the <c>pg2</c> server (see <c>pg2(3)</c>) if
+ <p>Starts the <c>pg2</c> server (see
+ <seealso marker="pg2">pg2(3)</seealso>) if
the parameter is <c>true</c>. This parameter should be set to
<c>true</c> in an embedded system which uses this service.</p>
<p>The default value is <c>false</c>.</p>
@@ -310,7 +319,8 @@ MaxT = TickTime + TickTime / 4</code>
<tag><c>start_timer = true | false</c></tag>
<item>
<p>Starts the <c>timer_server</c> if the parameter is
- <c>true</c> (see <c>timer(3)</c>). This parameter should be
+ <c>true</c> (see <seealso marker="stdlib:timer">timer(3)</seealso>).
+ This parameter should be
set to <c>true</c> in an embedded system which uses this
service.</p>
<p>The default value is <c>false</c>.</p>
@@ -351,6 +361,7 @@ MaxT = TickTime + TickTime / 4</code>
<seealso marker="pg2">pg2(3)</seealso>,
<seealso marker="rpc">rpc(3)</seealso>,
<seealso marker="seq_trace">seq_trace(3)</seealso>,
+ <seealso marker="stdlib:timer">timer(3)</seealso>,
<seealso marker="user">user(3)</seealso></p>
</section>
</appref>
diff --git a/lib/kernel/doc/src/net_adm.xml b/lib/kernel/doc/src/net_adm.xml
index f2aac9282c..3009b1913d 100644
--- a/lib/kernel/doc/src/net_adm.xml
+++ b/lib/kernel/doc/src/net_adm.xml
@@ -1,10 +1,10 @@
-<?xml version="1.0" encoding="latin1" ?>
+<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE erlref SYSTEM "erlref.dtd">
<erlref>
<header>
<copyright>
- <year>1996</year><year>2011</year>
+ <year>1996</year><year>2013</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
diff --git a/lib/kernel/doc/src/net_kernel.xml b/lib/kernel/doc/src/net_kernel.xml
index e54a427ff0..f5103136a1 100644
--- a/lib/kernel/doc/src/net_kernel.xml
+++ b/lib/kernel/doc/src/net_kernel.xml
@@ -1,10 +1,10 @@
-<?xml version="1.0" encoding="latin1" ?>
+<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE erlref SYSTEM "erlref.dtd">
<erlref>
<header>
<copyright>
- <year>1996</year><year>2011</year>
+ <year>1996</year><year>2013</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
diff --git a/lib/kernel/doc/src/notes.xml b/lib/kernel/doc/src/notes.xml
index b2e89ea850..c6538b7d05 100644
--- a/lib/kernel/doc/src/notes.xml
+++ b/lib/kernel/doc/src/notes.xml
@@ -30,6 +30,203 @@
</header>
<p>This document describes the changes made to the Kernel application.</p>
+<section><title>Kernel 3.0</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Fixed a deadlock possibility in terminate application</p>
+ <p>
+ Own Id: OTP-11171</p>
+ </item>
+ <item>
+ <p>
+ Fixed bug where sendfile would return the wrong error
+ code for a remotely closed socket if the socket was in
+ passive mode. (Thanks to Vincent Siliakus for reporting
+ the bug.)</p>
+ <p>
+ Own Id: OTP-11614</p>
+ </item>
+ <item>
+ <p>
+ The new option <c>persistent</c> is added to
+ <c>application:set_env/4</c> and
+ <c>application:unset_env/3</c>. An environment key set
+ with the <c>persistent</c> option will not be overridden
+ by the ones configured in the application resource file
+ on load. This means persistent values will stick after
+ the application is loaded and also on application reload.
+ (Thanks to José Valim)</p>
+ <p>
+ Own Id: OTP-11708</p>
+ </item>
+ <item>
+ <p>
+ The spec for file:set_cwd/1 is modified to also accept
+ binaries as arguments. This has always been allowed in
+ the code, but it was not reflected in the spec since
+ binaries are mostly used for raw file names. Raw file
+ names are names that are not encoded according to
+ file:native_name_encoding(), and these are not allowed in
+ file:set_cwd/1. The spec is now, however, more allowing
+ in order to avoid unnecessary dialyzer warnings. Raw file
+ names will still fail in runtime with reason
+ 'no_translation'. (Thanks to José Valim)</p>
+ <p>
+ Own Id: OTP-11787</p>
+ </item>
+ </list>
+ </section>
+
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p>
+ heart:set_cmd/1 is updated to allow unicode code points >
+ 255 in the given heart command</p>
+ <p>
+ Own Id: OTP-10843</p>
+ </item>
+ <item>
+ <p> Dialyzer's <c>unmatched_return</c> warnings have been
+ corrected. </p>
+ <p>
+ Own Id: OTP-10908</p>
+ </item>
+ <item>
+ <p>
+ Make erlang:open_port/2 spawn and spawn_executable handle
+ unicode.</p>
+ <p>
+ Own Id: OTP-11105</p>
+ </item>
+ <item>
+ <p>
+ Erlang/OTP has been ported to the realtime operating
+ system OSE. The port supports both smp and non-smp
+ emulator. For details around the port and how to started
+ see the User's Guide in the <seealso
+ marker="ose:ose_intro">ose</seealso> application. </p>
+ <p>
+ Note that not all parts of Erlang/OTP has been ported. </p>
+ <p>
+ Notable things that work are: non-smp and smp emulators,
+ OSE signal interaction, crypto, asn1, run_erl/to_erl,
+ tcp, epmd, distribution and most if not all non-os
+ specific functionality of Erlang.</p>
+ <p>
+ Notable things that does not work are: udp/sctp, os_mon,
+ erl_interface, binding of schedulers.</p>
+ <p>
+ Own Id: OTP-11334</p>
+ </item>
+ <item>
+ <p>
+ Add the {active,N} socket option for TCP, UDP, and SCTP,
+ where N is an integer in the range -32768..32767, to
+ allow a caller to specify the number of data messages to
+ be delivered to the controlling process. Once the
+ socket's delivered message count either reaches 0 or is
+ explicitly set to 0 with inet:setopts/2 or by including
+ {active,0} as an option when the socket is created, the
+ socket transitions to passive ({active, false}) mode and
+ the socket's controlling process receives a message to
+ inform it of the transition. TCP sockets receive
+ {tcp_passive,Socket}, UDP sockets receive
+ {udp_passive,Socket} and SCTP sockets receive
+ {sctp_passive,Socket}. </p>
+ <p>
+ The socket's delivered message counter defaults to 0, but
+ it can be set using {active,N} via any gen_tcp, gen_udp,
+ or gen_sctp function that takes socket options as
+ arguments, or via inet:setopts/2. New N values are added
+ to the socket's current counter value, and negative
+ numbers can be used to reduce the counter value.
+ Specifying a number that would cause the socket's counter
+ value to go above 32767 causes an einval error. If a
+ negative number is specified such that the counter value
+ would become negative, the socket's counter value is set
+ to 0 and the socket transitions to passive mode. If the
+ counter value is already 0 and inet:setopts(Socket,
+ [{active,0}]) is specified, the counter value remains at
+ 0 but the appropriate passive mode transition message is
+ generated for the socket.</p>
+ <p>
+ Thanks to Steve Vinoski</p>
+ <p>
+ Own Id: OTP-11368</p>
+ </item>
+ <item>
+ <p>
+ A call to either the <c>garbage_collect/1</c> BIF or the
+ <c>check_process_code/2</c> BIF may trigger garbage
+ collection of another processes than the process calling
+ the BIF. The previous implementations performed these
+ kinds of garbage collections without considering the
+ internal state of the process being garbage collected. In
+ order to be able to more easily and more efficiently
+ implement yielding native code, these types of garbage
+ collections have been rewritten. A garbage collection
+ like this is now triggered by an asynchronous request
+ signal, the actual garbage collection is performed by the
+ process being garbage collected itself, and finalized by
+ a reply signal to the process issuing the request. Using
+ this approach processes can disable garbage collection
+ and yield without having to set up the heap in a state
+ that can be garbage collected.</p>
+ <p>
+ The <seealso
+ marker="erts:erlang#garbage_collect/2"><c>garbage_collect/2</c></seealso>,
+ and <seealso
+ marker="erts:erlang#check_process_code/3"><c>check_process_code/3</c></seealso>
+ BIFs have been introduced. Both taking an option list as
+ last argument. Using these, one can issue asynchronous
+ requests.</p>
+ <p>
+ <c>code:purge/1</c> and <c>code:soft_purge/1</c> have
+ been rewritten to utilize asynchronous
+ <c>check_process_code</c> requests in order to
+ parallelize work.</p>
+ <p>
+ Characteristics impact: A call to the
+ <c>garbage_collect/1</c> BIF or the
+ <c>check_process_code/2</c> BIF will normally take longer
+ time to complete while the system as a whole wont be as
+ much negatively effected by the operation as before. A
+ call to <c>code:purge/1</c> and <c>code:soft_purge/1</c>
+ may complete faster or slower depending on the state of
+ the system while the system as a whole wont be as much
+ negatively effected by the operation as before.</p>
+ <p>
+ Own Id: OTP-11388 Aux Id: OTP-11535, OTP-11648 </p>
+ </item>
+ <item>
+ <p>
+ Add sync option to file:open/2.</p>
+ <p>
+ The sync option adds the POSIX O_SYNC flag to the open
+ system call on platforms that support the flag or its
+ equivalent, e.g., FILE_FLAG_WRITE_THROUGH on Windows. For
+ platforms that don't support it, file:open/2 returns
+ {error, enotsup} if the sync option is passed in. Thank
+ to Steve Vinoski and Joseph Blomstedt</p>
+ <p>
+ Own Id: OTP-11498</p>
+ </item>
+ <item>
+ <p> The contract of <c>inet:ntoa/1</c> has been
+ corrected. </p> <p> Thanks to Max Treskin. </p>
+ <p>
+ Own Id: OTP-11730</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>Kernel 2.16.4</title>
<section><title>Fixed Bugs and Malfunctions</title>
diff --git a/lib/kernel/doc/src/notes_history.xml b/lib/kernel/doc/src/notes_history.xml
index 2f6ceb9d42..58d5109774 100644
--- a/lib/kernel/doc/src/notes_history.xml
+++ b/lib/kernel/doc/src/notes_history.xml
@@ -1,10 +1,10 @@
-<?xml version="1.0" encoding="latin1" ?>
+<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE chapter SYSTEM "chapter.dtd">
<chapter>
<header>
<copyright>
- <year>2006</year><year>2009</year>
+ <year>2006</year><year>2013</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
diff --git a/lib/kernel/doc/src/os.xml b/lib/kernel/doc/src/os.xml
index 9122267c40..2b57e75023 100644
--- a/lib/kernel/doc/src/os.xml
+++ b/lib/kernel/doc/src/os.xml
@@ -1,10 +1,10 @@
-<?xml version="1.0" encoding="latin1" ?>
+<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE erlref SYSTEM "erlref.dtd">
<erlref>
<header>
<copyright>
- <year>1997</year><year>2012</year>
+ <year>1997</year><year>2013</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
diff --git a/lib/kernel/doc/src/part_notes.xml b/lib/kernel/doc/src/part_notes.xml
index ff43b9e007..d196878f19 100644
--- a/lib/kernel/doc/src/part_notes.xml
+++ b/lib/kernel/doc/src/part_notes.xml
@@ -1,10 +1,10 @@
-<?xml version="1.0" encoding="latin1" ?>
+<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE part SYSTEM "part.dtd">
<part xmlns:xi="http://www.w3.org/2001/XInclude">
<header>
<copyright>
- <year>2004</year><year>2009</year>
+ <year>2004</year><year>2013</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
diff --git a/lib/kernel/doc/src/part_notes_history.xml b/lib/kernel/doc/src/part_notes_history.xml
index a73cc911b8..ec4998408e 100644
--- a/lib/kernel/doc/src/part_notes_history.xml
+++ b/lib/kernel/doc/src/part_notes_history.xml
@@ -1,11 +1,11 @@
-<?xml version="1.0" encoding="latin1" ?>
+<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE part SYSTEM "part.dtd">
<part>
<header>
<copyright>
<year>2006</year>
- <year>2011</year>
+ <year>2013</year>
<holder>Ericsson AB, All Rights Reserved</holder>
</copyright>
<legalnotice>
diff --git a/lib/kernel/doc/src/pg2.xml b/lib/kernel/doc/src/pg2.xml
index d26ff0fc6b..5eb63c1ef6 100644
--- a/lib/kernel/doc/src/pg2.xml
+++ b/lib/kernel/doc/src/pg2.xml
@@ -1,10 +1,10 @@
-<?xml version="1.0" encoding="latin1" ?>
+<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE erlref SYSTEM "erlref.dtd">
<erlref>
<header>
<copyright>
- <year>1997</year><year>2011</year>
+ <year>1997</year><year>2013</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
diff --git a/lib/kernel/doc/src/ref_man.xml b/lib/kernel/doc/src/ref_man.xml
index 96604a2fa2..bd25d1e78d 100644
--- a/lib/kernel/doc/src/ref_man.xml
+++ b/lib/kernel/doc/src/ref_man.xml
@@ -1,4 +1,4 @@
-<?xml version="1.0" encoding="latin1" ?>
+<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE application SYSTEM "application.dtd">
<application xmlns:xi="http://www.w3.org/2001/XInclude">
@@ -13,12 +13,12 @@
compliance with the License. You should have received a copy of the
Erlang Public License along with this software. If not, it can be
retrieved online at http://www.erlang.org/.
-
+
Software distributed under the License is distributed on an "AS IS"
basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
the License for the specific language governing rights and limitations
under the License.
-
+
</legalnotice>
<title>Kernel Reference Manual</title>
@@ -65,4 +65,3 @@
<xi:include href="app.xml"/>
<xi:include href="config.xml"/>
</application>
-
diff --git a/lib/kernel/doc/src/ref_man.xml.src b/lib/kernel/doc/src/ref_man.xml.src
new file mode 100644
index 0000000000..bd25d1e78d
--- /dev/null
+++ b/lib/kernel/doc/src/ref_man.xml.src
@@ -0,0 +1,67 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<!DOCTYPE application SYSTEM "application.dtd">
+
+<application xmlns:xi="http://www.w3.org/2001/XInclude">
+ <header>
+ <copyright>
+ <year>1996</year><year>2013</year>
+ <holder>Ericsson AB. All Rights Reserved.</holder>
+ </copyright>
+ <legalnotice>
+ The contents of this file are subject to the Erlang Public License,
+ Version 1.1, (the "License"); you may not use this file except in
+ compliance with the License. You should have received a copy of the
+ Erlang Public License along with this software. If not, it can be
+ retrieved online at http://www.erlang.org/.
+
+ Software distributed under the License is distributed on an "AS IS"
+ basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ the License for the specific language governing rights and limitations
+ under the License.
+
+ </legalnotice>
+
+ <title>Kernel Reference Manual</title>
+ <prepared></prepared>
+ <docno></docno>
+ <date></date>
+ <rev></rev>
+ </header>
+ <description>
+ <p>The <em>Kernel</em> application has all the code necessary to run
+ the Erlang runtime system itself: file servers and code servers
+ and so on.</p>
+ </description>
+ <xi:include href="kernel_app.xml"/>
+ <xi:include href="application.xml"/>
+ <xi:include href="auth.xml"/>
+ <xi:include href="code.xml"/>
+ <xi:include href="disk_log.xml"/>
+ <xi:include href="erl_boot_server.xml"/>
+ <xi:include href="erl_ddll.xml"/>
+ <xi:include href="erl_prim_loader_stub.xml"/>
+ <xi:include href="erlang_stub.xml"/>
+ <xi:include href="error_handler.xml"/>
+ <xi:include href="error_logger.xml"/>
+ <xi:include href="file.xml"/>
+ <xi:include href="gen_tcp.xml"/>
+ <xi:include href="gen_udp.xml"/>
+ <xi:include href="gen_sctp.xml"/>
+ <xi:include href="global.xml"/>
+ <xi:include href="global_group.xml"/>
+ <xi:include href="heart.xml"/>
+ <xi:include href="inet.xml"/>
+ <xi:include href="inet_res.xml"/>
+ <xi:include href="init_stub.xml"/>
+ <xi:include href="net_adm.xml"/>
+ <xi:include href="net_kernel.xml"/>
+ <xi:include href="os.xml"/>
+ <xi:include href="pg2.xml"/>
+ <xi:include href="rpc.xml"/>
+ <xi:include href="seq_trace.xml"/>
+ <xi:include href="user.xml"/>
+ <xi:include href="wrap_log_reader.xml"/>
+ <xi:include href="zlib_stub.xml"/>
+ <xi:include href="app.xml"/>
+ <xi:include href="config.xml"/>
+</application>
diff --git a/lib/kernel/doc/src/rpc.xml b/lib/kernel/doc/src/rpc.xml
index 67fdccb734..e6c896f18d 100644
--- a/lib/kernel/doc/src/rpc.xml
+++ b/lib/kernel/doc/src/rpc.xml
@@ -1,10 +1,10 @@
-<?xml version="1.0" encoding="latin1" ?>
+<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE erlref SYSTEM "erlref.dtd">
<erlref>
<header>
<copyright>
- <year>1996</year><year>2011</year>
+ <year>1996</year><year>2013</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
diff --git a/lib/kernel/doc/src/seq_trace.xml b/lib/kernel/doc/src/seq_trace.xml
index 1ab955bd8a..45df06e0b4 100644
--- a/lib/kernel/doc/src/seq_trace.xml
+++ b/lib/kernel/doc/src/seq_trace.xml
@@ -1,10 +1,10 @@
-<?xml version="1.0" encoding="latin1" ?>
+<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE erlref SYSTEM "erlref.dtd">
<erlref>
<header>
<copyright>
- <year>1998</year><year>2011</year>
+ <year>1998</year><year>2013</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
diff --git a/lib/kernel/doc/src/specs.xml b/lib/kernel/doc/src/specs.xml
index 813bb06e1f..29d52f23bb 100644
--- a/lib/kernel/doc/src/specs.xml
+++ b/lib/kernel/doc/src/specs.xml
@@ -1,4 +1,4 @@
-<?xml version="1.0" encoding="latin1" ?>
+<?xml version="1.0" encoding="utf-8" ?>
<specs xmlns:xi="http://www.w3.org/2001/XInclude">
<xi:include href="../specs/specs_application.xml"/>
<xi:include href="../specs/specs_auth.xml"/>
diff --git a/lib/kernel/doc/src/user.xml b/lib/kernel/doc/src/user.xml
index 4d0f044321..df6dff9882 100644
--- a/lib/kernel/doc/src/user.xml
+++ b/lib/kernel/doc/src/user.xml
@@ -1,11 +1,11 @@
-<?xml version="1.0" encoding="latin1" ?>
+<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE erlref SYSTEM "erlref.dtd">
<erlref>
<header>
<copyright>
<year>1996</year>
- <year>2011</year>
+ <year>2013</year>
<holder>Ericsson AB, All Rights Reserved</holder>
</copyright>
<legalnotice>
diff --git a/lib/kernel/doc/src/wrap_log_reader.xml b/lib/kernel/doc/src/wrap_log_reader.xml
index 6cf480b532..5227b4d01c 100644
--- a/lib/kernel/doc/src/wrap_log_reader.xml
+++ b/lib/kernel/doc/src/wrap_log_reader.xml
@@ -1,10 +1,10 @@
-<?xml version="1.0" encoding="latin1" ?>
+<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE erlref SYSTEM "erlref.dtd">
<erlref>
<header>
<copyright>
- <year>1998</year><year>2011</year>
+ <year>1998</year><year>2013</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
diff --git a/lib/kernel/doc/src/zlib_stub.xml b/lib/kernel/doc/src/zlib_stub.xml
index fa14262181..5f5bfd56db 100644
--- a/lib/kernel/doc/src/zlib_stub.xml
+++ b/lib/kernel/doc/src/zlib_stub.xml
@@ -1,11 +1,11 @@
-<?xml version="1.0" encoding="latin1" ?>
+<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE erlref SYSTEM "erlref.dtd">
<erlref>
<header>
<copyright>
<year>1997</year>
- <year>2009</year>
+ <year>2013</year>
<holder>Ericsson AB, All Rights Reserved</holder>
</copyright>
<legalnotice>
diff --git a/lib/kernel/include/dist.hrl b/lib/kernel/include/dist.hrl
index e32c112e63..77556d1303 100644
--- a/lib/kernel/include/dist.hrl
+++ b/lib/kernel/include/dist.hrl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1999-2013. All Rights Reserved.
+%% Copyright Ericsson AB 1999-2014. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -37,3 +37,4 @@
-define(DFLAG_DIST_HDR_ATOM_CACHE,16#2000).
-define(DFLAG_SMALL_ATOM_TAGS, 16#4000).
-define(DFLAG_UTF8_ATOMS, 16#10000).
+-define(DFLAG_MAP_TAG, 16#20000).
diff --git a/lib/kernel/src/application.erl b/lib/kernel/src/application.erl
index 4e8ba1b78a..c4bef5188a 100644
--- a/lib/kernel/src/application.erl
+++ b/lib/kernel/src/application.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2013. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2014. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -30,6 +30,8 @@
-export([get_application/0, get_application/1, info/0]).
-export([start_type/0]).
+-export_type([start_type/0]).
+
%%%-----------------------------------------------------------------
-type start_type() :: 'normal'
@@ -58,8 +60,7 @@
%%------------------------------------------------------------------
--callback start(StartType :: normal | {takeover, node()} | {failover, node()},
- StartArgs :: term()) ->
+-callback start(StartType :: start_type(), StartArgs :: term()) ->
{'ok', pid()} | {'ok', pid(), State :: term()} | {'error', Reason :: term()}.
-callback stop(State :: term()) ->
@@ -132,7 +133,7 @@ ensure_all_started(Application, Type) ->
{ok, Started} ->
{ok, lists:reverse(Started)};
{error, Reason, Started} ->
- [stop(App) || App <- Started],
+ _ = [stop(App) || App <- Started],
{error, Reason}
end.
@@ -285,16 +286,18 @@ info() ->
set_env(Application, Key, Val) ->
application_controller:set_env(Application, Key, Val).
--spec set_env(Application, Par, Val, Timeout) -> 'ok' when
+-spec set_env(Application, Par, Val, Opts) -> 'ok' when
Application :: atom(),
Par :: atom(),
Val :: term(),
- Timeout :: timeout().
+ Opts :: [{timeout, timeout()} | {persistent, boolean()}].
set_env(Application, Key, Val, infinity) ->
- application_controller:set_env(Application, Key, Val, infinity);
+ set_env(Application, Key, Val, [{timeout, infinity}]);
set_env(Application, Key, Val, Timeout) when is_integer(Timeout), Timeout>=0 ->
- application_controller:set_env(Application, Key, Val, Timeout).
+ set_env(Application, Key, Val, [{timeout, Timeout}]);
+set_env(Application, Key, Val, Opts) when is_list(Opts) ->
+ application_controller:set_env(Application, Key, Val, Opts).
-spec unset_env(Application, Par) -> 'ok' when
Application :: atom(),
@@ -303,15 +306,17 @@ set_env(Application, Key, Val, Timeout) when is_integer(Timeout), Timeout>=0 ->
unset_env(Application, Key) ->
application_controller:unset_env(Application, Key).
--spec unset_env(Application, Par, Timeout) -> 'ok' when
+-spec unset_env(Application, Par, Opts) -> 'ok' when
Application :: atom(),
Par :: atom(),
- Timeout :: timeout().
+ Opts :: [{timeout, timeout()} | {persistent, boolean()}].
unset_env(Application, Key, infinity) ->
- application_controller:unset_env(Application, Key, infinity);
+ unset_env(Application, Key, [{timeout, infinity}]);
unset_env(Application, Key, Timeout) when is_integer(Timeout), Timeout>=0 ->
- application_controller:unset_env(Application, Key, Timeout).
+ unset_env(Application, Key, [{timeout, Timeout}]);
+unset_env(Application, Key, Opts) when is_list(Opts) ->
+ application_controller:unset_env(Application, Key, Opts).
-spec get_env(Par) -> 'undefined' | {'ok', Val} when
Par :: atom(),
diff --git a/lib/kernel/src/application_controller.erl b/lib/kernel/src/application_controller.erl
index 9ed2c7a7d9..daad45b6c2 100644
--- a/lib/kernel/src/application_controller.erl
+++ b/lib/kernel/src/application_controller.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2013. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2014. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -461,14 +461,16 @@ permit_application(ApplName, Flag) ->
set_env(AppName, Key, Val) ->
- gen_server:call(?AC, {set_env, AppName, Key, Val}).
-set_env(AppName, Key, Val, Timeout) ->
- gen_server:call(?AC, {set_env, AppName, Key, Val}, Timeout).
+ gen_server:call(?AC, {set_env, AppName, Key, Val, []}).
+set_env(AppName, Key, Val, Opts) ->
+ Timeout = proplists:get_value(timeout, Opts, 5000),
+ gen_server:call(?AC, {set_env, AppName, Key, Val, Opts}, Timeout).
unset_env(AppName, Key) ->
- gen_server:call(?AC, {unset_env, AppName, Key}).
-unset_env(AppName, Key, Timeout) ->
- gen_server:call(?AC, {unset_env, AppName, Key}, Timeout).
+ gen_server:call(?AC, {unset_env, AppName, Key, []}).
+unset_env(AppName, Key, Opts) ->
+ Timeout = proplists:get_value(timeout, Opts, 5000),
+ gen_server:call(?AC, {unset_env, AppName, Key, Opts}, Timeout).
%%%-----------------------------------------------------------------
%%% call-back functions from gen_server
@@ -488,7 +490,7 @@ init(Init, Kernel) ->
%% called during start-up of any app.
case check_conf_data(ConfData) of
ok ->
- ets:new(ac_tab, [set, public, named_table]),
+ _ = ets:new(ac_tab, [set, public, named_table]),
S = #state{conf_data = ConfData},
{ok, KAppl} = make_appl(Kernel),
case catch load(S, KAppl) of
@@ -609,8 +611,8 @@ check_para([Else | _ParaList], AppName) ->
| {'change_application_data', _, _}
| {'permit_application', atom() | {'application',atom(),_},_}
| {'start_application', _, _}
- | {'unset_env', _, _}
- | {'set_env', _, _, _}.
+ | {'unset_env', _, _, _}
+ | {'set_env', _, _, _, _}.
-spec handle_call(calls(), {pid(), term()}, state()) ->
{'noreply', state()} | {'reply', term(), state()}.
@@ -827,12 +829,12 @@ handle_call({change_application_data, Applications, Config}, _From, S) ->
{reply, Error, S};
{'EXIT', R} ->
{reply, {error, R}, S};
- NewAppls ->
+ {NewAppls, NewConfig} ->
lists:foreach(fun(Appl) ->
ets:insert(ac_tab, {{loaded, Appl#appl.name},
Appl})
end, NewAppls),
- {reply, ok, S#state{conf_data = Config}}
+ {reply, ok, S#state{conf_data = NewConfig}}
end;
handle_call(prep_config_change, _From, S) ->
@@ -858,13 +860,25 @@ handle_call(which_applications, _From, S) ->
end, S#state.running),
{reply, Reply, S};
-handle_call({set_env, AppName, Key, Val}, _From, S) ->
+handle_call({set_env, AppName, Key, Val, Opts}, _From, S) ->
ets:insert(ac_tab, {{env, AppName, Key}, Val}),
- {reply, ok, S};
+ case proplists:get_value(persistent, Opts, false) of
+ true ->
+ Fun = fun(Env) -> lists:keystore(Key, 1, Env, {Key, Val}) end,
+ {reply, ok, S#state{conf_data = change_app_env(S#state.conf_data, AppName, Fun)}};
+ false ->
+ {reply, ok, S}
+ end;
-handle_call({unset_env, AppName, Key}, _From, S) ->
+handle_call({unset_env, AppName, Key, Opts}, _From, S) ->
ets:delete(ac_tab, {env, AppName, Key}),
- {reply, ok, S};
+ case proplists:get_value(persistent, Opts, false) of
+ true ->
+ Fun = fun(Env) -> lists:keydelete(Key, 1, Env) end,
+ {reply, ok, S#state{conf_data = change_app_env(S#state.conf_data, AppName, Fun)}};
+ false ->
+ {reply, ok, S}
+ end;
handle_call({control_application, AppName}, {Pid, _Tag}, S) ->
Control = S#state.control,
@@ -1536,18 +1550,19 @@ do_change_apps(Applications, Config, OldAppls) ->
end,
Errors),
- map(fun(Appl) ->
- AppName = Appl#appl.name,
- case is_loaded_app(AppName, Applications) of
- {true, Application} ->
- do_change_appl(make_appl(Application),
- Appl, SysConfig);
+ {map(fun(Appl) ->
+ AppName = Appl#appl.name,
+ case is_loaded_app(AppName, Applications) of
+ {true, Application} ->
+ do_change_appl(make_appl(Application),
+ Appl, SysConfig);
- %% ignored removed apps - handled elsewhere
- false ->
- Appl
- end
- end, OldAppls).
+ %% ignored removed apps - handled elsewhere
+ false ->
+ Appl
+ end
+ end, OldAppls),
+ SysConfig}.
is_loaded_app(AppName, [{application, AppName, App} | _]) ->
{true, {application, AppName, App}};
@@ -1640,6 +1655,16 @@ merge_env([{App, AppEnv1} | T], Env2, Res) ->
merge_env([], Env2, Res) ->
Env2 ++ Res.
+%% Changes the environment for the given application
+%% If there is no application, an empty one is created
+change_app_env(Env, App, Fun) ->
+ case get_env_key(App, Env) of
+ {value, AppEnv, RestEnv} ->
+ [{App, Fun(AppEnv)} | RestEnv];
+ _ ->
+ [{App, Fun([])} | Env]
+ end.
+
%% Merges envs for an application. Env2 overrides Env1
merge_app_env(Env1, Env2) ->
merge_app_env(Env1, Env2, []).
@@ -1949,10 +1974,10 @@ test_change_apps(Apps, Conf) ->
test_do_change_appl([], _, _) ->
ok;
test_do_change_appl([A|Apps], [], [R|Res]) ->
- do_change_appl(R, #appl{name = A}, []),
+ _ = do_change_appl(R, #appl{name = A}, []),
test_do_change_appl(Apps, [], Res);
test_do_change_appl([A|Apps], [C|Conf], [R|Res]) ->
- do_change_appl(R, #appl{name = A}, C),
+ _ = do_change_appl(R, #appl{name = A}, C),
test_do_change_appl(Apps, Conf, Res).
test_make_apps([], Res) ->
diff --git a/lib/kernel/src/application_master.erl b/lib/kernel/src/application_master.erl
index 3e636197bb..bc15b5a7de 100644
--- a/lib/kernel/src/application_master.erl
+++ b/lib/kernel/src/application_master.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2013. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2014. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -27,7 +27,7 @@
-include("application_master.hrl").
--record(state, {child, appl_data, children = [], procs = 0, gleader}).
+-record(state, {child, appl_data, children = [], procs = 0, gleader, req=[]}).
%%-----------------------------------------------------------------
%% Func: start_link/1
@@ -125,7 +125,7 @@ init(Parent, Starter, ApplData, Type) ->
State = #state{appl_data = ApplData, gleader = OldGleader},
case start_it(State, Type) of
{ok, Pid} -> % apply(M,F,A) returned ok
- set_timer(ApplData#appl_data.maxT),
+ ok = set_timer(ApplData#appl_data.maxT),
unlink(Starter),
proc_lib:init_ack(Starter, {ok,self()}),
main_loop(Parent, State#state{child = Pid});
@@ -205,22 +205,25 @@ terminate_loop(Child, State) ->
%%-----------------------------------------------------------------
%% The Application Master is linked to *all* processes in the group
-%% (application).
+%% (application).
%%-----------------------------------------------------------------
handle_msg({get_child, Tag, From}, State) ->
- From ! {Tag, get_child_i(State#state.child)},
- State;
+ get_child_i(State, Tag, From);
handle_msg({stop, Tag, From}, State) ->
catch terminate(normal, State),
From ! {Tag, ok},
exit(normal);
+handle_msg({child, Ref, GrandChild, Mod}, #state{req=Reqs0}=State) ->
+ {value, {_, Tag, From}, Reqs} = lists:keytake(Ref, 1, Reqs0),
+ From ! {Tag, {GrandChild, Mod}},
+ State#state{req=Reqs};
handle_msg(_, State) ->
State.
-
-terminate(Reason, State) ->
- terminate_child(State#state.child, State),
- kill_children(State#state.children),
+terminate(Reason, State = #state{child=Child, children=Children, req=Reqs}) ->
+ _ = [From ! {Tag, error} || {_, Tag, From} <- Reqs],
+ terminate_child(Child, State),
+ kill_children(Children),
exit(Reason).
@@ -342,8 +345,8 @@ start_supervisor(Type, M, A) ->
loop_it(Parent, Child, Mod, AppState) ->
receive
- {Parent, get_child} ->
- Parent ! {self(), Child, Mod},
+ {Parent, get_child, Ref} ->
+ Parent ! {child, Ref, Child, Mod},
loop_it(Parent, Child, Mod, AppState);
{Parent, terminate} ->
NewAppState = prep_stop(Mod, AppState),
@@ -382,10 +385,15 @@ prep_stop(Mod, AppState) ->
NewAppState
end.
-get_child_i(Child) ->
- Child ! {self(), get_child},
- receive
- {Child, GrandChild, Mod} -> {GrandChild, Mod}
+get_child_i(#state{child=Child, req=Reqs}=State, Tag, From) ->
+ Ref = erlang:make_ref(),
+ case erlang:is_process_alive(Child) of
+ true ->
+ Child ! {self(), get_child, Ref},
+ State#state{req=[{Ref, Tag, From}|Reqs]};
+ false ->
+ From ! {Tag, error},
+ State
end.
terminate_child_i(Child, State) ->
@@ -418,4 +426,6 @@ kill_all_procs_1([], _, 0) -> ok;
kill_all_procs_1([], _, _) -> kill_all_procs().
set_timer(infinity) -> ok;
-set_timer(Time) -> timer:exit_after(Time, timeout).
+set_timer(Time) ->
+ {ok, _} = timer:exit_after(Time, timeout),
+ ok.
diff --git a/lib/kernel/src/auth.erl b/lib/kernel/src/auth.erl
index 7d463103e3..eda35147d3 100644
--- a/lib/kernel/src/auth.erl
+++ b/lib/kernel/src/auth.erl
@@ -324,7 +324,7 @@ read_cookie(Name, Size) ->
{ok, File} ->
case file:read(File, Size) of
{ok, List} ->
- file:close(File),
+ ok = file:close(File),
check_cookie(List, []);
{error, Reason} ->
make_error(Name, Reason)
@@ -376,7 +376,7 @@ create_cookie(Name) ->
case file:open(Name, [write, raw]) of
{ok, File} ->
R1 = file:write(File, Cookie),
- file:close(File),
+ ok = file:close(File),
R2 = file:raw_write_file_info(Name, make_info(Name)),
case {R1, R2} of
{ok, ok} ->
diff --git a/lib/kernel/src/code.erl b/lib/kernel/src/code.erl
index 03fba96d4b..0eda558ed5 100644
--- a/lib/kernel/src/code.erl
+++ b/lib/kernel/src/code.erl
@@ -364,7 +364,7 @@ load_code_server_prerequisites() ->
lists,
os,
unicode],
- [M = M:module_info(module) || M <- Needed],
+ _ = [M = M:module_info(module) || M <- Needed],
ok.
do_stick_dirs() ->
diff --git a/lib/kernel/src/code_server.erl b/lib/kernel/src/code_server.erl
index 5d74e8620b..fc7ac08699 100644
--- a/lib/kernel/src/code_server.erl
+++ b/lib/kernel/src/code_server.erl
@@ -153,7 +153,7 @@ loop(#state{supervisor=Supervisor}=State0) ->
{code_call, Pid, Req} ->
case handle_call(Req, {Pid, call}, State0) of
{reply, Res, State} ->
- reply(Pid, Res),
+ _ = reply(Pid, Res),
loop(State);
{noreply, State} ->
loop(State);
@@ -1410,45 +1410,236 @@ absname_vr([[X, $:]|Name], _, _AbsBase) ->
do_purge(Mod0) ->
Mod = to_atom(Mod0),
case erlang:check_old_code(Mod) of
- false -> false;
- true -> do_purge(processes(), Mod, false)
- end.
-
-do_purge([P|Ps], Mod, Purged) ->
- case erlang:check_process_code(P, Mod) of
+ false ->
+ false;
true ->
- Ref = erlang:monitor(process, P),
- exit(P, kill),
- receive
- {'DOWN',Ref,process,_Pid,_} -> ok
+ Res = check_proc_code(erlang:processes(), Mod, true),
+ try
+ erlang:purge_module(Mod)
+ catch
+ _:_ -> ignore
end,
- do_purge(Ps, Mod, true);
- false ->
- do_purge(Ps, Mod, Purged)
- end;
-do_purge([], Mod, Purged) ->
- catch erlang:purge_module(Mod),
- Purged.
+ Res
+ end.
%% do_soft_purge(Module)
%% Purge old code only if no procs remain that run old code.
%% Return true in that case, false if procs remain (in this
%% case old code is not purged)
-do_soft_purge(Mod) ->
+do_soft_purge(Mod0) ->
+ Mod = to_atom(Mod0),
case erlang:check_old_code(Mod) of
- false -> true;
- true -> do_soft_purge(processes(), Mod)
+ false ->
+ true;
+ true ->
+ case check_proc_code(erlang:processes(), Mod, false) of
+ false ->
+ false;
+ true ->
+ try
+ erlang:purge_module(Mod)
+ catch
+ _:_ -> ignore
+ end,
+ true
+ end
end.
-do_soft_purge([P|Ps], Mod) ->
- case erlang:check_process_code(P, Mod) of
- true -> false;
- false -> do_soft_purge(Ps, Mod)
+%%
+%% check_proc_code(Pids, Mod, Hard) - Send asynchronous
+%% requests to all processes to perform a check_process_code
+%% operation. Each process will check their own state and
+%% reply with the result. If 'Hard' equals
+%% - true, processes that refer 'Mod' will be killed. If
+%% any processes were killed true is returned; otherwise,
+%% false.
+%% - false, and any processes refer 'Mod', false will
+%% returned; otherwise, true.
+%%
+%% Requests will be sent to all processes identified by
+%% Pids at once, but without allowing GC to be performed.
+%% Check process code operations that are aborted due to
+%% GC need, will be restarted allowing GC. However, only
+%% ?MAX_CPC_GC_PROCS outstanding operation allowing GC at
+%% a time will be allowed. This in order not to blow up
+%% memory wise.
+%%
+%% We also only allow ?MAX_CPC_NO_OUTSTANDING_KILLS
+%% outstanding kills. This both in order to avoid flooding
+%% our message queue with 'DOWN' messages and limiting the
+%% amount of memory used to keep references to all
+%% outstanding kills.
+%%
+
+%% We maybe should allow more than two outstanding
+%% GC requests, but for now we play it safe...
+-define(MAX_CPC_GC_PROCS, 2).
+-define(MAX_CPC_NO_OUTSTANDING_KILLS, 10).
+
+-record(cpc_static, {hard, module, tag}).
+
+-record(cpc_kill, {outstanding = [],
+ no_outstanding = 0,
+ waiting = [],
+ killed = false}).
+
+check_proc_code(Pids, Mod, Hard) ->
+ Tag = erlang:make_ref(),
+ CpcS = #cpc_static{hard = Hard,
+ module = Mod,
+ tag = Tag},
+ check_proc_code(CpcS, cpc_init(CpcS, Pids, 0), 0, [], #cpc_kill{}, true).
+
+check_proc_code(#cpc_static{hard = true}, 0, 0, [],
+ #cpc_kill{outstanding = [], waiting = [], killed = Killed},
+ true) ->
+ %% No outstanding requests. We did a hard check, so result is whether or
+ %% not we killed any processes...
+ Killed;
+check_proc_code(#cpc_static{hard = false}, 0, 0, [], _KillState, Success) ->
+ %% No outstanding requests and we did a soft check...
+ Success;
+check_proc_code(#cpc_static{hard = false, tag = Tag} = CpcS, NoReq0, NoGcReq0,
+ [], _KillState, false) ->
+ %% Failed soft check; just cleanup the remaining replies corresponding
+ %% to the requests we've sent...
+ {NoReq1, NoGcReq1} = receive
+ {check_process_code, {Tag, _P, GC}, _Res} ->
+ case GC of
+ false -> {NoReq0-1, NoGcReq0};
+ true -> {NoReq0, NoGcReq0-1}
+ end
+ end,
+ check_proc_code(CpcS, NoReq1, NoGcReq1, [], _KillState, false);
+check_proc_code(#cpc_static{tag = Tag} = CpcS, NoReq0, NoGcReq0, NeedGC0,
+ KillState0, Success) ->
+
+ %% Check if we should request a GC operation
+ {NoGcReq1, NeedGC1} = case NoGcReq0 < ?MAX_CPC_GC_PROCS of
+ GcOpAllowed when GcOpAllowed == false;
+ NeedGC0 == [] ->
+ {NoGcReq0, NeedGC0};
+ _ ->
+ {NoGcReq0+1, cpc_request_gc(CpcS,NeedGC0)}
+ end,
+
+ %% Wait for a cpc reply or 'DOWN' message
+ {NoReq1, NoGcReq2, Pid, Result, KillState1} = cpc_recv(Tag,
+ NoReq0,
+ NoGcReq1,
+ KillState0),
+
+ %% Check the result of the reply
+ case Result of
+ aborted ->
+ %% Operation aborted due to the need to GC in order to
+ %% determine if the process is referring the module.
+ %% Schedule the operation for restart allowing GC...
+ check_proc_code(CpcS, NoReq1, NoGcReq2, [Pid|NeedGC1], KillState1,
+ Success);
+ false ->
+ %% Process not referring the module; done with this process...
+ check_proc_code(CpcS, NoReq1, NoGcReq2, NeedGC1, KillState1,
+ Success);
+ true ->
+ %% Process referring the module...
+ case CpcS#cpc_static.hard of
+ false ->
+ %% ... and soft check. The whole operation failed so
+ %% no point continuing; clean up and fail...
+ check_proc_code(CpcS, NoReq1, NoGcReq2, [], KillState1,
+ false);
+ true ->
+ %% ... and hard check; schedule kill of it...
+ check_proc_code(CpcS, NoReq1, NoGcReq2, NeedGC1,
+ cpc_sched_kill(Pid, KillState1), Success)
+ end;
+ 'DOWN' ->
+ %% Handled 'DOWN' message
+ check_proc_code(CpcS, NoReq1, NoGcReq2, NeedGC1,
+ KillState1, Success)
+ end.
+
+cpc_recv(Tag, NoReq, NoGcReq, #cpc_kill{outstanding = []} = KillState) ->
+ receive
+ {check_process_code, {Tag, Pid, GC}, Res} ->
+ cpc_handle_cpc(NoReq, NoGcReq, GC, Pid, Res, KillState)
end;
-do_soft_purge([], Mod) ->
- catch erlang:purge_module(Mod),
- true.
+cpc_recv(Tag, NoReq, NoGcReq,
+ #cpc_kill{outstanding = [R0, R1, R2, R3, R4 | _]} = KillState) ->
+ receive
+ {'DOWN', R, process, _, _} when R == R0;
+ R == R1;
+ R == R2;
+ R == R3;
+ R == R4 ->
+ cpc_handle_down(NoReq, NoGcReq, R, KillState);
+ {check_process_code, {Tag, Pid, GC}, Res} ->
+ cpc_handle_cpc(NoReq, NoGcReq, GC, Pid, Res, KillState)
+ end;
+cpc_recv(Tag, NoReq, NoGcReq, #cpc_kill{outstanding = [R|_]} = KillState) ->
+ receive
+ {'DOWN', R, process, _, _} ->
+ cpc_handle_down(NoReq, NoGcReq, R, KillState);
+ {check_process_code, {Tag, Pid, GC}, Res} ->
+ cpc_handle_cpc(NoReq, NoGcReq, GC, Pid, Res, KillState)
+ end.
+
+cpc_handle_down(NoReq, NoGcReq, R, #cpc_kill{outstanding = Rs,
+ no_outstanding = N} = KillState) ->
+ {NoReq, NoGcReq, undefined, 'DOWN',
+ cpc_sched_kill_waiting(KillState#cpc_kill{outstanding = cpc_list_rm(R, Rs),
+ no_outstanding = N-1})}.
+
+cpc_list_rm(R, [R|Rs]) ->
+ Rs;
+cpc_list_rm(R0, [R1|Rs]) ->
+ [R1|cpc_list_rm(R0, Rs)].
+
+cpc_handle_cpc(NoReq, NoGcReq, false, Pid, Res, KillState) ->
+ {NoReq-1, NoGcReq, Pid, Res, KillState};
+cpc_handle_cpc(NoReq, NoGcReq, true, Pid, Res, KillState) ->
+ {NoReq, NoGcReq-1, Pid, Res, KillState}.
+
+cpc_sched_kill_waiting(#cpc_kill{waiting = []} = KillState) ->
+ KillState;
+cpc_sched_kill_waiting(#cpc_kill{outstanding = Rs,
+ no_outstanding = N,
+ waiting = [P|Ps]} = KillState) ->
+ R = erlang:monitor(process, P),
+ exit(P, kill),
+ KillState#cpc_kill{outstanding = [R|Rs],
+ no_outstanding = N+1,
+ waiting = Ps,
+ killed = true}.
+
+cpc_sched_kill(Pid, #cpc_kill{no_outstanding = N, waiting = Pids} = KillState)
+ when N >= ?MAX_CPC_NO_OUTSTANDING_KILLS ->
+ KillState#cpc_kill{waiting = [Pid|Pids]};
+cpc_sched_kill(Pid,
+ #cpc_kill{outstanding = Rs, no_outstanding = N} = KillState) ->
+ R = erlang:monitor(process, Pid),
+ exit(Pid, kill),
+ KillState#cpc_kill{outstanding = [R|Rs],
+ no_outstanding = N+1,
+ killed = true}.
+
+cpc_request(#cpc_static{tag = Tag, module = Mod}, Pid, AllowGc) ->
+ erlang:check_process_code(Pid, Mod, [{async, {Tag, Pid, AllowGc}},
+ {allow_gc, AllowGc}]).
+
+cpc_request_gc(CpcS, [Pid|Pids]) ->
+ cpc_request(CpcS, Pid, true),
+ Pids.
+
+cpc_init(_CpcS, [], NoReqs) ->
+ NoReqs;
+cpc_init(CpcS, [Pid|Pids], NoReqs) ->
+ cpc_request(CpcS, Pid, false),
+ cpc_init(CpcS, Pids, NoReqs+1).
+
+% end of check_proc_code() implementation.
is_loaded(M, Db) ->
case ets:lookup(Db, M) of
@@ -1505,13 +1696,13 @@ finish_on_load_1(Mod, File, OnLoadRes, WaitingPids, Db) ->
erlang:finish_after_on_load(Mod, Keep),
Res = case Keep of
false ->
- finish_on_load_report(Mod, OnLoadRes),
+ _ = finish_on_load_report(Mod, OnLoadRes),
{error,on_load_failure};
true ->
ets:insert(Db, {Mod,File}),
{module,Mod}
end,
- [reply(Pid, Res) || Pid <- WaitingPids],
+ _ = [reply(Pid, Res) || Pid <- WaitingPids],
ok.
finish_on_load_report(_Mod, Atom) when is_atom(Atom) ->
diff --git a/lib/kernel/src/disk_log.erl b/lib/kernel/src/disk_log.erl
index c238eff12f..9a7726cfa0 100644
--- a/lib/kernel/src/disk_log.erl
+++ b/lib/kernel/src/disk_log.erl
@@ -1076,13 +1076,13 @@ log_end(S, [], [], Sync) ->
log_end(S, Pids, Bins, Sync) ->
case do_log(get(log), rflat(Bins)) of
N when is_integer(N) ->
- replies(Pids, ok),
+ ok = replies(Pids, ok),
S1 = (state_ok(S))#state{cnt = S#state.cnt+N},
log_end_sync(S1, Sync);
{error, {error, {full, _Name}}, N} when Pids =:= [] ->
log_end_sync(state_ok(S#state{cnt = S#state.cnt + N}), Sync);
{error, Error, N} ->
- replies(Pids, Error),
+ ok = replies(Pids, Error),
state_err(S#state{cnt = S#state.cnt + N}, Error)
end.
@@ -1091,7 +1091,7 @@ log_end_sync(S, []) ->
S;
log_end_sync(S, Sync) ->
Res = do_sync(get(log)),
- replies(Sync, Res),
+ ok = replies(Sync, Res),
state_err(S, Res).
%% Inlined.
@@ -1183,7 +1183,7 @@ do_exit(S, From, Message0, Reason) ->
_ -> Message0
end,
_ = disk_log_server:close(self()),
- replies(From, Message),
+ ok = replies(From, Message),
?PROFILE(ep:done()),
exit(Reason).
@@ -1881,7 +1881,8 @@ replies(Pids, Reply) ->
send_reply(Pids, M).
send_reply(Pid, M) when is_pid(Pid) ->
- Pid ! M;
+ Pid ! M,
+ ok;
send_reply([Pid | Pids], M) ->
Pid ! M,
send_reply(Pids, M);
@@ -2022,7 +2023,7 @@ notify_owners(Note) ->
cache_error(S, Pids) ->
Error = S#state.cache_error,
- replies(Pids, Error),
+ ok = replies(Pids, Error),
state_err(S#state{cache_error = ok}, Error).
state_ok(S) ->
diff --git a/lib/kernel/src/disk_log_1.erl b/lib/kernel/src/disk_log_1.erl
index 9d431bdd30..59f5cad001 100644
--- a/lib/kernel/src/disk_log_1.erl
+++ b/lib/kernel/src/disk_log_1.erl
@@ -295,12 +295,18 @@ read_chunk_ro(FdC, FileName, Pos, MaxBytes) ->
pread(FdC, FileName, Pos + ?HEADSZ, MaxBytes).
%% -> ok | throw(Error)
-close(#cache{fd = Fd, c = []}, _FileName, read_only) ->
- file:close(Fd);
+close(#cache{fd = Fd, c = []}, FileName, read_only) ->
+ case file:close(Fd) of
+ ok -> ok;
+ Error -> file_error(FileName, Error)
+ end;
close(#cache{fd = Fd, c = C}, FileName, read_write) ->
{Reply, _NewFdC} = write_cache(Fd, FileName, C),
mark(Fd, FileName, ?CLOSED),
- file:close(Fd),
+ case file:close(Fd) of
+ ok -> ok;
+ Error -> file_error(FileName, Error)
+ end,
if Reply =:= ok -> ok; true -> throw(Reply) end.
%% Open an internal file. Head is ignored if Mode is read_only.
@@ -320,7 +326,10 @@ int_open(FName, Repair, read_write, Head) ->
{ok, FileHead} ->
case is_head(FileHead) of
yes ->
- file:close(Fd),
+ case file:close(Fd) of
+ ok -> ok;
+ Error2 -> file_error(FName, Error2)
+ end,
case open_update(FName) of
{ok, Fd2} ->
mark(Fd2, FName, ?OPENED),
@@ -333,14 +342,14 @@ int_open(FName, Repair, read_write, Head) ->
yes_not_closed when Repair ->
repair(Fd, FName);
yes_not_closed when not Repair ->
- file:close(Fd),
+ _ = file:close(Fd),
throw({error, {need_repair, FName}});
no ->
- file:close(Fd),
+ _ = file:close(Fd),
throw({error, {not_a_log_file, FName}})
end;
eof ->
- file:close(Fd),
+ _= file:close(Fd),
throw({error, {not_a_log_file, FName}});
Error ->
file_error_close(Fd, FName, Error)
@@ -363,11 +372,11 @@ int_open(FName, _Repair, read_only, _Head) ->
FdC = #cache{fd = Fd},
{ok, {existed, FdC, {0, 0}, P}};
no ->
- file:close(Fd),
+ _= file:close(Fd),
throw({error, {not_a_log_file, FName}})
end;
eof ->
- file:close(Fd),
+ _ = file:close(Fd),
throw({error, {not_a_log_file, FName}});
Error ->
file_error_close(Fd, FName, Error)
@@ -398,7 +407,7 @@ int_log_head(Fd, Head) ->
none ->
{#cache{fd = Fd}, 0, 0};
Error ->
- file:close(Fd),
+ _= file:close(Fd),
throw(Error)
end.
@@ -450,13 +459,13 @@ ext_log_head(Fd, Head) ->
none ->
{#cache{fd = Fd}, {0, 0}};
Error ->
- file:close(Fd),
+ _= file:close(Fd),
throw(Error)
end.
%% -> _Any | throw()
mark(Fd, FileName, What) ->
- position_close2(Fd, FileName, 4),
+ {ok, _} = position_close2(Fd, FileName, 4),
fwrite_close2(Fd, FileName, What).
%% -> {ok, Bin} | Error
@@ -560,7 +569,7 @@ scan_f2(B, FSz, Ack, No, Bad, Size, Tail) ->
end.
done_scan(In, Out, OutName, FName, RecoveredTerms, BadChars) ->
- file:close(In),
+ _ = file:close(In),
case catch fclose(Out, OutName) of
ok ->
case file:rename(OutName, FName) of
@@ -574,21 +583,21 @@ done_scan(In, Out, OutName, FName, RecoveredTerms, BadChars) ->
file_error(FName, Error)
end;
Error ->
- file:delete(OutName),
+ _ = file:delete(OutName),
file_error(FName, Error)
end;
Error ->
- file:delete(OutName),
+ _ = file:delete(OutName),
throw(Error)
end.
-spec repair_err(file:io_device(), #cache{}, file:filename(),
file:filename(), {'error', file:posix()}) -> no_return().
repair_err(In, Out, OutName, ErrFileName, Error) ->
- file:close(In),
+ _= file:close(In),
catch fclose(Out, OutName),
%% OutName is often the culprit, try to remove it anyway...
- file:delete(OutName),
+ _ = file:delete(OutName),
file_error(ErrFileName, Error).
%% Used by wrap_log_reader.
@@ -764,10 +773,10 @@ mf_int_chunk(Handle, {FileNo, Pos}, Bin, N) ->
{ok, {_Alloc, FdC, _HeadSize, _FileSize}} ->
case chunk(FdC, FName, Pos, Bin, N) of
{NewFdC, eof} ->
- file:close(NewFdC#cache.fd),
+ _ = file:close(NewFdC#cache.fd),
mf_int_chunk(Handle, {NFileNo, 0}, [], N);
{NewFdC, Other} ->
- file:close(NewFdC#cache.fd),
+ _ = file:close(NewFdC#cache.fd),
{Handle, conv(Other, FileNo)}
end
end.
@@ -792,10 +801,10 @@ mf_int_chunk_read_only(Handle, {FileNo, Pos}, Bin, N) ->
{ok, {_Alloc, FdC, _HeadSize, _FileSize}} ->
case do_chunk_read_only(FdC, FName, Pos, Bin, N) of
{NewFdC, eof} ->
- file:close(NewFdC#cache.fd),
+ _ = file:close(NewFdC#cache.fd),
mf_int_chunk_read_only(Handle, {NFileNo,0}, [], N);
{NewFdC, Other} ->
- file:close(NewFdC#cache.fd),
+ _ = file:close(NewFdC#cache.fd),
{Handle, conv(Other, FileNo)}
end
end.
@@ -1017,7 +1026,7 @@ ext_file_open(FName, NewFile, OldFile, OldCnt, Head, Repair, Mode) ->
read_index_file(truncate, FName, MaxF) ->
remove_files(FName, 2, MaxF),
- file:delete(?index_file_name(FName)),
+ _ = file:delete(?index_file_name(FName)),
{1, 0, 0, 0};
read_index_file(_, FName, _MaxF) ->
read_index_file(FName).
@@ -1043,7 +1052,7 @@ read_index_file(FName) ->
_ErrorOrEof ->
{1, 0, 0, 0}
end,
- file:close(Fd),
+ _ = file:close(Fd),
R;
_Error ->
{1, 0, 0, 0}
@@ -1096,7 +1105,7 @@ write_index_file(read_write, FName, NewFile, OldFile, OldCnt) ->
%% Very old format, convert to the latest format!
case file:read_file(FileName) of
{ok, <<_CurF, Tail/binary>>} ->
- position_close2(Fd, FileName, bof),
+ {ok, _} = position_close2(Fd, FileName, bof),
Bin = <<0, 0:32, ?VERSION, NewFile:32>>,
NewTail = to_8_bytes(Tail, [], FileName, Fd),
fwrite_close2(Fd, FileName, [Bin | NewTail]),
@@ -1115,7 +1124,7 @@ write_index_file(read_write, FName, NewFile, OldFile, OldCnt) ->
R = file:pread(Fd, NewPos, SzSz),
OldPos = Offset + (OldFile - 1)*SzSz,
pwrite_close2(Fd, FileName, OldPos, OldCntBin),
- file:close(Fd),
+ _ = file:close(Fd),
case R of
{ok, <<Lost:SzSz/unit:8>>} -> Lost;
{ok, _} ->
@@ -1125,7 +1134,7 @@ write_index_file(read_write, FName, NewFile, OldFile, OldCnt) ->
end;
true ->
pwrite_close2(Fd, FileName, NewPos, OldCntBin),
- file:close(Fd),
+ _ = file:close(Fd),
0
end;
E ->
@@ -1137,7 +1146,7 @@ to_8_bytes(<<N:32,T/binary>>, NT, FileName, Fd) ->
to_8_bytes(B, NT, _FileName, _Fd) when byte_size(B) =:= 0 ->
NT;
to_8_bytes(_B, _NT, FileName, Fd) ->
- file:close(Fd),
+ _ = file:close(Fd),
throw({error, {invalid_index_file, FileName}}).
%% -> ok | throw(FileError)
@@ -1147,7 +1156,7 @@ index_file_trunc(FName, N) ->
{ok, Fd} ->
case file:read(Fd, 6) of
eof ->
- file:close(Fd),
+ _ = file:close(Fd),
ok;
{ok, <<0, 0:32, Version>>} when Version =:= ?VERSION ->
truncate_index_file(Fd, FileName, 10, 8, N);
@@ -1166,10 +1175,10 @@ truncate_index_file(Fd, FileName, Offset, N, SzSz) ->
Pos = Offset + N*SzSz,
case Pos > file_size(FileName) of
true ->
- file:close(Fd);
+ ok = file:close(Fd);
false ->
truncate_at_close2(Fd, FileName, {bof, Pos}),
- file:close(Fd)
+ ok = file:close(Fd)
end,
ok.
@@ -1412,7 +1421,8 @@ fwrite(#cache{c = []} = FdC, _FN, B, Size) ->
ok;
_ ->
put(write_cache_timer_is_running, true),
- erlang:send_after(?TIMEOUT, self(), {self(), write_cache})
+ erlang:send_after(?TIMEOUT, self(), {self(), write_cache}),
+ ok
end,
{ok, FdC#cache{sz = Size, c = B}};
fwrite(#cache{sz = Sz, c = C} = FdC, _FN, B, Size) when Sz < ?MAX ->
@@ -1511,7 +1521,7 @@ position_close2(Fd, FileName, Pos) ->
end.
truncate_at_close2(Fd, FileName, Pos) ->
- position_close2(Fd, FileName, Pos),
+ {ok, _} = position_close2(Fd, FileName, Pos),
case file:truncate(Fd) of
ok -> ok;
Error -> file_error_close(Fd, FileName, Error)
@@ -1519,7 +1529,7 @@ truncate_at_close2(Fd, FileName, Pos) ->
fclose(#cache{fd = Fd, c = C}, FileName) ->
%% The cache is empty if the file was opened in read_only mode.
- write_cache_close(Fd, FileName, C),
+ _ = write_cache_close(Fd, FileName, C),
file:close(Fd).
%% -> {Reply, #cache{}}; Reply = ok | Error
@@ -1549,5 +1559,5 @@ file_error(FileName, {error, Error}) ->
-spec file_error_close(file:fd(), file:filename(), {'error', file:posix()}) -> no_return().
file_error_close(Fd, FileName, {error, Error}) ->
- file:close(Fd),
+ _ = file:close(Fd),
throw({error, {file_error, FileName, Error}}).
diff --git a/lib/kernel/src/disk_log_server.erl b/lib/kernel/src/disk_log_server.erl
index 8894ed87e8..45334912eb 100644
--- a/lib/kernel/src/disk_log_server.erl
+++ b/lib/kernel/src/disk_log_server.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2009. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2014. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -83,8 +83,8 @@ accessible_logs() ->
init([]) ->
process_flag(trap_exit, true),
- ets:new(?DISK_LOG_NAME_TABLE, [named_table, set]),
- ets:new(?DISK_LOG_PID_TABLE, [named_table, set]),
+ _ = ets:new(?DISK_LOG_NAME_TABLE, [named_table, set]),
+ _= ets:new(?DISK_LOG_PID_TABLE, [named_table, set]),
{ok, #state{}}.
handle_call({open, W, A}, From, State) ->
@@ -159,15 +159,25 @@ ensure_started() ->
undefined ->
LogSup = {disk_log_sup, {disk_log_sup, start_link, []}, permanent,
1000, supervisor, [disk_log_sup]},
- supervisor:start_child(kernel_safe_sup, LogSup),
+ {ok, _} = ensure_child_started(kernel_safe_sup, LogSup),
LogServer = {disk_log_server,
{disk_log_server, start_link, []},
permanent, 2000, worker, [disk_log_server]},
- supervisor:start_child(kernel_safe_sup, LogServer),
+ {ok, _} = ensure_child_started(kernel_safe_sup, LogServer),
ok;
_ -> ok
end.
+ensure_child_started(Sup,Child) ->
+ case supervisor:start_child(Sup, Child) of
+ {ok,Pid} ->
+ {ok,Pid};
+ {error,{already_started,Pid}} ->
+ {ok,Pid};
+ Error ->
+ Error
+ end.
+
open([{Req, From} | L], State) ->
State2 = case do_open(Req, From, State) of
{pending, State1} ->
@@ -189,7 +199,7 @@ do_open({open, W, #arg{name = Name}=A}=Req, From, State) ->
false when W =:= local ->
case A#arg.distributed of
{true, Nodes} ->
- Fun = fun() -> open_distr_rpc(Nodes, A, From) end,
+ Fun = open_distr_rpc_fun(Nodes, A, From),
_Pid = spawn(Fun),
%% No pending reply is expected, but don't reply yet.
{pending, State};
@@ -215,11 +225,15 @@ do_open({open, W, #arg{name = Name}=A}=Req, From, State) ->
end
end.
+-spec open_distr_rpc_fun([node()], _, _) -> % XXX: underspecified
+ fun(() -> no_return()).
+
+open_distr_rpc_fun(Nodes, A, From) ->
+ fun() -> open_distr_rpc(Nodes, A, From) end.
+
%% Spawning a process is a means to avoid deadlock when
%% disk_log_servers mutually open disk_logs.
--spec open_distr_rpc([node()], _, _) -> no_return(). % XXX: underspecified
-
open_distr_rpc(Nodes, A, From) ->
{AllReplies, BadNodes} = rpc:multicall(Nodes, ?MODULE, dist_open, [A]),
{Ok, Bad} = cr(AllReplies, [], []),
diff --git a/lib/kernel/src/dist_ac.erl b/lib/kernel/src/dist_ac.erl
index 5c62aa31e9..a4d4ae386c 100644
--- a/lib/kernel/src/dist_ac.erl
+++ b/lib/kernel/src/dist_ac.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2009. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2013. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -283,7 +283,7 @@ handle_cast(init_sync, _S) ->
KernelConfig ! dist_ac_took_control,
%% we're really just interested in nodedowns.
- net_kernel:monitor_nodes(true),
+ ok = net_kernel:monitor_nodes(true),
{Known, NAppls, RStarted} = sync_dacs(Appls),
@@ -321,7 +321,7 @@ handle_call({takeover_application, AppName, RestartType}, From, S) ->
case keysearch(AppName, #appl.name, Appls) of
{value, Appl} when element(1, Appl#appl.id) =:= distributed ->
{distributed, Node} = Appl#appl.id,
- ac_takeover(req, AppName, Node, RestartType),
+ _ = ac_takeover(req, AppName, Node, RestartType),
NAppl = Appl#appl{id = takeover},
NAppls = keyreplace(AppName, #appl.name, Appls, NAppl),
TR = S#state.t_reqs,
@@ -341,10 +341,10 @@ handle_call({permit_application, AppName, Bool, LockId, StartInfo}, From, S) ->
%% here, but we have to be backwards-compatible.
case application_controller:get_loaded(AppName) of
{true, _} when not Bool ->
- ac_stop_it(AppName),
+ _ = ac_stop_it(AppName),
{reply, ok, S};
{true, _} when Bool ->
- ac_start_it(req, AppName),
+ _ = ac_start_it(req, AppName),
{reply, ok, S};
false ->
{reply, {error, {not_loaded, AppName}}, S}
@@ -533,7 +533,7 @@ handle_info({dist_ac_app_started, Node, Name, Res}, S) ->
%% Another node started appl. Update appl list.
{distributed, Node}
end,
- ac_started(req, Name, Node),
+ _ = ac_started(req, Name, Node),
NAppl = Appl#appl{id = NId},
NAppls = keyreplace(Name, #appl.name, Appls, NAppl),
TmpWeights = keydelete_all(Name, 1, S#state.tmp_weights),
@@ -622,7 +622,7 @@ handle_info({nodedown, Node}, S) ->
true ->
{true, Appl#appl{id = {failover, Node}}};
false ->
- ac_not_running(Appl#appl.name),
+ _ = ac_not_running(Appl#appl.name),
{true, Appl#appl{id = undefined}}
end;
(_) ->
@@ -656,7 +656,8 @@ handle_info({dist_ac_app_loaded, Node, Name, HisNodes, Permission, HeKnowsMe},
%% he's a new node connecting to us.
Msg = {dist_ac_app_loaded, node(), Name,
Nodes, dist_is_runnable(Appls, Name), true},
- {?DIST_AC, Node} ! Msg;
+ {?DIST_AC, Node} ! Msg,
+ ok;
true ->
ok
end,
@@ -811,29 +812,29 @@ start_appl(AppName, S, Type) ->
start_distributed(Appl, Name, Nodes, PermittedNodes, S, Type) ->
case find_start_node(Nodes, PermittedNodes, Name, S) of
{ok, Node} when Node =:= node() ->
- case Appl#appl.id of
- {failover, FoNode} when Type =:= req ->
- ac_failover(Name, FoNode, undefined);
- {distributed, Node2} when Type =:= req ->
- ac_takeover(req, Name, Node2, undefined);
- _ when Type =:= reply ->
- case lists:keysearch(Name, 2, S#state.remote_started) of
- {value, {Node3, _}} ->
- ac_takeover(reply, Name, Node3, undefined);
- _ ->
- ac_start_it(Type, Name)
- end;
- _ ->
- ac_start_it(Type, Name)
- end,
+ _ = case Appl#appl.id of
+ {failover, FoNode} when Type =:= req ->
+ ac_failover(Name, FoNode, undefined);
+ {distributed, Node2} when Type =:= req ->
+ ac_takeover(req, Name, Node2, undefined);
+ _ when Type =:= reply ->
+ case lists:keysearch(Name, 2, S#state.remote_started) of
+ {value, {Node3, _}} ->
+ ac_takeover(reply, Name, Node3, undefined);
+ _ ->
+ ac_start_it(Type, Name)
+ end;
+ _ ->
+ ac_start_it(Type, Name)
+ end,
{run_waiting, true};
{already_started, Node} ->
- ac_started(Type, Name, Node),
+ _ = ac_started(Type, Name, Node),
{{distributed, Node}, false};
{ok, Node} ->
case keysearch(Name, #appl.name, S#state.appls) of
{value, #appl{id = {distributed, Node}}} ->
- ac_started(Type, Name, Node),
+ _ = ac_started(Type, Name, Node),
{{distributed, Node}, false};
_ ->
wait_dist_start(Node, Appl, Name, Nodes,
@@ -842,7 +843,7 @@ start_distributed(Appl, Name, Nodes, PermittedNodes, S, Type) ->
not_started ->
wait_dist_start2(Appl, Name, Nodes, PermittedNodes, S, Type);
no_permission ->
- ac_not_started(Type, Name),
+ _ = ac_not_started(Type, Name),
{undefined, false}
end.
@@ -850,11 +851,11 @@ wait_dist_start(Node, Appl, Name, Nodes, PermittedNodes, S, Type) ->
monitor_node(Node, true),
receive
{dist_ac_app_started, Node, Name, ok} ->
- ac_started(Type, Name, Node),
+ _ = ac_started(Type, Name, Node),
monitor_node(Node, false),
{{distributed, Node}, false};
{dist_ac_app_started, Node, Name, {error, R}} ->
- ac_error(Type, Name, {Node, R}),
+ _ = ac_error(Type, Name, {Node, R}),
monitor_node(Node, false),
{Appl#appl.id, false};
{dist_ac_weight, Name, _Weigth, Node} ->
@@ -883,10 +884,10 @@ wait_dist_start(Node, Appl, Name, Nodes, PermittedNodes, S, Type) ->
wait_dist_start2(Appl, Name, Nodes, PermittedNodes, S, Type) ->
receive
{dist_ac_app_started, Node, Name, ok} ->
- ac_started(Type, Name, Node),
+ _ = ac_started(Type, Name, Node),
{{distributed, Node}, false};
{dist_ac_app_started, Node, Name, {error, R}} ->
- ac_error(Type, Name, {Node, R}),
+ _ = ac_error(Type, Name, {Node, R}),
{Appl#appl.id, false};
{nodedown, Node} ->
%% A node went down, try to start the app again - there may not
@@ -974,7 +975,7 @@ permit(false, {value, _}, AppName, From, S, _LockId) ->
case dist_get_runnable_nodes(S#state.appls, AppName) of
[] ->
%% There is no runnable node; stop application
- ac_stop_it(AppName),
+ _ = ac_stop_it(AppName),
SReqs = [{AppName, From} | S#state.s_reqs],
{noreply, S#state{s_reqs = SReqs}};
Nodes ->
@@ -1155,7 +1156,8 @@ send_nodes(Nodes, Msg) ->
end, FlatNodes).
send_after(Time, Msg) when is_integer(Time), Time >= 0 ->
- spawn_link(?MODULE, send_timeout, [self(), Time, Msg]);
+ _Pid = spawn_link(?MODULE, send_timeout, [self(), Time, Msg]),
+ ok;
send_after(_,_) -> % infinity
ok.
@@ -1305,7 +1307,7 @@ check_waiting([{From, AppName, false, Nodes} | Reqs],
S, Node, Appls, Res, SReqs) ->
case lists:delete(Node, Nodes) of
[] ->
- ac_stop_it(AppName),
+ _ = ac_stop_it(AppName),
NSReqs = [{AppName, From} | SReqs],
check_waiting(Reqs, Node, S, Appls, Res, NSReqs);
NNodes ->
diff --git a/lib/kernel/src/dist_util.erl b/lib/kernel/src/dist_util.erl
index fc50ec6717..b127fe2e33 100644
--- a/lib/kernel/src/dist_util.erl
+++ b/lib/kernel/src/dist_util.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1999-2013. All Rights Reserved.
+%% Copyright Ericsson AB 1999-2014. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -116,7 +116,8 @@ make_this_flags(RequestType, OtherNode) ->
?DFLAG_UNICODE_IO bor
?DFLAG_DIST_HDR_ATOM_CACHE bor
?DFLAG_SMALL_ATOM_TAGS bor
- ?DFLAG_UTF8_ATOMS).
+ ?DFLAG_UTF8_ATOMS bor
+ ?DFLAG_MAP_TAG).
handshake_other_started(#hs_data{request_type=ReqType}=HSData0) ->
{PreOtherFlags,Node,Version} = recv_name(HSData0),
diff --git a/lib/kernel/src/erl_boot_server.erl b/lib/kernel/src/erl_boot_server.erl
index 0d68d3e198..9a49655a9f 100644
--- a/lib/kernel/src/erl_boot_server.erl
+++ b/lib/kernel/src/erl_boot_server.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2011. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2013. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -191,7 +191,7 @@ init(Slaves) ->
{ok, UPort} = inet:port(U),
Ref = make_ref(),
Pid = proc_lib:spawn_link(?MODULE, boot_init, [Ref]),
- gen_tcp:controlling_process(L, Pid),
+ ok = gen_tcp:controlling_process(L, Pid),
Pid ! {Ref, L},
%% We trap exit inorder to restart boot_init and udp_port
process_flag(trap_exit, true),
@@ -233,9 +233,19 @@ handle_info({udp, U, IP, Port, Data}, S0) ->
%% erlang version as the boot server node
case {Valid,Data,Token} of
{true,Token,Token} ->
- gen_udp:send(U,IP,Port,[?EBOOT_REPLY,S0#state.priority,
- int16(S0#state.listen_port),
- S0#state.version]),
+ case gen_udp:send(U,IP,Port,[?EBOOT_REPLY,S0#state.priority,
+ int16(S0#state.listen_port),
+ S0#state.version])
+ of
+ ok -> ok;
+ {error, not_owner} ->
+ error_logger:error_msg("** Illegal boot server connection attempt: "
+ "not owner of ~w ** ~n", [U]);
+ {error, Reason} ->
+ Err = file:format_error(Reason),
+ error_logger:error_msg("** Illegal boot server connection attempt: "
+ "~w POSIX error ** ~n", [U, Err])
+ end,
{noreply,S0};
{false,_,_} ->
error_logger:error_msg("** Illegal boot server connection attempt: "
@@ -351,7 +361,14 @@ handle_command(S, PS, Msg) ->
end.
send_file_result(S, Cmd, Result) ->
- gen_tcp:send(S, term_to_binary({Cmd,Result})).
-
-send_result(S, Result) ->
- gen_tcp:send(S, term_to_binary(Result)).
+ send_result(S, {Cmd,Result}).
+
+send_result(S, Term) ->
+ case gen_tcp:send(S, term_to_binary(Term)) of
+ ok ->
+ ok;
+ Error ->
+ error_logger:error_msg("** Boot server could not send result "
+ "to socket: ~w** ~n", [Error]),
+ ok
+ end.
diff --git a/lib/kernel/src/erl_epmd.erl b/lib/kernel/src/erl_epmd.erl
index 91af49f303..b4fae24ef3 100644
--- a/lib/kernel/src/erl_epmd.erl
+++ b/lib/kernel/src/erl_epmd.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1998-2010. All Rights Reserved.
+%% Copyright Ericsson AB 1998-2013. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -217,17 +217,23 @@ do_register_node(NodeName, TcpPort) ->
Extra = "",
Elen = length(Extra),
Len = 1+2+1+1+2+2+2+length(Name)+2+Elen,
- gen_tcp:send(Socket, [?int16(Len), ?EPMD_ALIVE2_REQ,
- ?int16(TcpPort),
- $M,
- 0,
- ?int16(epmd_dist_high()),
- ?int16(epmd_dist_low()),
- ?int16(length(Name)),
- Name,
- ?int16(Elen),
- Extra]),
- wait_for_reg_reply(Socket, []);
+ Packet = [?int16(Len), ?EPMD_ALIVE2_REQ,
+ ?int16(TcpPort),
+ $M,
+ 0,
+ ?int16(epmd_dist_high()),
+ ?int16(epmd_dist_low()),
+ ?int16(length(Name)),
+ Name,
+ ?int16(Elen),
+ Extra],
+ case gen_tcp:send(Socket, Packet) of
+ ok ->
+ wait_for_reg_reply(Socket, []);
+ Error ->
+ close(Socket),
+ Error
+ end;
Error ->
Error
end.
@@ -294,8 +300,14 @@ get_port(Node, EpmdAddress, Timeout) ->
{ok, Socket} ->
Name = to_string(Node),
Len = 1+length(Name),
- gen_tcp:send(Socket, [?int16(Len),?EPMD_PORT_PLEASE2_REQ, Name]),
- wait_for_port_reply(Socket, []);
+ Msg = [?int16(Len),?EPMD_PORT_PLEASE2_REQ,Name],
+ case gen_tcp:send(Socket, Msg) of
+ ok ->
+ wait_for_port_reply(Socket, []);
+ _Error ->
+ ?port_please_failure2(_Error),
+ noport
+ end;
_Error ->
?port_please_failure2(_Error),
noport
@@ -374,7 +386,7 @@ wait_for_port_reply_name(Socket, Len, Sofar) ->
% io:format("data = ~p~n", _Data),
wait_for_port_reply_name(Socket, Len, Sofar);
{tcp_closed, Socket} ->
- "foobar"
+ ok
end.
@@ -424,19 +436,24 @@ get_names(EpmdAddress) ->
end.
do_get_names(Socket) ->
- gen_tcp:send(Socket, [?int16(1),?EPMD_NAMES]),
- receive
- {tcp, Socket, [P0,P1,P2,P3|T]} ->
- EpmdPort = ?u32(P0,P1,P2,P3),
- case get_epmd_port() of
- EpmdPort ->
- names_loop(Socket, T, []);
- _ ->
- close(Socket),
- {error, address}
+ case gen_tcp:send(Socket, [?int16(1),?EPMD_NAMES]) of
+ ok ->
+ receive
+ {tcp, Socket, [P0,P1,P2,P3|T]} ->
+ EpmdPort = ?u32(P0,P1,P2,P3),
+ case get_epmd_port() of
+ EpmdPort ->
+ names_loop(Socket, T, []);
+ _ ->
+ close(Socket),
+ {error, address}
+ end;
+ {tcp_closed, Socket} ->
+ {ok, []}
end;
- {tcp_closed, Socket} ->
- {ok, []}
+ _ ->
+ close(Socket),
+ {error, address}
end.
names_loop(Socket, Acc, Ps) ->
diff --git a/lib/kernel/src/erl_reply.erl b/lib/kernel/src/erl_reply.erl
index 1a61e630bc..f0be3ee654 100644
--- a/lib/kernel/src/erl_reply.erl
+++ b/lib/kernel/src/erl_reply.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2009. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2013. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -32,7 +32,7 @@ reply([Addr,Port,Msg]) ->
P = list_to_integer(atom_to_list(Port)),
M = atom_to_list(Msg),
{ok, S} = gen_tcp:connect(Ip,P,[]),
- gen_tcp:send(S,M),
+ ok = gen_tcp:send(S,M),
gen_tcp:close(S),
reply_done;
reply(_) ->
diff --git a/lib/kernel/src/error_logger.erl b/lib/kernel/src/error_logger.erl
index 92c1eb80dc..b8fbf02feb 100644
--- a/lib/kernel/src/error_logger.erl
+++ b/lib/kernel/src/error_logger.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2012. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2013. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -245,16 +245,18 @@ notify(Msg) ->
-spec swap_handler(Type :: swap_handler_type()) -> any().
swap_handler(tty) ->
- gen_event:swap_handler(error_logger, {error_logger, swap},
- {error_logger_tty_h, []}),
- simple_logger();
+ R = gen_event:swap_handler(error_logger, {error_logger, swap},
+ {error_logger_tty_h, []}),
+ ok = simple_logger(),
+ R;
swap_handler({logfile, File}) ->
- gen_event:swap_handler(error_logger, {error_logger, swap},
- {error_logger_file_h, File}),
- simple_logger();
+ R = gen_event:swap_handler(error_logger, {error_logger, swap},
+ {error_logger_file_h, File}),
+ ok = simple_logger(),
+ R;
swap_handler(silent) ->
- gen_event:delete_handler(error_logger, error_logger, delete),
- simple_logger();
+ _ = gen_event:delete_handler(error_logger, error_logger, delete),
+ ok = simple_logger();
swap_handler(false) ->
ok. % keep primitive event handler as-is
diff --git a/lib/kernel/src/erts_debug.erl b/lib/kernel/src/erts_debug.erl
index 6654cd9ee7..ef605d0bfe 100644
--- a/lib/kernel/src/erts_debug.erl
+++ b/lib/kernel/src/erts_debug.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1999-2012. All Rights Reserved.
+%% Copyright Ericsson AB 1999-2013. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -182,6 +182,11 @@ size(Tuple, Seen0, Sum0) when is_tuple(Tuple) ->
Sum = Sum0 + 1 + tuple_size(Tuple),
tuple_size(1, tuple_size(Tuple), Tuple, Seen, Sum)
end;
+size(Map, Seen0, Sum) when is_map(Map) ->
+ case remember_term(Map, Seen0) of
+ seen -> {Sum,Seen0};
+ Seen -> map_size(Map, Seen, Sum)
+ end;
size(Fun, Seen0, Sum) when is_function(Fun) ->
case remember_term(Fun, Seen0) of
seen -> {Sum,Seen0};
@@ -203,6 +208,12 @@ tuple_size(I, Sz, Tuple, Seen0, Sum0) ->
{Sum,Seen} = size(element(I, Tuple), Seen0, Sum0),
tuple_size(I+1, Sz, Tuple, Seen, Sum).
+map_size(Map,Seen0,Sum0) ->
+ Kt = erts_internal:map_to_tuple_keys(Map),
+ Vs = maps:values(Map),
+ {Sum1,Seen1} = size(Kt,Seen0,Sum0),
+ fold_size(Vs,Seen1,Sum1+length(Vs)+3).
+
fun_size(Fun, Seen, Sum) ->
case erlang:fun_info(Fun, type) of
{type,external} ->
@@ -210,14 +221,14 @@ fun_size(Fun, Seen, Sum) ->
{type,local} ->
Sz = erts_debug:flat_size(fun() -> ok end),
{env,Env} = erlang:fun_info(Fun, env),
- fun_size_1(Env, Seen, Sum+Sz+length(Env))
+ fold_size(Env, Seen, Sum+Sz+length(Env))
end.
-fun_size_1([H|T], Seen0, Sum0) ->
+fold_size([H|T], Seen0, Sum0) ->
{Sum,Seen} = size(H, Seen0, Sum0),
- fun_size_1(T, Seen, Sum);
-fun_size_1([], Seen, Sum) -> {Sum,Seen}.
-
+ fold_size(T, Seen, Sum);
+fold_size([], Seen, Sum) -> {Sum,Seen}.
+
remember_term(Term, Seen) ->
case gb_trees:lookup(Term, Seen) of
none -> gb_trees:insert(Term, [Term], Seen);
@@ -288,7 +299,7 @@ dff(Name, Fs) when is_list(Name) ->
try
dff(F, Fs)
after
- file:close(F)
+ _ = file:close(F)
end;
{error,Reason} ->
{error,{badopen,Reason}}
diff --git a/lib/kernel/src/file.erl b/lib/kernel/src/file.erl
index 36289053eb..20b703e084 100644
--- a/lib/kernel/src/file.erl
+++ b/lib/kernel/src/file.erl
@@ -95,7 +95,8 @@
Delay :: non_neg_integer()}
| 'delayed_write' | {'read_ahead', Size :: pos_integer()}
| 'read_ahead' | 'compressed'
- | {'encoding', unicode:encoding()}.
+ | {'encoding', unicode:encoding()}
+ | sync.
-type deep_list() :: [char() | atom() | deep_list()].
-type name() :: string() | atom() | deep_list().
-type name_all() :: string() | atom() | deep_list() | (RawFilename :: binary()).
@@ -110,7 +111,8 @@
-type date_time() :: calendar:datetime().
-type posix_file_advise() :: 'normal' | 'sequential' | 'random'
| 'no_reuse' | 'will_need' | 'dont_need'.
--type sendfile_option() :: {chunk_size, non_neg_integer()}.
+-type sendfile_option() :: {chunk_size, non_neg_integer()}
+ | {use_threads, boolean()}.
-type file_info_option() :: {'time', 'local'} | {'time', 'universal'}
| {'time', 'posix'}.
%%% BIFs
@@ -197,7 +199,8 @@ get_cwd(Drive) ->
check_and_call(get_cwd, [file_name(Drive)]).
-spec set_cwd(Dir) -> ok | {error, Reason} when
- Dir :: name(),
+ Dir :: name() | EncodedBinary,
+ EncodedBinary :: binary(),
Reason :: posix() | badarg | no_translation.
set_cwd(Dirname) ->
@@ -376,7 +379,7 @@ write_file(Name, Bin, ModeList) when is_list(ModeList) ->
ok ->
close(Handle);
E1 ->
- close(Handle),
+ _ = close(Handle),
E1
end;
E2 ->
@@ -770,7 +773,7 @@ copy_int({SourceName, SourceOpts}, Dest, Length)
case open(Source, [read | SourceOpts]) of
{ok, Handle} ->
Result = copy_opened_int(Handle, Dest, Length, 0),
- close(Handle),
+ _ = close(Handle),
Result;
{error, _} = Error ->
Error
@@ -786,9 +789,16 @@ copy_int(Source, {DestName, DestOpts}, Length)
Dest ->
case open(Dest, [write | DestOpts]) of
{ok, Handle} ->
- Result = copy_opened_int(Source, Handle, Length, 0),
- close(Handle),
- Result;
+ case copy_opened_int(Source, Handle, Length, 0) of
+ {ok, _} = OK ->
+ case close(Handle) of
+ ok -> OK;
+ Error -> Error
+ end;
+ Error ->
+ _ = close(Handle),
+ Error
+ end;
{error, _} = Error ->
Error
end
@@ -957,7 +967,7 @@ consult(File) ->
case open(File, [read]) of
{ok, Fd} ->
R = consult_stream(Fd),
- close(Fd),
+ _ = close(Fd),
R;
Error ->
Error
@@ -977,10 +987,10 @@ path_consult(Path, File) ->
{ok, Fd, Full} ->
case consult_stream(Fd) of
{ok, List} ->
- close(Fd),
+ _ = close(Fd),
{ok, List, Full};
E1 ->
- close(Fd),
+ _ = close(Fd),
E1
end;
E2 ->
@@ -1005,7 +1015,7 @@ eval(File, Bs) ->
case open(File, [read]) of
{ok, Fd} ->
R = eval_stream(Fd, ignore, Bs),
- close(Fd),
+ _ = close(Fd),
R;
Error ->
Error
@@ -1035,10 +1045,10 @@ path_eval(Path, File, Bs) ->
{ok, Fd, Full} ->
case eval_stream(Fd, ignore, Bs) of
ok ->
- close(Fd),
+ _ = close(Fd),
{ok, Full};
E1 ->
- close(Fd),
+ _ = close(Fd),
E1
end;
E2 ->
@@ -1065,7 +1075,7 @@ script(File, Bs) ->
case open(File, [read]) of
{ok, Fd} ->
R = eval_stream(Fd, return, Bs),
- close(Fd),
+ _ = close(Fd),
R;
Error ->
Error
@@ -1098,10 +1108,10 @@ path_script(Path, File, Bs) ->
{ok,Fd,Full} ->
case eval_stream(Fd, return, Bs) of
{ok,R} ->
- close(Fd),
+ _ = close(Fd),
{ok, R, Full};
E1 ->
- close(Fd),
+ _ = close(Fd),
E1
end;
E2 ->
@@ -1221,8 +1231,7 @@ change_time(Name, {{AY, AM, AD}, {AH, AMin, ASec}}=Atime,
sendfile(File, _Sock, _Offet, _Bytes, _Opts) when is_pid(File) ->
{error, badarg};
sendfile(File, Sock, Offset, Bytes, []) ->
- sendfile(File, Sock, Offset, Bytes, ?MAX_CHUNK_SIZE, [], [],
- false, false, false);
+ sendfile(File, Sock, Offset, Bytes, ?MAX_CHUNK_SIZE, [], [], []);
sendfile(File, Sock, Offset, Bytes, Opts) ->
ChunkSize0 = proplists:get_value(chunk_size, Opts, ?MAX_CHUNK_SIZE),
ChunkSize = if ChunkSize0 > ?MAX_CHUNK_SIZE ->
@@ -1232,8 +1241,7 @@ sendfile(File, Sock, Offset, Bytes, Opts) ->
%% Support for headers, trailers and options has been removed because the
%% Darwin and BSD API for using it does not play nice with
%% non-blocking sockets. See unix_efile.c for more info.
- sendfile(File, Sock, Offset, Bytes, ChunkSize, [], [],
- false,false,false).
+ sendfile(File, Sock, Offset, Bytes, ChunkSize, [], [], Opts).
%% sendfile/2
-spec sendfile(Filename, Socket) ->
@@ -1247,23 +1255,23 @@ sendfile(Filename, Sock) ->
{error, Reason};
{ok, Fd} ->
Res = sendfile(Fd, Sock, 0, 0, []),
- file:close(Fd),
+ _ = file:close(Fd),
Res
end.
%% Internal sendfile functions
sendfile(#file_descriptor{ module = Mod } = Fd, Sock, Offset, Bytes,
- ChunkSize, Headers, Trailers, Nodiskio, MNowait, Sync)
+ ChunkSize, Headers, Trailers, Opts)
when is_port(Sock) ->
case Mod:sendfile(Fd, Sock, Offset, Bytes, ChunkSize, Headers, Trailers,
- Nodiskio, MNowait, Sync) of
+ Opts) of
{error, enotsup} ->
sendfile_fallback(Fd, Sock, Offset, Bytes, ChunkSize,
Headers, Trailers);
Else ->
Else
end;
-sendfile(_,_,_,_,_,_,_,_,_,_) ->
+sendfile(_,_,_,_,_,_,_,_) ->
{error, badarg}.
%%%
@@ -1298,7 +1306,7 @@ sendfile_fallback(File, Sock, Offset, Bytes, ChunkSize) ->
{ok, CurrPos} = file:position(File, {cur, 0}),
{ok, _NewPos} = file:position(File, {bof, Offset}),
Res = sendfile_fallback_int(File, Sock, Bytes, ChunkSize, 0),
- file:position(File, {bof, CurrPos}),
+ _ = file:position(File, {bof, CurrPos}),
Res.
diff --git a/lib/kernel/src/file_io_server.erl b/lib/kernel/src/file_io_server.erl
index 0bcb1a658b..0e9ff5bc0f 100644
--- a/lib/kernel/src/file_io_server.erl
+++ b/lib/kernel/src/file_io_server.erl
@@ -162,29 +162,29 @@ server_loop(#state{mref = Mref} = State) ->
{file_request, From, ReplyAs, Request} when is_pid(From) ->
case file_request(Request, State) of
{reply, Reply, NewState} ->
- file_reply(From, ReplyAs, Reply),
+ _ = file_reply(From, ReplyAs, Reply),
server_loop(NewState);
{error, Reply, NewState} ->
%% error is the same as reply, except that
%% it breaks the io_request_loop further down
- file_reply(From, ReplyAs, Reply),
+ _ = file_reply(From, ReplyAs, Reply),
server_loop(NewState);
{stop, Reason, Reply, _NewState} ->
- file_reply(From, ReplyAs, Reply),
+ _ = file_reply(From, ReplyAs, Reply),
exit(Reason)
end;
{io_request, From, ReplyAs, Request} when is_pid(From) ->
case io_request(Request, State) of
{reply, Reply, NewState} ->
- io_reply(From, ReplyAs, Reply),
+ _ = io_reply(From, ReplyAs, Reply),
server_loop(NewState);
{error, Reply, NewState} ->
%% error is the same as reply, except that
%% it breaks the io_request_loop further down
- io_reply(From, ReplyAs, Reply),
+ _ = io_reply(From, ReplyAs, Reply),
server_loop(NewState);
{stop, Reason, Reply, _NewState} ->
- io_reply(From, ReplyAs, Reply),
+ _ = io_reply(From, ReplyAs, Reply),
exit(Reason)
end;
{'DOWN', Mref, _, _, Reason} ->
diff --git a/lib/kernel/src/file_server.erl b/lib/kernel/src/file_server.erl
index d036dbb516..eabf0401a3 100644
--- a/lib/kernel/src/file_server.erl
+++ b/lib/kernel/src/file_server.erl
@@ -78,7 +78,8 @@ init([]) ->
process_flag(trap_exit, true),
case ?PRIM_FILE:start() of
{ok, Handle} ->
- ets:new(?FILE_IO_SERVER_TABLE, [named_table]),
+ ?FILE_IO_SERVER_TABLE =
+ ets:new(?FILE_IO_SERVER_TABLE, [named_table]),
{ok, Handle};
{error, Reason} ->
{stop, Reason}
diff --git a/lib/kernel/src/gen_sctp.erl b/lib/kernel/src/gen_sctp.erl
index 067e07304d..adaa3159ec 100644
--- a/lib/kernel/src/gen_sctp.erl
+++ b/lib/kernel/src/gen_sctp.erl
@@ -36,7 +36,7 @@
-type assoc_id() :: term().
-type option() ::
- {active, true | false | once} |
+ {active, true | false | once | -32768..32767} |
{buffer, non_neg_integer()} |
{dontroute, boolean()} |
{high_msgq_watermark, pos_integer()} |
@@ -274,7 +274,7 @@ do_connect(S, Addr, Port, Opts, Timeout, ConnWait) when is_port(S), is_list(Opts
Mod:connect(S, IP, Port, Opts, ConnectTimer);
Error -> Error
after
- inet:stop_timer(Timer)
+ _ = inet:stop_timer(Timer)
end
catch
error:badarg ->
diff --git a/lib/kernel/src/gen_tcp.erl b/lib/kernel/src/gen_tcp.erl
index a98ed4c238..bc8ffbe5e3 100644
--- a/lib/kernel/src/gen_tcp.erl
+++ b/lib/kernel/src/gen_tcp.erl
@@ -30,7 +30,7 @@
-include("file.hrl").
-type option() ::
- {active, true | false | once} |
+ {active, true | false | once | -32768..32767} |
{buffer, non_neg_integer()} |
{delay_send, boolean()} |
{deliver, port | term} |
@@ -139,7 +139,7 @@ connect(Address, Port, Opts) ->
connect(Address, Port, Opts, Time) ->
Timer = inet:start_timer(Time),
Res = (catch connect1(Address,Port,Opts,Timer)),
- inet:stop_timer(Timer),
+ _ = inet:stop_timer(Timer),
case Res of
{ok,S} -> {ok,S};
{error, einval} -> exit(badarg);
diff --git a/lib/kernel/src/gen_udp.erl b/lib/kernel/src/gen_udp.erl
index e82b11d2ef..70dceb3679 100644
--- a/lib/kernel/src/gen_udp.erl
+++ b/lib/kernel/src/gen_udp.erl
@@ -26,7 +26,7 @@
-include("inet_int.hrl").
-type option() ::
- {active, true | false | once} |
+ {active, true | false | once | -32768..32767} |
{add_membership, {inet:ip_address(), inet:ip_address()}} |
{broadcast, boolean()} |
{buffer, non_neg_integer()} |
diff --git a/lib/kernel/src/global.erl b/lib/kernel/src/global.erl
index b24a9d5eac..0a4edea452 100644
--- a/lib/kernel/src/global.erl
+++ b/lib/kernel/src/global.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2012. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2014. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -1513,14 +1513,18 @@ delete_global_name(_Name, _Pid) ->
-record(him, {node, locker, vsn, my_tag}).
start_the_locker(DoTrace) ->
- spawn_link(fun() -> init_the_locker(DoTrace) end).
+ spawn_link(init_the_locker_fun(DoTrace)).
-init_the_locker(DoTrace) ->
- process_flag(trap_exit, true), % needed?
- S0 = #multi{do_trace = DoTrace},
- S1 = update_locker_known({add, get_known()}, S0),
- loop_the_locker(S1),
- erlang:error(locker_exited).
+-spec init_the_locker_fun(boolean()) -> fun(() -> no_return()).
+
+init_the_locker_fun(DoTrace) ->
+ fun() ->
+ process_flag(trap_exit, true), % needed?
+ S0 = #multi{do_trace = DoTrace},
+ S1 = update_locker_known({add, get_known()}, S0),
+ loop_the_locker(S1),
+ erlang:error(locker_exited)
+ end.
loop_the_locker(S) ->
?trace({loop_the_locker,S}),
@@ -2069,7 +2073,8 @@ random_sleep(Times) ->
case get(random_seed) of
undefined ->
{A1, A2, A3} = now(),
- random:seed(A1, A2, A3 + erlang:phash(node(), 100000));
+ _ = random:seed(A1, A2, A3 + erlang:phash(node(), 100000)),
+ ok;
_ -> ok
end,
%% First time 1/4 seconds, then doubling each time up to 8 seconds max.
diff --git a/lib/kernel/src/global_group.erl b/lib/kernel/src/global_group.erl
index 025a9b8a5b..da8b573749 100644
--- a/lib/kernel/src/global_group.erl
+++ b/lib/kernel/src/global_group.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1998-2011. All Rights Reserved.
+%% Copyright Ericsson AB 1998-2013. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -1149,9 +1149,14 @@ do_unlink(Pid, State) ->
%%%====================================================================================
%%% Send a nodeup/down messages to monitoring Pids in the own global group.
%%%====================================================================================
-send_monitor([P|T], M, no_conf) -> safesend_nc(P, M), send_monitor(T, M, no_conf);
-send_monitor([P|T], M, SyncState) -> safesend(P, M), send_monitor(T, M, SyncState);
-send_monitor([], _, _) -> ok.
+send_monitor([P|T], M, no_conf) ->
+ _ = safesend_nc(P, M),
+ send_monitor(T, M, no_conf);
+send_monitor([P|T], M, SyncState) ->
+ _ = safesend(P, M),
+ send_monitor(T, M, SyncState);
+send_monitor([], _, _) ->
+ ok.
safesend(Name, {Msg, Node}) when is_atom(Name) ->
case lists:member(Node, get_own_nodes()) of
diff --git a/lib/kernel/src/group.erl b/lib/kernel/src/group.erl
index ff835e1047..b36dbf33dd 100644
--- a/lib/kernel/src/group.erl
+++ b/lib/kernel/src/group.erl
@@ -309,15 +309,17 @@ io_requests([], Stat, _) ->
%% The ACK contains the return value.
io_reply(From, ReplyAs, Reply) ->
- From ! {io_reply,ReplyAs,Reply}.
+ From ! {io_reply,ReplyAs,Reply},
+ ok.
%% send_drv(Drv, Message)
%% send_drv_reqs(Drv, Requests)
send_drv(Drv, Msg) ->
- Drv ! {self(),Msg}.
+ Drv ! {self(),Msg},
+ ok.
-send_drv_reqs(_Drv, []) -> [];
+send_drv_reqs(_Drv, []) -> ok;
send_drv_reqs(Drv, Rs) ->
send_drv(Drv, {requests,Rs}).
diff --git a/lib/kernel/src/heart.erl b/lib/kernel/src/heart.erl
index 87cb9d7f51..daed6dd488 100644
--- a/lib/kernel/src/heart.erl
+++ b/lib/kernel/src/heart.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2012. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2013. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -182,20 +182,24 @@ wait_ack(Port) ->
end.
loop(Parent, Port, Cmd) ->
- send_heart_beat(Port),
+ _ = send_heart_beat(Port),
receive
- {From, set_cmd, NewCmd} when length(NewCmd) < 2047 ->
- send_heart_cmd(Port, NewCmd),
- wait_ack(Port),
- From ! {heart, ok},
- loop(Parent, Port, NewCmd);
- {From, set_cmd, NewCmd} ->
- From ! {heart, {error, {bad_cmd, NewCmd}}},
- loop(Parent, Port, Cmd);
+ {From, set_cmd, NewCmd0} ->
+ Enc = file:native_name_encoding(),
+ case catch unicode:characters_to_binary(NewCmd0,Enc,Enc) of
+ 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 ! {heart, {error, {bad_cmd, NewCmd0}}},
+ loop(Parent, Port, Cmd)
+ end;
{From, clear_cmd} ->
From ! {heart, ok},
- send_heart_cmd(Port, ""),
- wait_ack(Port),
+ _ = send_heart_cmd(Port, ""),
+ _ = wait_ack(Port),
loop(Parent, Port, "");
{From, get_cmd} ->
From ! {heart, get_heart_cmd(Port)},
@@ -222,7 +226,7 @@ loop(Parent, Port, Cmd) ->
-spec no_reboot_shutdown(port()) -> no_return().
no_reboot_shutdown(Port) ->
- send_shutdown(Port),
+ _ = send_shutdown(Port),
receive
{'EXIT', Port, Reason} when Reason =/= badsig ->
exit(normal)
@@ -232,10 +236,10 @@ do_cycle_port_program(Caller, Parent, Port, Cmd) ->
unregister(?HEART_PORT_NAME),
case catch start_portprogram() of
{ok, NewPort} ->
- send_shutdown(Port),
+ _ = send_shutdown(Port),
receive
{'EXIT', Port, _Reason} ->
- send_heart_cmd(NewPort, Cmd),
+ _ = send_heart_cmd(NewPort, Cmd),
Caller ! {heart, ok},
loop(Parent, NewPort, Cmd)
after
@@ -243,7 +247,7 @@ do_cycle_port_program(Caller, Parent, Port, Cmd) ->
%% 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),
+ _ = send_heart_cmd(NewPort, Cmd),
Caller ! {heart, {error, stop_error}},
loop(Parent, NewPort, Cmd)
end;
diff --git a/lib/kernel/src/hipe_unified_loader.erl b/lib/kernel/src/hipe_unified_loader.erl
index 0a0e6003ee..e5928c7b63 100644
--- a/lib/kernel/src/hipe_unified_loader.erl
+++ b/lib/kernel/src/hipe_unified_loader.erl
@@ -194,6 +194,13 @@ load_common(Mod, Bin, Beam, OldReferencesToPatch) ->
CodeSize, CodeBinary, Refs,
0,[] % ColdSize, CRrefs
] = binary_to_term(Bin),
+ ?debug_msg("***** ErLLVM *****~nVersion: ~s~nCheckSum: ~w~nConstAlign: ~w~n" ++
+ "ConstSize: ~w~nConstMap: ~w~nLabelMap: ~w~nExportMap ~w~nRefs ~w~n",
+ [Version, CheckSum, ConstAlign, ConstSize, ConstMap, LabelMap, ExportMap,
+ Refs]),
+ %% Write HiPE binary code to a file in the current directory in order to
+ %% debug by disassembling.
+ %% file:write_file("erl.o", CodeBinary, [binary]),
%% Check that we are loading up-to-date code.
version_check(Version, Mod),
case hipe_bifs:check_crc(CheckSum) of
@@ -203,6 +210,7 @@ load_common(Mod, Bin, Beam, OldReferencesToPatch) ->
"please regenerate native code for this runtime system\n", [Mod]),
bad_crc;
true ->
+ put(closures_to_patch, []),
%% Create data segment
{ConstAddr,ConstMap2} =
create_data_segment(ConstAlign, ConstSize, ConstMap),
@@ -220,17 +228,28 @@ load_common(Mod, Bin, Beam, OldReferencesToPatch) ->
{MFAs,Addresses} = exports(ExportMap, CodeAddress),
%% Remove references to old versions of the module.
ReferencesToPatch = get_refs_from(MFAs, []),
+ %% io:format("References to patch: ~w~n", [ReferencesToPatch]),
ok = remove_refs_from(MFAs),
%% Patch all dynamic references in the code.
%% Function calls, Atoms, Constants, System calls
ok = patch(Refs, CodeAddress, ConstMap2, Addresses, TrampolineMap),
+
%% Tell the system where the loaded funs are.
%% (patches the BEAM code to redirect to native.)
case Beam of
[] ->
- export_funs(Addresses);
+ %% This module was previously loaded as BEAM code during system
+ %% start-up before the code server has started (-enable-native-libs
+ %% is active), so we must now patch the pre-existing entries in the
+ %% fun table with the native code addresses for all closures.
+ lists:foreach(fun({FE, DestAddress}) ->
+ hipe_bifs:set_native_address_in_fe(FE, DestAddress)
+ end, erase(closures_to_patch)),
+ export_funs(Addresses),
+ ok;
BeamBinary when is_binary(BeamBinary) ->
%% Find all closures in the code.
+ [] = erase(closures_to_patch), %Clean up, assertion.
ClosurePatches = find_closure_patches(Refs),
AddressesOfClosuresToPatch =
calculate_addresses(ClosurePatches, CodeAddress, Addresses),
@@ -243,6 +262,9 @@ load_common(Mod, Bin, Beam, OldReferencesToPatch) ->
%% The call to export_funs/1 above updated the native addresses
%% for the targets, so passing 'Addresses' is not needed.
redirect(ReferencesToPatch),
+ %% Final clean up.
+ _ = erase(hipe_patch_closures),
+ _ = erase(hipe_assert_code_area),
?debug_msg("****************Loader Finished****************\n", []),
{module,Mod} % for compatibility with code:load_file/1
end.
@@ -560,12 +582,17 @@ patch_closure(DestMFA, Uniq, Index, Address, Addresses) ->
case get(hipe_patch_closures) of
false ->
[]; % This is taken care of when registering the module.
- true -> % We are not loading a module patch these closures
+ true ->
+ %% We are replacing a previosly loaded BEAM module with native code,
+ %% so we must reference the pre-existing entries in the fun table
+ %% from the native code. We must delay actually patching the native
+ %% address into the fun entry to ensure that the native code cannot
+ %% be called until it has been completely fixed up.
RemoteOrLocal = local, % closure code refs are local
DestAddress = get_native_address(DestMFA, Addresses, RemoteOrLocal),
BEAMAddress = hipe_bifs:fun_to_address(DestMFA),
- FE = hipe_bifs:make_fe(DestAddress, mod(DestMFA),
- {Uniq, Index, BEAMAddress}),
+ FE = hipe_bifs:get_fe(mod(DestMFA), {Uniq, Index, BEAMAddress}),
+ put(closures_to_patch, [{FE,DestAddress}|get(closures_to_patch)]),
?debug_msg("Patch FE(~w) to 0x~.16b->0x~.16b (emu:0x~.16b)\n",
[DestMFA, FE, DestAddress, BEAMAddress]),
?ASSERT(assert_local_patch(Address)),
diff --git a/lib/kernel/src/inet.erl b/lib/kernel/src/inet.erl
index b1c9d56c2d..41d422d7d4 100644
--- a/lib/kernel/src/inet.erl
+++ b/lib/kernel/src/inet.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2013. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2014. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -457,7 +457,7 @@ gethostbyname(Name,Family) ->
gethostbyname(Name,Family,Timeout) ->
Timer = start_timer(Timeout),
Res = gethostbyname_tm(Name,Family,Timer),
- stop_timer(Timer),
+ _ = stop_timer(Timer),
Res.
gethostbyname_tm(Name,Family,Timer) ->
@@ -488,7 +488,7 @@ gethostbyaddr(Address) ->
gethostbyaddr(Address,Timeout) ->
Timer = start_timer(Timeout),
Res = gethostbyaddr_tm(Address, Timer),
- stop_timer(Timer),
+ _ = stop_timer(Timer),
Res.
gethostbyaddr_tm(Address,Timer) ->
@@ -543,7 +543,7 @@ getaddr(Address, Family) ->
getaddr(Address, Family, Timeout) ->
Timer = start_timer(Timeout),
Res = getaddr_tm(Address, Family, Timer),
- stop_timer(Timer),
+ _ = stop_timer(Timer),
Res.
getaddr_tm(Address, Family, Timer) ->
@@ -569,7 +569,7 @@ getaddrs(Address, Family) ->
getaddrs(Address, Family, Timeout) ->
Timer = start_timer(Timeout),
Res = getaddrs_tm(Address, Family, Timer),
- stop_timer(Timer),
+ _ = stop_timer(Timer),
Res.
-spec getservbyport(Port :: port_number(), Protocol :: atom() | string()) ->
@@ -597,8 +597,7 @@ getservbyname(Name, Protocol) when is_atom(Name) ->
Error -> Error
end.
--spec ntoa(IpAddress) ->
- {ok, Address} | {error, einval} when
+-spec ntoa(IpAddress) -> Address | {error, einval} when
Address :: string(),
IpAddress :: ip_address().
ntoa(Addr) ->
@@ -717,6 +716,9 @@ con_opt([Opt | Opts], R, As) ->
false ->
{error, badarg}
end;
+ {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);
{Name,Val} when is_atom(Name) -> con_add(Name, Val, R, Opts, As);
_ -> {error, badarg}
end;
@@ -783,6 +785,9 @@ list_opt([Opt | Opts], R, As) ->
false ->
{error, badarg}
end;
+ {active,N} when is_integer(N), N < 32768, N >= -32768 ->
+ NOpts = lists:keydelete(active, 1, R#listen_opts.opts),
+ list_opt(Opts, R#listen_opts { opts = [{active,N}|NOpts] }, As);
{Name,Val} when is_atom(Name) -> list_add(Name, Val, R, Opts, As);
_ -> {error, badarg}
end;
@@ -837,6 +842,9 @@ udp_opt([Opt | Opts], R, As) ->
false ->
{error, badarg}
end;
+ {active,N} when is_integer(N), N < 32768, N >= -32768 ->
+ NOpts = lists:keydelete(active, 1, R#udp_opts.opts),
+ udp_opt(Opts, R#udp_opts { opts = [{active,N}|NOpts] }, As);
{Name,Val} when is_atom(Name) -> udp_add(Name, Val, R, Opts, As);
_ -> {error, badarg}
end;
@@ -855,7 +863,7 @@ udp_add(Name, Val, R, Opts, As) ->
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Currently supported options include:
% (*) {mode, list|binary} or just list|binary
-% (*) {active, true|false|once}
+% (*) {active, true|false|once|N}
% (*) {sctp_module, inet_sctp|inet6_sctp} or just inet|inet6
% (*) options set via setsockopt.
% The full list is below in sctp_options/0 .
@@ -917,6 +925,9 @@ sctp_opt([Opt|Opts], Mod, R, As) ->
false ->
{error, badarg}
end;
+ {active,N} when is_integer(N), N < 32768, N >= -32768 ->
+ NOpts = lists:keydelete(active, 1, R#sctp_opts.opts),
+ sctp_opt(Opts, Mod, R#sctp_opts { opts = [{active,N}|NOpts] }, As);
{Name,Val} -> sctp_opt (Opts, Mod, R, As, Name, Val);
_ -> {error,badarg}
end;
@@ -1495,7 +1506,7 @@ tcp_controlling_process(S, NewOwner) when is_port(S), is_pid(NewOwner) ->
{ok, A0} ->
case A0 of
false -> ok;
- _ -> prim_inet:setopt(S, active, false)
+ _ -> ok = prim_inet:setopt(S, active, false)
end,
case tcp_sync_input(S, NewOwner, false) of
true -> %% socket already closed,
@@ -1506,7 +1517,7 @@ tcp_controlling_process(S, NewOwner) when is_port(S), is_pid(NewOwner) ->
unlink(S), %% unlink from port
case A0 of
false -> ok;
- _ -> prim_inet:setopt(S, active, A0)
+ _ -> ok = prim_inet:setopt(S, active, A0)
end,
ok
catch
@@ -1549,13 +1560,12 @@ udp_controlling_process(S, NewOwner) when is_port(S), is_pid(NewOwner) ->
{error, not_owner};
_ ->
{ok, A0} = prim_inet:getopt(S, active),
- prim_inet:setopt(S, active, false),
+ ok = prim_inet:setopt(S, active, false),
udp_sync_input(S, NewOwner),
try erlang:port_connect(S, NewOwner) of
true ->
unlink(S),
- prim_inet:setopt(S, active, A0),
- ok
+ ok = prim_inet:setopt(S, active, A0)
catch
error:Reason ->
{error, Reason}
diff --git a/lib/kernel/src/inet6_tcp_dist.erl b/lib/kernel/src/inet6_tcp_dist.erl
index 2cb0e10c87..459fdc2ad5 100644
--- a/lib/kernel/src/inet6_tcp_dist.erl
+++ b/lib/kernel/src/inet6_tcp_dist.erl
@@ -92,7 +92,7 @@ accept_loop(Kernel, Listen) ->
case inet6_tcp:accept(Listen) of
{ok, Socket} ->
Kernel ! {accept,self(),Socket,inet6,tcp},
- controller(Kernel, Socket),
+ _ = controller(Kernel, Socket),
accept_loop(Kernel, Listen);
Error ->
exit(Error)
diff --git a/lib/kernel/src/inet_config.erl b/lib/kernel/src/inet_config.erl
index 2461f3ff25..fdc244f959 100644
--- a/lib/kernel/src/inet_config.erl
+++ b/lib/kernel/src/inet_config.erl
@@ -197,6 +197,9 @@ do_load_resolv({win32,Type}, longnames) ->
win32_load_from_registry(Type),
inet_db:set_lookup([native]);
+do_load_resolv({ose,_}, _) ->
+ inet_db:set_lookup([file]);
+
do_load_resolv(_, _) ->
inet_db:set_lookup([native]).
diff --git a/lib/kernel/src/inet_db.erl b/lib/kernel/src/inet_db.erl
index a7679c531b..2ebdc0f554 100644
--- a/lib/kernel/src/inet_db.erl
+++ b/lib/kernel/src/inet_db.erl
@@ -1117,7 +1117,7 @@ handle_call(Request, From, #state{db=Db}=State) ->
{set_cache_refresh, Time} when is_integer(Time), Time > 0 ->
Time1 = ((Time+999) div 1000)*1000, %% round up
ets:insert(Db, {cache_refresh_interval, Time1}),
- stop_timer(State#state.cache_timer),
+ _ = stop_timer(State#state.cache_timer),
{reply, ok, State#state{cache_timer = init_timer()}};
clear_hosts ->
@@ -1131,7 +1131,7 @@ handle_call(Request, From, #state{db=Db}=State) ->
reset ->
reset_db(Db),
- stop_timer(State#state.cache_timer),
+ _ = stop_timer(State#state.cache_timer),
{reply, ok, State#state{cache_timer = init_timer()}};
{add_rc_list, List} ->
@@ -1181,7 +1181,7 @@ handle_info(_Info, State) ->
-spec terminate(term(), state()) -> 'ok'.
terminate(_Reason, State) ->
- stop_timer(State#state.cache_timer),
+ _ = stop_timer(State#state.cache_timer),
ok.
%%%----------------------------------------------------------------------
@@ -1240,8 +1240,9 @@ do_add_host(Byname, Byaddr, Names, Type, IP) ->
ok.
do_del_host(Byname, Byaddr, IP) ->
- [ets:delete_object(Byname, {tolower(Name),Type,Addr}) ||
- {Name,Type,Addr} <- ets:lookup(Byaddr, IP)],
+ _ =
+ [ets:delete_object(Byname, {tolower(Name),Type,Addr}) ||
+ {Name,Type,Addr} <- ets:lookup(Byaddr, IP)],
ets:delete(Byaddr, IP),
ok.
diff --git a/lib/kernel/src/inet_gethost_native.erl b/lib/kernel/src/inet_gethost_native.erl
index 65d4c84e3b..4320987078 100644
--- a/lib/kernel/src/inet_gethost_native.erl
+++ b/lib/kernel/src/inet_gethost_native.erl
@@ -237,7 +237,7 @@ handle_message({Port, {data, Data}}, State = #state{port = Port}) ->
State;
Req ->
lists:foreach(fun({P,R,TR}) ->
- ?CANCEL_TIMER(TR),
+ _= ?CANCEL_TIMER(TR),
P ! {R,
{ok,
BinReply}}
@@ -276,7 +276,7 @@ handle_message({timeout, Pid, RID}, State) ->
{last, {LP,LR,_}} ->
LP ! {LR, {error,timeout}},
%% Remove the whole request structure...
- pick_request(State, RID),
+ _ = pick_request(State, RID),
%% Also cancel the request to the port program...
(catch port_command(State#state.port,
<<RID:32,?OP_CANCEL_REQUEST>>))
@@ -517,7 +517,7 @@ do_start(Sup, C) ->
{error, {{already_started, Pid}, _Child}} when is_pid(Pid) ->
ok;
{error, already_present} ->
- supervisor:delete_child(Sup, Child),
+ _ = supervisor:delete_child(Sup, Child),
do_start(Sup, C)
end.
diff --git a/lib/kernel/src/inet_int.hrl b/lib/kernel/src/inet_int.hrl
index 641a8dc0ca..889b596a22 100644
--- a/lib/kernel/src/inet_int.hrl
+++ b/lib/kernel/src/inet_int.hrl
@@ -46,6 +46,7 @@
-define(INET_PASSIVE, 0).
-define(INET_ACTIVE, 1).
-define(INET_ONCE, 2). % Active once then passive
+-define(INET_MULTI, 3). % Active N then passive
%% state codes (getstatus, INET_REQ_GETSTATUS)
-define(INET_F_OPEN, 16#0001).
diff --git a/lib/kernel/src/inet_parse.erl b/lib/kernel/src/inet_parse.erl
index 98bd8d386c..a88c94a453 100644
--- a/lib/kernel/src/inet_parse.erl
+++ b/lib/kernel/src/inet_parse.erl
@@ -288,7 +288,7 @@ parse_file(_, File, Fn) ->
case file:open(File, [read]) of
{ok, Fd} ->
Result = parse_fd(File,Fd, 1, Fn, []),
- file:close(Fd),
+ _ = file:close(Fd),
Result;
Error -> Error
end.
diff --git a/lib/kernel/src/inet_res.erl b/lib/kernel/src/inet_res.erl
index 94a9f7c64d..6037da1d22 100644
--- a/lib/kernel/src/inet_res.erl
+++ b/lib/kernel/src/inet_res.erl
@@ -139,7 +139,7 @@ resolve(Name, Class, Type, Opts, Timeout) ->
{ok, Nm} ->
Timer = inet:start_timer(Timeout),
Res = res_query(Nm, Class, Type, Opts, Timer),
- inet:stop_timer(Timer),
+ _ = inet:stop_timer(Timer),
Res;
Error ->
Error
@@ -339,7 +339,7 @@ gethostbyaddr(IP) -> gethostbyaddr_tm(IP,false).
gethostbyaddr(IP,Timeout) ->
Timer = inet:start_timer(Timeout),
Res = gethostbyaddr_tm(IP,Timer),
- inet:stop_timer(Timer),
+ _ = inet:stop_timer(Timer),
Res.
gethostbyaddr_tm({A,B,C,D} = IP, Timer) when ?ip(A,B,C,D) ->
@@ -424,7 +424,7 @@ gethostbyname(Name,Family) ->
gethostbyname(Name,Family,Timeout) ->
Timer = inet:start_timer(Timeout),
Res = gethostbyname_tm(Name,Family,Timer),
- inet:stop_timer(Timer),
+ _ = inet:stop_timer(Timer),
Res.
gethostbyname_tm(Name,inet,Timer) ->
@@ -483,7 +483,7 @@ getbyname(Name, Type) ->
getbyname(Name, Type, Timeout) ->
Timer = inet:start_timer(Timeout),
Res = getbyname_tm(Name, Type, Timer),
- inet:stop_timer(Timer),
+ _ = inet:stop_timer(Timer),
Res.
getbyname_tm(Name, Type, Timer) when is_list(Name) ->
@@ -921,18 +921,25 @@ query_tcp(Timeout, Id, Buffer, IP, Port, Verbose) ->
[{active,false},{packet,2},binary,Family],
Timeout) of
{ok, S} ->
- gen_tcp:send(S, Buffer),
- case gen_tcp:recv(S, 0, Timeout) of
- {ok, Answer} ->
- gen_tcp:close(S),
- case decode_answer(Answer, Id, Verbose) of
- {ok, _} = OK -> OK;
- {error, badid} -> {error, servfail};
- Error -> Error
+ case gen_tcp:send(S, Buffer) of
+ ok ->
+ case gen_tcp:recv(S, 0, Timeout) of
+ {ok, Answer} ->
+ gen_tcp:close(S),
+ case decode_answer(Answer, Id, Verbose) of
+ {ok, _} = OK -> OK;
+ {error, badid} -> {error, servfail};
+ Error -> Error
+ end;
+ Error ->
+ gen_tcp:close(S),
+ ?verbose(Verbose, "TCP server recv error: ~p\n",
+ [Error]),
+ Error
end;
Error ->
gen_tcp:close(S),
- ?verbose(Verbose, "TCP server recv error: ~p\n",
+ ?verbose(Verbose, "TCP server send error: ~p\n",
[Error]),
Error
end;
diff --git a/lib/kernel/src/inet_sctp.erl b/lib/kernel/src/inet_sctp.erl
index 2d799d79fa..93528d305d 100644
--- a/lib/kernel/src/inet_sctp.erl
+++ b/lib/kernel/src/inet_sctp.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2007-2011. All Rights Reserved.
+%% Copyright Ericsson AB 2007-2013. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -135,7 +135,7 @@ connect_get_assoc(S, Addr, Port, Active, Timer) ->
{sctp,S,Addr,Port,{_,#sctp_assoc_change{state=St}=Ev}} ->
case Active of
once ->
- prim_inet:setopt(S, active, once);
+ ok = prim_inet:setopt(S, active, once);
_ -> ok
end,
if St =:= comm_up ->
diff --git a/lib/kernel/src/inet_tcp_dist.erl b/lib/kernel/src/inet_tcp_dist.erl
index 8005eff58c..63f236b069 100644
--- a/lib/kernel/src/inet_tcp_dist.erl
+++ b/lib/kernel/src/inet_tcp_dist.erl
@@ -119,7 +119,7 @@ accept_loop(Kernel, Listen) ->
case inet_tcp:accept(Listen) of
{ok, Socket} ->
Kernel ! {accept,self(),Socket,inet,tcp},
- controller(Kernel, Socket),
+ _ = controller(Kernel, Socket),
accept_loop(Kernel, Listen);
Error ->
exit(Error)
diff --git a/lib/kernel/src/kernel.app.src b/lib/kernel/src/kernel.app.src
index cb8c98ab06..5658c6b6cf 100644
--- a/lib/kernel/src/kernel.app.src
+++ b/lib/kernel/src/kernel.app.src
@@ -114,6 +114,7 @@
pg2]},
{applications, []},
{env, [{error_logger, tty}]},
- {mod, {kernel, []}}
+ {mod, {kernel, []}},
+ {runtime_dependencies, ["erts-6.0", "stdlib-2.0", "sasl-2.4"]}
]
}.
diff --git a/lib/kernel/src/kernel.appup.src b/lib/kernel/src/kernel.appup.src
index 54628800a8..f8f4cc1ec2 100644
--- a/lib/kernel/src/kernel.appup.src
+++ b/lib/kernel/src/kernel.appup.src
@@ -1,7 +1,7 @@
%% -*- erlang -*-
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1999-2011. All Rights Reserved.
+%% Copyright Ericsson AB 1999-2014. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -16,12 +16,10 @@
%%
%% %CopyrightEnd%
{"%VSN%",
- %% Up from - max two major revisions back
- [{<<"2\\.16(\\.[0-9]+)*">>,[restart_new_emulator]}, %% R16
- {<<"2\\.15(\\.[0-9]+)*">>,[restart_new_emulator]}, %% R15
- {<<"2\\.14(\\.[0-9]+)*">>,[restart_new_emulator]}],%% R14
- %% Down to - max two major revisions back
- [{<<"2\\.16(\\.[0-9]+)*">>,[restart_new_emulator]}, %% R16
- {<<"2\\.15(\\.[0-9]+)*">>,[restart_new_emulator]}, %% R15
- {<<"2\\.14(\\.[0-9]+)*">>,[restart_new_emulator]}] %% R14
+ %% Up from - max one major revision back
+ [{<<"3\\.0(\\.[0-9]+)*">>,[restart_new_emulator]}, %% R17
+ {<<"2\\.16(\\.[0-9]+)*">>,[restart_new_emulator]}],%% R16
+ %% Down to - max one major revision back
+ [{<<"3\\.0(\\.[0-9]+)*">>,[restart_new_emulator]}, %% R17
+ {<<"2\\.16(\\.[0-9]+)*">>,[restart_new_emulator]}] %% R16
}.
diff --git a/lib/kernel/src/kernel.erl b/lib/kernel/src/kernel.erl
index 1e07620a3e..ecdb32424a 100644
--- a/lib/kernel/src/kernel.erl
+++ b/lib/kernel/src/kernel.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2010. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2013. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -32,8 +32,13 @@ start(_, []) ->
case supervisor:start_link({local, kernel_sup}, kernel, []) of
{ok, Pid} ->
Type = get_error_logger_type(),
- error_logger:swap_handler(Type),
- {ok, Pid, []};
+ case error_logger:swap_handler(Type) of
+ ok -> {ok, Pid, []};
+ Error ->
+ %% Not necessary since the node will crash anyway:
+ exit(Pid, shutdown),
+ Error
+ end;
Error -> Error
end.
diff --git a/lib/kernel/src/kernel_config.erl b/lib/kernel/src/kernel_config.erl
index 48141cfa03..56defcb167 100644
--- a/lib/kernel/src/kernel_config.erl
+++ b/lib/kernel/src/kernel_config.erl
@@ -121,7 +121,7 @@ send_timeout(Timeout, Pid) ->
end.
wait_nodes(Mandatory, Optional) ->
- net_kernel:monitor_nodes(true),
+ ok = net_kernel:monitor_nodes(true),
lists:foreach(fun(Node) ->
case net_adm:ping(Node) of
pong -> self() ! {nodeup, Node};
@@ -129,7 +129,9 @@ wait_nodes(Mandatory, Optional) ->
end
end,
Mandatory ++ Optional),
- rec_nodes(Mandatory, Optional).
+ R = rec_nodes(Mandatory, Optional),
+ ok = net_kernel:monitor_nodes(false),
+ R.
rec_nodes([], []) -> ok;
rec_nodes(Mandatory, Optional) ->
diff --git a/lib/kernel/src/net_adm.erl b/lib/kernel/src/net_adm.erl
index 9b2dac9544..3f5eac7822 100644
--- a/lib/kernel/src/net_adm.erl
+++ b/lib/kernel/src/net_adm.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2011. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2013. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -133,7 +133,7 @@ dns_hostname(Hostname) ->
-spec ping_list([atom()]) -> [atom()].
ping_list(Nodelist) ->
- net_kernel:monitor_nodes(true),
+ ok = net_kernel:monitor_nodes(true),
Sofar = ping_first(Nodelist, nodes()),
collect_new(Sofar, Nodelist).
@@ -159,7 +159,7 @@ collect_new(Sofar, Nodelist) ->
collect_new([Node | Sofar], Nodelist)
end
after 3000 ->
- net_kernel:monitor_nodes(false),
+ ok = net_kernel:monitor_nodes(false),
Sofar
end.
diff --git a/lib/kernel/src/net_kernel.erl b/lib/kernel/src/net_kernel.erl
index dd0071b914..04a0d94ebf 100644
--- a/lib/kernel/src/net_kernel.erl
+++ b/lib/kernel/src/net_kernel.erl
@@ -306,21 +306,21 @@ do_connect(Node, Type, WaitForBarred) -> %% Type = normal | hidden
end.
passive_connect_monitor(Parent, Node) ->
- monitor_nodes(true,[{node_type,all}]),
+ ok = monitor_nodes(true,[{node_type,all}]),
case lists:member(Node,nodes([connected])) of
true ->
- monitor_nodes(false,[{node_type,all}]),
+ ok = monitor_nodes(false,[{node_type,all}]),
Parent ! {self(),true};
_ ->
Ref = make_ref(),
Tref = erlang:send_after(connecttime(),self(),Ref),
receive
Ref ->
- monitor_nodes(false,[{node_type,all}]),
+ ok = monitor_nodes(false,[{node_type,all}]),
Parent ! {self(), false};
{nodeup,Node,_} ->
- monitor_nodes(false,[{node_type,all}]),
- erlang:cancel_timer(Tref),
+ ok = monitor_nodes(false,[{node_type,all}]),
+ _ = erlang:cancel_timer(Tref),
Parent ! {self(),true}
end
end.
@@ -734,7 +734,7 @@ handle_info(transition_period_end,
how = How}} = State) ->
?tckr_dbg(transition_period_ended),
case How of
- shorter -> Tckr ! {new_ticktime, T};
+ shorter -> Tckr ! {new_ticktime, T}, done;
_ -> done
end,
{noreply,State#state{tick = #tick{ticker = Tckr, time = T}}};
@@ -1573,9 +1573,10 @@ async_gen_server_reply(From, Msg) ->
ok ->
ok;
nosuspend ->
- spawn(fun() -> catch erlang:send(Pid, M, [noconnect]) end);
+ _ = spawn(fun() -> catch erlang:send(Pid, M, [noconnect]) end),
+ ok;
noconnect ->
ok; % The gen module takes care of this case.
- {'EXIT', _}=EXIT ->
- EXIT
+ {'EXIT', _} ->
+ ok
end.
diff --git a/lib/kernel/src/os.erl b/lib/kernel/src/os.erl
index 9415593485..187fd0001b 100644
--- a/lib/kernel/src/os.erl
+++ b/lib/kernel/src/os.erl
@@ -67,7 +67,7 @@ unsetenv(_) ->
%%% End of BIFs
-spec type() -> {Osfamily, Osname} when
- Osfamily :: unix | win32,
+ Osfamily :: unix | win32 | ose,
Osname :: atom().
type() ->
@@ -189,20 +189,25 @@ extensions() ->
Command :: atom() | io_lib:chars().
cmd(Cmd) ->
validate(Cmd),
- case type() of
- {unix, _} ->
- unix_cmd(Cmd);
- {win32, Wtype} ->
- Command0 = case {os:getenv("COMSPEC"),Wtype} of
- {false,windows} -> lists:concat(["command.com /c", Cmd]);
- {false,_} -> lists:concat(["cmd /c", Cmd]);
- {Cspec,_} -> lists:concat([Cspec," /c",Cmd])
- end,
- %% open_port/2 awaits string() in Command, but io_lib:chars() can be
- %% deep lists according to io_lib module description.
- Command = lists:flatten(Command0),
- Port = open_port({spawn, Command}, [stream, in, eof, hide]),
- get_data(Port, [])
+ Bytes = case type() of
+ {unix, _} ->
+ unix_cmd(Cmd);
+ {win32, Wtype} ->
+ Command0 = case {os:getenv("COMSPEC"),Wtype} of
+ {false,windows} -> lists:concat(["command.com /c", Cmd]);
+ {false,_} -> lists:concat(["cmd /c", Cmd]);
+ {Cspec,_} -> lists:concat([Cspec," /c",Cmd])
+ end,
+ %% open_port/2 awaits string() in Command, but io_lib:chars() can be
+ %% deep lists according to io_lib module description.
+ Command = lists:flatten(Command0),
+ Port = open_port({spawn, Command}, [stream, in, eof, hide]),
+ get_data(Port, [])
+ end,
+ String = unicode:characters_to_list(list_to_binary(Bytes)),
+ if %% Convert to unicode list if possible otherwise return bytes
+ is_list(String) -> String;
+ true -> Bytes
end.
unix_cmd(Cmd) ->
@@ -225,7 +230,9 @@ unix_cmd(Cmd) ->
%% and the commands are read from standard input. We set the
%% $1 parameter for easy identification of the resident shell.
%%
--define(SHELL, "/bin/sh -s unix:cmd 2>&1").
+-define(ROOT, "/").
+-define(ROOT_ANDROID, "/system").
+-define(SHELL, "bin/sh -s unix:cmd 2>&1").
-define(PORT_CREATOR_NAME, os_cmd_port_creator).
%%
@@ -275,7 +282,12 @@ start_port_srv(Request) ->
end.
start_port_srv_handle({Ref,Client}) ->
- Reply = try open_port({spawn, ?SHELL},[stream]) of
+ Path = case lists:reverse(erlang:system_info(system_architecture)) of
+ % androideabi
+ "ibaediordna" ++ _ -> filename:join([?ROOT_ANDROID, ?SHELL]);
+ _ -> filename:join([?ROOT, ?SHELL])
+ end,
+ Reply = try open_port({spawn, Path},[stream]) of
Port when is_port(Port) ->
(catch port_connect(Port, Client)),
unlink(Port),
@@ -284,8 +296,8 @@ start_port_srv_handle({Ref,Client}) ->
error:Reason ->
{Reason,erlang:get_stacktrace()}
end,
- Client ! {Ref,Reply}.
-
+ Client ! {Ref,Reply},
+ ok.
start_port_srv_loop() ->
receive
@@ -293,7 +305,7 @@ start_port_srv_loop() ->
is_pid(Client) ->
start_port_srv_handle(Request);
_Junk ->
- ignore
+ ok
end,
start_port_srv_loop().
@@ -343,7 +355,7 @@ mk_cmd(Cmd) when is_atom(Cmd) -> % backward comp.
mk_cmd(Cmd) ->
%% We insert a new line after the command, in case the command
%% contains a comment character.
- io_lib:format("(~ts\n) </dev/null; echo \"\^D\"\n", [Cmd]).
+ [$(, unicode:characters_to_binary(Cmd), "\n) </dev/null; echo \"\^D\"\n"].
validate(Atom) when is_atom(Atom) ->
@@ -351,7 +363,7 @@ validate(Atom) when is_atom(Atom) ->
validate(List) when is_list(List) ->
validate1(List).
-validate1([C|Rest]) when is_integer(C), 0 =< C, C < 256 ->
+validate1([C|Rest]) when is_integer(C) ->
validate1(Rest);
validate1([List|Rest]) when is_list(List) ->
validate1(List),
diff --git a/lib/kernel/src/pg2.erl b/lib/kernel/src/pg2.erl
index 1ff10eb303..b562d4ffd2 100644
--- a/lib/kernel/src/pg2.erl
+++ b/lib/kernel/src/pg2.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2012. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2013. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -45,7 +45,7 @@ start() ->
-spec create(Name :: name()) -> 'ok'.
create(Name) ->
- ensure_started(),
+ _ = ensure_started(),
case ets:member(pg2_table, {group, Name}) of
false ->
global:trans({{?MODULE, Name}, self()},
@@ -60,7 +60,7 @@ create(Name) ->
-spec delete(Name :: name()) -> 'ok'.
delete(Name) ->
- ensure_started(),
+ _ = ensure_started(),
global:trans({{?MODULE, Name}, self()},
fun() ->
gen_server:multi_call(?MODULE, {delete, Name})
@@ -71,7 +71,7 @@ delete(Name) ->
when Name :: name().
join(Name, Pid) when is_pid(Pid) ->
- ensure_started(),
+ _ = ensure_started(),
case ets:member(pg2_table, {group, Name}) of
false ->
{error, {no_such_group, Name}};
@@ -88,7 +88,7 @@ join(Name, Pid) when is_pid(Pid) ->
when Name :: name().
leave(Name, Pid) when is_pid(Pid) ->
- ensure_started(),
+ _ = ensure_started(),
case ets:member(pg2_table, {group, Name}) of
false ->
{error, {no_such_group, Name}};
@@ -105,7 +105,7 @@ leave(Name, Pid) when is_pid(Pid) ->
when Name :: name().
get_members(Name) ->
- ensure_started(),
+ _ = ensure_started(),
case ets:member(pg2_table, {group, Name}) of
true ->
group_members(Name);
@@ -117,7 +117,7 @@ get_members(Name) ->
when Name :: name().
get_local_members(Name) ->
- ensure_started(),
+ _ = ensure_started(),
case ets:member(pg2_table, {group, Name}) of
true ->
local_group_members(Name);
@@ -128,7 +128,7 @@ get_local_members(Name) ->
-spec which_groups() -> [Name :: name()].
which_groups() ->
- ensure_started(),
+ _ = ensure_started(),
all_groups().
-spec get_closest_pid(Name) -> pid() | {'error', Reason} when
@@ -165,7 +165,7 @@ get_closest_pid(Name) ->
init([]) ->
Ns = nodes(),
- net_kernel:monitor_nodes(true),
+ ok = net_kernel:monitor_nodes(true),
lists:foreach(fun(N) ->
{?MODULE, N} ! {new_pg2, node()},
self() ! {nodeup, N}
@@ -283,7 +283,7 @@ member_died(Ref) ->
join_group(Name, Pid) ->
Ref_Pid = {ref, Pid},
- try _ = ets:update_counter(pg2_table, Ref_Pid, {4, +1})
+ try _ = ets:update_counter(pg2_table, Ref_Pid, {4, +1}), true
catch _:_ ->
{RPid, Ref} = do_monitor(Pid),
true = ets:insert(pg2_table, {Ref_Pid, RPid, Ref, 1}),
diff --git a/lib/kernel/src/rpc.erl b/lib/kernel/src/rpc.erl
index 0e7e7d2031..2300b7e901 100644
--- a/lib/kernel/src/rpc.erl
+++ b/lib/kernel/src/rpc.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2013. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2014. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -66,7 +66,7 @@
%%------------------------------------------------------------------------
--type state() :: gb_tree().
+-type state() :: gb_trees:tree(pid(), {pid(), reference()}).
%%------------------------------------------------------------------------
@@ -158,20 +158,20 @@ handle_info({Caller, {reply, Reply}}, S) ->
{noreply, S}
end;
handle_info({From, {sbcast, Name, Msg}}, S) ->
- case catch Name ! Msg of %% use catch to get the printout
- {'EXIT', _} ->
- From ! {?NAME, node(), {nonexisting_name, Name}};
- _ ->
- From ! {?NAME, node(), node()}
- end,
+ _ = case catch Name ! Msg of %% use catch to get the printout
+ {'EXIT', _} ->
+ From ! {?NAME, node(), {nonexisting_name, Name}};
+ _ ->
+ From ! {?NAME, node(), node()}
+ end,
{noreply, S};
handle_info({From, {send, Name, Msg}}, S) ->
- case catch Name ! {From, Msg} of %% use catch to get the printout
- {'EXIT', _} ->
- From ! {?NAME, node(), {nonexisting_name, Name}};
- _ ->
- ok %% It's up to Name to respond !!!!!
- end,
+ _ = case catch Name ! {From, Msg} of %% use catch to get the printout
+ {'EXIT', _} ->
+ From ! {?NAME, node(), {nonexisting_name, Name}};
+ _ ->
+ ok %% It's up to Name to respond !!!!!
+ end,
{noreply, S};
handle_info({From, {call,Mod,Fun,Args,Gleader}}, S) ->
%% Special for hidden C node's, uugh ...
@@ -423,7 +423,7 @@ abcast(Name, Mess) ->
abcast([Node|Tail], Name, Mess) ->
Dest = {Name,Node},
case catch erlang:send(Dest, Mess, [noconnect]) of
- noconnect -> spawn(erlang, send, [Dest,Mess]);
+ noconnect -> spawn(erlang, send, [Dest,Mess]), ok;
_ -> ok
end,
abcast(Tail, Name, Mess);
diff --git a/lib/kernel/src/seq_trace.erl b/lib/kernel/src/seq_trace.erl
index a90b7b07c8..38a61f4644 100644
--- a/lib/kernel/src/seq_trace.erl
+++ b/lib/kernel/src/seq_trace.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1998-2011. All Rights Reserved.
+%% Copyright Ericsson AB 1998-2013. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -125,7 +125,7 @@ get_system_tracer() ->
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
set_token2([{Type,Val}|T]) ->
- erlang:seq_trace(Type, Val),
+ _ = erlang:seq_trace(Type, Val),
set_token2(T);
set_token2([]) ->
ok.
diff --git a/lib/kernel/src/standard_error.erl b/lib/kernel/src/standard_error.erl
index e41dcd01fc..10cf77e0d4 100644
--- a/lib/kernel/src/standard_error.erl
+++ b/lib/kernel/src/standard_error.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2009-2010. All Rights Reserved.
+%% Copyright Ericsson AB 2009-2013. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -69,7 +69,7 @@ run(P) ->
server_loop(Port) ->
receive
{io_request,From,ReplyAs,Request} when is_pid(From) ->
- do_io_request(Request, From, ReplyAs, Port),
+ _ = do_io_request(Request, From, ReplyAs, Port),
server_loop(Port);
{'EXIT',Port,badsig} -> % Ignore badsig errors
server_loop(Port);
@@ -175,7 +175,7 @@ io_reply(From, ReplyAs, Reply) ->
%% put_chars
put_chars(Chars, Port) when is_binary(Chars) ->
- put_port(Chars, Port),
+ _ = put_port(Chars, Port),
{ok,ok};
put_chars(Chars, Port) ->
case catch list_to_binary(Chars) of
diff --git a/lib/kernel/src/user.erl b/lib/kernel/src/user.erl
index c897d46bc2..40376ef752 100644
--- a/lib/kernel/src/user.erl
+++ b/lib/kernel/src/user.erl
@@ -103,11 +103,11 @@ catch_loop(Port, Shell, Q) ->
{unknown_exit,{Shell,Reason},_} -> % shell has exited
case Reason of
normal ->
- put_chars("*** ", Port, []);
+ put_port(<<"*** ">>, Port);
_ ->
- put_chars("*** ERROR: ", Port, [])
+ put_port(<<"*** ERROR: ">>, Port)
end,
- put_chars("Shell process terminated! ***\n", Port, []),
+ put_port(<<"Shell process terminated! ***\n">>, Port),
catch_loop(Port, start_new_shell());
{unknown_exit,_,Q1} ->
catch_loop(Port, Shell, Q1);
@@ -181,7 +181,7 @@ get_fd_geometry(Port) ->
do_io_request(Req, From, ReplyAs, Port, Q0) ->
case io_request(Req, Port, Q0) of
{_Status,Reply,Q1} ->
- io_reply(From, ReplyAs, Reply),
+ _ = io_reply(From, ReplyAs, Reply),
Q1;
{exit,What} ->
ok = send_port(Port, close),
diff --git a/lib/kernel/src/user_drv.erl b/lib/kernel/src/user_drv.erl
index 7b4ffb09ca..a91c23539d 100644
--- a/lib/kernel/src/user_drv.erl
+++ b/lib/kernel/src/user_drv.erl
@@ -488,21 +488,19 @@ set_unicode_state(Iport, Bool) ->
%% io_request(Request, InPort, OutPort)
%% io_requests(Requests, InPort, OutPort)
-
-io_request({put_chars, unicode,Cs}, _Iport, Oport) ->
- Oport ! {self(),{command,[?OP_PUTC|unicode:characters_to_binary(Cs,utf8)]}};
-io_request({move_rel,N}, _Iport, Oport) ->
- Oport ! {self(),{command,[?OP_MOVE|put_int16(N, [])]}};
-io_request({insert_chars,unicode,Cs}, _Iport, Oport) ->
- Oport ! {self(),{command,[?OP_INSC|unicode:characters_to_binary(Cs,utf8)]}};
-io_request({delete_chars,N}, _Iport, Oport) ->
- Oport ! {self(),{command,[?OP_DELC|put_int16(N, [])]}};
-io_request(beep, _Iport, Oport) ->
- Oport ! {self(),{command,[?OP_BEEP]}};
-io_request({requests,Rs}, Iport, Oport) ->
- io_requests(Rs, Iport, Oport);
-io_request(_R, _Iport, _Oport) ->
- ok.
+%% Note: InPort is unused.
+
+io_request(Request, Iport, Oport) ->
+ try io_command(Request) of
+ Command ->
+ Oport ! {self(),Command},
+ ok
+ catch
+ {requests,Rs} ->
+ io_requests(Rs, Iport, Oport);
+ _ ->
+ ok
+ end.
io_requests([R|Rs], Iport, Oport) ->
io_request(R, Iport, Oport),
@@ -513,6 +511,19 @@ io_requests([], _Iport, _Oport) ->
put_int16(N, Tail) ->
[(N bsr 8)band 255,N band 255|Tail].
+io_command({put_chars, unicode,Cs}) ->
+ {command,[?OP_PUTC|unicode:characters_to_binary(Cs,utf8)]};
+io_command({move_rel,N}) ->
+ {command,[?OP_MOVE|put_int16(N, [])]};
+io_command({insert_chars,unicode,Cs}) ->
+ {command,[?OP_INSC|unicode:characters_to_binary(Cs,utf8)]};
+io_command({delete_chars,N}) ->
+ {command,[?OP_DELC|put_int16(N, [])]};
+io_command(beep) ->
+ {command,[?OP_BEEP]};
+io_command(Else) ->
+ throw(Else).
+
%% gr_new()
%% gr_get_num(Group, Index)
%% gr_get_info(Group, Pid)
diff --git a/lib/kernel/src/wrap_log_reader.erl b/lib/kernel/src/wrap_log_reader.erl
index 689269fc28..7e1f4aa07f 100644
--- a/lib/kernel/src/wrap_log_reader.erl
+++ b/lib/kernel/src/wrap_log_reader.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1998-2012. All Rights Reserved.
+%% Copyright Ericsson AB 1998-2013. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -149,7 +149,7 @@ open_int(File, FileNo, FirstFileNo) ->
{ok, Head} ->
case disk_log_1:is_head(Head) of
no ->
- file:close(Fd),
+ _ = file:close(Fd),
{error, {not_a_log_file, FName}};
_ -> % yes or yes_not_closed
case last_mod_time(FName) of
@@ -161,12 +161,12 @@ open_int(File, FileNo, FirstFileNo) ->
first_no = FirstFileNo},
{ok, WR};
{error, E} ->
- file:close(Fd),
+ _ = file:close(Fd),
{error, {file_error, FName, E}}
end
end;
_Other ->
- file:close(Fd),
+ _ = file:close(Fd),
{error, {not_a_log_file, FName}}
end;
_Other ->
@@ -280,7 +280,7 @@ read_next_file(WR, N, NewFileNo, Bad) ->
true ->
case open_int(File, NewFileNo, FirstFileNo) of
{ok, NWR} ->
- close(WR), %% Now we can safely close the old file.
+ _ = close(WR), %% Now we can safely close the old file.
chunk(NWR, N, Bad);
Error ->
Error
diff --git a/lib/kernel/test/application_SUITE.erl b/lib/kernel/test/application_SUITE.erl
index 9ec8a15861..036e238c85 100644
--- a/lib/kernel/test/application_SUITE.erl
+++ b/lib/kernel/test/application_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2013. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2014. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -33,10 +33,10 @@
permit_false_start_local/1, permit_false_start_dist/1, script_start/1,
nodedown_start/1, init2973/0, loop2973/0, loop5606/1]).
--export([config_change/1,
+-export([config_change/1, persistent_env/1,
distr_changed_tc1/1, distr_changed_tc2/1,
ensure_started/1, ensure_all_started/1,
- shutdown_func/1, do_shutdown/1, shutdown_timeout/1]).
+ shutdown_func/1, do_shutdown/1, shutdown_timeout/1, shutdown_deadlock/1]).
-define(TESTCASE, testcase_name).
-define(testcase, ?config(?TESTCASE, Config)).
@@ -53,7 +53,9 @@ all() ->
load_use_cache, ensure_started, {group, reported_bugs}, start_phases,
script_start, nodedown_start, permit_false_start_local,
permit_false_start_dist, get_key, get_env, ensure_all_started,
- {group, distr_changed}, config_change, shutdown_func, shutdown_timeout].
+ {group, distr_changed}, config_change, shutdown_func, shutdown_timeout,
+ shutdown_deadlock,
+ persistent_env].
groups() ->
[{reported_bugs, [],
@@ -960,7 +962,7 @@ nodedown_start(Conf) when is_list(Conf) ->
ensure_started(suite) -> [];
ensure_started(doc) -> ["Test application:ensure_started/1."];
-ensure_started(Conf) ->
+ensure_started(_Conf) ->
{ok, Fd} = file:open("app1.app", [write]),
w_app1(Fd),
@@ -980,7 +982,7 @@ ensure_started(Conf) ->
ensure_all_started(suite) -> [];
ensure_all_started(doc) -> ["Test application:ensure_all_started/1-2."];
-ensure_all_started(Conf) ->
+ensure_all_started(_Conf) ->
{ok, Fd1} = file:open("app1.app", [write]),
w_app1(Fd1),
@@ -1947,14 +1949,22 @@ config_change(Conf) when is_list(Conf) ->
%% Find out application data from boot script
Boot = filename:join([code:root_dir(), "bin", "start.boot"]),
{ok, Bin} = file:read_file(Boot),
- Appls = get_appls(binary_to_term(Bin)),
+ Appls0 = get_appls(binary_to_term(Bin)),
+
+ %% And add app1 in order to test OTP-11864 - included config files
+ %% not read for new (not already loaded) applications
+ Appls = [app1() | Appls0],
%% Simulate contents of "sys.config"
Config = [{stdlib, [{par1,sys},{par2,sys}]},
"t1",
"t2.config",
filename:join([DataDir, "subdir", "t3"]),
- {stdlib, [{par6,sys}]}],
+ {stdlib, [{par6,sys}]},
+ "t4.config"],
+
+ %% Check that app1 is not loaded
+ false = lists:keymember(app1,1,application:loaded_applications()),
%% Order application_controller to update configuration
ok = application_controller:change_application_data(Appls,
@@ -1969,6 +1979,13 @@ config_change(Conf) when is_list(Conf) ->
{value, {par5,t3}} = lists:keysearch(par5, 1, Env),
{value, {par6,sys}} = lists:keysearch(par6, 1, Env),
+ %% Check that app1 parameters are correctly set after loading
+ [] = application:get_all_env(app1),
+ application:load(app1()),
+ App1Env = application:get_all_env(app1),
+ {value, {par1,t4}} = lists:keysearch(par1, 1, App1Env),
+ application:unload(app1),
+
ok = file:set_cwd(CWD).
%% This function is stolen from SASL module release_handler, OTP R10B
@@ -1987,6 +2004,51 @@ get_appls([_ | T], Res) ->
get_appls([], Res) ->
Res.
+
+persistent_env(suite) ->
+ [];
+persistent_env(doc) ->
+ ["Test set_env/4 and unset_env/3 with persistent true"];
+persistent_env(Conf) when is_list(Conf) ->
+ ok = application:set_env(appinc, own2, persist, [{persistent, true}]),
+ ok = application:set_env(appinc, key1, persist, [{persistent, true}]),
+
+ %% own_env1 and own2 are set in appinc
+ ok = application:load(appinc()),
+ {ok, value1} = application:get_env(appinc, own_env1),
+ {ok, persist} = application:get_env(appinc, own2),
+ {ok, persist} = application:get_env(appinc, key1),
+
+ %% Changing the environment after loaded reflects and should persist
+ ok = application:set_env(appinc, own_env1, persist, [{persistent, true}]),
+ {ok, persist} = application:get_env(appinc, own_env1),
+ {ok, persist} = application:get_env(appinc, own2),
+ {ok, persist} = application:get_env(appinc, key1),
+
+ %% On reload, own_env1, own2 and key1 should all persist
+ ok = application:unload(appinc),
+ ok = application:load(appinc()),
+ {ok, persist} = application:get_env(appinc, own_env1),
+ {ok, persist} = application:get_env(appinc, own2),
+ {ok, persist} = application:get_env(appinc, key1),
+
+ %% Unset own_env1 and key1, own2 should still persist
+ ok = application:unset_env(appinc, own_env1, [{persistent, true}]),
+ ok = application:unset_env(appinc, key1, [{persistent, true}]),
+ undefined = application:get_env(appinc, own_env1),
+ {ok, persist} = application:get_env(appinc, own2),
+ undefined = application:get_env(appinc, key1),
+
+ %% own_env1 should be back to its application value on reload
+ ok = application:unload(appinc),
+ ok = application:load(appinc()),
+ {ok, value1} = application:get_env(appinc, own_env1),
+ {ok, persist} = application:get_env(appinc, own2),
+ undefined = application:get_env(appinc, key1),
+
+ %% Clean up
+ ok = application:unload(appinc).
+
%%%-----------------------------------------------------------------
%%% Tests the 'shutdown_func' kernel config parameter
%%%-----------------------------------------------------------------
@@ -2051,7 +2113,32 @@ shutdown_timeout(Config) when is_list(Config) ->
end,
ok.
+%%%-----------------------------------------------------------------
+%%% Provokes a (previous) application shutdown deadlock
+%%%-----------------------------------------------------------------
+shutdown_deadlock(Config) when is_list(Config) ->
+ DataDir = ?config(data_dir,Config),
+ code:add_path(filename:join([DataDir,deadlock])),
+ %% ok = rpc:call(Cp1, application, start, [sasl]),
+ ok = application:start(deadlock),
+ Tester = self(),
+ application:set_env(deadlock, fail_stop, Tester),
+ spawn(fun() -> Tester ! {stop, application:stop(deadlock)} end),
+ receive
+ {deadlock, Server} ->
+ spawn(fun() ->
+ Master = application_controller:get_master(deadlock),
+ Child = application_master:get_child(Master),
+ Tester ! {child, Child}
+ end),
+ timer:sleep(100),
+ erlang:display({self(), "Sending Continue", Server}),
+ Server ! continue
+ end,
+ [_|_] = application:which_applications(),
+ application:unload(deadlock), % clean up!
+ ok.
%%-----------------------------------------------------------------
diff --git a/lib/kernel/test/application_SUITE_data/deadlock/deadlock.app b/lib/kernel/test/application_SUITE_data/deadlock/deadlock.app
index 0c1001bed6..233c7a3f76 100644
--- a/lib/kernel/test/application_SUITE_data/deadlock/deadlock.app
+++ b/lib/kernel/test/application_SUITE_data/deadlock/deadlock.app
@@ -4,5 +4,5 @@
{applications, [kernel, stdlib, sasl]},
{modules, [deadlock]},
{mod, {deadlock, []}},
- {env, [{fail_start, false}]}
+ {env, [{fail_start, false}, {fail_stop, false}]}
]}.
diff --git a/lib/kernel/test/application_SUITE_data/deadlock/deadlock.erl b/lib/kernel/test/application_SUITE_data/deadlock/deadlock.erl
index 5f68bf9078..3ef6105371 100644
--- a/lib/kernel/test/application_SUITE_data/deadlock/deadlock.erl
+++ b/lib/kernel/test/application_SUITE_data/deadlock/deadlock.erl
@@ -21,7 +21,7 @@ init([sup]) ->
{ok, {{one_for_one, 5, 10}, [
{
sasl_syslog_dm, {?MODULE, start_link, []},
- permanent, brutal_kill, worker,
+ permanent, 25000, worker,
[deadlock]
}
]}};
@@ -32,6 +32,8 @@ init([sup]) ->
init([child]) ->
case application:get_env(deadlock, fail_start) of
{ok, false} ->
+ process_flag(trap_exit, true),
+ io:format("~p: Traps exit~n",[?MODULE]),
%% we must not fail on the first init, otherwise supervisor
%% terminates immediately
{ok, []};
@@ -50,6 +52,14 @@ handle_info(_Msg, State) ->
{noreply, State}.
terminate(_Reason, _State) ->
+ case application:get_env(deadlock, fail_stop) of
+ {ok, false} -> ok;
+ {ok, Tester} ->
+ Tester ! {deadlock, self()},
+ io:format("~p: Waiting in terminate (~p)~n",[?MODULE,Tester]),
+ receive continue -> ok end
+ end,
+ io:format("~p: terminates~n", [?MODULE]),
ok.
code_change(_OldVsn, State, _Extra) ->
diff --git a/lib/kernel/test/application_SUITE_data/t4.config b/lib/kernel/test/application_SUITE_data/t4.config
new file mode 100644
index 0000000000..8b2bc52c01
--- /dev/null
+++ b/lib/kernel/test/application_SUITE_data/t4.config
@@ -0,0 +1 @@
+[{app1, [{par1,t4}]}]. \ No newline at end of file
diff --git a/lib/kernel/test/code_SUITE.erl b/lib/kernel/test/code_SUITE.erl
index cd9359f2aa..42b81d16b3 100644
--- a/lib/kernel/test/code_SUITE.erl
+++ b/lib/kernel/test/code_SUITE.erl
@@ -23,7 +23,8 @@
-export([all/0, suite/0,groups/0,init_per_group/2,end_per_group/2]).
-export([set_path/1, get_path/1, add_path/1, add_paths/1, del_path/1,
replace_path/1, load_file/1, load_abs/1, ensure_loaded/1,
- delete/1, purge/1, soft_purge/1, is_loaded/1, all_loaded/1,
+ delete/1, purge/1, purge_many_exits/1, soft_purge/1, is_loaded/1,
+ all_loaded/1,
load_binary/1, dir_req/1, object_code/1, set_path_file/1,
upgrade/1,
sticky_dir/1, pa_pz_option/1, add_del_path/1,
@@ -51,7 +52,7 @@ suite() -> [{ct_hooks,[ts_install_cth]}].
all() ->
[set_path, get_path, add_path, add_paths, del_path,
replace_path, load_file, load_abs, ensure_loaded,
- delete, purge, soft_purge, is_loaded, all_loaded,
+ delete, purge, purge_many_exits, soft_purge, is_loaded, all_loaded,
load_binary, dir_req, object_code, set_path_file,
upgrade,
pa_pz_option, add_del_path, dir_disappeared,
@@ -369,6 +370,42 @@ purge(Config) when is_list(Config) ->
process_flag(trap_exit, OldFlag),
ok.
+purge_many_exits(Config) when is_list(Config) ->
+ OldFlag = process_flag(trap_exit, true),
+ code:purge(code_b_test),
+ {'EXIT',_} = (catch code:purge({})),
+ false = code:purge(code_b_test),
+ TPids = lists:map(fun (_) ->
+ {code_b_test:do_spawn(),
+ spawn_link(fun () ->
+ receive
+ after infinity -> ok
+ end
+ end)}
+ end,
+ lists:seq(1, 1000)),
+ % Give them time to start...
+ receive after 1000 -> ok end,
+ true = code:delete(code_b_test),
+ lists:foreach(fun ({Pid1, Pid2}) ->
+ true = erlang:is_process_alive(Pid1),
+ false = code_b_test:check_exit(Pid1),
+ true = erlang:is_process_alive(Pid2)
+ end, TPids),
+ true = code:purge(code_b_test),
+ lists:foreach(fun ({Pid1, Pid2}) ->
+ false = erlang:is_process_alive(Pid1),
+ true = code_b_test:check_exit(Pid1),
+ true = erlang:is_process_alive(Pid2),
+ exit(Pid2, kill)
+ end, TPids),
+ lists:foreach(fun ({_Pid1, Pid2}) ->
+ receive {'EXIT', Pid2, _} -> ok end
+ end, TPids),
+ process_flag(trap_exit, OldFlag),
+ ok.
+
+
soft_purge(suite) -> [];
soft_purge(doc) -> [];
soft_purge(Config) when is_list(Config) ->
@@ -616,7 +653,7 @@ clash(Config) when is_list(Config) ->
DDir = ?config(data_dir,Config)++"clash/",
P = code:get_path(),
[TestServerPath|_] = [Path || Path <- code:get_path(),
- re:run(Path,"test_server/?$",[]) /= nomatch],
+ re:run(Path,"test_server/?$",[unicode]) /= nomatch],
%% test non-clashing entries
@@ -1490,7 +1527,10 @@ create_big_script(Config,Local) ->
Leftover <- UnloadFix,
lists:keymember(Leftover,1,InitialApplications) ],
%% Now we should have only "real" applications...
- [application:load(list_to_atom(Y)) || {match,[Y]} <- [ re:run(X,code:lib_dir()++"/"++"([^/-]*).*/ebin",[{capture,[1],list}]) || X <- code:get_path()],filter_app(Y,Local)],
+ [application:load(list_to_atom(Y))
+ || {match,[Y]} <- [re:run(X,code:lib_dir()++"/"++"([^/-]*).*/ebin",
+ [{capture,[1],list},unicode]) ||
+ X <- code:get_path()],filter_app(Y,Local)],
Apps = [ {N,V} || {N,_,V} <- application:loaded_applications()],
{ok,Fd} = file:open(Name ++ ".rel", [write]),
io:format(Fd,
diff --git a/lib/kernel/test/file_SUITE.erl b/lib/kernel/test/file_SUITE.erl
index e4c8f0ffaf..f6d6cd94ab 100644
--- a/lib/kernel/test/file_SUITE.erl
+++ b/lib/kernel/test/file_SUITE.erl
@@ -161,7 +161,13 @@ init_per_suite(Config) when is_list(Config) ->
ok ->
[{sasl,started}]
end,
- ok = application:start(os_mon),
+ ok = case os:type() of
+ {ose,_} ->
+ ok;
+ _ ->
+ application:start(os_mon)
+ end,
+
case os:type() of
{win32, _} ->
Priv = ?config(priv_dir, Config),
@@ -185,7 +191,13 @@ end_per_suite(Config) when is_list(Config) ->
_ ->
ok
end,
- application:stop(os_mon),
+
+ case os:type() of
+ {ose,_} ->
+ ok;
+ _ ->
+ application:stop(os_mon)
+ end,
case proplists:get_value(sasl, Config) of
started ->
application:stop(sasl);
@@ -416,7 +428,13 @@ make_del_dir(Config) when is_list(Config) ->
% because there are processes having that directory as current.
?line ok = ?FILE_MODULE:make_dir(NewDir),
?line {ok,CurrentDir} = file:get_cwd(),
- ?line ok = ?FILE_MODULE:set_cwd(NewDir),
+ case {os:type(), length(NewDir) >= 260 } of
+ {{win32,_}, true} ->
+ io:format("Skip set_cwd for windows path longer than 260 (MAX_PATH)\n", []),
+ io:format("\nNewDir = ~p\n", [NewDir]);
+ _ ->
+ ?line ok = ?FILE_MODULE:set_cwd(NewDir)
+ end,
try
%% Check that we get an error when trying to create...
%% a deep directory
@@ -473,32 +491,39 @@ cur_dir_0(Config) when is_list(Config) ->
atom_to_list(?MODULE)
++"_curdir"),
?line ok = ?FILE_MODULE:make_dir(NewDir),
- ?line io:format("cd to ~s",[NewDir]),
- ?line ok = ?FILE_MODULE:set_cwd(NewDir),
-
- %% Create a file in the new current directory, and check that it
- %% really is created there
- ?line UncommonName = "uncommon.fil",
- ?line {ok,Fd} = ?FILE_MODULE:open(UncommonName,read_write),
- ?line ok = ?FILE_MODULE:close(Fd),
- ?line {ok,NewDirFiles} = ?FILE_MODULE:list_dir("."),
- ?line true = lists:member(UncommonName,NewDirFiles),
-
- %% Delete the directory and return to the old current directory
- %% and check that the created file isn't there (too!)
- ?line expect({error, einval}, {error, eacces},
- ?FILE_MODULE:del_dir(NewDir)),
- ?line ?FILE_MODULE:delete(UncommonName),
- ?line {ok,[]} = ?FILE_MODULE:list_dir("."),
- ?line ok = ?FILE_MODULE:set_cwd(Dir1),
- ?line io:format("cd back to ~s",[Dir1]),
- ?line ok = ?FILE_MODULE:del_dir(NewDir),
- ?line {error, enoent} = ?FILE_MODULE:set_cwd(NewDir),
- ?line ok = ?FILE_MODULE:set_cwd(Dir1),
- ?line io:format("cd back to ~s",[Dir1]),
- ?line {ok,OldDirFiles} = ?FILE_MODULE:list_dir("."),
- ?line false = lists:member(UncommonName,OldDirFiles),
-
+ case {os:type(), length(NewDir) >= 260} of
+ {{win32,_}, true} ->
+ io:format("Skip set_cwd for windows path longer than 260 (MAX_PATH):\n"),
+ io:format("\nNewDir = ~p\n", [NewDir]);
+ _ ->
+ io:format("cd to ~s",[NewDir]),
+ ok = ?FILE_MODULE:set_cwd(NewDir),
+
+ %% Create a file in the new current directory, and check that it
+ %% really is created there
+ UncommonName = "uncommon.fil",
+ {ok,Fd} = ?FILE_MODULE:open(UncommonName,read_write),
+ ok = ?FILE_MODULE:close(Fd),
+ {ok,NewDirFiles} = ?FILE_MODULE:list_dir("."),
+ true = lists:member(UncommonName,NewDirFiles),
+
+ %% Delete the directory and return to the old current directory
+ %% and check that the created file isn't there (too!)
+ expect({error, einval}, {error, eacces},
+ ?FILE_MODULE:del_dir(NewDir)),
+ ?FILE_MODULE:delete(UncommonName),
+ {ok,[]} = ?FILE_MODULE:list_dir("."),
+ ok = ?FILE_MODULE:set_cwd(Dir1),
+ io:format("cd back to ~s",[Dir1]),
+
+ ok = ?FILE_MODULE:del_dir(NewDir),
+ {error, enoent} = ?FILE_MODULE:set_cwd(NewDir),
+ ok = ?FILE_MODULE:set_cwd(Dir1),
+ io:format("cd back to ~s",[Dir1]),
+ {ok,OldDirFiles} = ?FILE_MODULE:list_dir("."),
+ false = lists:member(UncommonName,OldDirFiles)
+ end,
+
%% Try doing some bad things
?line {error, badarg} = ?FILE_MODULE:set_cwd({foo,bar}),
?line {error, enoent} = ?FILE_MODULE:set_cwd(""),
@@ -525,11 +550,11 @@ cur_dir_1(Config) when is_list(Config) ->
?line Dog = test_server:timetrap(test_server:seconds(5)),
?line case os:type() of
- {unix, _} ->
- ?line {error, enotsup} = ?FILE_MODULE:get_cwd("d:");
- {win32, _} ->
- win_cur_dir_1(Config)
- end,
+ {win32, _} ->
+ win_cur_dir_1(Config);
+ _ ->
+ ?line {error, enotsup} = ?FILE_MODULE:get_cwd("d:")
+ end,
?line [] = flush(),
?line test_server:timetrap_cancel(Dog),
ok.
@@ -712,7 +737,10 @@ open1(Config) when is_list(Config) ->
?line io:format(Fd1,Str,[]),
?line {ok,0} = ?FILE_MODULE:position(Fd1,bof),
?line Str = io:get_line(Fd1,''),
- ?line Str = io:get_line(Fd2,''),
+ ?line case io:get_line(Fd2,'') of
+ Str -> Str;
+ eof -> Str
+ end,
?line ok = ?FILE_MODULE:close(Fd2),
?line {ok,0} = ?FILE_MODULE:position(Fd1,bof),
?line ok = ?FILE_MODULE:truncate(Fd1),
@@ -805,6 +833,20 @@ new_modes(Config) when is_list(Config) ->
?line {ok, [$\[]} = ?FILE_MODULE:read(Fd6, 1),
?line ok = ?FILE_MODULE:close(Fd6),
+ %% write and sync
+ case ?FILE_MODULE:open(Name1, [write, sync]) of
+ {ok, Fd7} ->
+ ok = io:write(Fd7, Marker),
+ ok = io:put_chars(Fd7, ".\n"),
+ ok = ?FILE_MODULE:close(Fd7),
+ {ok, Fd8} = ?FILE_MODULE:open(Name1, [read]),
+ {ok, Marker} = io:read(Fd8, prompt),
+ ok = ?FILE_MODULE:close(Fd8);
+ {error, enotsup} ->
+ %% for platforms that don't support the sync option
+ ok
+ end,
+
?line [] = flush(),
?line test_server:timetrap_cancel(Dog),
ok.
@@ -1232,7 +1274,7 @@ file_info_basic_directory(Config) when is_list(Config) ->
?line test_directory("/", read_write),
?line test_directory("c:/", read_write),
?line test_directory("c:\\", read_write);
- {unix, _} ->
+ _ ->
?line test_directory("/", read)
end,
test_server:timetrap_cancel(Dog).
@@ -1953,7 +1995,6 @@ names(Config) when is_list(Config) ->
?line Name1 = filename:join(RootDir, FileName),
?line Name2 = [RootDir,"/","foo1",".","fil"],
?line Name3 = [RootDir,"/",foo,$1,[[[],[],'.']],"f",il],
- ?line Name4 = list_to_atom(Name1),
?line {ok,Fd0} = ?FILE_MODULE:open(Name1,write),
?line ok = ?FILE_MODULE:close(Fd0),
@@ -1966,23 +2007,33 @@ names(Config) when is_list(Config) ->
?line ok = ?FILE_MODULE:close(Fd2),
?line {ok,Fd3} = ?FILE_MODULE:open(Name3,read),
?line ok = ?FILE_MODULE:close(Fd3),
- ?line {ok,Fd4} = ?FILE_MODULE:open(Name4,read),
- ?line ok = ?FILE_MODULE:close(Fd4),
+ case length(Name1) > 255 of
+ true ->
+ io:format("Path too long for an atom:\n\n~p\n", [Name1]);
+ false ->
+ Name4 = list_to_atom(Name1),
+ {ok,Fd4} = ?FILE_MODULE:open(Name4,read),
+ ok = ?FILE_MODULE:close(Fd4)
+ end,
%% Try some path names
?line Path1 = RootDir,
?line Path2 = [RootDir],
?line Path3 = ['',[],[RootDir,[[]]]],
- ?line Path4 = list_to_atom(Path1),
?line {ok,Fd11,_} = ?FILE_MODULE:path_open([Path1],FileName,read),
?line ok = ?FILE_MODULE:close(Fd11),
?line {ok,Fd12,_} = ?FILE_MODULE:path_open([Path2],FileName,read),
?line ok = ?FILE_MODULE:close(Fd12),
?line {ok,Fd13,_} = ?FILE_MODULE:path_open([Path3],FileName,read),
?line ok = ?FILE_MODULE:close(Fd13),
- ?line {ok,Fd14,_} = ?FILE_MODULE:path_open([Path4],FileName,read),
- ?line ok = ?FILE_MODULE:close(Fd14),
-
+ case length(Path1) > 255 of
+ true->
+ io:format("Path too long for an atom:\n\n~p\n", [Path1]);
+ false ->
+ Path4 = list_to_atom(Path1),
+ {ok,Fd14,_} = ?FILE_MODULE:path_open([Path4],FileName,read),
+ ok = ?FILE_MODULE:close(Fd14)
+ end,
?line [] = flush(),
?line test_server:timetrap_cancel(Dog),
ok.
@@ -2016,15 +2067,15 @@ e_delete(Config) when is_list(Config) ->
%% No permission.
?line case os:type() of
- {unix, _} ->
+ {win32, _} ->
+ %% Remove a character device.
+ ?line {error, eacces} = ?FILE_MODULE:delete("nul");
+ _ ->
?line ?FILE_MODULE:write_file_info(
Base, #file_info {mode=0}),
?line {error, eacces} = ?FILE_MODULE:delete(Afile),
?line ?FILE_MODULE:write_file_info(
- Base, #file_info {mode=8#600});
- {win32, _} ->
- %% Remove a character device.
- ?line {error, eacces} = ?FILE_MODULE:delete("nul")
+ Base, #file_info {mode=8#600})
end,
?line [] = flush(),
@@ -2126,6 +2177,9 @@ e_rename(Config) when is_list(Config) ->
%% At least Windows NT can
%% successfully move a file to
%% another drive.
+ ok;
+ {ose, _} ->
+ %% disabled for now
ok
end,
[] = flush(),
@@ -2157,13 +2211,13 @@ e_make_dir(Config) when is_list(Config) ->
%% No permission (on Unix only).
case os:type() of
- {unix, _} ->
+ {win32, _} ->
+ ok;
+ _ ->
?FILE_MODULE:write_file_info(Base, #file_info {mode=0}),
{error, eacces} = ?FILE_MODULE:make_dir(filename:join(Base, "xxxx")),
?FILE_MODULE:write_file_info(
- Base, #file_info {mode=8#600});
- {win32, _} ->
- ok
+ Base, #file_info {mode=8#600})
end,
test_server:timetrap_cancel(Dog),
ok.
@@ -2206,14 +2260,14 @@ e_del_dir(Config) when is_list(Config) ->
%% No permission.
case os:type() of
- {unix, _} ->
+ {win32, _} ->
+ ok;
+ _ ->
ADirectory = filename:join(Base, "no_perm"),
ok = ?FILE_MODULE:make_dir(ADirectory),
?FILE_MODULE:write_file_info( Base, #file_info {mode=0}),
{error, eacces} = ?FILE_MODULE:del_dir(ADirectory),
- ?FILE_MODULE:write_file_info( Base, #file_info {mode=8#600});
- {win32, _} ->
- ok
+ ?FILE_MODULE:write_file_info( Base, #file_info {mode=8#600})
end,
[] = flush(),
test_server:timetrap_cancel(Dog),
@@ -2641,6 +2695,9 @@ symlinks(Config) when is_list(Config) ->
case ?FILE_MODULE:make_symlink(Name, Alias) of
{error, enotsup} ->
{skipped, "Links not supported on this platform"};
+ {error, eperm} ->
+ {win32,_} = os:type(),
+ {skipped, "Windows user not privileged to create symlinks"};
ok ->
?line {ok, Info1} = ?FILE_MODULE:read_file_info(Name),
?line {ok, Info1} = ?FILE_MODULE:read_file_info(Alias),
@@ -3567,7 +3624,11 @@ otp_10852(Config) when is_list(Config) ->
ok = rpc_call(Node, list_dir_all, [B]),
ok = rpc_call(Node, read_file, [B]),
ok = rpc_call(Node, make_link, [B,B]),
- ok = rpc_call(Node, make_symlink, [B,B]),
+ case rpc_call(Node, make_symlink, [B,B]) of
+ ok -> ok;
+ {error, E} when (E =:= enotsup) or (E =:= eperm) ->
+ {win32,_} = os:type()
+ end,
ok = rpc_call(Node, delete, [B]),
ok = rpc_call(Node, make_dir, [B]),
ok = rpc_call(Node, del_dir, [B]),
diff --git a/lib/kernel/test/file_name_SUITE.erl b/lib/kernel/test/file_name_SUITE.erl
index 0c8082026a..9354af2e41 100644
--- a/lib/kernel/test/file_name_SUITE.erl
+++ b/lib/kernel/test/file_name_SUITE.erl
@@ -1,5 +1,4 @@
-module(file_name_SUITE).
-%% -*- coding: utf-8 -*-
%%
%% %CopyrightBegin%
%%
diff --git a/lib/kernel/test/gen_sctp_SUITE.erl b/lib/kernel/test/gen_sctp_SUITE.erl
index d2de96b269..881aaed429 100644
--- a/lib/kernel/test/gen_sctp_SUITE.erl
+++ b/lib/kernel/test/gen_sctp_SUITE.erl
@@ -35,8 +35,9 @@
open_unihoming_ipv6_socket/1,
open_multihoming_ipv6_socket/1,
open_multihoming_ipv4_and_ipv6_socket/1,
- basic_stream/1, xfer_stream_min/1, peeloff_active_once/1,
- peeloff_active_true/1, buffers/1,
+ basic_stream/1, xfer_stream_min/1, active_n/1,
+ peeloff_active_once/1, peeloff_active_true/1, peeloff_active_n/1,
+ buffers/1,
names_unihoming_ipv4/1, names_unihoming_ipv6/1,
names_multihoming_ipv4/1, names_multihoming_ipv6/1]).
@@ -48,9 +49,9 @@ all() ->
open_multihoming_ipv4_socket,
open_unihoming_ipv6_socket,
open_multihoming_ipv6_socket,
- open_multihoming_ipv4_and_ipv6_socket,
+ open_multihoming_ipv4_and_ipv6_socket, active_n,
basic_stream, xfer_stream_min, peeloff_active_once,
- peeloff_active_true, buffers,
+ peeloff_active_true, peeloff_active_n, buffers,
names_unihoming_ipv4, names_unihoming_ipv6,
names_multihoming_ipv4, names_multihoming_ipv6].
@@ -785,6 +786,106 @@ implicit_inet6(S1, Addr) ->
end,
?line ok = gen_sctp:close(S2).
+active_n(doc) ->
+ "Verify {active,N} socket management";
+active_n(suite) ->
+ [];
+active_n(Config) when is_list(Config) ->
+ N = 3,
+ S1 = ok(gen_sctp:open([{active,N}])),
+ [{active,N}] = ok(inet:getopts(S1, [active])),
+ ok = inet:setopts(S1, [{active,-N}]),
+ receive
+ {sctp_passive, S1} -> ok
+ after
+ 5000 ->
+ exit({error,sctp_passive_failure})
+ end,
+ [{active,false}] = ok(inet:getopts(S1, [active])),
+ ok = inet:setopts(S1, [{active,0}]),
+ receive
+ {sctp_passive, S1} -> ok
+ after
+ 5000 ->
+ exit({error,sctp_passive_failure})
+ end,
+ ok = inet:setopts(S1, [{active,32767}]),
+ {error,einval} = inet:setopts(S1, [{active,1}]),
+ {error,einval} = inet:setopts(S1, [{active,-32769}]),
+ ok = inet:setopts(S1, [{active,-32768}]),
+ receive
+ {sctp_passive, S1} -> ok
+ after
+ 5000 ->
+ exit({error,sctp_passive_failure})
+ end,
+ [{active,false}] = ok(inet:getopts(S1, [active])),
+ ok = inet:setopts(S1, [{active,N}]),
+ ok = inet:setopts(S1, [{active,true}]),
+ [{active,true}] = ok(inet:getopts(S1, [active])),
+ receive
+ _ -> exit({error,active_n})
+ after
+ 0 ->
+ ok
+ end,
+ ok = inet:setopts(S1, [{active,N}]),
+ ok = inet:setopts(S1, [{active,once}]),
+ [{active,once}] = ok(inet:getopts(S1, [active])),
+ receive
+ _ -> exit({error,active_n})
+ after
+ 0 ->
+ ok
+ end,
+ {error,einval} = inet:setopts(S1, [{active,32768}]),
+ ok = inet:setopts(S1, [{active,false}]),
+ [{active,false}] = ok(inet:getopts(S1, [active])),
+ ok = gen_sctp:listen(S1, true),
+ S1Port = ok(inet:port(S1)),
+ S2 = ok(gen_sctp:open(0, [{active,false}])),
+ Assoc = ok(gen_sctp:connect(S2, "localhost", S1Port, [])),
+ ok = inet:setopts(S1, [{active,N}]),
+ [{active,N}] = ok(inet:getopts(S1, [active])),
+ LoopFun = fun(Count, Count, _Fn) ->
+ receive
+ {sctp_passive,S1} ->
+ ok
+ after
+ 5000 ->
+ exit({error,timeout})
+ end;
+ (I, Count, Fn) ->
+ Msg = list_to_binary("message "++integer_to_list(I)),
+ ok = gen_sctp:send(S2, Assoc, 0, Msg),
+ receive
+ {sctp,S1,_,_,{[SR],Msg}} when is_record(SR, sctp_sndrcvinfo) ->
+ Fn(I+1, Count, Fn);
+ {sctp,S1,_,_,_} ->
+ %% ignore non-data messages
+ ok = inet:setopts(S1, [{active,1}]),
+ Fn(I, Count, Fn);
+ Other ->
+ exit({unexpected, Other})
+ after
+ 5000 ->
+ exit({error,timeout})
+ end
+ end,
+ ok = LoopFun(1, N, LoopFun),
+ S3 = ok(gen_sctp:open([{active,0}])),
+ receive
+ {sctp_passive,S3} ->
+ [{active,false}] = ok(inet:getopts(S3, [active]))
+ after
+ 5000 ->
+ exit({error,udp_passive})
+ end,
+ ok = gen_sctp:close(S3),
+ ok = gen_sctp:close(S2),
+ ok = gen_sctp:close(S1),
+ ok.
+
basic_stream(doc) ->
"Hello world stream socket";
basic_stream(suite) ->
@@ -972,6 +1073,14 @@ peeloff_active_true(suite) ->
peeloff_active_true(Config) ->
peeloff(Config, [{active,true}]).
+peeloff_active_n(doc) ->
+ "Peel off an SCTP stream socket ({active,N})";
+peeloff_active_n(suite) ->
+ [];
+
+peeloff_active_n(Config) ->
+ peeloff(Config, [{active,1}]).
+
peeloff(Config, SockOpts) when is_list(Config) ->
?line Addr = {127,0,0,1},
?line Stream = 0,
@@ -1656,7 +1765,13 @@ s_loop(Socket, Timeout, Parent, Handler, State) ->
end.
again(Socket) ->
- inet:setopts(Socket, [{active,once}]).
+ receive
+ {sctp_passive,Socket} ->
+ [{active, false}] = ok(inet:getopts(Socket, [active])),
+ ok = inet:setopts(Socket,[{active,1}])
+ after 0 ->
+ ok = inet:setopts(Socket, [{active,once}])
+ end.
gb_push(Key, Val, GBT) ->
case gb_trees:lookup(Key, GBT) of
diff --git a/lib/kernel/test/gen_tcp_misc_SUITE.erl b/lib/kernel/test/gen_tcp_misc_SUITE.erl
index ee271fbdfa..2df4bf7c95 100644
--- a/lib/kernel/test/gen_tcp_misc_SUITE.erl
+++ b/lib/kernel/test/gen_tcp_misc_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1998-2013. All Rights Reserved.
+%% Copyright Ericsson AB 1998-2014. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -25,7 +25,7 @@
-export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1,
init_per_group/2,end_per_group/2,
controlling_process/1, controlling_process_self/1,
- no_accept/1, close_with_pending_output/1,
+ no_accept/1, close_with_pending_output/1, active_n/1,
data_before_close/1, iter_max_socks/1, get_status/1,
passive_sockets/1, accept_closed_by_other_process/1,
init_per_testcase/2, end_per_testcase/2,
@@ -50,6 +50,14 @@
oct_acceptor/1,
otp_7731_server/1, zombie_server/2, do_iter_max_socks/2]).
+init_per_testcase(wrapping_oct, Config) when is_list(Config) ->
+ Dog = case os:type() of
+ {ose,_} ->
+ test_server:timetrap(test_server:minutes(20));
+ _Else ->
+ test_server:timetrap(test_server:seconds(600))
+ end,
+ [{watchdog, Dog}|Config];
init_per_testcase(iter_max_socks, Config) when is_list(Config) ->
Dog = case os:type() of
{win32,_} ->
@@ -58,6 +66,17 @@ init_per_testcase(iter_max_socks, Config) when is_list(Config) ->
test_server:timetrap(test_server:seconds(240))
end,
[{watchdog, Dog}|Config];
+init_per_testcase(accept_system_limit, Config) when is_list(Config) ->
+ case os:type() of
+ {ose,_} ->
+ {skip,"Skip in OSE"};
+ _ ->
+ Dog = test_server:timetrap(test_server:seconds(240)),
+ [{watchdog,Dog}|Config]
+ end;
+init_per_testcase(wrapping_oct, Config) when is_list(Config) ->
+ Dog = test_server:timetrap(test_server:seconds(600)),
+ [{watchdog, Dog}|Config];
init_per_testcase(_Func, Config) when is_list(Config) ->
Dog = test_server:timetrap(test_server:seconds(240)),
[{watchdog, Dog}|Config].
@@ -70,7 +89,7 @@ suite() -> [{ct_hooks,[ts_install_cth]}].
all() ->
[controlling_process, controlling_process_self, no_accept,
close_with_pending_output, data_before_close,
- iter_max_socks, passive_sockets,
+ iter_max_socks, passive_sockets, active_n,
accept_closed_by_other_process, otp_3924, closed_socket,
shutdown_active, shutdown_passive, shutdown_pending,
default_options, http_bad_packet, busy_send,
@@ -407,6 +426,114 @@ send_loop(Sock, Data, Left) ->
ok = gen_tcp:send(Sock, Data),
send_loop(Sock, Data, Left-1).
+%% Test {active,N} option
+active_n(doc) ->
+ ["Verify operation of the {active,N} option."];
+active_n(suite) -> [];
+active_n(Config) when is_list(Config) ->
+ N = 3,
+ LS = ok(gen_tcp:listen(0, [{active,N}])),
+ [{active,N}] = ok(inet:getopts(LS, [active])),
+ ok = inet:setopts(LS, [{active,-N}]),
+ receive
+ {tcp_passive, LS} -> ok
+ after
+ 5000 ->
+ exit({error,tcp_passive_failure})
+ end,
+ [{active,false}] = ok(inet:getopts(LS, [active])),
+ ok = inet:setopts(LS, [{active,0}]),
+ receive
+ {tcp_passive, LS} -> ok
+ after
+ 5000 ->
+ exit({error,tcp_passive_failure})
+ end,
+ ok = inet:setopts(LS, [{active,32767}]),
+ {error,einval} = inet:setopts(LS, [{active,1}]),
+ {error,einval} = inet:setopts(LS, [{active,-32769}]),
+ ok = inet:setopts(LS, [{active,-32768}]),
+ receive
+ {tcp_passive, LS} -> ok
+ after
+ 5000 ->
+ exit({error,tcp_passive_failure})
+ end,
+ [{active,false}] = ok(inet:getopts(LS, [active])),
+ ok = inet:setopts(LS, [{active,N}]),
+ ok = inet:setopts(LS, [{active,true}]),
+ [{active,true}] = ok(inet:getopts(LS, [active])),
+ receive
+ _ -> exit({error,active_n})
+ after
+ 0 ->
+ ok
+ end,
+ ok = inet:setopts(LS, [{active,N}]),
+ ok = inet:setopts(LS, [{active,once}]),
+ [{active,once}] = ok(inet:getopts(LS, [active])),
+ receive
+ _ -> exit({error,active_n})
+ after
+ 0 ->
+ ok
+ end,
+ {error,einval} = inet:setopts(LS, [{active,32768}]),
+ ok = inet:setopts(LS, [{active,false}]),
+ [{active,false}] = ok(inet:getopts(LS, [active])),
+ Port = ok(inet:port(LS)),
+ C = ok(gen_tcp:connect("localhost", Port, [{active,N}])),
+ [{active,N}] = ok(inet:getopts(C, [active])),
+ S = ok(gen_tcp:accept(LS)),
+ ok = inet:setopts(S, [{active,N}]),
+ [{active,N}] = ok(inet:getopts(S, [active])),
+ repeat(3,
+ fun(I) ->
+ Msg = "message "++integer_to_list(I),
+ ok = gen_tcp:send(C, Msg),
+ receive
+ {tcp,S,Msg} ->
+ ok = gen_tcp:send(S, Msg)
+ after
+ 5000 ->
+ exit({error,timeout})
+ end,
+ receive
+ {tcp,C,Msg} ->
+ ok
+ after
+ 5000 ->
+ exit({error,timeout})
+ end
+ end),
+ receive
+ {tcp_passive,S} ->
+ [{active,false}] = ok(inet:getopts(S, [active]))
+ after
+ 5000 ->
+ exit({error,tcp_passive})
+ end,
+ receive
+ {tcp_passive,C} ->
+ [{active,false}] = ok(inet:getopts(C, [active]))
+ after
+ 5000 ->
+ exit({error,tcp_passive})
+ end,
+ LS2 = ok(gen_tcp:listen(0, [{active,0}])),
+ receive
+ {tcp_passive,LS2} ->
+ [{active,false}] = ok(inet:getopts(LS2, [active]))
+ after
+ 5000 ->
+ exit({error,tcp_passive})
+ end,
+ ok = gen_tcp:close(LS2),
+ ok = gen_tcp:close(C),
+ ok = gen_tcp:close(S),
+ ok = gen_tcp:close(LS),
+ ok.
+
-define(OTP_3924_MAX_DELAY, 100).
%% Taken out of the blue, but on intra host connections
%% I expect propagation of a close to be quite fast
@@ -429,7 +556,6 @@ otp_3924(Config) when is_list(Config) ->
otp_3924_1(MaxDelay).
otp_3924_1(MaxDelay) ->
- Dog = test_server:timetrap(test_server:seconds(240)),
?line {ok, Node} = start_node(otp_3924),
?line DataLen = 100*1024,
?line Data = otp_3924_data(DataLen),
@@ -440,7 +566,6 @@ otp_3924_1(MaxDelay) ->
?line ok = otp_3924(MaxDelay, Node, Data, DataLen, N)
end),
?line test_server:stop_node(Node),
- test_server:timetrap_cancel(Dog),
ok.
otp_3924(MaxDelay, Node, Data, DataLen, N) ->
@@ -1845,7 +1970,9 @@ accept_system_limit(doc) ->
accept_system_limit(Config) when is_list(Config) ->
?line {ok, LS} = gen_tcp:listen(0, []),
?line {ok, TcpPort} = inet:port(LS),
- ?line Connector = spawn_link(fun () -> connector(TcpPort) end),
+ Me = self(),
+ ?line Connector = spawn_link(fun () -> connector(TcpPort, Me) end),
+ receive {Connector, sync} -> Connector ! {self(), continue} end,
?line ok = acceptor(LS, false, []),
?line Connector ! stop,
ok.
@@ -1862,8 +1989,10 @@ acceptor(LS, GotSL, A) ->
error
end.
-connector(TcpPort) ->
+connector(TcpPort, Tester) ->
ManyPorts = open_ports([]),
+ Tester ! {self(), sync},
+ receive {Tester, continue} -> timer:sleep(100) end,
ConnF = fun (Port) ->
case catch gen_tcp:connect({127,0,0,1}, TcpPort, []) of
{ok, Sock} ->
@@ -2597,13 +2726,11 @@ wrapping_oct(doc) ->
wrapping_oct(suite) ->
[];
wrapping_oct(Config) when is_list(Config) ->
- Dog = test_server:timetrap(test_server:seconds(600)),
{ok,Sock} = gen_tcp:listen(0,[{active,false},{mode,binary}]),
{ok,Port} = inet:port(Sock),
spawn_link(?MODULE,oct_acceptor,[Sock]),
Res = oct_datapump(Port,16#1FFFFFFFF),
gen_tcp:close(Sock),
- test_server:timetrap_cancel(Dog),
ok = Res,
ok.
@@ -2659,3 +2786,5 @@ oct_aloop(S,X,Times) ->
gen_tcp:close(S),
closed
end.
+
+ok({ok,V}) -> V.
diff --git a/lib/kernel/test/gen_udp_SUITE.erl b/lib/kernel/test/gen_udp_SUITE.erl
index cd768813cf..6bb41999c5 100644
--- a/lib/kernel/test/gen_udp_SUITE.erl
+++ b/lib/kernel/test/gen_udp_SUITE.erl
@@ -1,8 +1,7 @@
-%% -*- coding: utf-8 -*-
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1998-2012. All Rights Reserved.
+%% Copyright Ericsson AB 1998-2013. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -34,7 +33,7 @@
init_per_group/2,end_per_group/2]).
-export([init_per_testcase/2, end_per_testcase/2]).
--export([send_to_closed/1,
+-export([send_to_closed/1, active_n/1,
buffer_size/1, binary_passive_recv/1, bad_address/1,
read_packets/1, open_fd/1, connect/1, implicit_inet6/1]).
@@ -43,7 +42,7 @@ suite() -> [{ct_hooks,[ts_install_cth]}].
all() ->
[send_to_closed, buffer_size, binary_passive_recv,
bad_address, read_packets, open_fd, connect,
- implicit_inet6].
+ implicit_inet6, active_n].
groups() ->
[].
@@ -466,6 +465,108 @@ open_fd(Config) when is_list(Config) ->
?t:fail(io_lib:format("~w", [flush()]))
end.
+active_n(Config) when is_list(Config) ->
+ N = 3,
+ S1 = ok(gen_udp:open(0, [{active,N}])),
+ [{active,N}] = ok(inet:getopts(S1, [active])),
+ ok = inet:setopts(S1, [{active,-N}]),
+ receive
+ {udp_passive, S1} -> ok
+ after
+ 5000 ->
+ exit({error,udp_passive_failure})
+ end,
+ [{active,false}] = ok(inet:getopts(S1, [active])),
+ ok = inet:setopts(S1, [{active,0}]),
+ receive
+ {udp_passive, S1} -> ok
+ after
+ 5000 ->
+ exit({error,udp_passive_failure})
+ end,
+ ok = inet:setopts(S1, [{active,32767}]),
+ {error,einval} = inet:setopts(S1, [{active,1}]),
+ {error,einval} = inet:setopts(S1, [{active,-32769}]),
+ ok = inet:setopts(S1, [{active,-32768}]),
+ receive
+ {udp_passive, S1} -> ok
+ after
+ 5000 ->
+ exit({error,udp_passive_failure})
+ end,
+ [{active,false}] = ok(inet:getopts(S1, [active])),
+ ok = inet:setopts(S1, [{active,N}]),
+ ok = inet:setopts(S1, [{active,true}]),
+ [{active,true}] = ok(inet:getopts(S1, [active])),
+ receive
+ _ -> exit({error,active_n})
+ after
+ 0 ->
+ ok
+ end,
+ ok = inet:setopts(S1, [{active,N}]),
+ ok = inet:setopts(S1, [{active,once}]),
+ [{active,once}] = ok(inet:getopts(S1, [active])),
+ receive
+ _ -> exit({error,active_n})
+ after
+ 0 ->
+ ok
+ end,
+ {error,einval} = inet:setopts(S1, [{active,32768}]),
+ ok = inet:setopts(S1, [{active,false}]),
+ [{active,false}] = ok(inet:getopts(S1, [active])),
+ S1Port = ok(inet:port(S1)),
+ S2 = ok(gen_udp:open(0, [{active,N}])),
+ S2Port = ok(inet:port(S2)),
+ [{active,N}] = ok(inet:getopts(S2, [active])),
+ ok = inet:setopts(S1, [{active,N}]),
+ [{active,N}] = ok(inet:getopts(S1, [active])),
+ lists:foreach(
+ fun(I) ->
+ Msg = "message "++integer_to_list(I),
+ ok = gen_udp:send(S2, "localhost", S1Port, Msg),
+ receive
+ {udp,S1,_,S2Port,Msg} ->
+ ok = gen_udp:send(S1, "localhost", S2Port, Msg)
+ after
+ 5000 ->
+ exit({error,timeout})
+ end,
+ receive
+ {udp,S2,_,S1Port,Msg} ->
+ ok
+ after
+ 5000 ->
+ exit({error,timeout})
+ end
+ end, lists:seq(1,N)),
+ receive
+ {udp_passive,S1} ->
+ [{active,false}] = ok(inet:getopts(S1, [active]))
+ after
+ 5000 ->
+ exit({error,udp_passive})
+ end,
+ receive
+ {udp_passive,S2} ->
+ [{active,false}] = ok(inet:getopts(S2, [active]))
+ after
+ 5000 ->
+ exit({error,udp_passive})
+ end,
+ S3 = ok(gen_udp:open(0, [{active,0}])),
+ receive
+ {udp_passive,S3} ->
+ [{active,false}] = ok(inet:getopts(S3, [active]))
+ after
+ 5000 ->
+ exit({error,udp_passive})
+ end,
+ ok = gen_udp:close(S3),
+ ok = gen_udp:close(S2),
+ ok = gen_udp:close(S1),
+ ok.
%
% Utils
diff --git a/lib/kernel/test/global_SUITE_data/global_trace.erl b/lib/kernel/test/global_SUITE_data/global_trace.erl
index 00bacf8f54..1396d86c79 100644
--- a/lib/kernel/test/global_SUITE_data/global_trace.erl
+++ b/lib/kernel/test/global_SUITE_data/global_trace.erl
@@ -1,4 +1,3 @@
-%% -*- coding: utf-8 -*-
%%
%% %CopyrightBegin%
%%
diff --git a/lib/kernel/test/heart_SUITE.erl b/lib/kernel/test/heart_SUITE.erl
index 320b23bea1..35d3b75b34 100644
--- a/lib/kernel/test/heart_SUITE.erl
+++ b/lib/kernel/test/heart_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2012. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2014. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -93,10 +93,10 @@ start_check(Type, Name) ->
start_check(Type, Name, []).
start_check(Type, Name, Envs) ->
Args = case ?t:os_type() of
- {win32,_} ->
- "-heart " ++ env_encode([{"HEART_COMMAND", no_reboot}|Envs]);
+ {win32,_} ->
+ "+t50000 -heart " ++ env_encode([{"HEART_COMMAND", no_reboot}|Envs]);
_ ->
- "-heart " ++ env_encode(Envs)
+ "+t50000 -heart " ++ env_encode(Envs)
end,
{ok, Node} = case Type of
loose ->
diff --git a/lib/kernel/test/kernel_SUITE.erl b/lib/kernel/test/kernel_SUITE.erl
index 0f29d895e5..1884e8cf58 100644
--- a/lib/kernel/test/kernel_SUITE.erl
+++ b/lib/kernel/test/kernel_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2011. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2014. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -23,9 +23,6 @@
-include_lib("test_server/include/test_server.hrl").
-% Default timetrap timeout (set in init_per_testcase).
--define(default_timeout, ?t:minutes(1)).
-
% Test server specific exports
-export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1,
init_per_group/2,end_per_group/2]).
@@ -59,11 +56,8 @@ end_per_group(_GroupName, Config) ->
init_per_testcase(_Case, Config) ->
- ?line Dog=test_server:timetrap(?default_timeout),
- [{watchdog, Dog}|Config].
-end_per_testcase(_Case, Config) ->
- Dog=?config(watchdog, Config),
- test_server:timetrap_cancel(Dog),
+ Config.
+end_per_testcase(_Case, _Config) ->
ok.
%
@@ -78,56 +72,80 @@ app_test(Config) when is_list(Config) ->
ok.
-%% Test that appup allows upgrade from/downgrade to a maximum of two
-%% major releases back.
+%% Test that appup allows upgrade from/downgrade to a maximum of one
+%% major release back.
appup_test(_Config) ->
- application:load(kernel),
- {_,_,Vsn} = lists:keyfind(kernel,1,application:loaded_applications()),
- AppupFile = filename:join([code:lib_dir(kernel),ebin,"kernel.appup"]),
+ appup_tests(kernel,create_test_vsns(kernel)).
+
+appup_tests(_App,{[],[]}) ->
+ {skip,"no previous releases available"};
+appup_tests(App,{OkVsns,NokVsns}) ->
+ application:load(App),
+ {_,_,Vsn} = lists:keyfind(App,1,application:loaded_applications()),
+ AppupFileName = atom_to_list(App) ++ ".appup",
+ AppupFile = filename:join([code:lib_dir(App),ebin,AppupFileName]),
{ok,[{Vsn,UpFrom,DownTo}=AppupScript]} = file:consult(AppupFile),
ct:log("~p~n",[AppupScript]),
- {OkVsns,NokVsns} = create_test_vsns(Vsn),
+ ct:log("Testing ok versions: ~p~n",[OkVsns]),
check_appup(OkVsns,UpFrom,{ok,[restart_new_emulator]}),
check_appup(OkVsns,DownTo,{ok,[restart_new_emulator]}),
+ ct:log("Testing not ok versions: ~p~n",[NokVsns]),
check_appup(NokVsns,UpFrom,error),
check_appup(NokVsns,DownTo,error),
ok.
-create_test_vsns(Current) ->
- [XStr,YStr|Rest] = string:tokens(Current,"."),
- X = list_to_integer(XStr),
- Y = list_to_integer(YStr),
- SecondMajor = vsn(X,Y-2),
- SecondMinor = SecondMajor ++ ".1.3",
- FirstMajor = vsn(X,Y-1),
- FirstMinor = FirstMajor ++ ".57",
- ThisMajor = vsn(X,Y),
- This =
- case Rest of
- [] ->
- [];
- ["1"] ->
- [ThisMajor];
- _ ->
- ThisMinor = ThisMajor ++ ".1",
- [ThisMajor,ThisMinor]
+create_test_vsns(App) ->
+ ThisMajor = erlang:system_info(otp_release),
+ FirstMajor = previous_major(ThisMajor),
+ SecondMajor = previous_major(FirstMajor),
+ Ok = app_vsn(App,[ThisMajor,FirstMajor]),
+ Nok0 = app_vsn(App,[SecondMajor]),
+ Nok = case Ok of
+ [Ok1|_] ->
+ [Ok1 ++ ",1" | Nok0]; % illegal
+ _ ->
+ Nok0
+ end,
+ {Ok,Nok}.
+
+previous_major("17") ->
+ "r16b";
+previous_major("r16b") ->
+ "r15b";
+previous_major(Rel) ->
+ integer_to_list(list_to_integer(Rel)-1).
+
+app_vsn(App,[R|Rs]) ->
+ OldRel =
+ case test_server:is_release_available(R) of
+ true ->
+ {release,R};
+ false ->
+ case ct:get_config({otp_releases,list_to_atom(R)}) of
+ undefined ->
+ false;
+ Prog0 ->
+ case os:find_executable(Prog0) of
+ false ->
+ false;
+ Prog ->
+ {prog,Prog}
+ end
+ end
end,
- OkVsns = This ++ [FirstMajor, FirstMinor, SecondMajor, SecondMinor],
-
- ThirdMajor = vsn(X,Y-3),
- ThirdMinor = ThirdMajor ++ ".10.12",
- Illegal = ThisMajor ++ ",1",
- Newer1Major = vsn(X,Y+1),
- Newer1Minor = Newer1Major ++ ".1",
- Newer2Major = ThisMajor ++ "1",
- NokVsns = [ThirdMajor,ThirdMinor,
- Illegal,
- Newer1Major,Newer1Minor,
- Newer2Major],
- {OkVsns,NokVsns}.
-
-vsn(X,Y) ->
- integer_to_list(X) ++ "." ++ integer_to_list(Y).
+ case OldRel of
+ false ->
+ app_vsn(App,Rs);
+ _ ->
+ {ok,N} = test_server:start_node(prevrel,peer,[{erl,[OldRel]}]),
+ _ = rpc:call(N,application,load,[App]),
+ As = rpc:call(N,application,loaded_applications,[]),
+ {_,_,V} = lists:keyfind(App,1,As),
+ test_server:stop_node(N),
+ [V|app_vsn(App,Rs)]
+ end;
+app_vsn(_App,[]) ->
+ [].
check_appup([Vsn|Vsns],Instrs,Expected) ->
case systools_relup:appup_search_for_version(Vsn, Instrs) of
diff --git a/lib/kernel/test/os_SUITE.erl b/lib/kernel/test/os_SUITE.erl
index 73ed704ae3..9b474c4cdf 100644
--- a/lib/kernel/test/os_SUITE.erl
+++ b/lib/kernel/test/os_SUITE.erl
@@ -20,7 +20,7 @@
-export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1,
init_per_group/2,end_per_group/2]).
--export([space_in_cwd/1, quoting/1, space_in_name/1, bad_command/1,
+-export([space_in_cwd/1, quoting/1, cmd_unicode/1, space_in_name/1, bad_command/1,
find_executable/1, unix_comment_in_command/1, deep_list_command/1, evil/1]).
-include_lib("test_server/include/test_server.hrl").
@@ -28,9 +28,8 @@
suite() -> [{ct_hooks,[ts_install_cth]}].
all() ->
- [space_in_cwd, quoting, space_in_name, bad_command,
- find_executable, unix_comment_in_command, deep_list_command,
- evil].
+ [space_in_cwd, quoting, cmd_unicode, space_in_name, bad_command,
+ find_executable, unix_comment_in_command, deep_list_command, evil].
groups() ->
[].
@@ -95,6 +94,21 @@ quoting(Config) when is_list(Config) ->
?line [] = receive_all(),
ok.
+
+cmd_unicode(doc) -> "Test that unicode arguments work.";
+cmd_unicode(suite) -> [];
+cmd_unicode(Config) when is_list(Config) ->
+ ?line DataDir = ?config(data_dir, Config),
+ ?line Echo = filename:join(DataDir, "my_echo"),
+
+ ?line comp("one", os:cmd(Echo ++ " one")),
+ ?line comp("one::two", os:cmd(Echo ++ " one two")),
+ ?line comp("åäö::ϼΩ", os:cmd(Echo ++ " åäö " ++ [1020, 937])),
+ ?t:sleep(5),
+ ?line [] = receive_all(),
+ ok.
+
+
space_in_name(doc) ->
"Test that program with a space in its name can be executed.";
space_in_name(suite) -> [];
@@ -302,8 +316,8 @@ comp(Expected, Got) ->
Expected ->
ok;
Other ->
- ok = io:format("Expected: ~s\n", [Expected]),
- ok = io:format("Got: ~s\n", [Other]),
+ ok = io:format("Expected: ~ts\n", [Expected]),
+ ok = io:format("Got: ~ts\n", [Other]),
test_server:fail()
end.
diff --git a/lib/kernel/test/os_SUITE_data/my_echo.c b/lib/kernel/test/os_SUITE_data/my_echo.c
index 2127511dd1..712c828bb5 100644
--- a/lib/kernel/test/os_SUITE_data/my_echo.c
+++ b/lib/kernel/test/os_SUITE_data/my_echo.c
@@ -1,3 +1,30 @@
+#ifdef __WIN32__
+#include <windows.h>
+
+int wmain(int argc, wchar_t **argv)
+{
+ char* sep = "";
+ int len;
+
+ /*
+ * Echo all arguments separated with '::', so that we can check that
+ * quotes are interpreted correctly.
+ */
+
+ while (argc-- > 1) {
+ char *utf8;
+ len = WideCharToMultiByte(CP_UTF8, 0, argv[1], -1, NULL, 0, NULL, NULL);
+ utf8 = malloc(len*sizeof(char));
+ WideCharToMultiByte(CP_UTF8, 0, argv++[1], -1, utf8, len, NULL, NULL);
+ printf("%s%s", sep, utf8);
+ free(utf8);
+ sep = "::";
+ }
+ putchar('\n');
+ return 0;
+}
+#else
+
#include <stdio.h>
int
@@ -17,3 +44,4 @@ main(int argc, char** argv)
putchar('\n');
return 0;
}
+#endif
diff --git a/lib/kernel/test/prim_file_SUITE.erl b/lib/kernel/test/prim_file_SUITE.erl
index 199e597e78..05bd5b3a3d 100644
--- a/lib/kernel/test/prim_file_SUITE.erl
+++ b/lib/kernel/test/prim_file_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2000-2013. All Rights Reserved.
+%% Copyright Ericsson AB 2000-2014. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -78,7 +78,7 @@
_ -> apply(?PRIM_FILE, F, [H | A])
end).
-suite() -> [{ct_hooks,[ts_install_cth]}].
+suite() -> [].
all() ->
[read_write_file, {group, dirs}, {group, files},
@@ -183,7 +183,6 @@ time_dist({_D1, _T1} = DT1, {_D2, _T2} = DT2) ->
read_write_file(suite) -> [];
read_write_file(doc) -> [];
read_write_file(Config) when is_list(Config) ->
- ?line Dog = test_server:timetrap(test_server:seconds(5)),
?line RootDir = ?config(priv_dir,Config),
?line Name = filename:join(RootDir,
atom_to_list(?MODULE)
@@ -232,7 +231,6 @@ read_write_file(Config) when is_list(Config) ->
?line {ok,Bin5} = ?PRIM_FILE:read_file(Name),
?line {Bin1,Bin2} = split_binary(Bin5,byte_size(Bin1)),
- ?line test_server:timetrap_cancel(Dog),
ok.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@@ -254,7 +252,6 @@ make_del_dir_b(Config) when is_list(Config) ->
Result.
make_del_dir(Config, Handle, Suffix) ->
- ?line Dog = test_server:timetrap(test_server:seconds(5)),
?line RootDir = ?config(priv_dir,Config),
?line NewDir = filename:join(RootDir,
atom_to_list(?MODULE)
@@ -269,7 +266,13 @@ make_del_dir(Config, Handle, Suffix) ->
% because there are processes having that directory as current.
?line ok = ?PRIM_FILE_call(make_dir, Handle, [NewDir]),
?line {ok, CurrentDir} = ?PRIM_FILE_call(get_cwd, Handle, []),
- ?line ok = ?PRIM_FILE_call(set_cwd, Handle, [NewDir]),
+ case {os:type(), length(NewDir) >= 260 } of
+ {{win32,_}, true} ->
+ io:format("Skip set_cwd for windows path longer than 260 (MAX_PATH)\n", []),
+ io:format("\nNewDir = ~p\n", [NewDir]);
+ _ ->
+ ok = ?PRIM_FILE_call(set_cwd, Handle, [NewDir])
+ end,
try
%% Check that we get an error when trying to create...
%% a deep directory
@@ -302,9 +305,7 @@ make_del_dir(Config, Handle, Suffix) ->
{error, einval} -> ok %FreeBSD
end,
?line {error, enoent} = ?PRIM_FILE_call(del_dir, Handle, [""]),
- ?line {error, badarg} = ?PRIM_FILE_call(del_dir, Handle, [[3,2,1,{}]]),
-
- ?line test_server:timetrap_cancel(Dog)
+ ?line {error, badarg} = ?PRIM_FILE_call(del_dir, Handle, [[3,2,1,{}]])
after
?line ok = ?PRIM_FILE_call(set_cwd, Handle, [CurrentDir])
end,
@@ -324,7 +325,6 @@ cur_dir_0b(Config) when is_list(Config) ->
Result.
cur_dir_0(Config, Handle) ->
- ?line Dog = test_server:timetrap(test_server:seconds(5)),
%% Find out the current dir, and cd to it ;-)
?line {ok,BaseDir} = ?PRIM_FILE_call(get_cwd, Handle, []),
?line Dir1 = BaseDir ++ "", %% Check that it's a string
@@ -341,31 +341,37 @@ cur_dir_0(Config, Handle) ->
?line RootDir = ?config(priv_dir,Config),
?line NewDir = filename:join(RootDir, DirName),
?line ok = ?PRIM_FILE_call(make_dir, Handle, [NewDir]),
- ?line io:format("cd to ~s",[NewDir]),
- ?line ok = ?PRIM_FILE_call(set_cwd, Handle, [NewDir]),
-
- %% Create a file in the new current directory, and check that it
- %% really is created there
- ?line UncommonName = "uncommon.fil",
- ?line {ok,Fd} = ?PRIM_FILE:open(UncommonName, [read, write]),
- ?line ok = ?PRIM_FILE:close(Fd),
- ?line {ok,NewDirFiles} = ?PRIM_FILE_call(list_dir, Handle, ["."]),
- ?line true = lists:member(UncommonName,NewDirFiles),
-
- %% Delete the directory and return to the old current directory
- %% and check that the created file isn't there (too!)
- ?line expect({error, einval}, {error, eacces}, {error, eexist},
+ case {os:type(), length(NewDir) >= 260} of
+ {{win32,_}, true} ->
+ io:format("Skip set_cwd for windows path longer than 260 (MAX_PATH):\n"),
+ io:format("\nNewDir = ~p\n", [NewDir]);
+ _ ->
+ io:format("cd to ~s",[NewDir]),
+ ok = ?PRIM_FILE_call(set_cwd, Handle, [NewDir]),
+
+ %% Create a file in the new current directory, and check that it
+ %% really is created there
+ UncommonName = "uncommon.fil",
+ {ok,Fd} = ?PRIM_FILE:open(UncommonName, [read, write]),
+ ok = ?PRIM_FILE:close(Fd),
+ {ok,NewDirFiles} = ?PRIM_FILE_call(list_dir, Handle, ["."]),
+ true = lists:member(UncommonName,NewDirFiles),
+
+ %% Delete the directory and return to the old current directory
+ %% and check that the created file isn't there (too!)
+ expect({error, einval}, {error, eacces}, {error, eexist},
?PRIM_FILE_call(del_dir, Handle, [NewDir])),
- ?line ?PRIM_FILE_call(delete, Handle, [UncommonName]),
- ?line {ok,[]} = ?PRIM_FILE_call(list_dir, Handle, ["."]),
- ?line ok = ?PRIM_FILE_call(set_cwd, Handle, [Dir1]),
- ?line io:format("cd back to ~s",[Dir1]),
- ?line ok = ?PRIM_FILE_call(del_dir, Handle, [NewDir]),
- ?line {error, enoent} = ?PRIM_FILE_call(set_cwd, Handle, [NewDir]),
- ?line ok = ?PRIM_FILE_call(set_cwd, Handle, [Dir1]),
- ?line io:format("cd back to ~s",[Dir1]),
- ?line {ok,OldDirFiles} = ?PRIM_FILE_call(list_dir, Handle, ["."]),
- ?line false = lists:member(UncommonName,OldDirFiles),
+ ?PRIM_FILE_call(delete, Handle, [UncommonName]),
+ {ok,[]} = ?PRIM_FILE_call(list_dir, Handle, ["."]),
+ ok = ?PRIM_FILE_call(set_cwd, Handle, [Dir1]),
+ io:format("cd back to ~s",[Dir1]),
+ ok = ?PRIM_FILE_call(del_dir, Handle, [NewDir]),
+ {error, enoent} = ?PRIM_FILE_call(set_cwd, Handle, [NewDir]),
+ ok = ?PRIM_FILE_call(set_cwd, Handle, [Dir1]),
+ io:format("cd back to ~s",[Dir1]),
+ {ok,OldDirFiles} = ?PRIM_FILE_call(list_dir, Handle, ["."]),
+ false = lists:member(UncommonName,OldDirFiles)
+ end,
%% Try doing some bad things
?line {error, badarg} =
@@ -385,7 +391,6 @@ cur_dir_0(Config, Handle) ->
?line {ok, BaseDir} = ?PRIM_FILE_call(get_cwd, Handle, []),
?line false = lists:member($\\, BaseDir),
- ?line test_server:timetrap_cancel(Dog),
ok.
%% Tests ?PRIM_FILE:get_cwd/1.
@@ -404,16 +409,13 @@ cur_dir_1b(Config) when is_list(Config) ->
Result.
cur_dir_1(Config, Handle) ->
- ?line Dog = test_server:timetrap(test_server:seconds(5)),
-
?line case os:type() of
- {unix, _} ->
- ?line {error, enotsup} =
- ?PRIM_FILE_call(get_cwd, Handle, ["d:"]);
{win32, _} ->
- win_cur_dir_1(Config, Handle)
+ win_cur_dir_1(Config, Handle);
+ _ ->
+ ?line {error, enotsup} =
+ ?PRIM_FILE_call(get_cwd, Handle, ["d:"])
end,
- ?line test_server:timetrap_cancel(Dog),
ok.
win_cur_dir_1(_Config, Handle) ->
@@ -439,7 +441,6 @@ win_cur_dir_1(_Config, Handle) ->
open1(suite) -> [];
open1(doc) -> [];
open1(Config) when is_list(Config) ->
- ?line Dog = test_server:timetrap(test_server:seconds(5)),
?line RootDir = ?config(priv_dir,Config),
?line NewDir = filename:join(RootDir,
atom_to_list(?MODULE)
@@ -453,7 +454,10 @@ open1(Config) when is_list(Config) ->
?line ?PRIM_FILE:write(Fd1,Str),
?line {ok,0} = ?PRIM_FILE:position(Fd1,bof),
?line {ok, Str} = ?PRIM_FILE:read(Fd1,Length),
- ?line {ok, Str} = ?PRIM_FILE:read(Fd2,Length),
+ ?line case ?PRIM_FILE:read(Fd2,Length) of
+ {ok,Str} -> Str;
+ eof -> Str
+ end,
?line ok = ?PRIM_FILE:close(Fd2),
?line {ok,0} = ?PRIM_FILE:position(Fd1,bof),
?line ok = ?PRIM_FILE:truncate(Fd1),
@@ -462,7 +466,6 @@ open1(Config) when is_list(Config) ->
?line {ok,Fd3} = ?PRIM_FILE:open(Name, [read]),
?line eof = ?PRIM_FILE:read(Fd3,Length),
?line ok = ?PRIM_FILE:close(Fd3),
- ?line test_server:timetrap_cancel(Dog),
ok.
%% Tests all open modes.
@@ -514,7 +517,6 @@ modes(Config) when is_list(Config) ->
close(suite) -> [];
close(doc) -> [];
close(Config) when is_list(Config) ->
- ?line Dog = test_server:timetrap(test_server:seconds(5)),
?line RootDir = ?config(priv_dir,Config),
?line Name = filename:join(RootDir,
atom_to_list(?MODULE)
@@ -531,13 +533,11 @@ close(Config) when is_list(Config) ->
?line Val = ?PRIM_FILE:close(Fd1),
?line io:format("Second close gave: ~p", [Val]),
- ?line test_server:timetrap_cancel(Dog),
ok.
access(suite) -> [];
access(doc) -> [];
access(Config) when is_list(Config) ->
- ?line Dog = test_server:timetrap(test_server:seconds(5)),
?line RootDir = ?config(priv_dir,Config),
?line Name = filename:join(RootDir,
atom_to_list(?MODULE)
@@ -559,7 +559,6 @@ access(Config) when is_list(Config) ->
?line {ok, Str} = ?PRIM_FILE:read(Fd3,length(Str)),
?line ok = ?PRIM_FILE:close(Fd3),
- ?line test_server:timetrap_cancel(Dog),
ok.
%% Tests ?PRIM_FILE:read/2 and ?PRIM_FILE:write/2.
@@ -567,7 +566,6 @@ access(Config) when is_list(Config) ->
read_write(suite) -> [];
read_write(doc) -> [];
read_write(Config) when is_list(Config) ->
- ?line Dog = test_server:timetrap(test_server:seconds(5)),
?line RootDir = ?config(priv_dir, Config),
?line NewDir = filename:join(RootDir,
atom_to_list(?MODULE)
@@ -579,7 +577,6 @@ read_write(Config) when is_list(Config) ->
?line {ok, Fd} = ?PRIM_FILE:open(Name, [read, write]),
?line read_write_test(Fd),
- ?line test_server:timetrap_cancel(Dog),
ok.
read_write_test(File) ->
@@ -597,7 +594,6 @@ read_write_test(File) ->
pread_write(suite) -> [];
pread_write(doc) -> [];
pread_write(Config) when is_list(Config) ->
- ?line Dog = test_server:timetrap(test_server:seconds(5)),
?line RootDir = ?config(priv_dir, Config),
?line NewDir = filename:join(RootDir,
atom_to_list(?MODULE)
@@ -609,7 +605,6 @@ pread_write(Config) when is_list(Config) ->
?line {ok, Fd} = ?PRIM_FILE:open(Name, [read, write]),
?line pread_write_test(Fd),
- ?line test_server:timetrap_cancel(Dog),
ok.
pread_write_test(File) ->
@@ -629,7 +624,6 @@ pread_write_test(File) ->
append(doc) -> "Test appending to a file.";
append(suite) -> [];
append(Config) when is_list(Config) ->
- ?line Dog = test_server:timetrap(test_server:seconds(5)),
?line RootDir = ?config(priv_dir, Config),
?line NewDir = filename:join(RootDir,
atom_to_list(?MODULE)
@@ -656,13 +650,11 @@ append(Config) when is_list(Config) ->
?line Expected = list_to_binary([First, Second, Third]),
?line {ok, Expected} = ?PRIM_FILE:read_file(Name1),
- ?line test_server:timetrap_cancel(Dog),
ok.
exclusive(suite) -> [];
exclusive(doc) -> "Test exclusive access to a file.";
exclusive(Config) when is_list(Config) ->
- ?line Dog = test_server:timetrap(test_server:seconds(5)),
?line RootDir = ?config(priv_dir,Config),
?line NewDir = filename:join(RootDir,
atom_to_list(?MODULE)
@@ -672,7 +664,6 @@ exclusive(Config) when is_list(Config) ->
?line {ok,Fd} = ?PRIM_FILE:open(Name, [write, exclusive]),
?line {error, eexist} = ?PRIM_FILE:open(Name, [write, exclusive]),
?line ok = ?PRIM_FILE:close(Fd),
- ?line test_server:timetrap_cancel(Dog),
ok.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@@ -681,7 +672,6 @@ exclusive(Config) when is_list(Config) ->
pos1(suite) -> [];
pos1(doc) -> [];
pos1(Config) when is_list(Config) ->
- ?line Dog = test_server:timetrap(test_server:seconds(5)),
?line RootDir = ?config(priv_dir,Config),
?line Name = filename:join(RootDir,
atom_to_list(?MODULE)
@@ -738,13 +728,11 @@ pos1(Config) when is_list(Config) ->
?line {ok, 0} = ?PRIM_FILE:position(Fd2,{eof,-8}),
?line {ok, "A"} = ?PRIM_FILE:read(Fd2,1),
?line {error, einval} = ?PRIM_FILE:position(Fd2,{eof,-9}),
- ?line test_server:timetrap_cancel(Dog),
ok.
pos2(suite) -> [];
pos2(doc) -> [];
pos2(Config) when is_list(Config) ->
- ?line Dog = test_server:timetrap(test_server:seconds(5)),
?line RootDir = ?config(priv_dir,Config),
?line Name = filename:join(RootDir,
atom_to_list(?MODULE)
@@ -761,7 +749,6 @@ pos2(Config) when is_list(Config) ->
?line {ok, "D"} = ?PRIM_FILE:read(Fd2,1),
?line io:format("DONE"),
- ?line test_server:timetrap_cancel(Dog),
ok.
@@ -779,7 +766,6 @@ file_info_basic_file_b(Config) when is_list(Config) ->
Result.
file_info_basic_file(Config, Handle, Suffix) ->
- ?line Dog = test_server:timetrap(test_server:seconds(5)),
?line RootDir = ?config(priv_dir, Config),
%% Create a short file.
@@ -808,7 +794,6 @@ file_info_basic_file(Config, Handle, Suffix) ->
?line {MD, MT} = ModifyTime,
?line all_integers(tuple_to_list(MD) ++ tuple_to_list(MT)),
- ?line test_server:timetrap_cancel(Dog),
ok.
file_info_basic_directory_a(suite) -> [];
@@ -825,8 +810,6 @@ file_info_basic_directory_b(Config) when is_list(Config) ->
Result.
file_info_basic_directory(Config, Handle) ->
- ?line Dog = test_server:timetrap(test_server:seconds(5)),
-
%% Note: filename:join/1 removes any trailing slash,
%% which is essential for ?PRIM_FILE:read_file_info/1 to work on
%% platforms such as Windows95.
@@ -843,10 +826,10 @@ file_info_basic_directory(Config, Handle) ->
?line test_directory("/", read_write, Handle),
?line test_directory("c:/", read_write, Handle),
?line test_directory("c:\\", read_write, Handle);
- {unix, _} ->
+ _ ->
?line test_directory("/", read, Handle)
end,
- ?line test_server:timetrap_cancel(Dog).
+ ok.
test_directory(Name, ExpectedAccess, Handle) ->
?line {ok, FileInfo} = ?PRIM_FILE_call(read_file_info, Handle, [Name]),
@@ -887,14 +870,12 @@ file_info_bad_b(Config) when is_list(Config) ->
Result.
file_info_bad(Config, Handle) ->
- ?line Dog = test_server:timetrap(test_server:seconds(5)),
?line RootDir = filename:join([?config(priv_dir, Config)]),
?line {error, enoent} =
?PRIM_FILE_call(
read_file_info, Handle,
[filename:join(RootDir,
atom_to_list(?MODULE)++"_nonexistent")]),
- ?line test_server:timetrap_cancel(Dog),
ok.
%% Test that the file times behave as they should.
@@ -1189,7 +1170,6 @@ get_good_directory(Config) ->
truncate(suite) -> [];
truncate(doc) -> [];
truncate(Config) when is_list(Config) ->
- ?line Dog = test_server:timetrap(test_server:seconds(5)),
?line RootDir = ?config(priv_dir,Config),
?line Name = filename:join(RootDir,
atom_to_list(?MODULE)
@@ -1215,14 +1195,12 @@ truncate(Config) when is_list(Config) ->
?line {ok, 5} = ?PRIM_FILE:position(Fd2, 5),
?line {error, _} = ?PRIM_FILE:truncate(Fd2),
- ?line test_server:timetrap_cancel(Dog),
ok.
datasync(suite) -> [];
datasync(doc) -> "Tests that ?PRIM_FILE:datasync/1 at least doesn't crash.";
datasync(Config) when is_list(Config) ->
- ?line Dog = test_server:timetrap(test_server:seconds(5)),
?line PrivDir = ?config(priv_dir, Config),
?line Sync = filename:join(PrivDir,
atom_to_list(?MODULE)
@@ -1233,14 +1211,12 @@ datasync(Config) when is_list(Config) ->
?line ok = ?PRIM_FILE:datasync(Fd),
?line ok = ?PRIM_FILE:close(Fd),
- ?line test_server:timetrap_cancel(Dog),
ok.
sync(suite) -> [];
sync(doc) -> "Tests that ?PRIM_FILE:sync/1 at least doesn't crash.";
sync(Config) when is_list(Config) ->
- ?line Dog = test_server:timetrap(test_server:seconds(5)),
?line PrivDir = ?config(priv_dir, Config),
?line Sync = filename:join(PrivDir,
atom_to_list(?MODULE)
@@ -1251,14 +1227,12 @@ sync(Config) when is_list(Config) ->
?line ok = ?PRIM_FILE:sync(Fd),
?line ok = ?PRIM_FILE:close(Fd),
- ?line test_server:timetrap_cancel(Dog),
ok.
advise(suite) -> [];
advise(doc) -> "Tests that ?PRIM_FILE:advise/4 at least doesn't crash.";
advise(Config) when is_list(Config) ->
- ?line Dog = test_server:timetrap(test_server:seconds(5)),
?line PrivDir = ?config(priv_dir, Config),
?line Advise = filename:join(PrivDir,
atom_to_list(?MODULE)
@@ -1322,7 +1296,6 @@ advise(Config) when is_list(Config) ->
?line eof = ?PRIM_FILE:read_line(Fd9),
?line ok = ?PRIM_FILE:close(Fd9),
- ?line test_server:timetrap_cancel(Dog),
ok.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@@ -1366,7 +1339,6 @@ check_large_write(Dog, Fd, _, _, []) ->
allocate(suite) -> [];
allocate(doc) -> "Tests that ?PRIM_FILE:allocate/3 at least doesn't crash.";
allocate(Config) when is_list(Config) ->
- ?line Dog = test_server:timetrap(test_server:seconds(5)),
?line PrivDir = ?config(priv_dir, Config),
?line Allocate = filename:join(PrivDir,
atom_to_list(?MODULE)
@@ -1399,7 +1371,6 @@ allocate(Config) when is_list(Config) ->
?line ok = ?PRIM_FILE:write(Fd4, Line2),
?line ok = ?PRIM_FILE:close(Fd4),
- ?line test_server:timetrap_cancel(Dog),
ok.
allocate_and_assert(Fd, Offset, Length) ->
@@ -1447,7 +1418,6 @@ delete_b(Config) when is_list(Config) ->
Result.
delete(Config, Handle, Suffix) ->
- ?line Dog = test_server:timetrap(test_server:seconds(5)),
?line RootDir = ?config(priv_dir,Config),
?line Name = filename:join(RootDir,
atom_to_list(?MODULE)
@@ -1463,7 +1433,6 @@ delete(Config, Handle, Suffix) ->
?line {error, _} = ?PRIM_FILE:open(Name, [read]),
%% Try deleting a nonexistent file
?line {error, enoent} = ?PRIM_FILE_call(delete, Handle, [Name]),
- ?line test_server:timetrap_cancel(Dog),
ok.
rename_a(suite) ->[];
@@ -1480,7 +1449,6 @@ rename_b(Config) when is_list(Config) ->
Result.
rename(Config, Handle, Suffix) ->
- ?line Dog = test_server:timetrap(test_server:seconds(5)),
?line RootDir = ?config(priv_dir,Config),
?line FileName1 = atom_to_list(?MODULE)++"_rename"++Suffix++".fil",
?line FileName2 = atom_to_list(?MODULE)++"_rename"++Suffix++".ful",
@@ -1533,7 +1501,6 @@ rename(Config, Handle, Suffix) ->
?PRIM_FILE_call(rename, Handle, [DirName2, Name2foo]),
?line io:format("Errmsg2: ~p",[Msg2]),
- ?line test_server:timetrap_cancel(Dog),
ok.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@@ -1568,15 +1535,15 @@ e_delete(Config) when is_list(Config) ->
%% No permission.
?line case os:type() of
- {unix, _} ->
+ {win32, _} ->
+ %% Remove a character device.
+ ?line {error, eacces} = ?PRIM_FILE:delete("nul");
+ _ ->
?line ?PRIM_FILE:write_file_info(
Base, #file_info {mode=0}),
?line {error, eacces} = ?PRIM_FILE:delete(Afile),
?line ?PRIM_FILE:write_file_info(
- Base, #file_info {mode=8#600});
- {win32, _} ->
- %% Remove a character device.
- ?line {error, eacces} = ?PRIM_FILE:delete("nul")
+ Base, #file_info {mode=8#600})
end,
?line test_server:timetrap_cancel(Dog),
@@ -1656,7 +1623,12 @@ e_rename(Config) when is_list(Config) ->
%% XXX - Gross hack!
?line Comment =
case os:type() of
- {unix, _} ->
+ {win32, _} ->
+ %% At least Windows NT can
+ %% successfully move a file to
+ %% another drive.
+ ok;
+ {unix, _ } ->
OtherFs = "/tmp",
?line NameOnOtherFs =
filename:join(OtherFs,
@@ -1681,10 +1653,8 @@ e_rename(Config) when is_list(Config) ->
Else
end,
Com;
- {win32, _} ->
- %% At least Windows NT can
- %% successfully move a file to
- %% another drive.
+ {ose, _} ->
+ %% disabled for now
ok
end,
?line test_server:timetrap_cancel(Dog),
@@ -1714,14 +1684,14 @@ e_make_dir(Config) when is_list(Config) ->
%% No permission (on Unix only).
case os:type() of
- {unix, _} ->
+ {win32, _} ->
+ ok;
+ _ ->
?line ?PRIM_FILE:write_file_info(Base, #file_info {mode=0}),
?line {error, eacces} =
?PRIM_FILE:make_dir(filename:join(Base, "xxxx")),
?line
- ?PRIM_FILE:write_file_info(Base, #file_info {mode=8#600});
- {win32, _} ->
- ok
+ ?PRIM_FILE:write_file_info(Base, #file_info {mode=8#600})
end,
?line test_server:timetrap_cancel(Dog),
ok.
@@ -1767,15 +1737,15 @@ e_del_dir(Config) when is_list(Config) ->
%% No permission.
case os:type() of
- {unix, _} ->
+ {win32, _} ->
+ ok;
+ _ ->
?line ADirectory = filename:join(Base, "no_perm"),
?line ok = ?PRIM_FILE:make_dir(ADirectory),
?line ?PRIM_FILE:write_file_info(Base, #file_info {mode=0}),
?line {error, eacces} = ?PRIM_FILE:del_dir(ADirectory),
?line ?PRIM_FILE:write_file_info(
- Base, #file_info {mode=8#600});
- {win32, _} ->
- ok
+ Base, #file_info {mode=8#600})
end,
?line test_server:timetrap_cancel(Dog),
ok.
@@ -2023,6 +1993,9 @@ symlinks(Config, Handle, Suffix) ->
case ?PRIM_FILE_call(make_symlink, Handle, [Name, Alias]) of
{error, enotsup} ->
{skipped, "Links not supported on this platform"};
+ {error, eperm} ->
+ {win32,_} = os:type(),
+ {skipped, "Windows user not privileged to create links"};
ok ->
?line {ok, Info1} =
?PRIM_FILE_call(read_file_info, Handle, [Name]),
diff --git a/lib/kernel/test/ram_file_SUITE.erl b/lib/kernel/test/ram_file_SUITE.erl
index 5c4437d4d3..615251a257 100644
--- a/lib/kernel/test/ram_file_SUITE.erl
+++ b/lib/kernel/test/ram_file_SUITE.erl
@@ -1,8 +1,7 @@
-%% -*- coding: utf-8 -*-
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2001-2012. All Rights Reserved.
+%% Copyright Ericsson AB 2001-2013. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
diff --git a/lib/kernel/test/sendfile_SUITE.erl b/lib/kernel/test/sendfile_SUITE.erl
index 4cf4c6489d..123e849ccb 100644
--- a/lib/kernel/test/sendfile_SUITE.erl
+++ b/lib/kernel/test/sendfile_SUITE.erl
@@ -24,7 +24,14 @@
-compile(export_all).
-all() ->
+all() -> [{group,async_threads},
+ {group,no_async_threads}].
+
+groups() ->
+ [{async_threads,[],tcs()},
+ {no_async_threads,[],tcs()}].
+
+tcs() ->
[t_sendfile_small
,t_sendfile_big_all
,t_sendfile_big_size
@@ -33,6 +40,7 @@ all() ->
,t_sendfile_offset
,t_sendfile_sendafter
,t_sendfile_recvafter
+ ,t_sendfile_recvafter_remoteclose
,t_sendfile_sendduring
,t_sendfile_recvduring
,t_sendfile_closeduring
@@ -63,6 +71,19 @@ init_per_suite(Config) ->
end_per_suite(Config) ->
file:delete(proplists:get_value(big_file, Config)).
+init_per_group(async_threads,Config) ->
+ case erlang:system_info(thread_pool_size) of
+ 0 ->
+ {skip,"No async threads"};
+ _ ->
+ [{sendfile_opts,[{use_threads,true}]}|Config]
+ end;
+init_per_group(no_async_threads,Config) ->
+ [{sendfile_opts,[{use_threads,false}]}|Config].
+
+end_per_group(_,_Config) ->
+ ok.
+
init_per_testcase(TC,Config) when TC == t_sendfile_recvduring;
TC == t_sendfile_sendduring ->
Filename = proplists:get_value(small_file, Config),
@@ -71,7 +92,7 @@ init_per_testcase(TC,Config) when TC == t_sendfile_recvduring;
{_Size, Data} = sendfile_file_info(Filename),
{ok,D} = file:open(Filename, [raw,binary,read]),
prim_file:sendfile(D, Sock, 0, 0, 0,
- [],[],false,false,false),
+ [],[],[]),
Data
end,
@@ -92,6 +113,7 @@ t_sendfile_small(Config) when is_list(Config) ->
Send = fun(Sock) ->
{Size, Data} = sendfile_file_info(Filename),
+ %% Here we make sure to test the sendfile/2 api
{ok, Size} = file:sendfile(Filename, Sock),
Data
end,
@@ -101,6 +123,7 @@ t_sendfile_small(Config) when is_list(Config) ->
t_sendfile_many_small(Config) when is_list(Config) ->
Filename = proplists:get_value(small_file, Config),
FileOpts = proplists:get_value(file_opts, Config, []),
+ SendfileOpts = proplists:get_value(sendfile_opts, Config),
error_logger:add_report_handler(?MODULE,[self()]),
@@ -109,7 +132,7 @@ t_sendfile_many_small(Config) when is_list(Config) ->
N = 10000,
{ok,D} = file:open(Filename,[read|FileOpts]),
[begin
- {ok,Size} = file:sendfile(D,Sock,0,0,[])
+ {ok,Size} = file:sendfile(D,Sock,0,0,SendfileOpts)
end || _I <- lists:seq(1,N)],
file:close(D),
Size*N
@@ -127,11 +150,12 @@ t_sendfile_many_small(Config) when is_list(Config) ->
t_sendfile_big_all(Config) when is_list(Config) ->
Filename = proplists:get_value(big_file, Config),
+ SendfileOpts = proplists:get_value(sendfile_opts, Config),
Send = fun(Sock) ->
{ok, #file_info{size = Size}} =
file:read_file_info(Filename),
- {ok, Size} = file:sendfile(Filename, Sock),
+ {ok, Size} = sendfile(Filename, Sock, SendfileOpts),
Size
end,
@@ -140,12 +164,13 @@ t_sendfile_big_all(Config) when is_list(Config) ->
t_sendfile_big_size(Config) ->
Filename = proplists:get_value(big_file, Config),
FileOpts = proplists:get_value(file_opts, Config, []),
+ SendfileOpts = proplists:get_value(sendfile_opts, Config),
SendAll = fun(Sock) ->
{ok, #file_info{size = Size}} =
file:read_file_info(Filename),
{ok,D} = file:open(Filename,[read|FileOpts]),
- {ok, Size} = file:sendfile(D, Sock,0,Size,[]),
+ {ok, Size} = file:sendfile(D, Sock,0,Size,SendfileOpts),
Size
end,
@@ -154,12 +179,13 @@ t_sendfile_big_size(Config) ->
t_sendfile_partial(Config) ->
Filename = proplists:get_value(small_file, Config),
FileOpts = proplists:get_value(file_opts, Config, []),
+ SendfileOpts = proplists:get_value(sendfile_opts, Config),
SendSingle = fun(Sock) ->
{_Size, <<Data:5/binary,_/binary>>} =
sendfile_file_info(Filename),
{ok,D} = file:open(Filename,[read|FileOpts]),
- {ok,5} = file:sendfile(D,Sock,0,5,[]),
+ {ok,5} = file:sendfile(D,Sock,0,5,SendfileOpts),
file:close(D),
Data
end,
@@ -170,14 +196,14 @@ t_sendfile_partial(Config) ->
{ok,D} = file:open(Filename,[read|FileOpts]),
{ok, <<FData/binary>>} = file:read(D,5),
FSend = fun(Sock) ->
- {ok,5} = file:sendfile(D,Sock,0,5,[]),
+ {ok,5} = file:sendfile(D,Sock,0,5,SendfileOpts),
FData
end,
ok = sendfile_send(FSend),
SSend = fun(Sock) ->
- {ok,3} = file:sendfile(D,Sock,5,3,[]),
+ {ok,3} = file:sendfile(D,Sock,5,3,SendfileOpts),
SData
end,
@@ -190,12 +216,13 @@ t_sendfile_partial(Config) ->
t_sendfile_offset(Config) ->
Filename = proplists:get_value(small_file, Config),
FileOpts = proplists:get_value(file_opts, Config, []),
+ SendfileOpts = proplists:get_value(sendfile_opts, Config),
Send = fun(Sock) ->
{_Size, <<_:5/binary,Data:3/binary,_/binary>> = AllData} =
sendfile_file_info(Filename),
{ok,D} = file:open(Filename,[read|FileOpts]),
- {ok,3} = file:sendfile(D,Sock,5,3,[]),
+ {ok,3} = file:sendfile(D,Sock,5,3,SendfileOpts),
{ok, AllData} = file:read(D,100),
file:close(D),
Data
@@ -205,10 +232,11 @@ t_sendfile_offset(Config) ->
t_sendfile_sendafter(Config) ->
Filename = proplists:get_value(small_file, Config),
+ SendfileOpts = proplists:get_value(sendfile_opts, Config),
Send = fun(Sock) ->
{Size, Data} = sendfile_file_info(Filename),
- {ok, Size} = file:sendfile(Filename, Sock),
+ {ok, Size} = sendfile(Filename, Sock, SendfileOpts),
ok = gen_tcp:send(Sock, <<2>>),
<<Data/binary,2>>
end,
@@ -217,10 +245,11 @@ t_sendfile_sendafter(Config) ->
t_sendfile_recvafter(Config) ->
Filename = proplists:get_value(small_file, Config),
+ SendfileOpts = proplists:get_value(sendfile_opts, Config),
Send = fun(Sock) ->
{Size, Data} = sendfile_file_info(Filename),
- {ok, Size} = file:sendfile(Filename, Sock),
+ {ok, Size} = sendfile(Filename, Sock, SendfileOpts),
ok = gen_tcp:send(Sock, <<1>>),
{ok,<<1>>} = gen_tcp:recv(Sock, 1),
<<Data/binary,1>>
@@ -228,8 +257,28 @@ t_sendfile_recvafter(Config) ->
ok = sendfile_send(Send).
+%% This tests specifically for a bug fixed in 17.0
+t_sendfile_recvafter_remoteclose(Config) ->
+ Filename = proplists:get_value(small_file, Config),
+
+ Send = fun(Sock, SFServer) ->
+ {Size, _Data} = sendfile_file_info(Filename),
+ {ok, Size} = file:sendfile(Filename, Sock),
+
+ %% Make sure the remote end has been closed
+ SFServer ! stop,
+ timer:sleep(100),
+
+ %% In the bug this returned {error,ebadf}
+ {error,closed} = gen_tcp:recv(Sock, 1),
+ -1
+ end,
+
+ ok = sendfile_send({127,0,0,1},Send,0).
+
t_sendfile_sendduring(Config) ->
Filename = proplists:get_value(big_file, Config),
+ SendfileOpts = proplists:get_value(sendfile_opts, Config),
Send = fun(Sock) ->
{ok, #file_info{size = Size}} =
@@ -238,7 +287,7 @@ t_sendfile_sendduring(Config) ->
timer:sleep(50),
ok = gen_tcp:send(Sock, <<2>>)
end),
- {ok, Size} = file:sendfile(Filename, Sock),
+ {ok, Size} = sendfile(Filename, Sock, SendfileOpts),
Size+1
end,
@@ -246,6 +295,7 @@ t_sendfile_sendduring(Config) ->
t_sendfile_recvduring(Config) ->
Filename = proplists:get_value(big_file, Config),
+ SendfileOpts = proplists:get_value(sendfile_opts, Config),
Send = fun(Sock) ->
{ok, #file_info{size = Size}} =
@@ -255,7 +305,7 @@ t_sendfile_recvduring(Config) ->
ok = gen_tcp:send(Sock, <<1>>),
{ok,<<1>>} = gen_tcp:recv(Sock, 1)
end),
- {ok, Size} = file:sendfile(Filename, Sock),
+ {ok, Size} = sendfile(Filename, Sock, SendfileOpts),
timer:sleep(1000),
Size+1
end,
@@ -264,6 +314,7 @@ t_sendfile_recvduring(Config) ->
t_sendfile_closeduring(Config) ->
Filename = proplists:get_value(big_file, Config),
+ SendfileOpts = proplists:get_value(sendfile_opts, Config),
Send = fun(Sock,SFServPid) ->
spawn_link(fun() ->
@@ -272,13 +323,14 @@ t_sendfile_closeduring(Config) ->
end),
case erlang:system_info(thread_pool_size) of
0 ->
- {error, closed} = file:sendfile(Filename, Sock);
+ {error, closed} = sendfile(Filename, Sock,
+ SendfileOpts);
_Else ->
%% This can return how much has been sent or
%% {error,closed} depending on OS.
%% How much is sent impossible to know as
%% the socket was closed mid sendfile
- case file:sendfile(Filename, Sock) of
+ case sendfile(Filename, Sock, SendfileOpts) of
{error, closed} ->
ok;
{ok, Size} when is_integer(Size) ->
@@ -292,6 +344,7 @@ t_sendfile_closeduring(Config) ->
t_sendfile_crashduring(Config) ->
Filename = proplists:get_value(big_file, Config),
+ SendfileOpts = proplists:get_value(sendfile_opts, Config),
error_logger:add_report_handler(?MODULE,[self()]),
@@ -300,7 +353,7 @@ t_sendfile_crashduring(Config) ->
timer:sleep(50),
exit(die)
end),
- {error, closed} = file:sendfile(Filename, Sock),
+ {error, closed} = sendfile(Filename, Sock, SendfileOpts),
-1
end,
process_flag(trap_exit,true),
@@ -395,6 +448,16 @@ sendfile_file_info(File) ->
{ok, Data} = file:read_file(File),
{Size, Data}.
+sendfile(Filename,Sock,Opts) ->
+ case file:open(Filename, [read, raw, binary]) of
+ {error, Reason} ->
+ {error, Reason};
+ {ok, Fd} ->
+ Res = file:sendfile(Fd, Sock, 0, 0, Opts),
+ _ = file:close(Fd),
+ Res
+ end.
+
%% Error handler
diff --git a/lib/kernel/test/zlib_SUITE.erl b/lib/kernel/test/zlib_SUITE.erl
index e91f6f18d4..3be6f39d95 100644
--- a/lib/kernel/test/zlib_SUITE.erl
+++ b/lib/kernel/test/zlib_SUITE.erl
@@ -178,7 +178,7 @@ api_deflateInit(Config) when is_list(Config) ->
?m(ok,zlib:close(Z))
end, lists:seq(1,8)),
- Strategies = [filtered,huffman_only,default],
+ Strategies = [filtered,huffman_only,rle,default],
lists:foreach(fun(Strategy) ->
?line Z = zlib:open(),
?m(ok, zlib:deflateInit(Z,best_speed,deflated,-15,8,Strategy)),
@@ -220,7 +220,6 @@ api_deflateParams(Config) when is_list(Config) ->
?m(_, zlib:deflate(Z1, <<1,1,1,1,1,1,1,1,1>>, none)),
?m(ok, zlib:deflateParams(Z1, best_compression, huffman_only)),
?m(_, zlib:deflate(Z1, <<1,1,1,1,1,1,1,1,1>>, sync)),
- ?m({'EXIT',_}, zlib:deflateParams(Z1,best_speed, filtered)),
?m(ok, zlib:close(Z1)).
api_deflate(doc) -> "Test deflate";
diff --git a/lib/kernel/vsn.mk b/lib/kernel/vsn.mk
index 12fe0a7637..dd5316b825 100644
--- a/lib/kernel/vsn.mk
+++ b/lib/kernel/vsn.mk
@@ -1 +1 @@
-KERNEL_VSN = 2.16.4
+KERNEL_VSN = 3.0