aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--bootstrap/lib/compiler/ebin/compile.beambin39328 -> 39368 bytes
-rw-r--r--bootstrap/lib/compiler/ebin/compiler.app4
-rw-r--r--bootstrap/lib/kernel/ebin/inet_dns.beambin19772 -> 19808 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/inet_tcp_dist.beambin6876 -> 6808 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/kernel.app2
-rw-r--r--bootstrap/lib/stdlib/ebin/c.beambin14096 -> 14660 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/erl_anno.beambin5060 -> 5008 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/erl_lint.beambin89616 -> 89464 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/ets.beambin22396 -> 22604 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/gb_sets.beambin8284 -> 8432 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/gb_trees.beambin4988 -> 5176 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/maps.beambin2304 -> 2628 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/shell_default.beambin3884 -> 3932 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/stdlib.app2
-rw-r--r--erts/configure.in1
-rw-r--r--erts/doc/src/erlang.xml358
-rw-r--r--erts/doc/src/notes.xml502
-rw-r--r--erts/emulator/beam/erl_alloc_util.c61
-rw-r--r--erts/emulator/beam/erl_process.c151
-rw-r--r--erts/emulator/sys/unix/erl_child_setup.c16
-rw-r--r--erts/preloaded/src/erts.app.src2
-rw-r--r--lib/asn1/doc/src/notes.xml17
-rw-r--r--lib/asn1/vsn.mk2
-rw-r--r--lib/common_test/doc/src/notes.xml73
-rw-r--r--lib/compiler/doc/src/notes.xml88
-rw-r--r--lib/compiler/src/beam_bsm.erl6
-rw-r--r--lib/compiler/src/compile.erl6
-rw-r--r--lib/compiler/src/compiler.app.src4
-rw-r--r--lib/compiler/test/warnings_SUITE.erl17
-rw-r--r--lib/compiler/vsn.mk2
-rw-r--r--lib/cosEvent/doc/src/notes.xml18
-rw-r--r--lib/cosEventDomain/doc/src/notes.xml18
-rw-r--r--lib/cosFileTransfer/doc/src/notes.xml18
-rw-r--r--lib/cosNotification/doc/src/notes.xml18
-rw-r--r--lib/cosProperty/doc/src/notes.xml18
-rw-r--r--lib/cosTime/doc/src/notes.xml18
-rw-r--r--lib/cosTransactions/doc/src/notes.xml18
-rw-r--r--lib/crypto/doc/src/notes.xml43
-rw-r--r--lib/crypto/vsn.mk2
-rw-r--r--lib/debugger/doc/src/notes.xml18
-rw-r--r--lib/debugger/vsn.mk2
-rw-r--r--lib/dialyzer/doc/src/dialyzer.xml1
-rw-r--r--lib/dialyzer/doc/src/notes.xml86
-rw-r--r--lib/dialyzer/src/dialyzer.erl39
-rw-r--r--lib/dialyzer/test/plt_SUITE.erl85
-rw-r--r--lib/dialyzer/vsn.mk2
-rw-r--r--lib/edoc/doc/src/notes.xml15
-rw-r--r--lib/edoc/vsn.mk2
-rw-r--r--lib/eldap/doc/src/eldap.xml4
-rw-r--r--lib/eldap/doc/src/notes.xml16
-rw-r--r--lib/erl_docgen/vsn.mk2
-rw-r--r--lib/eunit/doc/overview.edoc15
-rw-r--r--lib/eunit/doc/src/notes.xml14
-rw-r--r--lib/eunit/include/eunit.hrl20
-rw-r--r--lib/eunit/vsn.mk2
-rw-r--r--lib/hipe/doc/src/notes.xml36
-rw-r--r--lib/hipe/vsn.mk2
-rw-r--r--lib/inets/doc/src/notes.xml12
-rw-r--r--lib/inets/src/http_server/httpd_request.erl8
-rw-r--r--lib/inets/vsn.mk2
-rw-r--r--lib/jinterface/doc/src/notes.xml53
-rw-r--r--lib/jinterface/java_src/com/ericsson/otp/erlang/OtpSelf.java3
-rw-r--r--lib/jinterface/vsn.mk2
-rw-r--r--lib/kernel/doc/src/notes.xml73
-rw-r--r--lib/kernel/src/application_controller.erl3
-rw-r--r--lib/kernel/src/code.erl2
-rw-r--r--lib/kernel/src/inet_tcp_dist.erl2
-rw-r--r--lib/kernel/src/kernel.app.src2
-rw-r--r--lib/kernel/vsn.mk2
-rw-r--r--lib/mnesia/doc/src/notes.xml32
-rw-r--r--lib/mnesia/vsn.mk2
-rw-r--r--lib/observer/doc/src/notes.xml22
-rw-r--r--lib/observer/vsn.mk2
-rw-r--r--lib/orber/doc/src/notes.xml18
-rw-r--r--lib/orber/src/orber.app.src2
-rw-r--r--lib/os_mon/doc/src/notes.xml19
-rw-r--r--lib/os_mon/vsn.mk2
-rw-r--r--lib/parsetools/doc/src/notes.xml15
-rw-r--r--lib/parsetools/vsn.mk2
-rw-r--r--lib/percept/doc/src/notes.xml15
-rw-r--r--lib/percept/vsn.mk2
-rw-r--r--lib/public_key/doc/src/notes.xml31
-rw-r--r--lib/sasl/doc/src/notes.xml24
-rw-r--r--lib/sasl/vsn.mk2
-rw-r--r--lib/ssh/doc/src/notes.xml61
-rw-r--r--lib/ssh/doc/src/ssh.xml62
-rw-r--r--lib/ssh/doc/src/ssh_channel.xml32
-rw-r--r--lib/ssh/doc/src/ssh_client_key_api.xml20
-rw-r--r--lib/ssh/doc/src/ssh_connection.xml42
-rw-r--r--lib/ssh/doc/src/ssh_server_key_api.xml24
-rw-r--r--lib/ssh/doc/src/ssh_sftp.xml4
-rw-r--r--lib/ssh/doc/src/ssh_sftpd.xml16
-rw-r--r--lib/ssh/src/ssh.erl4
-rw-r--r--lib/ssh/src/ssh_connection_handler.erl261
-rw-r--r--lib/ssh/test/Makefile3
-rw-r--r--lib/ssh/test/ssh_basic_SUITE.erl267
-rw-r--r--lib/ssh/test/ssh_relay.erl407
-rw-r--r--lib/ssl/doc/src/notes.xml63
-rw-r--r--lib/ssl/doc/src/ssl.xml12
-rw-r--r--lib/ssl/doc/src/ssl_crl_cache_api.xml8
-rw-r--r--lib/ssl/doc/src/ssl_session_cache_api.xml20
-rw-r--r--lib/ssl/test/ssl_alpn_handshake_SUITE.erl6
-rw-r--r--lib/ssl/test/ssl_basic_SUITE.erl12
-rw-r--r--lib/ssl/test/ssl_npn_handshake_SUITE.erl6
-rw-r--r--lib/ssl/test/ssl_sni_SUITE.erl51
-rw-r--r--lib/ssl/test/ssl_test_lib.erl3
-rw-r--r--lib/ssl/test/ssl_to_openssl_SUITE.erl53
-rw-r--r--lib/stdlib/doc/src/c.xml8
-rw-r--r--lib/stdlib/doc/src/ets.xml4
-rw-r--r--lib/stdlib/doc/src/gb_sets.xml13
-rw-r--r--lib/stdlib/doc/src/gb_trees.xml13
-rw-r--r--lib/stdlib/doc/src/maps.xml22
-rw-r--r--lib/stdlib/doc/src/notes.xml218
-rw-r--r--lib/stdlib/src/c.erl23
-rw-r--r--lib/stdlib/src/erl_anno.erl2
-rw-r--r--lib/stdlib/src/erl_lint.erl11
-rw-r--r--lib/stdlib/src/ets.erl43
-rw-r--r--lib/stdlib/src/gb_sets.erl24
-rw-r--r--lib/stdlib/src/gb_trees.erl31
-rw-r--r--lib/stdlib/src/maps.erl21
-rw-r--r--lib/stdlib/src/shell_default.erl3
-rw-r--r--lib/stdlib/src/stdlib.app.src2
-rw-r--r--lib/stdlib/test/dict_SUITE.erl50
-rw-r--r--lib/stdlib/test/dict_test_lib.erl5
-rw-r--r--lib/stdlib/test/ets_SUITE.erl17
-rw-r--r--lib/stdlib/test/maps_SUITE.erl21
-rw-r--r--lib/stdlib/test/sets_SUITE.erl44
-rw-r--r--lib/stdlib/test/sets_test_lib.erl5
-rw-r--r--lib/stdlib/vsn.mk2
-rw-r--r--lib/syntax_tools/doc/src/notes.xml14
-rw-r--r--lib/syntax_tools/vsn.mk2
-rw-r--r--lib/test_server/doc/src/notes.xml49
-rw-r--r--lib/test_server/src/erl2html2.erl18
-rw-r--r--lib/test_server/test/erl2html2_SUITE.erl66
-rw-r--r--lib/test_server/test/erl2html2_SUITE_data/include/header3.hrl1
-rw-r--r--lib/test_server/test/erl2html2_SUITE_data/m1.erl6
-rw-r--r--lib/tools/doc/src/cprof.xml2
-rw-r--r--lib/tools/doc/src/notes.xml59
-rw-r--r--lib/tools/vsn.mk2
-rw-r--r--lib/typer/doc/src/notes.xml14
-rw-r--r--lib/typer/vsn.mk2
-rw-r--r--lib/webtool/doc/src/notes.xml17
-rw-r--r--lib/wx/c_src/wxe_driver.c11
-rw-r--r--lib/wx/c_src/wxe_impl.cpp14
-rw-r--r--lib/wx/c_src/wxe_impl.h3
-rw-r--r--lib/wx/doc/src/notes.xml49
-rw-r--r--lib/wx/vsn.mk2
-rw-r--r--lib/xmerl/doc/src/notes.xml14
-rw-r--r--otp_versions.table1
149 files changed, 1976 insertions, 2589 deletions
diff --git a/bootstrap/lib/compiler/ebin/compile.beam b/bootstrap/lib/compiler/ebin/compile.beam
index e648a70b2f..111f85acd2 100644
--- a/bootstrap/lib/compiler/ebin/compile.beam
+++ b/bootstrap/lib/compiler/ebin/compile.beam
Binary files differ
diff --git a/bootstrap/lib/compiler/ebin/compiler.app b/bootstrap/lib/compiler/ebin/compiler.app
index 39635bd447..dfe077d5b9 100644
--- a/bootstrap/lib/compiler/ebin/compiler.app
+++ b/bootstrap/lib/compiler/ebin/compiler.app
@@ -69,5 +69,5 @@
{registered, []},
{applications, [kernel, stdlib]},
{env, []},
- {runtime_dependencies, ["stdlib-2.0","kernel-3.0","hipe-3.10.3","erts-7.0",
- "crypto-3.3"]}]}.
+ {runtime_dependencies, ["stdlib-2.5","kernel-4.0","hipe-3.12","erts-7.0",
+ "crypto-3.6"]}]}.
diff --git a/bootstrap/lib/kernel/ebin/inet_dns.beam b/bootstrap/lib/kernel/ebin/inet_dns.beam
index 6d04559d9a..0c5b6c73e1 100644
--- a/bootstrap/lib/kernel/ebin/inet_dns.beam
+++ b/bootstrap/lib/kernel/ebin/inet_dns.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/inet_tcp_dist.beam b/bootstrap/lib/kernel/ebin/inet_tcp_dist.beam
index c322eb9fdc..a3635e5dde 100644
--- a/bootstrap/lib/kernel/ebin/inet_tcp_dist.beam
+++ b/bootstrap/lib/kernel/ebin/inet_tcp_dist.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/kernel.app b/bootstrap/lib/kernel/ebin/kernel.app
index e2cc4bac63..bfeea49e91 100644
--- a/bootstrap/lib/kernel/ebin/kernel.app
+++ b/bootstrap/lib/kernel/ebin/kernel.app
@@ -115,6 +115,6 @@
{applications, []},
{env, [{error_logger, tty}]},
{mod, {kernel, []}},
- {runtime_dependencies, ["erts-7.0", "stdlib-2.0", "sasl-2.4"]}
+ {runtime_dependencies, ["erts-7.0", "stdlib-2.5", "sasl-2.4"]}
]
}.
diff --git a/bootstrap/lib/stdlib/ebin/c.beam b/bootstrap/lib/stdlib/ebin/c.beam
index a08df44eb7..0e07dc1531 100644
--- a/bootstrap/lib/stdlib/ebin/c.beam
+++ b/bootstrap/lib/stdlib/ebin/c.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/erl_anno.beam b/bootstrap/lib/stdlib/ebin/erl_anno.beam
index f30442bc06..a07f730e99 100644
--- a/bootstrap/lib/stdlib/ebin/erl_anno.beam
+++ b/bootstrap/lib/stdlib/ebin/erl_anno.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/erl_lint.beam b/bootstrap/lib/stdlib/ebin/erl_lint.beam
index 7c80cbe624..5a8bc2a7f1 100644
--- a/bootstrap/lib/stdlib/ebin/erl_lint.beam
+++ b/bootstrap/lib/stdlib/ebin/erl_lint.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/ets.beam b/bootstrap/lib/stdlib/ebin/ets.beam
index 6f2085cf22..7d30fc9fc1 100644
--- a/bootstrap/lib/stdlib/ebin/ets.beam
+++ b/bootstrap/lib/stdlib/ebin/ets.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/gb_sets.beam b/bootstrap/lib/stdlib/ebin/gb_sets.beam
index cf763f51a0..71da2376ba 100644
--- a/bootstrap/lib/stdlib/ebin/gb_sets.beam
+++ b/bootstrap/lib/stdlib/ebin/gb_sets.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/gb_trees.beam b/bootstrap/lib/stdlib/ebin/gb_trees.beam
index 6660dcb787..db59d5af19 100644
--- a/bootstrap/lib/stdlib/ebin/gb_trees.beam
+++ b/bootstrap/lib/stdlib/ebin/gb_trees.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/maps.beam b/bootstrap/lib/stdlib/ebin/maps.beam
index 5209c7cfd8..d1aa8bb9dd 100644
--- a/bootstrap/lib/stdlib/ebin/maps.beam
+++ b/bootstrap/lib/stdlib/ebin/maps.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/shell_default.beam b/bootstrap/lib/stdlib/ebin/shell_default.beam
index fa64e33080..f295c9f116 100644
--- a/bootstrap/lib/stdlib/ebin/shell_default.beam
+++ b/bootstrap/lib/stdlib/ebin/shell_default.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/stdlib.app b/bootstrap/lib/stdlib/ebin/stdlib.app
index 50eb39d712..92ecc16b4c 100644
--- a/bootstrap/lib/stdlib/ebin/stdlib.app
+++ b/bootstrap/lib/stdlib/ebin/stdlib.app
@@ -104,7 +104,7 @@
dets]},
{applications, [kernel]},
{env, []},
- {runtime_dependencies, ["sasl-2.4","kernel-3.0.2","erts-7.0","crypto-3.3",
+ {runtime_dependencies, ["sasl-2.4","kernel-4.0","erts-7.0","crypto-3.3",
"compiler-5.0"]}
]}.
diff --git a/erts/configure.in b/erts/configure.in
index 62515fe081..39d3c51e3f 100644
--- a/erts/configure.in
+++ b/erts/configure.in
@@ -649,6 +649,7 @@ case $chk_arch_ in
powerpc) ARCH=ppc;;
ppc) ARCH=ppc;;
ppc64) ARCH=ppc64;;
+ ppc64le) ARCH=ppc64;;
"Power Macintosh") ARCH=ppc;;
armv5b) ARCH=arm;;
armv5teb) ARCH=arm;;
diff --git a/erts/doc/src/erlang.xml b/erts/doc/src/erlang.xml
index 6ca57566aa..3fea64cef5 100644
--- a/erts/doc/src/erlang.xml
+++ b/erts/doc/src/erlang.xml
@@ -539,55 +539,94 @@
<name name="cancel_timer" arity="2"/>
<fsummary>Cancel a timer</fsummary>
<desc>
- <p>Cancels a timer. <c><anno>TimerRef</anno></c> needs to refer to
- a timer that was created by either
- <seealso marker="#send_after/4"><c>erlang:send_after()</c></seealso>,
- or <seealso marker="#start_timer/4"><c>erlang:start_timer()</c></seealso>.</p>
- <p>Currently available <c><anno>Option</anno>s</c>:</p>
+ <p>
+ Cancels a timer that has been created by either
+ <seealso marker="#start_timer/4"><c>erlang:start_timer()</c></seealso>,
+ or <seealso marker="#send_after/4"><c>erlang:send_after()</c></seealso>.
+ <c><anno>TimerRef</anno></c> identifies the timer, and
+ was returned by the BIF that created the timer.
+ </p>
+ <p>Currently available <c><anno>Option</anno></c>s:</p>
<taglist>
<tag><c>{async, Async}</c></tag>
<item>
- <p>Asynchronous request for cancellation. <c>Async</c>
- defaults to <c>false</c>. That is the operation will be
- performed synchronously. When <c>Async</c> is set to
- <c>true</c> the cancel operation will be performed
- asynchronously. That is, <c>cancel_timer()</c> will send
- a request for cancellation to the timer service that
- manages the timer, and then return <c>ok</c>.</p></item>
+ <p>
+ Asynchronous request for cancellation. <c>Async</c>
+ defaults to <c>false</c> which will cause the
+ cancellation to be performed synchronously. When
+ <c>Async</c> is set to <c>true</c>, the cancel
+ operation will be performed asynchronously. That is,
+ <c>erlang:cancel_timer()</c> will send an asynchronous
+ request for cancellation to the timer service that
+ manages the timer, and then return <c>ok</c>.
+ </p>
+ </item>
<tag><c>{info, Info}</c></tag>
<item>
- <p>Request information about the <c>Result</c> of the
- cancellation. <c>Info</c> defaults to <c>true</c>. That
- is information will be given. When <c>Info</c> is set to
- <c>false</c> no information about the result of the cancel
- operation will be given. When the operation is performed
- synchronously the <c>Result</c> will returned from
- <c>cancel_timer()</c>. When the operation is performed
- asynchronously, a message on the form
- <c>{cancel_timer, <anno>TimerRef</anno>, <anno>Result</anno>}</c>
- will be sent to the caller of <c>cancel_timer()</c> when
- the operation has been performed.</p></item>
+ <p>
+ Request information about the <c><anno>Result</anno></c>
+ of the cancellation. <c>Info</c> defaults to <c>true</c>
+ which means that the <c><anno>Result</anno></c> will
+ be given. When <c>Info</c> is set to <c>false</c>, no
+ information about the result of the cancellation
+ will be given. When the operation is performed</p>
+ <taglist>
+ <tag>synchronously</tag>
+ <item>
+ <p>
+ If <c>Info</c> is <c>true</c>, the <c>Result</c> will
+ returned by <c>erlang:cancel_timer()</c>; otherwise,
+ <c>ok</c> will be returned.
+ </p>
+ </item>
+ <tag>asynchronously</tag>
+ <item>
+ <p>
+ If <c>Info</c> is <c>true</c>, a message on the form
+ <c>{cancel_timer, <anno>TimerRef</anno>,
+ <anno>Result</anno>}</c> will be sent to the
+ caller of <c>erlang:cancel_timer()</c> when the
+ cancellation operation has been performed; otherwise,
+ no message will be sent.
+ </p>
+ </item>
+ </taglist>
+ </item>
</taglist>
- <p>When the <c><anno>Result</anno></c> equals <c>false</c> a timer
- corresponding to <c><anno>TimerRef</anno></c> could not be found. This
- can be either because the timer had expired, been canceled, or because
- <c><anno>TimerRef</anno></c> do not correspond to a timer. When the
- <c><anno>Result</anno></c> is an integer, it represents
- the time in milli seconds left before the timer will expire.</p>
- <note><p>The timer service that manages the timer may be co-located
- with another scheduler than the scheduler that the calling process
- is executing on. In this case communication with the timer
- service will be performed using asynchronous signals. If the calling
- process is in critical path and can do other things while waiting
- for the result of this operation, you want to use the <c>{async, true}</c>
- option.</p></note>
+ <p>
+ More <c><anno>Option</anno></c>s may be added in the future.
+ </p>
+ <p>
+ When the <c><anno>Result</anno></c> equals <c>false</c>, a
+ timer corresponding to <c><anno>TimerRef</anno></c> could not
+ be found. This can be either because the timer had expired,
+ already had been canceled, or because <c><anno>TimerRef</anno></c>
+ never has corresponded to a timer. If the timer has expired,
+ the timeout message has been sent, but it does not tell you
+ whether or not it has arrived at its destination yet. When the
+ <c><anno>Result</anno></c> is an integer, it represents the
+ time in milli-seconds left until the timer will expire.
+ </p>
+ <note>
+ <p>
+ The timer service that manages the timer may be co-located
+ with another scheduler than the scheduler that the calling
+ process is executing on. If this is the case, communication
+ with the timer service will take much longer time than if it
+ is located locally. If the calling process is in critical
+ path, and can do other things while waiting for the result
+ of this operation, or is not interested in the result of
+ the operation, you want to use the <c>{async, true}</c>
+ option. If using the <c>{async, false}</c> option, the calling
+ process will be blocked until the operation has been
+ performed.
+ </p>
+ </note>
<p>See also
<seealso marker="#send_after/4"><c>erlang:send_after/4</c></seealso>,
<seealso marker="#start_timer/4"><c>erlang:start_timer/4</c></seealso>,
and
<seealso marker="#read_timer/2"><c>erlang:read_timer/2</c></seealso>.</p>
- <p>Note: Cancelling a timer does not guarantee that the message
- has not already been delivered to the message queue.</p>
</desc>
</func>
<func>
@@ -596,7 +635,7 @@
<desc>
<p>Cancels a timer. The same as calling
<seealso marker="#cancel_timer/2"><c>erlang:cancel_timer(TimerRef,
- [{async, false}, {info, true}])</c></seealso>.</p>
+ [])</c></seealso>.</p>
</desc>
</func>
<func>
@@ -4548,37 +4587,60 @@ os_prompt% </pre>
<name name="read_timer" arity="2"/>
<fsummary>Read the state of a timer</fsummary>
<desc>
- <p>Read the state of a timer. <c><anno>TimerRef</anno></c>
- needs to refer to a timer that was created by either
- <seealso marker="#send_after/4"><c>erlang:send_after()</c></seealso>,
- or <seealso marker="#start_timer/4"><c>erlang:start_timer()</c></seealso>.</p>
+ <p>
+ Read the state of a timer that has been created by either
+ <seealso marker="#start_timer/4"><c>erlang:start_timer()</c></seealso>,
+ or <seealso marker="#send_after/4"><c>erlang:send_after()</c></seealso>.
+ <c><anno>TimerRef</anno></c> identifies the timer, and
+ was returned by the BIF that created the timer.
+ </p>
<p>Currently available <c><anno>Option</anno>s</c>:</p>
<taglist>
<tag><c>{async, Async}</c></tag>
<item>
- <p>Asynchronous request. <c>Async</c> defaults to <c>false</c>. That
- is the operation will be performed synchronously, and the <c>Result</c>
- will returned from <c>read_timer()</c>. When <c>Async</c> is set to
- <c>true</c>, <c>read_timer()</c> will send a request for the
- <c>Result</c> to a timer service that manages the timer and then
- return <c>ok</c>. A message on the format
- <c>{read_timer, <anno>TimerRef</anno>, <anno>Result</anno>}</c>
- will be sent to the caller of <c>read_timer()</c> when
- the operation has been processed.</p></item>
+ <p>
+ Asynchronous request for state information. <c>Async</c>
+ defaults to <c>false</c> which will cause the operation
+ to be performed synchronously. In this case, the <c>Result</c>
+ will be returned by <c>erlang:read_timer()</c>. When
+ <c>Async</c> is set to <c>true</c>, <c>erlang:read_timer()</c>
+ will send an asynchronous request for the state information
+ to the timer service that manages the timer, and then return
+ <c>ok</c>. A message on the format <c>{read_timer,
+ <anno>TimerRef</anno>, <anno>Result</anno>}</c> will be
+ sent to the caller of <c>erlang:read_timer()</c> when the
+ operation has been processed.
+ </p>
+ </item>
</taglist>
- <p>When the <c><anno>Result</anno></c> equals <c>false</c> a timer
- corresponding to <c><anno>TimerRef</anno></c> could not be found. This
- can be either because the timer had expired, been canceled, or because
- <c><anno>TimerRef</anno></c> do not correspond to a timer. When the
- <c><anno>Result</anno></c> is an integer, it represents
- the time in milli seconds left before the timer will expire.</p>
- <note><p>The timer service that manages the timer may be co-located
- with another scheduler than the scheduler that the calling process
- is executing on. In this case communication with the timer
- service will be performed using asynchronous signals. If the calling
- process is in critical path and can do other things while waiting
- for the result of this operation, you want to use the <c>{async, true}</c>
- option.</p></note>
+ <p>
+ More <c><anno>Option</anno></c>s may be added in the future.
+ </p>
+ <p>
+ When the <c><anno>Result</anno></c> equals <c>false</c>, a
+ timer corresponding to <c><anno>TimerRef</anno></c> could not
+ be found. This can be either because the timer had expired,
+ had been canceled, or because <c><anno>TimerRef</anno></c>
+ never has corresponded to a timer. If the timer has expired,
+ the timeout message has been sent, but it does not tell you
+ whether or not it has arrived at its destination yet. When the
+ <c><anno>Result</anno></c> is an integer, it represents the
+ time in milli-seconds left until the timer will expire.
+ </p>
+ <note>
+ <p>
+ The timer service that manages the timer may be co-located
+ with another scheduler than the scheduler that the calling
+ process is executing on. If this is the case, communication
+ with the timer service will take much longer time than if it
+ is located locally. If the calling process is in critical
+ path, and can do other things while waiting for the result
+ of this operation you want to use the <c>{async, true}</c>
+ option. If using the <c>{async, false}</c> option, the calling
+ process will be blocked until the operation has been
+ performed.
+ </p>
+ </note>
<p>See also
<seealso marker="#send_after/4"><c>erlang:send_after/4</c></seealso>,
<seealso marker="#start_timer/4"><c>erlang:start_timer/4</c></seealso>,
@@ -4592,7 +4654,7 @@ os_prompt% </pre>
<desc>
<p>Read the state of a timer. The same as calling
<seealso marker="#read_timer/2"><c>erlang:read_timer(TimerRef,
- [{async, false}])</c></seealso>.</p>
+ [])</c></seealso>.</p>
</desc>
</func>
<func>
@@ -4744,48 +4806,14 @@ true</pre>
<name name="send_after" arity="4"/>
<fsummary>Start a timer</fsummary>
<desc>
- <p>Starts a timer. When the timer expires, the message
- <c><anno>Msg</anno></c> will be sent to
- <c><anno>Dest</anno></c>.</p>
- <p>If <c><anno>Dest</anno></c> is a <c>pid()</c> it has to
- be a <c>pid()</c> of a local process, dead or alive.</p>
- <p>Currently available <c><anno>Option</anno>s</c>:</p>
- <taglist>
- <tag><c>{abs, Abs}</c></tag>
- <item>
- <p>Absolute timeout. When <c>Abs</c> is <c>false</c>
- the <c><anno>Time</anno></c> value will be interpreted
- as a time in milli-seconds relative current
- <seealso marker="time_correction#Erlang_Monotonic_Time">Erlang
- monotonic time</seealso>. When <c>Abs</c> is <c>true</c> the
- <c><anno>Time</anno></c> value will be interpreted as an absolute
- Erlang monotonic time of milli second time unit. <c>Abs</c>
- defaults to <c>false</c>.</p>
- </item>
- </taglist>
- <p>The absolute time when the timer is set to expire needs
- to be in the range between
- <seealso marker="#system_info_start_time"><c>erlang:system_info(start_time)</c></seealso>
- and
- <seealso marker="#system_info_end_time"><c>erlang:system_info(end_time)</c></seealso>.
- If a negative relative time is specified the time is not
- allowed to be negative.</p>
- <p>If <c><anno>Dest</anno></c> is an <c>atom()</c>, it is supposed to be the name of
- a registered process. The process referred to by the name is
- looked up at the time of delivery. No error is given if
- the name does not refer to a process.</p>
- <p>If <c><anno>Dest</anno></c> is a <c>pid()</c>, the timer will be automatically
- canceled if the process referred to by the <c>pid()</c> is not alive,
- or when the process exits. This feature was introduced in
- erts version 5.4.11. Note that timers will not be
- automatically canceled when <c><anno>Dest</anno></c> is an <c>atom()</c>.</p>
- <p>See also
- <seealso marker="#start_timer/4"><c>erlang:send_timer/4</c></seealso>,
- <seealso marker="#cancel_timer/2"><c>erlang:cancel_timer/2</c></seealso>,
- and
- <seealso marker="#read_timer/2"><c>erlang:read_timer/2</c></seealso>.</p>
- <p>Failure: <c>badarg</c> if the arguments does not satisfy
- the requirements specified above.</p>
+ <p>
+ Starts a timer. When the timer expires, the message
+ <c><anno>Msg</anno></c> will be sent to the process
+ identified by <c><anno>Dest</anno></c>. Appart from
+ the format of the message sent to
+ <c><anno>Dest</anno></c> when the timer expires
+ <c>erlang:send_after/4</c> works exactly as
+ <seealso marker="#start_timer/4"><c>erlang:start_timer/4</c></seealso>.</p>
</desc>
</func>
<func>
@@ -4793,36 +4821,8 @@ true</pre>
<fsummary>Start a timer</fsummary>
<desc>
<p>Starts a timer. The same as calling
- <seealso marker="#send_timer/4"><c>erlang:send_after(<anno>Time</anno>,
- <anno>Dest</anno>, <anno>Msg</anno>, [{abs, false}])</c></seealso>.</p>
- </desc>
- </func>
- <func>
- <name name="send_after" arity="3"/>
- <type_desc variable="Time">0 &lt;= Time &lt;= 4294967295</type_desc>
- <fsummary>Start a timer</fsummary>
- <desc>
- <p>Starts a timer which will send the message <c>Msg</c>
- to <c><anno>Dest</anno></c> after <c><anno>Time</anno></c> milliseconds.</p>
- <p>If <c><anno>Dest</anno></c> is a <c>pid()</c> it has to be a <c>pid()</c> of a local process, dead or alive.</p>
- <p>The <c><anno>Time</anno></c> value can, in the current implementation, not be greater than 4294967295.</p>
- <p>If <c><anno>Dest</anno></c> is an <c>atom()</c>, it is supposed to be the name of
- a registered process. The process referred to by the name is
- looked up at the time of delivery. No error is given if
- the name does not refer to a process.</p>
-
- <p>If <c><anno>Dest</anno></c> is a <c>pid()</c>, the timer will be automatically
- canceled if the process referred to by the <c>pid()</c> is not alive,
- or when the process exits. This feature was introduced in
- erts version 5.4.11. Note that timers will not be
- automatically canceled when <c><anno>Dest</anno></c> is an <c>atom</c>.</p>
- <p>See also
- <seealso marker="#start_timer/3">erlang:start_timer/3</seealso>,
- <seealso marker="#cancel_timer/2">erlang:cancel_timer/2</seealso>,
- and
- <seealso marker="#read_timer/2">erlang:read_timer/2</seealso>.</p>
- <p>Failure: <c>badarg</c> if the arguments does not satisfy
- the requirements specified above.</p>
+ <seealso marker="#send_after/4"><c>erlang:send_after(<anno>Time</anno>,
+ <anno>Dest</anno>, <anno>Msg</anno>, [])</c></seealso>.</p>
</desc>
</func>
<func>
@@ -5231,41 +5231,59 @@ true</pre>
<name name="start_timer" arity="4"/>
<fsummary>Start a timer</fsummary>
<desc>
- <p>Starts a timer. When the timer expires, the message
+ <p>
+ Starts a timer. When the timer expires, the message
<c>{timeout, <anno>TimerRef</anno>, <anno>Msg</anno>}</c>
- will be sent to <c><anno>Dest</anno></c>.</p>
- <p>If <c><anno>Dest</anno></c> is a <c>pid()</c> it has to
- be a <c>pid()</c> of a local process, dead or alive.</p>
- <p>Currently available <c><anno>Option</anno>s</c>:</p>
+ will be sent to the process identified by
+ <c><anno>Dest</anno></c>.
+ </p>
+ <p>Currently available <c><anno>Option</anno></c>s:</p>
<taglist>
<tag><c>{abs, Abs}</c></tag>
<item>
- <p>Absolute timeout. When <c>Abs</c> is <c>false</c>
- the <c><anno>Time</anno></c> value will be interpreted
- as a time in milli-seconds relative current
- <seealso marker="time_correction#Erlang_Monotonic_Time">Erlang
- monotonic time</seealso>. When <c>Abs</c> is <c>true</c> the
- <c><anno>Time</anno></c> value will be interpreted as an absolute
- Erlang monotonic time of milli second time unit. <c>Abs</c>
- defaults to <c>false</c>.</p>
+ <p>
+ Absolute <c><anno>Time</anno></c> value. <c>Abs</c>
+ defaults to <c>false</c> which means that the
+ <c><anno>Time</anno></c> value will be interpreted
+ as a time in milli-seconds relative current
+ <seealso marker="time_correction#Erlang_Monotonic_Time">Erlang
+ monotonic time</seealso>. When <c>Abs</c> is set to
+ <c>true</c>, the <c><anno>Time</anno></c> value will
+ be interpreted as an absolute Erlang monotonic time of
+ milli-seconds
+ <seealso marker="#type_time_unit">time unit</seealso>.
+ </p>
</item>
</taglist>
- <p>The absolute time when the timer is set to expire needs
- to be in the range between
- <seealso marker="#system_info_start_time"><c>erlang:system_info(start_time)</c></seealso>
- and
- <seealso marker="#system_info_end_time"><c>erlang:system_info(end_time)</c></seealso>.
- If a negative relative time is specified the time is not
- allowed to be negative.</p>
- <p>If <c><anno>Dest</anno></c> is an <c>atom()</c>, it is supposed to be the name of
- a registered process. The process referred to by the name is
- looked up at the time of delivery. No error is given if
- the name does not refer to a process.</p>
- <p>If <c><anno>Dest</anno></c> is a <c>pid()</c>, the timer will be automatically
- canceled if the process referred to by the <c>pid()</c> is not alive,
- or when the process exits. This feature was introduced in
- erts version 5.4.11. Note that timers will not be
- automatically canceled when <c><anno>Dest</anno></c> is an <c>atom()</c>.</p>
+ <p>
+ More <c><anno>Option</anno></c>s may be added in the future.
+ </p>
+ <p>
+ The absolute point in time that the timer is set to expire on
+ has to be in the interval
+ <c>[</c><seealso marker="#system_info_start_time"><c>erlang:system_info(start_time)</c></seealso><c>,
+ </c><seealso marker="#system_info_end_time"><c>erlang:system_info(end_time)</c></seealso><c>]</c>.
+ Further, if a relative time is specified, the <c><anno>Time</anno></c> value
+ is not allowed to be negative.
+ </p>
+ <p>
+ If <c><anno>Dest</anno></c> is a <c>pid()</c>, it has to
+ be a <c>pid()</c> of a process created on the current
+ runtime system instance. This process may or may not
+ have terminated. If <c><anno>Dest</anno></c> is an
+ <c>atom()</c>, it will be interpreted as the name of a
+ locally registered process. The process referred to by the
+ name is looked up at the time of timer expiration. No error
+ is given if the name does not refer to a process.
+ </p>
+ <p>
+ If <c><anno>Dest</anno></c> is a <c>pid()</c>, the timer will
+ be automatically canceled if the process referred to by the
+ <c>pid()</c> is not alive, or when the process exits. This
+ feature was introduced in erts version 5.4.11. Note that
+ timers will not be automatically canceled when
+ <c><anno>Dest</anno></c> is an <c>atom()</c>.
+ </p>
<p>See also
<seealso marker="#send_after/4"><c>erlang:send_after/4</c></seealso>,
<seealso marker="#cancel_timer/2"><c>erlang:cancel_timer/2</c></seealso>,
@@ -5281,7 +5299,7 @@ true</pre>
<desc>
<p>Starts a timer. The same as calling
<seealso marker="#start_timer/4"><c>erlang:start_timer(<anno>Time</anno>,
- <anno>Dest</anno>, <anno>Msg</anno>, [{abs, false}])</c></seealso>.</p>
+ <anno>Dest</anno>, <anno>Msg</anno>, [])</c></seealso>.</p>
</desc>
</func>
<func>
@@ -6845,7 +6863,9 @@ ok
<item><p>The <seealso marker="#monotonic_time/0">Erlang monotonic
time</seealso> in <c>native</c>
<seealso marker="#type_time_unit">time unit</seealso> at the
- time when current Erlang runtime system instance started.</p></item>
+ time when current Erlang runtime system instance started. See also
+ <seealso marker="#system_info_end_time"><c>erlang:system_info(end_time)</c></seealso>.
+ </p></item>
<tag><c>system_version</c></tag>
<item>
<p>Returns a string containing version number and
diff --git a/erts/doc/src/notes.xml b/erts/doc/src/notes.xml
index c85cbe543d..35e6e55e72 100644
--- a/erts/doc/src/notes.xml
+++ b/erts/doc/src/notes.xml
@@ -30,508 +30,6 @@
</header>
<p>This document describes the changes made to the ERTS application.</p>
-<section><title>Erts 7.0</title>
-
- <section><title>Fixed Bugs and Malfunctions</title>
- <list>
- <item>
- <p>
- Fix issuing with spaces and quoting in the arguments when
- using erlang:open_port spawn_executable on windows. The
- behavior now mimics how unix works. This change implies a
- backwards incompatibility for how spawn_executable works
- on windows.</p>
- <p>
- *** POTENTIAL INCOMPATIBILITY ***</p>
- <p>
- Own Id: OTP-11905</p>
- </item>
- <item>
- <p>
- Fix global call trace when hipe compiled code call beam
- compiled functions. Tracing of beam functions should now
- alway work regardless who the caller is.</p>
- <p>
- Own Id: OTP-11939</p>
- </item>
- <item>
- <p>
- Correct cache alignment for ETS <c>write_concurrency</c>
- locks to improve performance by reduced false sharing.
- May increase memory footprint for tables with
- <c>write_concurrency</c>.</p>
- <p>
- Own Id: OTP-11974</p>
- </item>
- <item>
- <p>
- All possibly blocking operations in the fd/spawn and
- terminal driver have been converted to non-blocking
- operations. Before this fix it was possible for the VM to
- be blocked for a long time if the entity consuming
- stdout/stderr did not consume it fast enough.</p>
- <p>
- Own Id: OTP-12239</p>
- </item>
- <item>
- <p>
- Add missing overhead for offheap binaries created from
- external format. This fix can improve the garbage
- collection of large binaries originating from
- <c>binary_to_term</c> or messages from remote nodes.</p>
- <p>
- Own Id: OTP-12554</p>
- </item>
- <item>
- <p>
- Ensure hashing of zero is consistent</p>
- <p> Erlang treats positive and negative zero as
- equal:</p>
- <p>
- <c>true = 0.0 =:= 0.0/-1</c></p>
- <p>However, Erlangs hash functions: hash, phash and
- phash2 did not reflect this behaviour. The hash values
- produced by the different hash functions would not be
- identical for positive and negative zero.</p> <p>This
- change ensures that hash value of positive zero is always
- produced regardless of the signedness of the zero float,
- i.e.,</p>
- <p>
- <c>true = erlang:phash2(0.0) =:=
- erlang:phash2(0.0/-1)</c></p>
- <p>
- Own Id: OTP-12641</p>
- </item>
- <item>
- <p>
- Ensure NIF term creation disallows illegal floating point
- values and too long atoms. Such values will cause a NIF
- to throw badarg exception when it returns.</p>
- <p>
- Own Id: OTP-12655</p>
- </item>
- <item>
- <p>
- Fixed building of Map results from match_specs</p>
- <p>
- A faulty "box-value" entered into the heap which could
- cause a segmentation fault in the garbage collector if it
- was written on a heap fragment.</p>
- <p>
- Own Id: OTP-12656</p>
- </item>
- <item>
- <p>
- Fix hipe bug when matching a "writable" binary. The bug
- has been seen to sometimes cause a failed binary matching
- of a correct utf8 character, but other symptoms are also
- possible.</p>
- <p>
- Own Id: OTP-12667</p>
- </item>
- <item>
- <p>
- Keep dirty schedulers from waking other schedulers.</p>
- <p>
- Own Id: OTP-12685</p>
- </item>
- <item>
- <p>
- Disable floating point exceptions if the VM is compiled
- by clang/llvm. This is a known long-standing problem in
- clang/llvm.</p>
- <p>
- Own Id: OTP-12717</p>
- </item>
- <item>
- <p>
- Fix bug in <c>file:sendfile</c> for FreeBSD causing not
- the entire file to be sent.</p>
- <p>
- Own Id: OTP-12720</p>
- </item>
- </list>
- </section>
-
-
- <section><title>Improvements and New Features</title>
- <list>
- <item>
- <p>
- Add <c>md5</c> and <c>module</c> entries to
- <c>?MODULE:module_info/0/1</c> and remove obsolete entry
- 'import'.</p>
- <p>
- *** POTENTIAL INCOMPATIBILITY ***</p>
- <p>
- Own Id: OTP-11940</p>
- </item>
- <item>
- <p>
- Debug function <c>erlang:display/1</c> shows content of
- binaries and bitstrings, not only the length.</p>
- <p>
- Own Id: OTP-11941</p>
- </item>
- <item>
- <p>The time functionality of Erlang has been extended.
- This both includes a <seealso
- marker="time_correction#The_New_Time_API">new
- API</seealso> for time, as well as <seealso
- marker="time_correction#Time_Warp_Modes">time warp
- modes</seealso> which alters the behavior of the system
- when system time changes. <em>You are strongly encouraged
- to use the new API</em> instead of the old API based on
- <seealso
- marker="erlang#now/0"><c>erlang:now/0</c></seealso>.
- <c>erlang:now/0</c> has been deprecated since it is and
- forever will be a scalability bottleneck. For more
- information see the <seealso
- marker="time_correction">Time and Time
- Correction</seealso> chapter of the ERTS User's
- Guide.</p>
- <p>Besides the API changes and time warp modes a lot of
- scalability and performance improvements regarding time
- management has been made internally in the runtime
- system. Examples of such improvements are scheduler
- specific timer wheels, scheduler specific BIF timer
- management, parallel retrieval of monotonic time and
- system time on systems with primitives that are not
- buggy.</p>
- <p>
- Own Id: OTP-11997</p>
- </item>
- <item>
- <p><c>erlang:function_exported(M, F, A)</c> will now
- return <c>true</c> if <c>M:F/A</c> refers to a BIF.</p>
- <p>
- *** POTENTIAL INCOMPATIBILITY ***</p>
- <p>
- Own Id: OTP-12099</p>
- </item>
- <item>
- <p>
- New BIF: <c>erlang:get_keys/0</c>, lists all keys
- associated with the process dictionary. Note:
- <c>erlang:get_keys/0</c> is auto-imported.</p>
- <p>
- *** POTENTIAL INCOMPATIBILITY ***</p>
- <p>
- Own Id: OTP-12151 Aux Id: seq12521 </p>
- </item>
- <item>
- <p>
- Make distributed send of large messages yield to improve
- real-time characteristics.</p>
- <p>
- Own Id: OTP-12232</p>
- </item>
- <item>
- <p>
- Use high accuracy poll timeouts</p>
- <p>
- Where available, use poll/select API's that can handle
- time resolutions less than 1ms. In the cases where such
- API's are not available the timeout is rounded up to the
- nearest ms.</p>
- <p>
- Own Id: OTP-12236</p>
- </item>
- <item>
- <p>
- The internal group to user_drv protocol has been changed
- to be synchronous in order to guarantee that output sent
- to a process implementing the user_drv protocol is
- printed before replying. This protocol is used by the
- standard_output device and the ssh application when
- acting as a client. </p>
- <p>
- This change changes the previous unlimited buffer when
- printing to standard_io and other devices that end up in
- user_drv to 1KB.</p>
- <p>
- *** POTENTIAL INCOMPATIBILITY ***</p>
- <p>
- Own Id: OTP-12240</p>
- </item>
- <item>
- <p>The previously introduced "eager check I/O" feature is
- now enabled by default.</p>
- <p>Eager check I/O can be disabled using the <c>erl</c>
- command line argument: <seealso
- marker="erl#+secio"><c>+secio false</c></seealso></p>
- <p>Characteristics impact compared to previous
- default:</p> <list> <item>Lower latency and smoother
- management of externally triggered I/O operations.</item>
- <item>A slightly reduced priority of externally triggered
- I/O operations.</item> </list>
- <p>
- Own Id: OTP-12254 Aux Id: OTP-12117 </p>
- </item>
- <item>
- <p>
- Properly support maps in match_specs</p>
- <p>
- Own Id: OTP-12270</p>
- </item>
- <item>
- <p>
- The notice that a crashdump has been written has been
- moved to be printed before the crashdump is generated
- instead of afterwords. The wording of the notice has also
- been changed.</p>
- <p>
- *** POTENTIAL INCOMPATIBILITY ***</p>
- <p>
- Own Id: OTP-12292</p>
- </item>
- <item>
- <p>
- New function <c>ets:take/2</c>. Works the same as
- <c>ets:delete/2</c> but also returns the deleted
- object(s).</p>
- <p>
- Own Id: OTP-12309</p>
- </item>
- <item>
- <p>
- Tracing with cpu_timestamp option has been enabled on
- Linux.</p>
- <p>
- Own Id: OTP-12366</p>
- </item>
- <item>
- <p>
- ets:info/1,2 now contains information about whether
- write_concurrency or read_concurrency is enabled.</p>
- <p>
- Own Id: OTP-12376</p>
- </item>
- <item>
- <p>
- Improved usage of <c>gcc</c>'s builtins for atomic memory
- access. These are used when no other implementation of
- atomic memory operations is available. For example, when
- compiling for ARM when <c>libatomic_ops</c> is not
- available.</p>
- <p>
- The largest improvement will be seen when compiling with
- a <c>gcc</c> with support for the <c>__atomic_*</c>
- builtins (using a <c>gcc</c> of at least version 4.7),
- but also when only the legacy <c>__sync_*</c> builtins
- are available (using a <c>gcc</c> of at least version
- 4.1) an improvement can be seen.</p>
- <p>
- For more information see the "<seealso
- marker="doc/installation_guide:INSTALL#Advanced-configuration-and-build-of-ErlangOTP_Configuring_Atomic-Memory-Operations-and-the-VM">Atomic
- Memory Operations and the VM</seealso>" section of
- <c>$ERL_TOP/HOWTO/INSTALL.md</c>.</p>
- <p>
- Own Id: OTP-12383</p>
- </item>
- <item>
- <p>
- Introduce <c>math:log2/1</c> function to math module.</p>
- <p>
- Own Id: OTP-12411</p>
- </item>
- <item>
- <p>
- Remove perfctr support</p>
- <p>
- Development of perfctr in the linux kernel ceased in
- 2010. The perfctr support code in the Erlang VM is thus
- effectively dead code and therefor removed.</p>
- <p>
- Own Id: OTP-12508</p>
- </item>
- <item>
- <p><c>zlib:inflateChunk/2</c> has been added. It works
- like <c>zlib:inflate/2</c>, but decompresses no more data
- than will fit in the buffer configured by
- <c>zlib:setBufSize/2</c>.</p>
- <p>
- Own Id: OTP-12548</p>
- </item>
- <item>
- <p>
- Use linear search for small select_val arrays</p>
- <p>
- Own Id: OTP-12555</p>
- </item>
- <item>
- <p>
- New BIF ets:update_counter/4 with a default object as
- argument, which will be inserted in the table if the key
- was not found.</p>
- <p>
- Own Id: OTP-12563</p>
- </item>
- <item>
- <p>
- Export missing types from zlib module</p>
- <p>
- Own Id: OTP-12584</p>
- </item>
- <item>
- <p>
- Use persistent hashmaps for large Maps <p>Maps will use a
- persistent hashmap implementation when the number of
- pairs in a Map becomes sufficiently large. The change
- will occur when a Map reaches 33 pairs in size but this
- limit might change in the future.</p></p>
- <p>The most significant impact for the user by this
- change is speed, and to a lesser degree memory
- consumption and introspection of Maps. Memory consumption
- size is probalistic but lesser than <c>gb_trees</c> or
- <c>dict</c> for instance. Any other impacts will be
- transparent for the user except for the following
- changes.</p>
- <p>Semantics of Maps have changed in two incompatible
- ways compared to the experimental implementation in OTP
- 17:</p> <list> <item>Hashing of maps is done different by
- <c>erlang:phash2/1,2</c>, <c>erlang:phash/1</c> and
- <c>erlang:hash/2</c>.</item> <item>Comparing two maps
- with ==, /=, =&lt;, &lt;, &gt;= and &gt;, is done
- different if the keys contain floating point
- numbers.</item> </list>
- <p>
- *** POTENTIAL INCOMPATIBILITY ***</p>
- <p>
- Own Id: OTP-12585</p>
- </item>
- <item>
- <p>
- Scalability improvement for <seealso
- marker="erlang#make_ref/0">erlang:make_ref/0</seealso>,
- and other functionality that create references. Each
- scheduler now manage its own set of references. By this
- no communication at all is needed when creating
- references.</p>
- <p>
- Previous implementation generated a strictly
- monotonically increasing sequence of references
- corresponding to creation time on the runtime system
- instance. This is <em>not</em> the case with current
- implementation. You can only expect reference to be
- unique. The Erlang/OTP documentation has never mentioned
- anything else but the uniqueness property, so this change
- <em>is</em> fully compatible. The only reason we've
- marked this as a potential incompatibility is since an
- early draft for an Erlang specification mentions strict
- monotonicity as a property.</p>
- <p>
- If you need to create data with a strict monotonicity
- property use <seealso
- marker="erlang#unique_integer/1">erlang:unique_integer([monotonic])</seealso>.
- Do <em>not</em> use the deprecated <seealso
- marker="erlang:now/0">erlang:now()</seealso>.</p>
- <p>
- *** POTENTIAL INCOMPATIBILITY ***</p>
- <p>
- Own Id: OTP-12610</p>
- </item>
- <item>
- <p>
- Enable different abort signal from heart</p>
- <p>By using environment variable HEART_KILL_SIGNAL, heart
- can now use a different signal to kill the old running
- Erlang.</p>
- <p>By default the signal is SIGKILL but SIGABRT may also
- be used by setting environment variable:
- HEART_KILL_SIGNAL=SIGABRT</p>
- <p>
- Own Id: OTP-12613 Aux Id: seq12826 </p>
- </item>
- <item>
- <p>
- Update autconf to latest version 2015-03-04</p>
- <p>
- Own Id: OTP-12646</p>
- </item>
- <item>
- <p>
- Optimization of timers internally in the VM. This include
- process timers (<c>receive ... after</c>), port timers
- (<c>driver_set_timer()</c>) as well as BIF timers
- (<c>erlang:send_after()</c>/<c>erlang:start_timer()</c>).</p>
- <p>
- Each scheduler thread now has its own lock-free timer
- service instead of one locked central service. This
- dramatically improves performance of timer management on
- systems with a large amount of schedulers and timers.</p>
- <p>
- The timer service internal data structure has also been
- optimized to be able to handle more timers than before.
- That is, each timer service is by its self able to handle
- more timers without dramatic performance loss than the
- old centralized timer service.</p>
- <p>
- The API of BIF timers has also been extended. Timeout
- values are for example no longer limited to 32-bit
- integers. For more information see the documentation of
- <seealso
- marker="erlang#start_timer/4"><c>erlang:start_timer/4</c></seealso>,
- <seealso
- marker="erlang#send_after/4"><c>erlang:send_after/4</c></seealso>,
- <seealso
- marker="erlang#cancel_timer/2"><c>erlang:cancel_timer/2</c></seealso>,
- and <seealso
- marker="erlang#read_timer/2"><c>erlang:read_timer/2</c></seealso>.</p>
- <p>
- Own Id: OTP-12650 Aux Id: OTP-11997 </p>
- </item>
- <item>
- <p>
- Specialize instructions from common assembler patterns</p>
- <p>Specialize common instructions of <c>rem</c>,
- <c>band</c>, <c>minus</c> and <c>plus</c> in the beam
- loader. This will reduce the number of fetches and thus
- lessen the instruction dispatch pressure during runtime
- and speed up those operations in some common cases.</p>
- <p>Specialize move patterns from x-registers to the stack
- with a new <c>move_window</c> instruction. This change
- will reduce instruction dispatch pressure.</p>
- <p>
- Own Id: OTP-12690</p>
- </item>
- <item>
- <p>
- Fix cross compilation for Android.</p>
- <p>
- Own Id: OTP-12693</p>
- </item>
- <item>
- <p>
- Fix incorrect use of autoconf macro AC_EGREP_CPP, which
- could cause faulty configuration if run from a path
- containing the string 'yes'.</p>
- <p>
- Own Id: OTP-12706</p>
- </item>
- <item>
- <p>
- Minimal Java version is now 1.6</p>
- <p>
- Own Id: OTP-12718</p>
- </item>
- <item>
- <p>
- Send format and args on process exit to error_logger</p>
- <p>
- Previously, the emulator would generate a whole string
- with values and call the error_logger passing
- <c>"~s~n"</c>. This changes it to a format string
- containing <c>~p</c> with the respective values as
- arguments.</p>
- <p>
- Own Id: OTP-12735</p>
- </item>
- </list>
- </section>
-
-</section>
-
<section><title>Erts 6.4.1</title>
<section><title>Fixed Bugs and Malfunctions</title>
diff --git a/erts/emulator/beam/erl_alloc_util.c b/erts/emulator/beam/erl_alloc_util.c
index 2f277690e4..b92533f228 100644
--- a/erts/emulator/beam/erl_alloc_util.c
+++ b/erts/emulator/beam/erl_alloc_util.c
@@ -718,7 +718,7 @@ static void make_name_atoms(Allctr_t *allctr);
static Block_t *create_carrier(Allctr_t *, Uint, UWord);
static void destroy_carrier(Allctr_t *, Block_t *, Carrier_t **);
static void mbc_free(Allctr_t *allctr, void *p, Carrier_t **busy_pcrr_pp);
-static void dealloc_block(Allctr_t *, void *, int);
+static void dealloc_block(Allctr_t *, void *, ErtsAlcFixList_t *, int);
/* internal data... */
@@ -1067,17 +1067,21 @@ typedef struct {
} ErtsAllctrFixDDBlock_t;
#endif
+#define ERTS_ALC_FIX_NO_UNUSE (((ErtsAlcType_t) 1) << ERTS_ALC_N_BITS)
+
static ERTS_INLINE void
dealloc_fix_block(Allctr_t *allctr,
ErtsAlcType_t type,
void *ptr,
+ ErtsAlcFixList_t *fix,
int dec_cc_on_redirect)
{
#ifdef ERTS_SMP
/* May be redirected... */
- ((ErtsAllctrFixDDBlock_t *) ptr)->fix_type = type;
+ ASSERT((type & ERTS_ALC_FIX_NO_UNUSE) == 0);
+ ((ErtsAllctrFixDDBlock_t *) ptr)->fix_type = type | ERTS_ALC_FIX_NO_UNUSE;
#endif
- dealloc_block(allctr, ptr, dec_cc_on_redirect);
+ dealloc_block(allctr, ptr, fix, dec_cc_on_redirect);
}
static ERTS_INLINE void
@@ -1123,8 +1127,7 @@ fix_cpool_check_shrink(Allctr_t *allctr,
if (fix->u.cpool.min_list_size > fix->list_size)
fix->u.cpool.min_list_size = fix->list_size;
- fix->u.cpool.allocated--;
- dealloc_fix_block(allctr, type, p, 0);
+ dealloc_fix_block(allctr, type, p, fix, 0);
}
}
}
@@ -1170,7 +1173,8 @@ static ERTS_INLINE void
fix_cpool_free(Allctr_t *allctr,
ErtsAlcType_t type,
void *p,
- Carrier_t **busy_pcrr_pp)
+ Carrier_t **busy_pcrr_pp,
+ int unuse)
{
ErtsAlcFixList_t *fix;
@@ -1178,8 +1182,9 @@ fix_cpool_free(Allctr_t *allctr,
&& type <= ERTS_ALC_N_MAX_A_FIXED_SIZE);
fix = &allctr->fix[type - ERTS_ALC_N_MIN_A_FIXED_SIZE];
-
- fix->u.cpool.used--;
+
+ if (unuse)
+ fix->u.cpool.used--;
if ((!busy_pcrr_pp || !*busy_pcrr_pp)
&& !fix->u.cpool.shrink_list
@@ -1237,8 +1242,7 @@ fix_cpool_alloc_shrink(Allctr_t *allctr, erts_aint32_t flgs)
fix->list = *((void **) ptr);
fix->list_size--;
fix->u.cpool.shrink_list--;
- fix->u.cpool.allocated--;
- dealloc_fix_block(allctr, type, ptr, 0);
+ dealloc_fix_block(allctr, type, ptr, fix, 0);
}
if (fix->u.cpool.min_list_size > fix->list_size)
fix->u.cpool.min_list_size = fix->list_size;
@@ -1399,7 +1403,7 @@ fix_nocpool_alloc_shrink(Allctr_t *allctr, erts_aint32_t flgs)
ptr = fix->list;
fix->list = *((void **) ptr);
fix->list_size--;
- dealloc_block(allctr, ptr, 0);
+ dealloc_block(allctr, ptr, NULL, 0);
fix->u.nocpool.allocated--;
}
if (fix->list_size != 0) {
@@ -1746,11 +1750,13 @@ handle_delayed_fix_dealloc(Allctr_t *allctr, void *ptr)
type = ((ErtsAllctrFixDDBlock_t *) ptr)->fix_type;
- ASSERT(ERTS_ALC_N_MIN_A_FIXED_SIZE <= type
- && type <= ERTS_ALC_N_MAX_A_FIXED_SIZE);
+ ASSERT(ERTS_ALC_N_MIN_A_FIXED_SIZE
+ <= (type & ~ERTS_ALC_FIX_NO_UNUSE));
+ ASSERT((type & ~ERTS_ALC_FIX_NO_UNUSE)
+ <= ERTS_ALC_N_MAX_A_FIXED_SIZE);
if (!ERTS_ALC_IS_CPOOL_ENABLED(allctr))
- fix_nocpool_free(allctr, type, ptr);
+ fix_nocpool_free(allctr, (type & ~ERTS_ALC_FIX_NO_UNUSE), ptr);
else {
Block_t *blk = UMEM2BLK(ptr);
Carrier_t *busy_pcrr_p;
@@ -1765,7 +1771,9 @@ handle_delayed_fix_dealloc(Allctr_t *allctr, void *ptr)
NULL, &busy_pcrr_p);
if (used_allctr == allctr) {
doit:
- fix_cpool_free(allctr, type, ptr, &busy_pcrr_p);
+ fix_cpool_free(allctr, (type & ~ERTS_ALC_FIX_NO_UNUSE),
+ ptr, &busy_pcrr_p,
+ !(type & ERTS_ALC_FIX_NO_UNUSE));
clear_busy_pool_carrier(allctr, busy_pcrr_p);
}
else {
@@ -1885,7 +1893,7 @@ handle_delayed_dealloc(Allctr_t *allctr,
if (fix)
handle_delayed_fix_dealloc(allctr, ptr);
else
- dealloc_block(allctr, ptr, 1);
+ dealloc_block(allctr, ptr, NULL, 1);
}
}
@@ -1991,15 +1999,24 @@ erts_alcu_check_delayed_dealloc(Allctr_t *allctr,
ERTS_ALCU_DD_OPS_LIM_LOW, NULL, NULL, NULL)
static void
-dealloc_block(Allctr_t *allctr, void *ptr, int dec_cc_on_redirect)
+dealloc_block(Allctr_t *allctr, void *ptr, ErtsAlcFixList_t *fix, int dec_cc_on_redirect)
{
Block_t *blk = UMEM2BLK(ptr);
ERTS_SMP_LC_ASSERT(!allctr->thread_safe
|| erts_lc_mtx_is_locked(&allctr->mutex));
- if (IS_SBC_BLK(blk))
+ if (IS_SBC_BLK(blk)) {
destroy_carrier(allctr, blk, NULL);
+#ifdef ERTS_SMP
+ if (fix && ERTS_ALC_IS_CPOOL_ENABLED(allctr)) {
+ ErtsAlcType_t type = ((ErtsAllctrFixDDBlock_t *) ptr)->fix_type;
+ if (!(type & ERTS_ALC_FIX_NO_UNUSE))
+ fix->u.cpool.used--;
+ fix->u.cpool.allocated--;
+ }
+#endif
+ }
#ifndef ERTS_SMP
else
mbc_free(allctr, ptr, NULL);
@@ -2012,6 +2029,12 @@ dealloc_block(Allctr_t *allctr, void *ptr, int dec_cc_on_redirect)
used_allctr = get_used_allctr(allctr, ERTS_ALC_TS_PREF_LOCK_NO, ptr,
NULL, &busy_pcrr_p);
if (used_allctr == allctr) {
+ if (fix) {
+ ErtsAlcType_t type = ((ErtsAllctrFixDDBlock_t *) ptr)->fix_type;
+ if (!(type & ERTS_ALC_FIX_NO_UNUSE))
+ fix->u.cpool.used--;
+ fix->u.cpool.allocated--;
+ }
mbc_free(allctr, ptr, &busy_pcrr_p);
clear_busy_pool_carrier(allctr, busy_pcrr_p);
}
@@ -5215,7 +5238,7 @@ do_erts_alcu_free(ErtsAlcType_t type, void *extra, void *p,
if (allctr->fix) {
if (ERTS_ALC_IS_CPOOL_ENABLED(allctr))
- fix_cpool_free(allctr, type, p, busy_pcrr_pp);
+ fix_cpool_free(allctr, type, p, busy_pcrr_pp, 1);
else
fix_nocpool_free(allctr, type, p);
}
diff --git a/erts/emulator/beam/erl_process.c b/erts/emulator/beam/erl_process.c
index af8db519d4..b64a7f8902 100644
--- a/erts/emulator/beam/erl_process.c
+++ b/erts/emulator/beam/erl_process.c
@@ -2887,22 +2887,29 @@ scheduler_wait(int *fcalls, ErtsSchedulerData *esdp, ErtsRunQueue *rq)
}
if (aux_work) {
- flgs = erts_smp_atomic32_read_acqb(&ssi->flags);
- current_time = erts_get_monotonic_time(esdp);
- if (current_time >= erts_next_timeout_time(esdp->next_tmo_ref)) {
- if (!ERTS_SCHEDULER_IS_DIRTY(esdp) && !thr_prgr_active) {
- erts_thr_progress_active(esdp, thr_prgr_active = 1);
- sched_wall_time_change(esdp, 1);
+ if (!ERTS_SCHEDULER_IS_DIRTY(esdp)) {
+ flgs = erts_smp_atomic32_read_acqb(&ssi->flags);
+ current_time = erts_get_monotonic_time(esdp);
+ if (current_time >= erts_next_timeout_time(esdp->next_tmo_ref)) {
+ if (!thr_prgr_active) {
+ erts_thr_progress_active(esdp, thr_prgr_active = 1);
+ sched_wall_time_change(esdp, 1);
+ }
+ erts_bump_timers(esdp->timer_wheel, current_time);
}
- erts_bump_timers(esdp->timer_wheel, current_time);
}
}
else {
ErtsMonotonicTime timeout_time;
- timeout_time = erts_check_next_timeout_time(esdp);
- current_time = erts_get_monotonic_time(esdp);
- if (current_time >= timeout_time) {
- if (!ERTS_SCHEDULER_IS_DIRTY(esdp) && !thr_prgr_active) {
+ int do_timeout = 0;
+ if (!ERTS_SCHEDULER_IS_DIRTY(esdp)) {
+ timeout_time = erts_check_next_timeout_time(esdp);
+ current_time = erts_get_monotonic_time(esdp);
+ do_timeout = (current_time >= timeout_time);
+ } else
+ timeout_time = ERTS_MONOTONIC_TIME_MAX;
+ if (do_timeout) {
+ if (!thr_prgr_active) {
erts_thr_progress_active(esdp, thr_prgr_active = 1);
sched_wall_time_change(esdp, 1);
}
@@ -2926,23 +2933,28 @@ scheduler_wait(int *fcalls, ErtsSchedulerData *esdp, ErtsRunQueue *rq)
int res;
ASSERT(flgs & ERTS_SSI_FLG_TSE_SLEEPING);
ASSERT(flgs & ERTS_SSI_FLG_WAITING);
- current_time = erts_get_monotonic_time(esdp);
+ current_time = ERTS_SCHEDULER_IS_DIRTY(esdp) ? 0 :
+ erts_get_monotonic_time(esdp);
do {
Sint64 timeout;
if (current_time >= timeout_time)
break;
- timeout = ERTS_MONOTONIC_TO_NSEC(timeout_time
- - current_time
- - 1) + 1;
+ if (!ERTS_SCHEDULER_IS_DIRTY(esdp)) {
+ timeout = ERTS_MONOTONIC_TO_NSEC(timeout_time
+ - current_time
+ - 1) + 1;
+ } else
+ timeout = -1;
res = erts_tse_twait(ssi->event, timeout);
- current_time = erts_get_monotonic_time(esdp);
+ current_time = ERTS_SCHEDULER_IS_DIRTY(esdp) ? 0 :
+ erts_get_monotonic_time(esdp);
} while (res == EINTR);
}
}
if (!ERTS_SCHEDULER_IS_DIRTY(esdp))
erts_thr_progress_finalize_wait(esdp);
}
- if (current_time >= timeout_time)
+ if (!ERTS_SCHEDULER_IS_DIRTY(esdp) && current_time >= timeout_time)
erts_bump_timers(esdp->timer_wheel, current_time);
}
@@ -3010,9 +3022,11 @@ scheduler_wait(int *fcalls, ErtsSchedulerData *esdp, ErtsRunQueue *rq)
ASSERT(!erts_port_task_have_outstanding_io_tasks());
erl_sys_schedule(1); /* Might give us something to do */
- current_time = erts_get_monotonic_time(esdp);
- if (current_time >= erts_next_timeout_time(esdp->next_tmo_ref))
- erts_bump_timers(esdp->timer_wheel, current_time);
+ if (!ERTS_SCHEDULER_IS_DIRTY(esdp)) {
+ current_time = erts_get_monotonic_time(esdp);
+ if (current_time >= erts_next_timeout_time(esdp->next_tmo_ref))
+ erts_bump_timers(esdp->timer_wheel, current_time);
+ }
sys_aux_work:
#ifndef ERTS_SMP
@@ -3021,15 +3035,18 @@ scheduler_wait(int *fcalls, ErtsSchedulerData *esdp, ErtsRunQueue *rq)
aux_work = erts_atomic32_read_acqb(&ssi->aux_work);
if (aux_work) {
- if (!working)
- sched_wall_time_change(esdp, working = 1);
+ if (!ERTS_SCHEDULER_IS_DIRTY(esdp)) {
+ if (!working)
+ sched_wall_time_change(esdp, working = 1);
#ifdef ERTS_SMP
- if (!thr_prgr_active)
- erts_thr_progress_active(esdp, thr_prgr_active = 1);
+ if (!thr_prgr_active)
+ erts_thr_progress_active(esdp, thr_prgr_active = 1);
#endif
+ }
aux_work = handle_aux_work(&esdp->aux_work_data, aux_work, 1);
#ifdef ERTS_SMP
- if (aux_work && erts_thr_progress_update(esdp))
+ if (!ERTS_SCHEDULER_IS_DIRTY(esdp) && aux_work &&
+ erts_thr_progress_update(esdp))
erts_thr_progress_leader_update(esdp);
#endif
}
@@ -3127,7 +3144,7 @@ scheduler_wait(int *fcalls, ErtsSchedulerData *esdp, ErtsRunQueue *rq)
erl_sys_schedule(0);
- {
+ if (!ERTS_SCHEDULER_IS_DIRTY(esdp)) {
ErtsMonotonicTime current_time = erts_get_monotonic_time(esdp);
if (current_time >= erts_next_timeout_time(esdp->next_tmo_ref))
erts_bump_timers(esdp->timer_wheel, current_time);
@@ -6790,7 +6807,8 @@ suspend_scheduler(ErtsSchedulerData *esdp)
}
}
- (void) erts_get_monotonic_time(esdp);
+ if (!ERTS_SCHEDULER_IS_DIRTY(esdp))
+ (void) erts_get_monotonic_time(esdp);
erts_smp_runq_lock(esdp->run_queue);
non_empty_runq(esdp->run_queue);
@@ -6906,7 +6924,7 @@ suspend_scheduler(ErtsSchedulerData *esdp)
& ERTS_RUNQ_FLGS_QMASK);
aux_work = erts_atomic32_read_acqb(&ssi->aux_work);
if (aux_work|qmask) {
- if (!thr_prgr_active) {
+ if (!ERTS_SCHEDULER_IS_DIRTY(esdp) && !thr_prgr_active) {
erts_thr_progress_active(esdp, thr_prgr_active = 1);
sched_wall_time_change(esdp, 1);
}
@@ -6914,7 +6932,8 @@ suspend_scheduler(ErtsSchedulerData *esdp)
aux_work = handle_aux_work(&esdp->aux_work_data,
aux_work,
1);
- if (aux_work && erts_thr_progress_update(esdp))
+ if (!ERTS_SCHEDULER_IS_DIRTY(esdp) && aux_work &&
+ erts_thr_progress_update(esdp))
erts_thr_progress_leader_update(esdp);
if (qmask) {
erts_smp_runq_lock(esdp->run_queue);
@@ -6924,32 +6943,40 @@ suspend_scheduler(ErtsSchedulerData *esdp)
}
if (aux_work) {
- current_time = erts_get_monotonic_time(esdp);
- if (current_time >= erts_next_timeout_time(esdp->next_tmo_ref)) {
- if (!thr_prgr_active) {
- erts_thr_progress_active(esdp, thr_prgr_active = 1);
- sched_wall_time_change(esdp, 1);
+ if (!ERTS_SCHEDULER_IS_DIRTY(esdp)) {
+ current_time = erts_get_monotonic_time(esdp);
+ if (current_time >= erts_next_timeout_time(esdp->next_tmo_ref)) {
+ if (!thr_prgr_active) {
+ erts_thr_progress_active(esdp, thr_prgr_active = 1);
+ sched_wall_time_change(esdp, 1);
+ }
+ erts_bump_timers(esdp->timer_wheel, current_time);
}
- erts_bump_timers(esdp->timer_wheel, current_time);
}
}
else {
ErtsMonotonicTime timeout_time;
- timeout_time = erts_check_next_timeout_time(esdp);
- current_time = erts_get_monotonic_time(esdp);
-
- if (current_time >= timeout_time) {
+ int do_timeout = 0;
+ if (!ERTS_SCHEDULER_IS_DIRTY(esdp)) {
+ timeout_time = erts_check_next_timeout_time(esdp);
+ current_time = erts_get_monotonic_time(esdp);
+ do_timeout = (current_time >= timeout_time);
+ } else
+ timeout_time = ERTS_MONOTONIC_TIME_MAX;
+ if (do_timeout) {
if (!thr_prgr_active) {
erts_thr_progress_active(esdp, thr_prgr_active = 1);
sched_wall_time_change(esdp, 1);
}
}
- else {
- if (thr_prgr_active) {
- erts_thr_progress_active(esdp, thr_prgr_active = 0);
- sched_wall_time_change(esdp, 0);
+ else {
+ if (!ERTS_SCHEDULER_IS_DIRTY(esdp)) {
+ if (thr_prgr_active) {
+ erts_thr_progress_active(esdp, thr_prgr_active = 0);
+ sched_wall_time_change(esdp, 0);
+ }
+ erts_thr_progress_prepare_wait(esdp);
}
- erts_thr_progress_prepare_wait(esdp);
flgs = sched_spin_suspended(ssi,
ERTS_SCHED_SUSPEND_SLEEP_SPINCOUNT);
if (flgs == (ERTS_SSI_FLG_SLEEPING
@@ -6962,23 +6989,29 @@ suspend_scheduler(ErtsSchedulerData *esdp)
| ERTS_SSI_FLG_SUSPENDED)) {
int res;
- current_time = erts_get_monotonic_time(esdp);
+ current_time = ERTS_SCHEDULER_IS_DIRTY(esdp) ? 0 :
+ erts_get_monotonic_time(esdp);
do {
Sint64 timeout;
if (current_time >= timeout_time)
break;
- timeout = ERTS_MONOTONIC_TO_NSEC(timeout_time
- - current_time
- - 1) + 1;
+ if (!ERTS_SCHEDULER_IS_DIRTY(esdp)) {
+ timeout = ERTS_MONOTONIC_TO_NSEC(timeout_time
+ - current_time
+ - 1) + 1;
+ } else
+ timeout = -1;
res = erts_tse_twait(ssi->event, timeout);
- current_time = erts_get_monotonic_time(esdp);
+ current_time = ERTS_SCHEDULER_IS_DIRTY(esdp) ? 0 :
+ erts_get_monotonic_time(esdp);
} while (res == EINTR);
}
}
- erts_thr_progress_finalize_wait(esdp);
+ if (!ERTS_SCHEDULER_IS_DIRTY(esdp))
+ erts_thr_progress_finalize_wait(esdp);
}
- if (current_time >= timeout_time)
+ if (!ERTS_SCHEDULER_IS_DIRTY(esdp) && current_time >= timeout_time)
erts_bump_timers(esdp->timer_wheel, current_time);
}
@@ -9196,13 +9229,15 @@ Process *schedule(Process *p, int calls)
ERTS_SMP_CHK_NO_PROC_LOCKS;
- if (esdp->check_time_reds >= ERTS_CHECK_TIME_REDS)
- (void) erts_get_monotonic_time(esdp);
+ if (!ERTS_SCHEDULER_IS_DIRTY(esdp)) {
+ if (esdp->check_time_reds >= ERTS_CHECK_TIME_REDS)
+ (void) erts_get_monotonic_time(esdp);
- if (esdp->last_monotonic_time >= erts_next_timeout_time(esdp->next_tmo_ref)) {
- erts_smp_runq_unlock(rq);
- erts_bump_timers(esdp->timer_wheel, esdp->last_monotonic_time);
- erts_smp_runq_lock(rq);
+ if (esdp->last_monotonic_time >= erts_next_timeout_time(esdp->next_tmo_ref)) {
+ erts_smp_runq_unlock(rq);
+ erts_bump_timers(esdp->timer_wheel, esdp->last_monotonic_time);
+ erts_smp_runq_lock(rq);
+ }
}
BM_STOP_TIMER(system);
@@ -9649,7 +9684,7 @@ Process *schedule(Process *p, int calls)
ASSERT(erts_proc_read_refc(p) > 0);
- if (ERTS_PTMR_IS_TIMED_OUT(p)) {
+ if (!(state & ERTS_PSFLG_EXITING) && ERTS_PTMR_IS_TIMED_OUT(p)) {
BeamInstr** pi;
#ifdef ERTS_SMP
ETHR_MEMBAR(ETHR_LoadLoad|ETHR_LoadStore);
diff --git a/erts/emulator/sys/unix/erl_child_setup.c b/erts/emulator/sys/unix/erl_child_setup.c
index 5ad92dad02..d050748703 100644
--- a/erts/emulator/sys/unix/erl_child_setup.c
+++ b/erts/emulator/sys/unix/erl_child_setup.c
@@ -55,7 +55,7 @@ void sys_sigrelease(int sig)
#endif /* !SIG_SIGSET */
#if defined(__ANDROID__)
-int __system_properties_fd(void);
+static int system_properties_fd(void);
#endif /* __ANDROID__ */
#if defined(__ANDROID__)
@@ -104,9 +104,12 @@ main(int argc, char *argv[])
#if defined(HAVE_CLOSEFROM)
closefrom(from);
#elif defined(__ANDROID__)
- for (i = from; i <= to; i++) {
- if (i!=__system_properties_fd)
- (void) close(i);
+ if (from <= to) {
+ int spfd = system_properties_fd();
+ for (i = from; i <= to; i++) {
+ if (i != spfd)
+ (void) close(i);
+ }
}
#else
for (i = from; i <= to; i++)
@@ -143,9 +146,9 @@ main(int argc, char *argv[])
}
#if defined(__ANDROID__)
-int __system_properties_fd(void)
+static int system_properties_fd(void)
{
- int s, fd;
+ int fd;
char *env;
env = getenv("ANDROID_PROPERTY_WORKSPACE");
@@ -156,4 +159,3 @@ int __system_properties_fd(void)
return fd;
}
#endif /* __ANDROID__ */
-
diff --git a/erts/preloaded/src/erts.app.src b/erts/preloaded/src/erts.app.src
index 345a6ae3be..cf9a06599a 100644
--- a/erts/preloaded/src/erts.app.src
+++ b/erts/preloaded/src/erts.app.src
@@ -35,7 +35,7 @@
{registered, []},
{applications, []},
{env, []},
- {runtime_dependencies, ["stdlib-2.0", "kernel-3.0", "sasl-2.4"]}
+ {runtime_dependencies, ["stdlib-2.5", "kernel-4.0", "sasl-2.4"]}
]}.
%% vim: ft=erlang
diff --git a/lib/asn1/doc/src/notes.xml b/lib/asn1/doc/src/notes.xml
index f73d21b9e3..9feb673c04 100644
--- a/lib/asn1/doc/src/notes.xml
+++ b/lib/asn1/doc/src/notes.xml
@@ -31,23 +31,6 @@
<p>This document describes the changes made to the asn1 application.</p>
-<section><title>Asn1 4.0</title>
-
- <section><title>Fixed Bugs and Malfunctions</title>
- <list>
- <item>
- <p>
- Many bugs have been eliminated in the the ASN.1 compiler
- so that it can now successfully compile many more ASN.1
- specifications. Error messages have also been improved.</p>
- <p>
- Own Id: OTP-12395</p>
- </item>
- </list>
- </section>
-
-</section>
-
<section><title>Asn1 3.0.4</title>
<section><title>Fixed Bugs and Malfunctions</title>
diff --git a/lib/asn1/vsn.mk b/lib/asn1/vsn.mk
index d4c46863a3..c909c908d6 100644
--- a/lib/asn1/vsn.mk
+++ b/lib/asn1/vsn.mk
@@ -1 +1 @@
-ASN1_VSN = 4.0
+ASN1_VSN = 3.0.4
diff --git a/lib/common_test/doc/src/notes.xml b/lib/common_test/doc/src/notes.xml
index 218f76d403..472e3b7833 100644
--- a/lib/common_test/doc/src/notes.xml
+++ b/lib/common_test/doc/src/notes.xml
@@ -32,79 +32,6 @@
<file>notes.xml</file>
</header>
-<section><title>Common_Test 1.11</title>
-
- <section><title>Fixed Bugs and Malfunctions</title>
- <list>
- <item>
- <p>
- The status of an aborted test due to test suite
- compilation error has changed from 'auto_skipped' to
- 'failed'. This affects both the textual log file, event
- handling and CT hook callbacks. The logging of
- compilation failures has also been improved, especially
- in the case of multiple test suites failing compilation.</p>
- <p>
- Own Id: OTP-10816</p>
- </item>
- </list>
- </section>
-
-
- <section><title>Improvements and New Features</title>
- <list>
- <item>
- <p>
- Earlier there was no way to add optional parameters like
- default-operation to an edit-config request sent with
- ct_netconfc:edit_config/3,4, you had to use
- ct_netconfc:send_rpc/2,3. For simplicity and completion,
- a new optional argument, OptParams, is now added to the
- edit_config function.</p>
- <p>
- Own Id: OTP-10446 Aux Id: kunagi-266 [177] </p>
- </item>
- <item>
- <p>
- When running OTP tests using the ts interface, it is now
- possible to specify so called test categories per OTP
- application. A test category is represented by a CT test
- specification and defines an arbitrary subset of existing
- test suites, groups and cases. Examples of test
- categories are 'smoke' (smoke tests) and 'bench'
- (benchmarks). (Call ts:help() for more info). Also,
- functions for reading terms from the current test
- specification during test, ct:get_testspec_terms/0 and
- ct:get_testspec_terms/1, have been implemented.</p>
- <p>
- Own Id: OTP-11962</p>
- </item>
- <item>
- <p>
- Obsolete scripts and make file operations have been
- removed and the installation chapter in the Common Test
- User's Guide has been updated.</p>
- <p>
- Own Id: OTP-12421</p>
- </item>
- <item>
- <p>
- The 'keep_alive' interval has been reduced to 8 seconds,
- which is two seconds shorter than the default
- 'idle_timeout' value for ct_telnet:expect/3. This way,
- the telnet server receives a NOP message (which might
- trigger an action) before the operation times out. Also
- the TCP option 'nodelay' has been enabled per default for
- all telnet connections, in order to reduce the risk for
- communication timeouts.</p>
- <p>
- Own Id: OTP-12678 Aux Id: seq12818 </p>
- </item>
- </list>
- </section>
-
-</section>
-
<section><title>Common_Test 1.10.1</title>
<section><title>Fixed Bugs and Malfunctions</title>
diff --git a/lib/compiler/doc/src/notes.xml b/lib/compiler/doc/src/notes.xml
index 0654738247..9b5b44f3e1 100644
--- a/lib/compiler/doc/src/notes.xml
+++ b/lib/compiler/doc/src/notes.xml
@@ -31,94 +31,6 @@
<p>This document describes the changes made to the Compiler
application.</p>
-<section><title>Compiler 6.0</title>
-
- <section><title>Fixed Bugs and Malfunctions</title>
- <list>
- <item>
- <p>
- The compiler optimizes away building of terms that are
- never actually used. As a result, the compiler in OTP 18
- may produce more warnings for terms that are built but
- not used than the compiler in OTP 17.</p>
- <p>
- Own Id: OTP-12453</p>
- </item>
- <item>
- <p>
- Using a map could incorrectly suppress warnings for
- unused variables.</p>
- <p>
- Own Id: OTP-12515</p>
- </item>
- <item>
- <p>
- The compiler now properly reports unknown parse
- transforms. That is, <c>undef</c> exceptions coming from
- the parse transform itself is reported differently from
- the absence of the parse transform.</p>
- <p>
- Own Id: OTP-12723</p>
- </item>
- </list>
- </section>
-
-
- <section><title>Improvements and New Features</title>
- <list>
- <item>
- <p>
- The <c>cerl</c> and <c>cerl_trees</c> modules in the
- <c>compiler</c> application are now documented.</p>
- <p>
- Own Id: OTP-11978</p>
- </item>
- <item>
- <p>
- The deprecated '<c>asm</c>' option has been removed.</p>
- <p>
- *** POTENTIAL INCOMPATIBILITY ***</p>
- <p>
- Own Id: OTP-12100</p>
- </item>
- <item>
- <p>
- Support variables as Map keys in expressions and patterns</p>
- <p>Erlang will accept any expression as keys in Map
- expressions and it will accept literals or bound
- variables as keys in Map patterns.</p>
- <p>
- Own Id: OTP-12218</p>
- </item>
- <item>
- <p>
- Infer Map type information in beam_type compiler
- optimization pass.</p>
- <p>
- Own Id: OTP-12253</p>
- </item>
- <item>
- <p>
- Compiler optimizations have been improved.</p>
- <p>
- Own Id: OTP-12393</p>
- </item>
- <item>
- <p>
- Five undocumented functions in the module <c>core_lib</c>
- have been deprecated and will be removed in the next
- major release. The functions are: <c>get_anno/{1,2}</c>,
- <c>is_literal/1</c>, <c>is_literal_list/1</c>, and
- <c>literal_value</c>. Use the appropriate functions in
- the <c>cerl</c> module instead.</p>
- <p>
- Own Id: OTP-12497</p>
- </item>
- </list>
- </section>
-
-</section>
-
<section><title>Compiler 5.0.4</title>
<section><title>Fixed Bugs and Malfunctions</title>
diff --git a/lib/compiler/src/beam_bsm.erl b/lib/compiler/src/beam_bsm.erl
index 2a15c1ddf3..ee3e88959d 100644
--- a/lib/compiler/src/beam_bsm.erl
+++ b/lib/compiler/src/beam_bsm.erl
@@ -242,6 +242,12 @@ btb_reaches_match_2([{bif,_,{f,F},Ss,Dst}=I|Is], Regs0, D0) ->
Regs = btb_kill([Dst], Regs0),
D = btb_follow_branch(F, Regs, D0),
btb_reaches_match_1(Is, Regs, D);
+btb_reaches_match_2([{get_map_elements,{f,F},Src,{list,Ls}}=I|Is], Regs0, D0) ->
+ {Ss,Ds} = beam_utils:split_even(Ls),
+ btb_ensure_not_used([Src|Ss], I, Regs0),
+ Regs = btb_kill(Ds, Regs0),
+ D = btb_follow_branch(F, Regs, D0),
+ btb_reaches_match_1(Is, Regs, D);
btb_reaches_match_2([{test,bs_start_match2,{f,F},Live,[Ctx,_],Ctx}=I|Is],
Regs0, D0) ->
CtxRegs = btb_context_regs(Regs0),
diff --git a/lib/compiler/src/compile.erl b/lib/compiler/src/compile.erl
index 22810c910c..0158cf64db 100644
--- a/lib/compiler/src/compile.erl
+++ b/lib/compiler/src/compile.erl
@@ -342,10 +342,10 @@ run_tc({Name,Fun}, St) ->
run_eprof({Name,Fun}, Name, St) ->
io:format("~p: Running eprof\n", [Name]),
- eprof:start_profiling([self()]),
+ c:appcall(tools, eprof, start_profiling, [[self()]]),
Val = (catch Fun(St)),
- eprof:stop_profiling(),
- eprof:analyze(),
+ c:appcall(tools, eprof, stop_profiling, []),
+ c:appcall(tools, eprof, analyze, []),
Val;
run_eprof({_,Fun}, _, St) ->
catch Fun(St).
diff --git a/lib/compiler/src/compiler.app.src b/lib/compiler/src/compiler.app.src
index 2a40c1c379..17d1bd91ce 100644
--- a/lib/compiler/src/compiler.app.src
+++ b/lib/compiler/src/compiler.app.src
@@ -69,5 +69,5 @@
{registered, []},
{applications, [kernel, stdlib]},
{env, []},
- {runtime_dependencies, ["stdlib-2.0","kernel-3.0","hipe-3.10.3","erts-7.0",
- "crypto-3.3"]}]}.
+ {runtime_dependencies, ["stdlib-2.5","kernel-4.0","hipe-3.12","erts-7.0",
+ "crypto-3.6"]}]}.
diff --git a/lib/compiler/test/warnings_SUITE.erl b/lib/compiler/test/warnings_SUITE.erl
index f6ba75577d..5742b7e6cf 100644
--- a/lib/compiler/test/warnings_SUITE.erl
+++ b/lib/compiler/test/warnings_SUITE.erl
@@ -38,7 +38,8 @@
-export([pattern/1,pattern2/1,pattern3/1,pattern4/1,
guard/1,bad_arith/1,bool_cases/1,bad_apply/1,
files/1,effect/1,bin_opt_info/1,bin_construction/1,
- comprehensions/1,maps/1,redundant_boolean_clauses/1,
+ comprehensions/1,maps/1,maps_bin_opt_info/1,
+ redundant_boolean_clauses/1,
latin1_fallback/1,underscore/1,no_warnings/1]).
% Default timetrap timeout (set in init_per_testcase).
@@ -64,6 +65,7 @@ groups() ->
[pattern,pattern2,pattern3,pattern4,guard,
bad_arith,bool_cases,bad_apply,files,effect,
bin_opt_info,bin_construction,comprehensions,maps,
+ maps_bin_opt_info,
redundant_boolean_clauses,latin1_fallback,
underscore,no_warnings]}].
@@ -619,6 +621,19 @@ maps(Config) when is_list(Config) ->
run(Config, Ts),
ok.
+maps_bin_opt_info(Config) when is_list(Config) ->
+ Ts = [{map_bsm,
+ <<"
+ t1(<<0:8,7:8,T/binary>>,#{val := I}=M) ->
+ t1(T, M#{val := I+1});
+ t1(<<_:8>>,M) ->
+ M.
+ ">>,
+ [bin_opt_info],
+ {warnings,[{2,beam_bsm,bin_opt}]}}],
+ [] = run(Config, Ts),
+ ok.
+
redundant_boolean_clauses(Config) when is_list(Config) ->
Ts = [{redundant_boolean_clauses,
<<"
diff --git a/lib/compiler/vsn.mk b/lib/compiler/vsn.mk
index 69f71ba5dd..05e682c893 100644
--- a/lib/compiler/vsn.mk
+++ b/lib/compiler/vsn.mk
@@ -1 +1 @@
-COMPILER_VSN = 6.0
+COMPILER_VSN = 5.0.4
diff --git a/lib/cosEvent/doc/src/notes.xml b/lib/cosEvent/doc/src/notes.xml
index 229e0c9945..8f519447fc 100644
--- a/lib/cosEvent/doc/src/notes.xml
+++ b/lib/cosEvent/doc/src/notes.xml
@@ -32,23 +32,7 @@
<file>notes.xml</file>
</header>
- <section><title>cosEvent 2.2</title>
-
- <section><title>Improvements and New Features</title>
- <list>
- <item>
- <p> Remove the usage of erlang:now() from all Corba
- applications and use the new rand module instead of
- random. </p>
- <p>
- Own Id: OTP-12687</p>
- </item>
- </list>
- </section>
-
-</section>
-
-<section><title>cosEvent 2.1.15</title>
+ <section><title>cosEvent 2.1.15</title>
<section><title>Improvements and New Features</title>
<list>
diff --git a/lib/cosEventDomain/doc/src/notes.xml b/lib/cosEventDomain/doc/src/notes.xml
index 72408b52f4..2c3bf16411 100644
--- a/lib/cosEventDomain/doc/src/notes.xml
+++ b/lib/cosEventDomain/doc/src/notes.xml
@@ -31,23 +31,7 @@
<file>notes.xml</file>
</header>
- <section><title>cosEventDomain 1.2</title>
-
- <section><title>Improvements and New Features</title>
- <list>
- <item>
- <p> Remove the usage of erlang:now() from all Corba
- applications and use the new rand module instead of
- random. </p>
- <p>
- Own Id: OTP-12687</p>
- </item>
- </list>
- </section>
-
-</section>
-
-<section><title>cosEventDomain 1.1.14</title>
+ <section><title>cosEventDomain 1.1.14</title>
<section><title>Improvements and New Features</title>
<list>
diff --git a/lib/cosFileTransfer/doc/src/notes.xml b/lib/cosFileTransfer/doc/src/notes.xml
index a3cce2a7d8..1d0c826d40 100644
--- a/lib/cosFileTransfer/doc/src/notes.xml
+++ b/lib/cosFileTransfer/doc/src/notes.xml
@@ -30,23 +30,7 @@
<file>notes.xml</file>
</header>
- <section><title>cosFileTransfer 1.2</title>
-
- <section><title>Improvements and New Features</title>
- <list>
- <item>
- <p> Remove the usage of erlang:now() from all Corba
- applications and use the new rand module instead of
- random. </p>
- <p>
- Own Id: OTP-12687</p>
- </item>
- </list>
- </section>
-
-</section>
-
-<section><title>cosFileTransfer 1.1.16</title>
+ <section><title>cosFileTransfer 1.1.16</title>
<section><title>Improvements and New Features</title>
<list>
diff --git a/lib/cosNotification/doc/src/notes.xml b/lib/cosNotification/doc/src/notes.xml
index b16571a1cf..2e4f922142 100644
--- a/lib/cosNotification/doc/src/notes.xml
+++ b/lib/cosNotification/doc/src/notes.xml
@@ -31,23 +31,7 @@
<file>notes.xml</file>
</header>
- <section><title>cosNotification 1.2</title>
-
- <section><title>Improvements and New Features</title>
- <list>
- <item>
- <p> Remove the usage of erlang:now() from all Corba
- applications and use the new rand module instead of
- random. </p>
- <p>
- Own Id: OTP-12687</p>
- </item>
- </list>
- </section>
-
-</section>
-
-<section><title>cosNotification 1.1.21</title>
+ <section><title>cosNotification 1.1.21</title>
<section><title>Improvements and New Features</title>
<list>
diff --git a/lib/cosProperty/doc/src/notes.xml b/lib/cosProperty/doc/src/notes.xml
index 1885a8fd6b..739f41617f 100644
--- a/lib/cosProperty/doc/src/notes.xml
+++ b/lib/cosProperty/doc/src/notes.xml
@@ -31,23 +31,7 @@
<file>notes.xml</file>
</header>
- <section><title>cosProperty 1.2</title>
-
- <section><title>Improvements and New Features</title>
- <list>
- <item>
- <p> Remove the usage of erlang:now() from all Corba
- applications and use the new rand module instead of
- random. </p>
- <p>
- Own Id: OTP-12687</p>
- </item>
- </list>
- </section>
-
-</section>
-
-<section><title>cosProperty 1.1.17</title>
+ <section><title>cosProperty 1.1.17</title>
<section><title>Improvements and New Features</title>
<list>
diff --git a/lib/cosTime/doc/src/notes.xml b/lib/cosTime/doc/src/notes.xml
index 6c948c8c2b..f218f19a6b 100644
--- a/lib/cosTime/doc/src/notes.xml
+++ b/lib/cosTime/doc/src/notes.xml
@@ -32,23 +32,7 @@
<file>notes.xml</file>
</header>
- <section><title>cosTime 1.2</title>
-
- <section><title>Improvements and New Features</title>
- <list>
- <item>
- <p> Remove the usage of erlang:now() from all Corba
- applications and use the new rand module instead of
- random. </p>
- <p>
- Own Id: OTP-12687</p>
- </item>
- </list>
- </section>
-
-</section>
-
-<section><title>cosTime 1.1.14</title>
+ <section><title>cosTime 1.1.14</title>
<section><title>Improvements and New Features</title>
<list>
diff --git a/lib/cosTransactions/doc/src/notes.xml b/lib/cosTransactions/doc/src/notes.xml
index ae3b9eb6f2..4b20f23efb 100644
--- a/lib/cosTransactions/doc/src/notes.xml
+++ b/lib/cosTransactions/doc/src/notes.xml
@@ -32,23 +32,7 @@
<file>notes.xml</file>
</header>
- <section><title>cosTransactions 1.3</title>
-
- <section><title>Improvements and New Features</title>
- <list>
- <item>
- <p> Remove the usage of erlang:now() from all Corba
- applications and use the new rand module instead of
- random. </p>
- <p>
- Own Id: OTP-12687</p>
- </item>
- </list>
- </section>
-
-</section>
-
-<section><title>cosTransactions 1.2.14</title>
+ <section><title>cosTransactions 1.2.14</title>
<section><title>Improvements and New Features</title>
<list>
diff --git a/lib/crypto/doc/src/notes.xml b/lib/crypto/doc/src/notes.xml
index 6ab109e349..a0ebc4b3dd 100644
--- a/lib/crypto/doc/src/notes.xml
+++ b/lib/crypto/doc/src/notes.xml
@@ -30,49 +30,6 @@
</header>
<p>This document describes the changes made to the Crypto application.</p>
-<section><title>Crypto 3.6</title>
-
- <section><title>Fixed Bugs and Malfunctions</title>
- <list>
- <item>
- <p>
- Enhance crypto:generate_key to calculate ECC public keys
- from private key.</p>
- <p>
- Own Id: OTP-12394</p>
- </item>
- <item>
- <p>
- Fix bug in <c>crypto:generate_key</c> for <c>ecdh</c>
- that could cause VM crash for faulty input.</p>
- <p>
- Own Id: OTP-12733</p>
- </item>
- </list>
- </section>
-
-
- <section><title>Improvements and New Features</title>
- <list>
- <item>
- <p>
- Use the EVP API for AES-CBC crypto to enables the use of
- hardware acceleration for AES-CBC crypto on newer Intel
- CPUs (AES-NI), among other platforms.</p>
- <p>
- Own Id: OTP-12380</p>
- </item>
- <item>
- <p>
- Add AES ECB block encryption.</p>
- <p>
- Own Id: OTP-12403</p>
- </item>
- </list>
- </section>
-
-</section>
-
<section><title>Crypto 3.5</title>
<section><title>Improvements and New Features</title>
diff --git a/lib/crypto/vsn.mk b/lib/crypto/vsn.mk
index 55b1b3e8c4..8489b59562 100644
--- a/lib/crypto/vsn.mk
+++ b/lib/crypto/vsn.mk
@@ -1 +1 @@
-CRYPTO_VSN = 3.6
+CRYPTO_VSN = 3.5
diff --git a/lib/debugger/doc/src/notes.xml b/lib/debugger/doc/src/notes.xml
index 2bf80597b5..7384189a6f 100644
--- a/lib/debugger/doc/src/notes.xml
+++ b/lib/debugger/doc/src/notes.xml
@@ -32,24 +32,6 @@
<p>This document describes the changes made to the Debugger
application.</p>
-<section><title>Debugger 4.1</title>
-
- <section><title>Improvements and New Features</title>
- <list>
- <item>
- <p>
- Support variables as Map keys in expressions and patterns</p>
- <p>Erlang will accept any expression as keys in Map
- expressions and it will accept literals or bound
- variables as keys in Map patterns.</p>
- <p>
- Own Id: OTP-12218</p>
- </item>
- </list>
- </section>
-
-</section>
-
<section><title>Debugger 4.0.3</title>
<section><title>Fixed Bugs and Malfunctions</title>
diff --git a/lib/debugger/vsn.mk b/lib/debugger/vsn.mk
index b6fd4e8e44..b82f0f4e37 100644
--- a/lib/debugger/vsn.mk
+++ b/lib/debugger/vsn.mk
@@ -1 +1 @@
-DEBUGGER_VSN = 4.1
+DEBUGGER_VSN = 4.0.3
diff --git a/lib/dialyzer/doc/src/dialyzer.xml b/lib/dialyzer/doc/src/dialyzer.xml
index 2a8bf6edcc..5f52906625 100644
--- a/lib/dialyzer/doc/src/dialyzer.xml
+++ b/lib/dialyzer/doc/src/dialyzer.xml
@@ -368,6 +368,7 @@ Option :: {files, [Filename :: string()]}
| {include_dirs, [DirName :: string()]}
| {output_file, FileName :: string()}
| {output_plt, FileName :: string()}
+ | {check_plt, boolean()},
| {analysis_type, 'succ_typings' |
'plt_add' |
'plt_build' |
diff --git a/lib/dialyzer/doc/src/notes.xml b/lib/dialyzer/doc/src/notes.xml
index d30882b5b9..8976679c1d 100644
--- a/lib/dialyzer/doc/src/notes.xml
+++ b/lib/dialyzer/doc/src/notes.xml
@@ -31,92 +31,6 @@
<p>This document describes the changes made to the Dialyzer
application.</p>
-<section><title>Dialyzer 2.8</title>
-
- <section><title>Fixed Bugs and Malfunctions</title>
- <list>
- <item>
- <p> The translation of Erlang forms to the type
- representation used by Dialyzer has been improved in
- several ways. The most important change is that deeply
- nested records can be handled. </p>
- <p>
- Own Id: OTP-12350</p>
- </item>
- <item>
- <p> Update the PLT properly when a module is changed.
- (Thanks to James Fish for the bug report, and to Stavros
- Aronis for fixing the bug.) </p>
- <p>
- Own Id: OTP-12637</p>
- </item>
- <item>
- <p>
- An argument of '*'/2 is not constraind if the other
- operand can be zero.</p>
- <p>
- Own Id: OTP-12725</p>
- </item>
- </list>
- </section>
-
-
- <section><title>Improvements and New Features</title>
- <list>
- <item>
- <p> The <c>-dialyzer()</c> attribute can be used for
- suppressing warnings in a module by specifying functions
- or warning options. It can also be used for requesting
- warnings in a module. </p>
- <p>
- Own Id: OTP-10280</p>
- </item>
- <item>
- <p> The pre-defined types <c>array()</c>, <c>dict()</c>,
- <c>digraph()</c>, <c>gb_set()</c>, <c>gb_tree()</c>,
- <c>queue()</c>, <c>set()</c>, and <c>tid()</c> have been
- removed. </p>
- <p>
- Own Id: OTP-11445 Aux Id: OTP-10342, OTP-9352 </p>
- </item>
- <item>
- <p> A few type names that have been used for representing
- certain predefined types can now be used for user-defined
- types. This affects the types <c>product/_</c>,
- <c>union/_</c>, and <c>range/2</c> as well as
- <c>tuple/N</c> (N > 0), <c>map/N</c> (N > 0),
- <c>atom/1</c>, <c>integer/1</c>, <c>binary/2</c>,
- <c>record/_,</c> and <c>'fun'/_</c>. A consequence is
- that, for example, it is no longer possible to refer to a
- record type with <c>record(r)</c>; instead the usual
- record notation, <c>#r{}</c>, is to be used. </p>
- <p>
- *** POTENTIAL INCOMPATIBILITY ***</p>
- <p>
- Own Id: OTP-11851</p>
- </item>
- <item>
- <p> When implementing user-defined behaviours it is now
- possible to specify optional callback functions. See OTP
- Design Principles User's Guide, Sys and Proc_Lib,
- User-Defined Behaviours, for details. </p>
- <p>
- Own Id: OTP-11861</p>
- </item>
- <item>
- <p>Add two options to the Dialyzer:
- <c>no_missing_calls</c> suppresses warnings about calls
- to missing or unexported functions; <c>unknown</c> lets
- warnings about unknown functions or types affect the exit
- status. See also dialyzer(3). </p>
- <p>
- Own Id: OTP-12682</p>
- </item>
- </list>
- </section>
-
-</section>
-
<section><title>Dialyzer 2.7.4</title>
<section><title>Fixed Bugs and Malfunctions</title>
diff --git a/lib/dialyzer/src/dialyzer.erl b/lib/dialyzer/src/dialyzer.erl
index c9e7da9ef0..c8537e3bd8 100644
--- a/lib/dialyzer/src/dialyzer.erl
+++ b/lib/dialyzer/src/dialyzer.erl
@@ -2,7 +2,7 @@
%%-----------------------------------------------------------------------
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2006-2014. All Rights Reserved.
+%% Copyright Ericsson AB 2006-2015. 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
@@ -162,14 +162,7 @@ run(Opts) ->
{error, Msg} ->
throw({dialyzer_error, Msg});
OptsRecord ->
- case OptsRecord#options.check_plt of
- true ->
- case cl_check_init(OptsRecord) of
- {ok, ?RET_NOTHING_SUSPICIOUS} -> ok;
- {error, ErrorMsg1} -> throw({dialyzer_error, ErrorMsg1})
- end;
- false -> ok
- end,
+ ok = check_init(OptsRecord),
case dialyzer_cl:start(OptsRecord) of
{?RET_DISCREPANCIES, Warnings} -> Warnings;
{?RET_NOTHING_SUSPICIOUS, _} -> []
@@ -179,6 +172,16 @@ run(Opts) ->
erlang:error({dialyzer_error, lists:flatten(ErrorMsg)})
end.
+check_init(#options{analysis_type = plt_check}) ->
+ ok;
+check_init(#options{check_plt = true} = OptsRecord) ->
+ case cl_check_init(OptsRecord) of
+ {ok, _} -> ok;
+ {error, Msg} -> throw({dialyzer_error, Msg})
+ end;
+check_init(#options{check_plt = false}) ->
+ ok.
+
internal_gui(OptsRecord) ->
F = fun() ->
dialyzer_gui_wx:start(OptsRecord),
@@ -199,17 +202,13 @@ gui(Opts) ->
throw({dialyzer_error, Msg});
OptsRecord ->
ok = check_gui_options(OptsRecord),
- case cl_check_init(OptsRecord) of
- {ok, ?RET_NOTHING_SUSPICIOUS} ->
- F = fun() ->
- dialyzer_gui_wx:start(OptsRecord)
- end,
- case doit(F) of
- {ok, _} -> ok;
- {error, Msg} -> throw({dialyzer_error, Msg})
- end;
- {error, ErrorMsg1} ->
- throw({dialyzer_error, ErrorMsg1})
+ ok = check_init(OptsRecord),
+ F = fun() ->
+ dialyzer_gui_wx:start(OptsRecord)
+ end,
+ case doit(F) of
+ {ok, _} -> ok;
+ {error, Msg} -> throw({dialyzer_error, Msg})
end
catch
throw:{dialyzer_error, ErrorMsg} ->
diff --git a/lib/dialyzer/test/plt_SUITE.erl b/lib/dialyzer/test/plt_SUITE.erl
index ef4cdc57f0..ecbac14e5d 100644
--- a/lib/dialyzer/test/plt_SUITE.erl
+++ b/lib/dialyzer/test/plt_SUITE.erl
@@ -6,12 +6,13 @@
-include_lib("common_test/include/ct.hrl").
-include("dialyzer_test_constants.hrl").
--export([suite/0, all/0, build_plt/1, beam_tests/1, update_plt/1]).
+-export([suite/0, all/0, build_plt/1, beam_tests/1, update_plt/1,
+ run_plt_check/1, run_succ_typings/1]).
suite() ->
[{timetrap, ?plt_timeout}].
-all() -> [build_plt, beam_tests, update_plt].
+all() -> [build_plt, beam_tests, update_plt, run_plt_check, run_succ_typings].
build_plt(Config) ->
OutDir = ?config(priv_dir, Config),
@@ -37,14 +38,76 @@ beam_tests(Config) when is_list(Config) ->
">>,
Opts = [no_auto_import],
{ok, BeamFile} = compile(Config, Prog, no_auto_import, Opts),
- [] = run_dialyzer([BeamFile]),
+ [] = run_dialyzer(plt_build, [BeamFile], []),
ok.
-run_dialyzer(Files) ->
- dialyzer:run([{analysis_type, plt_build},
- {files, Files},
- {from, byte_code},
- {check_plt, false}]).
+run_plt_check(Config) when is_list(Config) ->
+ Mod1 = <<"
+ -module(run_plt_check1).
+ ">>,
+
+ Mod2A = <<"
+ -module(run_plt_check2).
+ ">>,
+
+ {ok, BeamFile1} = compile(Config, Mod1, run_plt_check1, []),
+ {ok, BeamFile2} = compile(Config, Mod2A, run_plt_check2, []),
+ [] = run_dialyzer(plt_build, [BeamFile1, BeamFile2], []),
+
+ Mod2B = <<"
+ -module(run_plt_check2).
+
+ -export([call/1]).
+
+ call(X) -> run_plt_check1:call(X).
+ ">>,
+
+ {ok, BeamFile2} = compile(Config, Mod2B, run_plt_check2, []),
+
+ % callgraph warning as run_plt_check2:call/1 makes a call to unexported
+ % function run_plt_check1:call/1.
+ [_] = run_dialyzer(plt_check, [], []),
+
+ ok.
+
+run_succ_typings(Config) when is_list(Config) ->
+ Mod1A = <<"
+ -module(run_succ_typings1).
+
+ -export([call/0]).
+
+ call() -> a.
+ ">>,
+
+ {ok, BeamFile1} = compile(Config, Mod1A, run_succ_typings1, []),
+ [] = run_dialyzer(plt_build, [BeamFile1], []),
+
+ Mod1B = <<"
+ -module(run_succ_typings1).
+
+ -export([call/0]).
+
+ call() -> b.
+ ">>,
+
+ Mod2 = <<"
+ -module(run_succ_typings2).
+
+ -export([call/0]).
+
+ -spec call() -> b.
+ call() -> run_succ_typings1:call().
+ ">>,
+
+ {ok, BeamFile1} = compile(Config, Mod1B, run_succ_typings1, []),
+ {ok, BeamFile2} = compile(Config, Mod2, run_succ_typings2, []),
+ % contract types warning as run_succ_typings2:call/0 makes a call to
+ % run_succ_typings1:call/0, which returns a (not b) in the PLT.
+ [_] = run_dialyzer(succ_typings, [BeamFile2], [{check_plt, false}]),
+ % warning not returned as run_succ_typings1 is updated in the PLT.
+ [] = run_dialyzer(succ_typings, [BeamFile2], [{check_plt, true}]),
+
+ ok.
%%% [James Fish:]
%%% If a function is removed from a module and the module has previously
@@ -103,3 +166,9 @@ compile(Config, Prog, Module, CompileOpts) ->
Opts = [{outdir, PrivDir}, debug_info | CompileOpts],
{ok, Module} = compile:file(Filename, Opts),
{ok, filename:join([PrivDir, lists:concat([Module, ".beam"])])}.
+
+run_dialyzer(Analysis, Files, Opts) ->
+ dialyzer:run([{analysis_type, Analysis},
+ {files, Files},
+ {from, byte_code} |
+ Opts]).
diff --git a/lib/dialyzer/vsn.mk b/lib/dialyzer/vsn.mk
index 48e0830109..527afaf4ef 100644
--- a/lib/dialyzer/vsn.mk
+++ b/lib/dialyzer/vsn.mk
@@ -1 +1 @@
-DIALYZER_VSN = 2.8
+DIALYZER_VSN = 2.7.4
diff --git a/lib/edoc/doc/src/notes.xml b/lib/edoc/doc/src/notes.xml
index 48bb415ab3..e350adb540 100644
--- a/lib/edoc/doc/src/notes.xml
+++ b/lib/edoc/doc/src/notes.xml
@@ -31,21 +31,6 @@
<p>This document describes the changes made to the EDoc
application.</p>
-<section><title>Edoc 0.7.17</title>
-
- <section><title>Improvements and New Features</title>
- <list>
- <item>
- <p>
- Remove functionality related to packages</p>
- <p>
- Own Id: OTP-12431</p>
- </item>
- </list>
- </section>
-
-</section>
-
<section><title>Edoc 0.7.16</title>
<section><title>Fixed Bugs and Malfunctions</title>
diff --git a/lib/edoc/vsn.mk b/lib/edoc/vsn.mk
index 49a73331c6..24cfbf16d5 100644
--- a/lib/edoc/vsn.mk
+++ b/lib/edoc/vsn.mk
@@ -1 +1 @@
-EDOC_VSN = 0.7.17
+EDOC_VSN = 0.7.16
diff --git a/lib/eldap/doc/src/eldap.xml b/lib/eldap/doc/src/eldap.xml
index a6fad8a857..253ba7c2ff 100644
--- a/lib/eldap/doc/src/eldap.xml
+++ b/lib/eldap/doc/src/eldap.xml
@@ -121,7 +121,7 @@ filter() See present/1, substrings/2,
<item>Any error responded from ssl:connect/3</item>
</taglist>
<p>The <c>Timeout</c> parameter is for the actual tls upgrade (phase 2) while the timeout in
- <seealso marker="#open/2">erl_tar:open/2</seealso> is used for the initial negotiation about
+ <seealso marker="#open/2">eldap:open/2</seealso> is used for the initial negotiation about
upgrade (phase 1).
</p>
</desc>
@@ -298,7 +298,7 @@ filter() See present/1, substrings/2,
search(Handle, [{base, "dc=example, dc=com"}, {filter, Filter}, {attributes, ["cn"]}]),
</pre>
<p>The <c>timeout</c> option in the <c>SearchOptions</c> is for the ldap server, while
- the timeout in <seealso marker="#open/2">erl_tar:open/2</seealso> is used for each
+ the timeout in <seealso marker="#open/2">eldap:open/2</seealso> is used for each
individual request in the search operation.
</p>
</desc>
diff --git a/lib/eldap/doc/src/notes.xml b/lib/eldap/doc/src/notes.xml
index a7aefefb4a..e76101c30e 100644
--- a/lib/eldap/doc/src/notes.xml
+++ b/lib/eldap/doc/src/notes.xml
@@ -30,22 +30,6 @@
</header>
<p>This document describes the changes made to the Eldap application.</p>
-<section><title>Eldap 1.2</title>
-
- <section><title>Improvements and New Features</title>
- <list>
- <item>
- <p>
- Support added for LDAP Password Modify Extended Operation
- (RFC 3062). Thanks to danielwhite.</p>
- <p>
- Own Id: OTP-12282</p>
- </item>
- </list>
- </section>
-
-</section>
-
<section><title>Eldap 1.1.1</title>
<section><title>Fixed Bugs and Malfunctions</title>
diff --git a/lib/erl_docgen/vsn.mk b/lib/erl_docgen/vsn.mk
index 5823c96253..2abd3d2b7e 100644
--- a/lib/erl_docgen/vsn.mk
+++ b/lib/erl_docgen/vsn.mk
@@ -1 +1 @@
-ERL_DOCGEN_VSN = 0.3.8
+ERL_DOCGEN_VSN = 0.4
diff --git a/lib/eunit/doc/overview.edoc b/lib/eunit/doc/overview.edoc
index df716cdeea..eb60f673ef 100644
--- a/lib/eunit/doc/overview.edoc
+++ b/lib/eunit/doc/overview.edoc
@@ -572,6 +572,21 @@ Examples:
<dt>`assertNotMatch(GuardedPattern, Expr)'</dt>
<dd>The inverse case of assertMatch, for convenience.
</dd>
+<dt>`assertReceive(GuardedPattern, Timeout)'</dt>
+<dd>Waits for up to the `Timeout' milliseconds for a message to arrive
+in the mailbox of the current process that matches against the
+`GuardedPattern' if testing is enabled.
+If no message matching the `GuardedPattern' is received in the specified
+`Timeout' interval, the assertion fails and an informative exception will
+be generated; see the `assert' macro for further details. `GuardedPattern'
+can be anything that you can write on the left hand side of the `->'
+symbol in a case-clause, except that it cannot contain comma-separated
+guard tests.
+
+Examples:
+```?assertReceive(done, 1000)'''
+```?assertReceive(Bin when byte_size(Bin) > 10, 1000)'''
+</dd>
<dt>`assertEqual(Expect, Expr)'</dt>
<dd>Evaluates the expressions `Expect' and `Expr' and compares the
results for equality, if testing is enabled. If the values are not
diff --git a/lib/eunit/doc/src/notes.xml b/lib/eunit/doc/src/notes.xml
index 3c6daf142e..6b76e097b6 100644
--- a/lib/eunit/doc/src/notes.xml
+++ b/lib/eunit/doc/src/notes.xml
@@ -32,20 +32,6 @@
</header>
<p>This document describes the changes made to the EUnit application.</p>
-<section><title>Eunit 2.2.10</title>
-
- <section><title>Fixed Bugs and Malfunctions</title>
- <list>
- <item>
- <p>The <c>eunit</c> application is now unicode safe.</p>
- <p>
- Own Id: OTP-11660</p>
- </item>
- </list>
- </section>
-
-</section>
-
<section><title>Eunit 2.2.9</title>
<section><title>Fixed Bugs and Malfunctions</title>
diff --git a/lib/eunit/include/eunit.hrl b/lib/eunit/include/eunit.hrl
index 53d291430d..8a829396ec 100644
--- a/lib/eunit/include/eunit.hrl
+++ b/lib/eunit/include/eunit.hrl
@@ -166,6 +166,26 @@
%% This is mostly a convenience which gives more detailed reports.
%% Note: Guard is a guarded pattern, and can not be used for value.
-ifdef(NOASSERT).
+-define(assertReceive(Guard, Timeout), ok).
+-else.
+-define(assertReceive(Guard, Timeout),
+ begin
+ ((fun () ->
+ receive (Guard) -> ok
+ after Timeout -> erlang:error({assertReceive_timedout,
+ [{module, ?MODULE},
+ {line, ?LINE},
+ {pattern, (??Guard)},
+ {timeout, __V}]})
+ end
+ end)())
+ end).
+-endif.
+-define(_assertReceive(Guard, Timeout), ?_test(?assertReceive(Guard, Timeout))).
+
+%% This is mostly a convenience which gives more detailed reports.
+%% Note: Guard is a guarded pattern, and can not be used for value.
+-ifdef(NOASSERT).
-define(assertMatch(Guard, Expr), ok).
-else.
-define(assertMatch(Guard, Expr),
diff --git a/lib/eunit/vsn.mk b/lib/eunit/vsn.mk
index 8b489bdc04..dca8b3ece0 100644
--- a/lib/eunit/vsn.mk
+++ b/lib/eunit/vsn.mk
@@ -1 +1 @@
-EUNIT_VSN = 2.2.10
+EUNIT_VSN = 2.2.9
diff --git a/lib/hipe/doc/src/notes.xml b/lib/hipe/doc/src/notes.xml
index 1cc8558fe8..8d3358533b 100644
--- a/lib/hipe/doc/src/notes.xml
+++ b/lib/hipe/doc/src/notes.xml
@@ -30,42 +30,6 @@
</header>
<p>This document describes the changes made to HiPE.</p>
-<section><title>Hipe 3.12</title>
-
- <section><title>Fixed Bugs and Malfunctions</title>
- <list>
- <item>
- <p> Fix a minor bug in the handling of opaque types. </p>
- <p>
- Own Id: OTP-12666</p>
- </item>
- <item>
- <p>
- Fix hipe bug when matching a "writable" binary. The bug
- has been seen to sometimes cause a failed binary matching
- of a correct utf8 character, but other symptoms are also
- possible.</p>
- <p>
- Own Id: OTP-12667</p>
- </item>
- </list>
- </section>
-
-
- <section><title>Improvements and New Features</title>
- <list>
- <item>
- <p>
- Improved error handling when memory allocation for HiPE
- code fails.</p>
- <p>
- Own Id: OTP-12448</p>
- </item>
- </list>
- </section>
-
-</section>
-
<section><title>Hipe 3.11.3</title>
<section><title>Fixed Bugs and Malfunctions</title>
diff --git a/lib/hipe/vsn.mk b/lib/hipe/vsn.mk
index e507ae933f..60b4e0559b 100644
--- a/lib/hipe/vsn.mk
+++ b/lib/hipe/vsn.mk
@@ -1 +1 @@
-HIPE_VSN = 3.12
+HIPE_VSN = 3.11.3
diff --git a/lib/inets/doc/src/notes.xml b/lib/inets/doc/src/notes.xml
index 7939787601..bae8e327a3 100644
--- a/lib/inets/doc/src/notes.xml
+++ b/lib/inets/doc/src/notes.xml
@@ -32,19 +32,15 @@
<file>notes.xml</file>
</header>
- <section><title>Inets 6.0</title>
+ <section><title>Inets 5.10.8</title>
- <section><title>Improvements and New Features</title>
+ <section><title>Fixed Bugs and Malfunctions</title>
<list>
<item>
<p>
- Remove Server Side Include support from inets, as this is
- an old technic that has security issues and was not well
- tested.</p>
- <p>
- *** POTENTIAL INCOMPATIBILITY ***</p>
+ Reject messages with a Content-Length less than 0</p>
<p>
- Own Id: OTP-12156</p>
+ Own Id: OTP-12739 Aux Id: seq12860 </p>
</item>
</list>
</section>
diff --git a/lib/inets/src/http_server/httpd_request.erl b/lib/inets/src/http_server/httpd_request.erl
index 6985065c3e..3ff07616f9 100644
--- a/lib/inets/src/http_server/httpd_request.erl
+++ b/lib/inets/src/http_server/httpd_request.erl
@@ -417,8 +417,12 @@ check_header({"content-length", Value}, Maxsizes) ->
case length(Value) =< MaxLen of
true ->
try
- _ = list_to_integer(Value),
- ok
+ list_to_integer(Value)
+ of
+ I when I>= 0 ->
+ ok;
+ _ ->
+ {error, {size_error, Max, 411, "negative content-length"}}
catch _:_ ->
{error, {size_error, Max, 411, "content-length not an integer"}}
end;
diff --git a/lib/inets/vsn.mk b/lib/inets/vsn.mk
index d5cb460404..ecb84e447c 100644
--- a/lib/inets/vsn.mk
+++ b/lib/inets/vsn.mk
@@ -18,6 +18,6 @@
# %CopyrightEnd%
APPLICATION = inets
-INETS_VSN = 6.0
+INETS_VSN = 5.10.8
PRE_VSN =
APP_VSN = "$(APPLICATION)-$(INETS_VSN)$(PRE_VSN)"
diff --git a/lib/jinterface/doc/src/notes.xml b/lib/jinterface/doc/src/notes.xml
index f854fa1f3a..fc5f8be53e 100644
--- a/lib/jinterface/doc/src/notes.xml
+++ b/lib/jinterface/doc/src/notes.xml
@@ -30,59 +30,6 @@
</header>
<p>This document describes the changes made to the Jinterface application.</p>
-<section><title>Jinterface 1.6</title>
-
- <section><title>Fixed Bugs and Malfunctions</title>
- <list>
- <item>
- <p>
- Reformat the sources for JInterface uniformly and
- according to the standard Java style guidelines. Provide
- description of the rules applied in Eclipse format (for
- other editors one can check the settings against these).</p>
- <p>
- In short, the formatting style is: * indentation uses
- only spaces; each level is 4 positions * no trailing
- whitespace * mostly default Java style formatting (any
- difference is minor) * always use {} blocks * use 'final'
- as much as possible</p>
- <p>
- Own Id: OTP-12333</p>
- </item>
- </list>
- </section>
-
-
- <section><title>Improvements and New Features</title>
- <list>
- <item>
- <p>
- Add basic transport factory implementation. This makes
- possible creating connections between nodes using ssh
- channels for example.</p>
- <p>
- Own Id: OTP-12686</p>
- </item>
- <item>
- <p>
- Add Jinterface generic match and bind methods to provide
- low level interface base methods sufficient for variety
- of higher level pattern matching/variable binding
- implementations.</p>
- <p>
- Own Id: OTP-12691</p>
- </item>
- <item>
- <p>
- Minimal Java version is now 1.6</p>
- <p>
- Own Id: OTP-12718</p>
- </item>
- </list>
- </section>
-
-</section>
-
<section><title>Jinterface 1.5.12</title>
<section><title>Fixed Bugs and Malfunctions</title>
diff --git a/lib/jinterface/java_src/com/ericsson/otp/erlang/OtpSelf.java b/lib/jinterface/java_src/com/ericsson/otp/erlang/OtpSelf.java
index 5b9d13ad81..74afbbcca6 100644
--- a/lib/jinterface/java_src/com/ericsson/otp/erlang/OtpSelf.java
+++ b/lib/jinterface/java_src/com/ericsson/otp/erlang/OtpSelf.java
@@ -153,9 +153,6 @@ public class OtpSelf extends OtpLocalNode {
* the port number you wish to use for incoming connections.
* Specifying 0 lets the system choose an available port.
*
- * @param transportFactory
- * the transport factory to use when creating connections.
- *
* @exception IOException
* in case of server transport failure
*/
diff --git a/lib/jinterface/vsn.mk b/lib/jinterface/vsn.mk
index 4df01d1151..72ad316333 100644
--- a/lib/jinterface/vsn.mk
+++ b/lib/jinterface/vsn.mk
@@ -1 +1 @@
-JINTERFACE_VSN = 1.6
+JINTERFACE_VSN = 1.5.12
diff --git a/lib/kernel/doc/src/notes.xml b/lib/kernel/doc/src/notes.xml
index 0bd9a067ca..6f7f18a8e7 100644
--- a/lib/kernel/doc/src/notes.xml
+++ b/lib/kernel/doc/src/notes.xml
@@ -30,79 +30,6 @@
</header>
<p>This document describes the changes made to the Kernel application.</p>
-<section><title>Kernel 4.0</title>
-
- <section><title>Fixed Bugs and Malfunctions</title>
- <list>
- <item>
- <p>
- Fix error handling in <c>file:read_line/1</c> for Unicode
- contents.</p>
- <p>
- Own Id: OTP-12144</p>
- </item>
- <item>
- <p>
- Introduce <c>os:getenv/2</c> which is similar to
- <c>os:getenv/1</c> but returns the passed default value
- if the required environment variable is undefined.</p>
- <p>
- Own Id: OTP-12342</p>
- </item>
- <item>
- <p>
- It is now possible to paste text in JCL mode (using
- Ctrl-Y) that has been copied in the previous shell
- session. Also a bug that caused the JCL mode to crash
- when pasting text has been fixed.</p>
- <p>
- Own Id: OTP-12673</p>
- </item>
- </list>
- </section>
-
-
- <section><title>Improvements and New Features</title>
- <list>
- <item>
- <p>
- New BIF: <c>erlang:get_keys/0</c>, lists all keys
- associated with the process dictionary. Note:
- <c>erlang:get_keys/0</c> is auto-imported.</p>
- <p>
- *** POTENTIAL INCOMPATIBILITY ***</p>
- <p>
- Own Id: OTP-12151 Aux Id: seq12521 </p>
- </item>
- <item>
- <p>
- The internal group to user_drv protocol has been changed
- to be synchronous in order to guarantee that output sent
- to a process implementing the user_drv protocol is
- printed before replying. This protocol is used by the
- standard_output device and the ssh application when
- acting as a client. </p>
- <p>
- This change changes the previous unlimited buffer when
- printing to standard_io and other devices that end up in
- user_drv to 1KB.</p>
- <p>
- *** POTENTIAL INCOMPATIBILITY ***</p>
- <p>
- Own Id: OTP-12240</p>
- </item>
- <item>
- <p>The <c>inflateInit/2</c> and <c>deflateInit/6</c>
- functions now accepts a WindowBits argument equal to 8
- and -8.</p>
- <p>
- Own Id: OTP-12564</p>
- </item>
- </list>
- </section>
-
-</section>
-
<section><title>Kernel 3.2</title>
<section><title>Fixed Bugs and Malfunctions</title>
diff --git a/lib/kernel/src/application_controller.erl b/lib/kernel/src/application_controller.erl
index 6635885aaf..a1a99a4e18 100644
--- a/lib/kernel/src/application_controller.erl
+++ b/lib/kernel/src/application_controller.erl
@@ -490,7 +490,8 @@ 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,
+ {read_concurrency,true}]),
S = #state{conf_data = ConfData},
{ok, KAppl} = make_appl(Kernel),
case catch load(S, KAppl) of
diff --git a/lib/kernel/src/code.erl b/lib/kernel/src/code.erl
index d73d1ff281..5cc38325b1 100644
--- a/lib/kernel/src/code.erl
+++ b/lib/kernel/src/code.erl
@@ -107,7 +107,7 @@ is_module_native(_) ->
-spec make_stub_module(Module, Beam, Info) -> Module when
Module :: module(),
Beam :: binary(),
- Info :: {list(), list()}.
+ Info :: {list(), list(), binary()}.
make_stub_module(_, _, _) ->
erlang:nif_error(undef).
diff --git a/lib/kernel/src/inet_tcp_dist.erl b/lib/kernel/src/inet_tcp_dist.erl
index 835dcf2705..fb60a14afb 100644
--- a/lib/kernel/src/inet_tcp_dist.erl
+++ b/lib/kernel/src/inet_tcp_dist.erl
@@ -112,7 +112,6 @@ listen_options(Opts0) ->
end,
case application:get_env(kernel, inet_dist_listen_options) of
{ok,ListenOpts} ->
- erlang:display({inet_dist_listen_options, ListenOpts}),
ListenOpts ++ Opts1;
_ ->
Opts1
@@ -340,7 +339,6 @@ do_setup(Kernel, Node, Type, MyNode, LongOrShortNames,SetupTime) ->
connect_options(Opts) ->
case application:get_env(kernel, inet_dist_connect_options) of
{ok,ConnectOpts} ->
- erlang:display({inet_dist_listen_options, ConnectOpts}),
ConnectOpts ++ Opts;
_ ->
Opts
diff --git a/lib/kernel/src/kernel.app.src b/lib/kernel/src/kernel.app.src
index 0cb10791d7..9787dca162 100644
--- a/lib/kernel/src/kernel.app.src
+++ b/lib/kernel/src/kernel.app.src
@@ -115,6 +115,6 @@
{applications, []},
{env, [{error_logger, tty}]},
{mod, {kernel, []}},
- {runtime_dependencies, ["erts-7.0", "stdlib-2.0", "sasl-2.4"]}
+ {runtime_dependencies, ["erts-7.0", "stdlib-2.5", "sasl-2.4"]}
]
}.
diff --git a/lib/kernel/vsn.mk b/lib/kernel/vsn.mk
index c912da0091..e1d447a465 100644
--- a/lib/kernel/vsn.mk
+++ b/lib/kernel/vsn.mk
@@ -1 +1 @@
-KERNEL_VSN = 4.0
+KERNEL_VSN = 3.2
diff --git a/lib/mnesia/doc/src/notes.xml b/lib/mnesia/doc/src/notes.xml
index 7f6ff1e655..dc98efbff3 100644
--- a/lib/mnesia/doc/src/notes.xml
+++ b/lib/mnesia/doc/src/notes.xml
@@ -38,37 +38,7 @@
thus constitutes one section in this document. The title of each
section is the version number of Mnesia.</p>
- <section><title>Mnesia 4.13</title>
-
- <section><title>Fixed Bugs and Malfunctions</title>
- <list>
- <item>
- <p>
- Mnesia's dirty functions did not always exit with
- <c>{aborted, Reason}</c> as documented when an error
- occurred.</p>
- <p>
- Own Id: OTP-12714</p>
- </item>
- </list>
- </section>
-
-
- <section><title>Improvements and New Features</title>
- <list>
- <item>
- <p>
- Make Mnesia DCD dump behavior at start up optional, when
- turned off mnesia loads large disc_copies tables faster.</p>
- <p>
- Own Id: OTP-12481</p>
- </item>
- </list>
- </section>
-
-</section>
-
-<section><title>Mnesia 4.12.5</title>
+ <section><title>Mnesia 4.12.5</title>
<section><title>Fixed Bugs and Malfunctions</title>
<list>
diff --git a/lib/mnesia/vsn.mk b/lib/mnesia/vsn.mk
index 79dd495c4b..b23339e408 100644
--- a/lib/mnesia/vsn.mk
+++ b/lib/mnesia/vsn.mk
@@ -1 +1 @@
-MNESIA_VSN = 4.13
+MNESIA_VSN = 4.12.5
diff --git a/lib/observer/doc/src/notes.xml b/lib/observer/doc/src/notes.xml
index 338708db43..a9ec68fc9e 100644
--- a/lib/observer/doc/src/notes.xml
+++ b/lib/observer/doc/src/notes.xml
@@ -31,28 +31,6 @@
<p>This document describes the changes made to the Observer
application.</p>
-<section><title>Observer 2.1</title>
-
- <section><title>Improvements and New Features</title>
- <list>
- <item>
- <p>
- Added the possibility to view sasl log entries for
- processes.</p>
- <p>
- Own Id: OTP-12504</p>
- </item>
- <item>
- <p>
- Add memory allocator usage and utilization graphs.</p>
- <p>
- Own Id: OTP-12631</p>
- </item>
- </list>
- </section>
-
-</section>
-
<section><title>Observer 2.0.4</title>
<section><title>Fixed Bugs and Malfunctions</title>
diff --git a/lib/observer/vsn.mk b/lib/observer/vsn.mk
index 7e7e32099b..10ed3bdfe5 100644
--- a/lib/observer/vsn.mk
+++ b/lib/observer/vsn.mk
@@ -1 +1 @@
-OBSERVER_VSN = 2.1
+OBSERVER_VSN = 2.0.4
diff --git a/lib/orber/doc/src/notes.xml b/lib/orber/doc/src/notes.xml
index 1ffd86a1fb..2167a43eee 100644
--- a/lib/orber/doc/src/notes.xml
+++ b/lib/orber/doc/src/notes.xml
@@ -33,23 +33,7 @@
</header>
- <section><title>Orber 3.8</title>
-
- <section><title>Improvements and New Features</title>
- <list>
- <item>
- <p> Remove the usage of erlang:now() from all Corba
- applications and use the new rand module instead of
- random. </p>
- <p>
- Own Id: OTP-12687</p>
- </item>
- </list>
- </section>
-
-</section>
-
-<section><title>Orber 3.7.1</title>
+ <section><title>Orber 3.7.1</title>
<section><title>Fixed Bugs and Malfunctions</title>
<list>
diff --git a/lib/orber/src/orber.app.src b/lib/orber/src/orber.app.src
index 5dda63982f..217c1b247f 100644
--- a/lib/orber/src/orber.app.src
+++ b/lib/orber/src/orber.app.src
@@ -104,7 +104,7 @@
{applications, [stdlib, kernel, mnesia]},
{env, []},
{mod, {orber, []}},
- {runtime_dependencies, ["stdlib-2.0","ssl-5.3.4","mnesia-4.12","kernel-3.0",
+ {runtime_dependencies, ["stdlib-2.5","ssl-5.3.4","mnesia-4.12","kernel-3.0",
"inets-5.10","erts-7.0"]}
]}.
diff --git a/lib/os_mon/doc/src/notes.xml b/lib/os_mon/doc/src/notes.xml
index bd4206d748..d3acc1effc 100644
--- a/lib/os_mon/doc/src/notes.xml
+++ b/lib/os_mon/doc/src/notes.xml
@@ -30,25 +30,6 @@
</header>
<p>This document describes the changes made to the OS_Mon application.</p>
-<section><title>Os_Mon 2.4</title>
-
- <section><title>Improvements and New Features</title>
- <list>
- <item>
- <p>
- cpu_sup should use native sysctl/libkvm calls on BSD</p>
- <p>
- This avoids forking off with os:cmd every time we just
- want to collect the load averages. riak does this every
- second, which results in a lot of unnecessary load.</p>
- <p>
- Own Id: OTP-12730</p>
- </item>
- </list>
- </section>
-
-</section>
-
<section><title>Os_Mon 2.3.1</title>
<section><title>Fixed Bugs and Malfunctions</title>
diff --git a/lib/os_mon/vsn.mk b/lib/os_mon/vsn.mk
index 7f2667e40a..833e855e0e 100644
--- a/lib/os_mon/vsn.mk
+++ b/lib/os_mon/vsn.mk
@@ -1 +1 @@
-OS_MON_VSN = 2.4
+OS_MON_VSN = 2.3.1
diff --git a/lib/parsetools/doc/src/notes.xml b/lib/parsetools/doc/src/notes.xml
index 1751238d20..c8cb70b6d2 100644
--- a/lib/parsetools/doc/src/notes.xml
+++ b/lib/parsetools/doc/src/notes.xml
@@ -30,21 +30,6 @@
</header>
<p>This document describes the changes made to the Parsetools application.</p>
-<section><title>Parsetools 2.1</title>
-
- <section><title>Improvements and New Features</title>
- <list>
- <item>
- <p> The new <c>-dialyzer()</c> attribute is used for
- suppressing Dialyzer warnings in generated code. </p>
- <p>
- Own Id: OTP-12271</p>
- </item>
- </list>
- </section>
-
-</section>
-
<section><title>Parsetools 2.0.12</title>
<section><title>Fixed Bugs and Malfunctions</title>
diff --git a/lib/parsetools/vsn.mk b/lib/parsetools/vsn.mk
index b99b3bb713..dd9cc2991c 100644
--- a/lib/parsetools/vsn.mk
+++ b/lib/parsetools/vsn.mk
@@ -1 +1 @@
-PARSETOOLS_VSN = 2.1
+PARSETOOLS_VSN = 2.0.12
diff --git a/lib/percept/doc/src/notes.xml b/lib/percept/doc/src/notes.xml
index 19d6cd6d01..b51c8fcb4d 100644
--- a/lib/percept/doc/src/notes.xml
+++ b/lib/percept/doc/src/notes.xml
@@ -32,21 +32,6 @@
</header>
<p>This document describes the changes made to the Percept application.</p>
-<section><title>Percept 0.8.11</title>
-
- <section><title>Fixed Bugs and Malfunctions</title>
- <list>
- <item>
- <p>
- Fix http server configuration</p>
- <p>
- Own Id: OTP-12662</p>
- </item>
- </list>
- </section>
-
-</section>
-
<section><title>Percept 0.8.10</title>
<section><title>Fixed Bugs and Malfunctions</title>
diff --git a/lib/percept/vsn.mk b/lib/percept/vsn.mk
index 833ab35aa5..4451354e21 100644
--- a/lib/percept/vsn.mk
+++ b/lib/percept/vsn.mk
@@ -1 +1 @@
-PERCEPT_VSN = 0.8.11
+PERCEPT_VSN = 0.8.10
diff --git a/lib/public_key/doc/src/notes.xml b/lib/public_key/doc/src/notes.xml
index df65ad7004..f241a91eb0 100644
--- a/lib/public_key/doc/src/notes.xml
+++ b/lib/public_key/doc/src/notes.xml
@@ -34,37 +34,6 @@
<file>notes.xml</file>
</header>
-<section><title>Public_Key 1.0</title>
-
- <section><title>Improvements and New Features</title>
- <list>
- <item>
- <p>
- public_key: Remove legacy switch compact_bit_string</p>
- <p>
- E.i bitstrings will not be decode as {Unused, Binary},
- they are now Erlang bitstrings.</p>
- <p>
- Also the compact_bit_string implies the
- legacy_erlang_types switch So removing the switch will
- also make OCTET STRING values be represented as binaries.</p>
- <p>
- Undecoded open type will now be wrapped in a
- asn1_OPENTYPE tuple.</p>
- <p>
- This will change some values in records returned by the
- public_key API making this change a potentiall
- incompatibility.</p>
- <p>
- *** POTENTIAL INCOMPATIBILITY ***</p>
- <p>
- Own Id: OTP-12110</p>
- </item>
- </list>
- </section>
-
-</section>
-
<section><title>Public_Key 0.23</title>
<section><title>Improvements and New Features</title>
diff --git a/lib/sasl/doc/src/notes.xml b/lib/sasl/doc/src/notes.xml
index c0ac0cf79c..95d7c6fa50 100644
--- a/lib/sasl/doc/src/notes.xml
+++ b/lib/sasl/doc/src/notes.xml
@@ -30,30 +30,6 @@
</header>
<p>This document describes the changes made to the SASL application.</p>
-<section><title>SASL 2.4.2</title>
-
- <section><title>Fixed Bugs and Malfunctions</title>
- <list>
- <item>
- <p>
- The undocumented upgrade instruction
- <c>{remove_module,PrePurge,PostPurge,DepMods}</c> is
- removed. This instruction was added for symmetry reasons
- in OTP R7B, but was never documented or tested.</p>
- <p>
- The existing instruction <c>{add_module,Mod,DepMods}</c>
- is now documented, and the complementing instruction
- <c>{delete_module,Mod,DepMods}</c> is added.</p>
- <p>
- *** POTENTIAL INCOMPATIBILITY ***</p>
- <p>
- Own Id: OTP-11540</p>
- </item>
- </list>
- </section>
-
-</section>
-
<section><title>SASL 2.4.1</title>
<section><title>Fixed Bugs and Malfunctions</title>
diff --git a/lib/sasl/vsn.mk b/lib/sasl/vsn.mk
index 8d1a043410..4259a2d76c 100644
--- a/lib/sasl/vsn.mk
+++ b/lib/sasl/vsn.mk
@@ -1 +1 @@
-SASL_VSN = 2.4.2
+SASL_VSN = 2.4.1
diff --git a/lib/ssh/doc/src/notes.xml b/lib/ssh/doc/src/notes.xml
index af5b78bff2..579a3ae4a8 100644
--- a/lib/ssh/doc/src/notes.xml
+++ b/lib/ssh/doc/src/notes.xml
@@ -29,66 +29,19 @@
<file>notes.xml</file>
</header>
-<section><title>Ssh 4.0</title>
+<section><title>Ssh 3.2.3</title>
<section><title>Fixed Bugs and Malfunctions</title>
<list>
<item>
<p>
- Included test of the 'e' and 'f' parameters in dh key
- exchange as specified in rfc 4253 section 8.</p>
+ A new option for handling the SSH_MSG_DEBUG message's
+ printouts. A fun could be given in the options that will
+ be called whenever the SSH_MSG_DEBUG message arrives.
+ This enables the user to format the printout or just
+ discard it.</p>
<p>
- Own Id: OTP-12649</p>
- </item>
- <item>
- <p>
- Fixes the bug that once the rekey_limit bytes (by
- default, 1GB) had been transmitted the connection was
- rekeyed every minute, not after the next 'rekey_limit'.</p>
- <p>
- Thanks to Simon Cornish for the report and the fix!</p>
- <p>
- Own Id: OTP-12692</p>
- </item>
- <item>
- <p>
- Fixes a bug that causes an SFTP connection to always fail
- when {timeout, Timeout} option is used with
- ssh_sftp:start_channel.</p>
- <p>
- Thanks to Simon Cornish</p>
- <p>
- Own Id: OTP-12708</p>
- </item>
- </list>
- </section>
-
-
- <section><title>Improvements and New Features</title>
- <list>
- <item>
- <p>
- The internal group to user_drv protocol has been changed
- to be synchronous in order to guarantee that output sent
- to a process implementing the user_drv protocol is
- printed before replying. This protocol is used by the
- standard_output device and the ssh application when
- acting as a client. </p>
- <p>
- This change changes the previous unlimited buffer when
- printing to standard_io and other devices that end up in
- user_drv to 1KB.</p>
- <p>
- *** POTENTIAL INCOMPATIBILITY ***</p>
- <p>
- Own Id: OTP-12240</p>
- </item>
- <item>
- <p>
- If ssh_connection:subsystem/4 fails we do not want to
- crash but rather terminate gracefully.</p>
- <p>
- Own Id: OTP-12648 Aux Id: seq12834 </p>
+ Own Id: OTP-12738 Aux Id: seq12860 </p>
</item>
</list>
</section>
diff --git a/lib/ssh/doc/src/ssh.xml b/lib/ssh/doc/src/ssh.xml
index d49d3ac2a7..df13442fc6 100644
--- a/lib/ssh/doc/src/ssh.xml
+++ b/lib/ssh/doc/src/ssh.xml
@@ -57,29 +57,28 @@
this module, or abstractions to indicate the intended use of the data
type, or both:</p>
<taglist>
- <tag><c>boolean()</c></tag>
- <item><p>= <c>true | false</c></p></item>
- <tag><c>string()</c></tag>
- <item><p>= <c>[byte()]</c></p></item>
- <tag><c>ssh_daemon_ref()</c></tag>
- <item><p>Opaque to the user,
- returned by <c>ssh:daemon/[1,2,3]</c></p></item>
- <tag><c>ssh_connection_ref()</c></tag>
- <item><p>Opaque to the user,
- returned by <c>ssh:connect/3</c></p></item>
- <tag><c>ip_address()</c></tag>
+ <tag><c>boolean() =</c></tag>
+ <item><p><c>true | false</c></p></item>
+ <tag><c>string() =</c></tag>
+ <item><p><c>[byte()]</c></p></item>
+ <tag><c>ssh_daemon_ref() =</c></tag>
+ <item><p>opaque() -
+ as returned by <c>ssh:daemon/[1,2,3]</c></p></item>
+ <tag><c>ssh_connection_ref() =</c></tag>
+ <item><p>opaque() - as returned by <c>ssh:connect/3</c></p></item>
+ <tag><c>ip_address() =</c></tag>
<item><p><c>inet::ip_address</c></p></item>
- <tag><c>subsystem_spec()</c></tag>
- <item><p>= <c>{subsystem_name(),
- {channel_callback(), channel_init_args()}}</c></p></item>
- <tag><c>subsystem_name()</c></tag>
- <item><p>= <c>string()</c></p></item>
- <tag><c>channel_callback()</c></tag>
- <item><p>= <c>atom()</c> - Name of the Erlang module
- implementing the subsystem using the <c>ssh_channel</c> behavior, see
- <seealso marker="ssh_channel">ssh_channel(3)</seealso></p></item>
- <tag><c>channel_init_args()</c></tag>
- <item><p>= <c>list()</c></p></item>
+ <tag><c>subsystem_spec() =</c></tag>
+ <item><p><c>{subsystem_name(),
+ {channel_callback(), channel_init_args()}}</c></p></item>
+ <tag><c>subsystem_name() =</c></tag>
+ <item><p><c>string()</c></p></item>
+ <tag><c>channel_callback() =</c></tag>
+ <item><p><c>atom()</c> - Name of the Erlang module
+ implementing the subsystem using the <c>ssh_channel</c> behavior, see
+ <seealso marker="ssh_channel">ssh_channel(3)</seealso></p></item>
+ <tag><c>channel_init_args() =</c></tag>
+ <item><p><c>list()</c></p></item>
</taglist>
</section>
@@ -227,6 +226,13 @@
<item>
<p>Sets a time-out on a connection when no channels are active.
Defaults to <c>infinity</c>.</p></item>
+ <tag><c><![CDATA[{ssh_msg_debug_fun, fun(ConnectionRef::ssh_connection_ref(), AlwaysDisplay::boolean(), Msg::binary(), LanguageTag::binary()) -> _}]]></c></tag>
+ <item>
+ <p>Provide a fun to implement your own logging of the SSH message SSH_MSG_DEBUG. The last three parameters are from the message, see RFC4253, section 11.3. The <c>ConnectionRef</c> is the reference to the connection on which the message arrived. The return value from the fun is not checked.</p>
+ <p>The default behaviour is ignore the message.
+ To get a printout for each message with <c>AlwaysDisplay = true</c>, use for example <c>{ssh_msg_debug_fun, fun(_,true,M,_)-> io:format("DEBUG: ~p~n", [M]) end}</c></p>
+ </item>
+
</taglist>
</desc>
</func>
@@ -427,8 +433,16 @@
<item>
<p>Provides a fun to implement your own logging when a user disconnects from the server.</p>
</item>
- </taglist>
- </desc>
+
+ <tag><c><![CDATA[{ssh_msg_debug_fun, fun(ConnectionRef::ssh_connection_ref(), AlwaysDisplay::boolean(), Msg::binary(), LanguageTag::binary()) -> _}]]></c></tag>
+ <item>
+ <p>Provide a fun to implement your own logging of the SSH message SSH_MSG_DEBUG. The last three parameters are from the message, see RFC4253, section 11.3. The <c>ConnectionRef</c> is the reference to the connection on which the message arrived. The return value from the fun is not checked.</p>
+ <p>The default behaviour is ignore the message.
+ To get a printout for each message with <c>AlwaysDisplay = true</c>, use for example <c>{ssh_msg_debug_fun, fun(_,true,M,_)-> io:format("DEBUG: ~p~n", [M]) end}</c></p>
+ </item>
+
+ </taglist>
+ </desc>
</func>
diff --git a/lib/ssh/doc/src/ssh_channel.xml b/lib/ssh/doc/src/ssh_channel.xml
index b8a03c350a..2fdecf9072 100644
--- a/lib/ssh/doc/src/ssh_channel.xml
+++ b/lib/ssh/doc/src/ssh_channel.xml
@@ -62,22 +62,22 @@
type, or both:</p>
<taglist>
- <tag><c>boolean()</c></tag>
- <item><p>= <c>true | false</c></p></item>
- <tag><c>string()</c></tag>
- <item><p>= list of ASCII characters</p></item>
- <tag><c>timeout()</c></tag>
- <item><p>= <c>infinity | integer()</c> in milliseconds</p></item>
- <tag><c>ssh_connection_ref()</c></tag>
- <item><p>Opaque to the user, returned by
- <c>ssh:connect/3</c> or sent to an SSH channel process</p></item>
- <tag><c>ssh_channel_id()</c></tag>
- <item><p>= <c>integer()</c></p></item>
- <tag><c>ssh_data_type_code()</c></tag>
- <item><p>= <c>1</c> ("stderr") | <c>0</c> ("normal") are
- the valid values,
- see <url href="http://www.ietf.org/rfc/rfc4254.txt">RFC 4254</url>
- Section 5.2</p></item>
+ <tag><c>boolean() =</c></tag>
+ <item><p><c>true | false</c></p></item>
+ <tag><c>string() =</c></tag>
+ <item><p>list of ASCII characters</p></item>
+ <tag><c>timeout() =</c></tag>
+ <item><p><c>infinity | integer()</c> in milliseconds</p></item>
+ <tag><c>ssh_connection_ref() =</c></tag>
+ <item><p>opaque() -as returned by
+ <c>ssh:connect/3</c> or sent to an SSH channel process</p></item>
+ <tag><c>ssh_channel_id() =</c></tag>
+ <item><p><c>integer()</c></p></item>
+ <tag><c>ssh_data_type_code() =</c></tag>
+ <item><p><c>1</c> ("stderr") | <c>0</c> ("normal") are
+ the valid values,
+ see <url href="http://www.ietf.org/rfc/rfc4254.txt">RFC 4254</url>
+ Section 5.2</p></item>
</taglist>
</section>
diff --git a/lib/ssh/doc/src/ssh_client_key_api.xml b/lib/ssh/doc/src/ssh_client_key_api.xml
index a8dda042c9..9a892d71fd 100644
--- a/lib/ssh/doc/src/ssh_client_key_api.xml
+++ b/lib/ssh/doc/src/ssh_client_key_api.xml
@@ -50,16 +50,16 @@
<seealso marker="public_key:public_key_records"> public_key user's guide:</seealso>
</p>
<taglist>
- <tag><c>boolean()</c></tag>
- <item><p>= <c>true | false</c></p></item>
- <tag><c>string()</c></tag>
- <item><p>= <c>[byte()]</c></p></item>
- <tag><c>public_key()</c></tag>
- <item><p>= <c>#'RSAPublicKey'{}| {integer(), #'Dss-Parms'{}}| term()</c></p></item>
- <tag><c>private_key()</c></tag>
- <item><p>= <c>#'RSAPrivateKey'{} | #'DSAPrivateKey'{} | term()</c></p></item>
- <tag><c>public_key_algorithm()</c></tag>
- <item><p>= <c>'ssh-rsa'| 'ssh-dss' | atom()</c></p></item>
+ <tag><c>boolean() =</c></tag>
+ <item><p><c>true | false</c></p></item>
+ <tag><c>string() =</c></tag>
+ <item><p><c>[byte()]</c></p></item>
+ <tag><c>public_key() =</c></tag>
+ <item><p><c>#'RSAPublicKey'{}| {integer(), #'Dss-Parms'{}}| term()</c></p></item>
+ <tag><c>private_key() =</c></tag>
+ <item><p><c>#'RSAPrivateKey'{} | #'DSAPrivateKey'{} | term()</c></p></item>
+ <tag><c>public_key_algorithm() =</c></tag>
+ <item><p><c>'ssh-rsa'| 'ssh-dss' | atom()</c></p></item>
</taglist>
</section>
diff --git a/lib/ssh/doc/src/ssh_connection.xml b/lib/ssh/doc/src/ssh_connection.xml
index 669a361db9..5422633dc3 100644
--- a/lib/ssh/doc/src/ssh_connection.xml
+++ b/lib/ssh/doc/src/ssh_connection.xml
@@ -56,29 +56,29 @@
type, or both:</p>
<taglist>
- <tag><c>boolean()</c></tag>
- <item><p>= <c>true | false </c></p></item>
- <tag><c>string()</c></tag>
- <item><p>= list of ASCII characters</p></item>
- <tag><c>timeout()</c></tag>
- <item><p>= <c>infinity | integer()</c> in milliseconds</p></item>
- <tag><c>ssh_connection_ref()</c></tag>
- <item><p>Opaque to the user, returned by
- <c>ssh:connect/3</c> or sent to an SSH channel processes</p></item>
- <tag><c>ssh_channel_id()</c></tag>
- <item><p>= <c>integer()</c></p></item>
- <tag><c>ssh_data_type_code()</c></tag>
- <item><p>= <c>1</c> ("stderr") | <c>0</c> ("normal") are
+ <tag><c>boolean() =</c></tag>
+ <item><p><c>true | false </c></p></item>
+ <tag><c>string() =</c></tag>
+ <item><p>list of ASCII characters</p></item>
+ <tag><c>timeout() =</c></tag>
+ <item><p><c>infinity | integer()</c> in milliseconds</p></item>
+ <tag><c>ssh_connection_ref() =</c></tag>
+ <item><p>opaque() -as returned by
+ <c>ssh:connect/3</c> or sent to an SSH channel processes</p></item>
+ <tag><c>ssh_channel_id() =</c></tag>
+ <item><p><c>integer()</c></p></item>
+ <tag><c>ssh_data_type_code() =</c></tag>
+ <item><p><c>1</c> ("stderr") | <c>0</c> ("normal") are
valid values, see
<url href="http://www.ietf.org/rfc/rfc4254.txt">RFC 4254</url> Section 5.2.</p></item>
- <tag><c>ssh_request_status() ssh_request_status()</c></tag>
- <item><p>= <c>success | failure</c></p></item>
- <tag><c>event()</c></tag>
- <item><p>= <c>{ssh_cm, ssh_connection_ref(), ssh_event_msg()}</c></p></item>
- <tag><c>ssh_event_msg()</c></tag>
- <item><p>= <c>data_events() | status_events() | terminal_events()</c></p></item>
- <tag><c>reason()</c></tag>
- <item><p>= <c>timeout | closed</c></p></item>
+ <tag><c>ssh_request_status() =</c></tag>
+ <item><p> <c>success | failure</c></p></item>
+ <tag><c>event() =</c></tag>
+ <item><p><c>{ssh_cm, ssh_connection_ref(), ssh_event_msg()}</c></p></item>
+ <tag><c>ssh_event_msg() =</c></tag>
+ <item><p><c>data_events() | status_events() | terminal_events()</c></p></item>
+ <tag><c>reason() =</c></tag>
+ <item><p><c>timeout | closed</c></p></item>
</taglist>
<taglist>
diff --git a/lib/ssh/doc/src/ssh_server_key_api.xml b/lib/ssh/doc/src/ssh_server_key_api.xml
index 34ce7f7660..73dd90c962 100644
--- a/lib/ssh/doc/src/ssh_server_key_api.xml
+++ b/lib/ssh/doc/src/ssh_server_key_api.xml
@@ -50,20 +50,20 @@
<seealso marker="public_key:public_key_records"> public_key user's guide</seealso>.
</p>
-<taglist>
- <tag><c>boolean()</c></tag>
- <item><p>= <c>true | false</c></p></item>
- <tag><c>string()</c></tag>
- <item><p>= <c>[byte()]</c></p></item>
- <tag><c>public_key()</c></tag>
- <item><p>= <c>#'RSAPublicKey'{}| {integer(), #'Dss-Parms'{}}| term()</c></p></item>
- <tag><c>private_key()</c></tag>
- <item><p>= <c>#'RSAPrivateKey'{} | #'DSAPrivateKey'{} | term()</c></p></item>
- <tag><c>public_key_algorithm()</c></tag>
- <item><p>= <c>'ssh-rsa'| 'ssh-dss' | atom()</c></p></item>
+ <taglist>
+ <tag><c>boolean() =</c></tag>
+ <item><p><c>true | false</c></p></item>
+ <tag><c>string() =</c></tag>
+ <item><p><c>[byte()]</c></p></item>
+ <tag><c>public_key() =</c></tag>
+ <item><p><c>#'RSAPublicKey'{}| {integer(), #'Dss-Parms'{}}| term()</c></p></item>
+ <tag><c>private_key() =</c></tag>
+ <item><p><c>#'RSAPrivateKey'{} | #'DSAPrivateKey'{} | term()</c></p></item>
+ <tag><c>public_key_algorithm() =</c></tag>
+ <item><p><c>'ssh-rsa'| 'ssh-dss' | atom()</c></p></item>
</taglist>
</section>
-
+
<funcs>
<func>
<name>Module:host_key(Algorithm, DaemonOptions) ->
diff --git a/lib/ssh/doc/src/ssh_sftp.xml b/lib/ssh/doc/src/ssh_sftp.xml
index 643130fe6b..fc418bc934 100644
--- a/lib/ssh/doc/src/ssh_sftp.xml
+++ b/lib/ssh/doc/src/ssh_sftp.xml
@@ -43,8 +43,8 @@
</p>
<taglist>
- <tag><c>ssh_connection_ref()</c></tag>
- <item><p>Opaque to the user, returned by <c>ssh:connect/3</c></p></item>
+ <tag><c>ssh_connection_ref() =</c></tag>
+ <item><p>opaque() - as returned by <c>ssh:connect/3</c></p></item>
<tag><c>timeout()</c></tag>
<item><p>= <c>infinity | integer() in milliseconds. Default infinity.</c></p></item>
</taglist>
diff --git a/lib/ssh/doc/src/ssh_sftpd.xml b/lib/ssh/doc/src/ssh_sftpd.xml
index bc2660f595..8b2497e6a3 100644
--- a/lib/ssh/doc/src/ssh_sftpd.xml
+++ b/lib/ssh/doc/src/ssh_sftpd.xml
@@ -37,16 +37,16 @@
<section>
<title>DATA TYPES</title>
<taglist>
- <tag><c>subsystem_spec()</c></tag>
- <item><p>= <c>{subsystem_name(), {channel_callback(), channel_init_args()}}</c></p></item>
- <tag><c>subsystem_name()</c></tag>
- <item><p>= <c>"sftp"</c></p></item>
- <tag><c>channel_callback()</c></tag>
- <item><p>= <c>atom()</c> - Name of the Erlang module implementing the subsystem using the
+ <tag><c>subsystem_spec() =</c></tag>
+ <item><p><c>{subsystem_name(), {channel_callback(), channel_init_args()}}</c></p></item>
+ <tag><c>subsystem_name() =</c></tag>
+ <item><p><c>"sftp"</c></p></item>
+ <tag><c>channel_callback() =</c></tag>
+ <item><p><c>atom()</c> - Name of the Erlang module implementing the subsystem using the
<c>ssh_channel</c> behavior, see the
<seealso marker="ssh_channel">ssh_channel(3)</seealso> manual page.</p></item>
- <tag><c>channel_init_args()</c></tag>
- <item><p>= <c>list()</c> - The one given as argument to function <c>subsystem_spec/1</c>.</p></item>
+ <tag><c>channel_init_args() =</c></tag>
+ <item><p><c>list()</c> - The one given as argument to function <c>subsystem_spec/1</c>.</p></item>
</taglist>
</section>
<funcs>
diff --git a/lib/ssh/src/ssh.erl b/lib/ssh/src/ssh.erl
index d4b02a024e..71e7d77475 100644
--- a/lib/ssh/src/ssh.erl
+++ b/lib/ssh/src/ssh.erl
@@ -312,6 +312,8 @@ handle_option([{disconnectfun, _} = Opt | Rest], SocketOptions, SshOptions) ->
handle_option(Rest, SocketOptions, [handle_ssh_option(Opt) | SshOptions]);
handle_option([{failfun, _} = Opt | Rest], SocketOptions, SshOptions) ->
handle_option(Rest, SocketOptions, [handle_ssh_option(Opt) | SshOptions]);
+handle_option([{ssh_msg_debug_fun, _} = Opt | Rest], SocketOptions, SshOptions) ->
+ handle_option(Rest, SocketOptions, [handle_ssh_option(Opt) | SshOptions]);
%%Backwards compatibility should not be underscore between ip and v6 in API
handle_option([{ip_v6_disabled, Value} | Rest], SocketOptions, SshOptions) ->
handle_option(Rest, SocketOptions, [handle_ssh_option({ipv6_disabled, Value}) | SshOptions]);
@@ -417,6 +419,8 @@ handle_ssh_option({disconnectfun , Value} = Opt) when is_function(Value) ->
Opt;
handle_ssh_option({failfun, Value} = Opt) when is_function(Value) ->
Opt;
+handle_ssh_option({ssh_msg_debug_fun, Value} = Opt) when is_function(Value,4) ->
+ Opt;
handle_ssh_option({ipv6_disabled, Value} = Opt) when is_boolean(Value) ->
throw({error, {{ipv6_disabled, Opt}, option_no_longer_valid_use_inet_option_instead}});
diff --git a/lib/ssh/src/ssh_connection_handler.erl b/lib/ssh/src/ssh_connection_handler.erl
index 4dea284071..65208ae158 100644
--- a/lib/ssh/src/ssh_connection_handler.erl
+++ b/lib/ssh/src/ssh_connection_handler.erl
@@ -71,6 +71,7 @@
key_exchange_init_msg, % #ssh_msg_kexinit{}
renegotiate = false, % boolean()
last_size_rekey = 0,
+ event_queue = [],
connection_queue,
address,
port,
@@ -83,6 +84,11 @@
{next_state, state_name(), term(), timeout()} |
{stop, term(), term()}.
+-type gen_fsm_sync_return() :: {next_state, state_name(), term()} |
+ {next_state, state_name(), term(), timeout()} |
+ {reply, term(), state_name(), term()} |
+ {stop, term(), term(), term()}.
+
%%====================================================================
%% Internal application API
%%====================================================================
@@ -433,9 +439,7 @@ key_exchange(#ssh_msg_kex_dh_gex_reply{} = Msg,
new_keys(#ssh_msg_newkeys{} = Msg, #state{ssh_params = Ssh0} = State0) ->
{ok, Ssh} = ssh_transport:handle_new_keys(Msg, Ssh0),
- {NextStateName, State} =
- after_new_keys(State0#state{ssh_params = Ssh}),
- {next_state, NextStateName, next_packet(State)}.
+ after_new_keys(next_packet(State0#state{ssh_params = Ssh})).
%%--------------------------------------------------------------------
-spec userauth(#ssh_msg_service_request{} | #ssh_msg_service_accept{} |
@@ -559,11 +563,13 @@ userauth(#ssh_msg_userauth_banner{message = Msg},
-spec connected({#ssh_msg_kexinit{}, binary()}, %%| %% #ssh_msg_kexdh_init{},
#state{}) -> gen_fsm_state_return().
%%--------------------------------------------------------------------
-connected({#ssh_msg_kexinit{}, _Payload} = Event, State) ->
- kexinit(Event, State#state{renegotiate = true}).
-%% ;
-%% connected(#ssh_msg_kexdh_init{} = Event, State) ->
-%% key_exchange(Event, State#state{renegotiate = true}).
+connected({#ssh_msg_kexinit{}, _Payload} = Event, #state{ssh_params = Ssh0} = State0) ->
+ {KeyInitMsg, SshPacket, Ssh} = ssh_transport:key_exchange_init_msg(Ssh0),
+ State = State0#state{ssh_params = Ssh,
+ key_exchange_init_msg = KeyInitMsg,
+ renegotiate = true},
+ send_msg(SshPacket, State),
+ kexinit(Event, State).
%%--------------------------------------------------------------------
-spec handle_event(#ssh_msg_disconnect{} | #ssh_msg_ignore{} | #ssh_msg_debug{} |
@@ -581,44 +587,17 @@ handle_event(#ssh_msg_disconnect{description = Desc} = DisconnectMsg, _StateName
handle_event(#ssh_msg_ignore{}, StateName, State) ->
{next_state, StateName, next_packet(State)};
-handle_event(#ssh_msg_debug{always_display = true, message = DbgMsg},
- StateName, State) ->
- io:format("DEBUG: ~p\n", [DbgMsg]),
- {next_state, StateName, next_packet(State)};
-
-handle_event(#ssh_msg_debug{}, StateName, State) ->
+handle_event(#ssh_msg_debug{always_display = Display, message = DbgMsg, language=Lang},
+ StateName, #state{opts = Opts} = State) ->
+ F = proplists:get_value(ssh_msg_debug_fun, Opts,
+ fun(_ConnRef, _AlwaysDisplay, _Msg, _Language) -> ok end
+ ),
+ catch F(self(), Display, DbgMsg, Lang),
{next_state, StateName, next_packet(State)};
handle_event(#ssh_msg_unimplemented{}, StateName, State) ->
{next_state, StateName, next_packet(State)};
-handle_event({adjust_window, ChannelId, Bytes}, StateName,
- #state{connection_state =
- #connection{channel_cache = Cache}} = State0) ->
- State =
- case ssh_channel:cache_lookup(Cache, ChannelId) of
- #channel{recv_window_size = WinSize, remote_id = Id} = Channel ->
- ssh_channel:cache_update(Cache, Channel#channel{recv_window_size =
- WinSize + Bytes}),
- Msg = ssh_connection:channel_adjust_window_msg(Id, Bytes),
- send_replies([{connection_reply, Msg}], State0);
- undefined ->
- State0
- end,
- {next_state, StateName, next_packet(State)};
-
-handle_event({reply_request, success, ChannelId}, StateName,
- #state{connection_state =
- #connection{channel_cache = Cache}} = State0) ->
- State = case ssh_channel:cache_lookup(Cache, ChannelId) of
- #channel{remote_id = RemoteId} ->
- Msg = ssh_connection:channel_success_msg(RemoteId),
- send_replies([{connection_reply, Msg}], State0);
- undefined ->
- State0
- end,
- {next_state, StateName, State};
-
handle_event(renegotiate, connected, #state{ssh_params = Ssh0}
= State) ->
{KeyInitMsg, SshPacket, Ssh} = ssh_transport:key_exchange_init_msg(Ssh0),
@@ -630,8 +609,7 @@ handle_event(renegotiate, connected, #state{ssh_params = Ssh0}
renegotiate = true})};
handle_event(renegotiate, StateName, State) ->
- timer:apply_after(?REKEY_TIMOUT, gen_fsm, send_all_state_event, [self(), renegotiate]),
- %% Allready in keyexcahange so ignore
+ %% Already in key-exchange so safe to ignore
{next_state, StateName, State};
%% Rekey due to sent data limit reached?
@@ -653,6 +631,38 @@ handle_event(data_size, connected, #state{ssh_params = Ssh0} = State) ->
{next_state, connected, next_packet(State)}
end;
handle_event(data_size, StateName, State) ->
+ %% Already in key-exchange so safe to ignore
+ {next_state, StateName, State};
+
+handle_event(Event, StateName, State) when StateName /= connected ->
+ Events = [{event, Event} | State#state.event_queue],
+ {next_state, StateName, State#state{event_queue = Events}};
+
+handle_event({adjust_window, ChannelId, Bytes}, StateName,
+ #state{connection_state =
+ #connection{channel_cache = Cache}} = State0) ->
+ State =
+ case ssh_channel:cache_lookup(Cache, ChannelId) of
+ #channel{recv_window_size = WinSize, remote_id = Id} = Channel ->
+ ssh_channel:cache_update(Cache, Channel#channel{recv_window_size =
+ WinSize + Bytes}),
+ Msg = ssh_connection:channel_adjust_window_msg(Id, Bytes),
+ send_replies([{connection_reply, Msg}], State0);
+ undefined ->
+ State0
+ end,
+ {next_state, StateName, next_packet(State)};
+
+handle_event({reply_request, success, ChannelId}, StateName,
+ #state{connection_state =
+ #connection{channel_cache = Cache}} = State0) ->
+ State = case ssh_channel:cache_lookup(Cache, ChannelId) of
+ #channel{remote_id = RemoteId} ->
+ Msg = ssh_connection:channel_success_msg(RemoteId),
+ send_replies([{connection_reply, Msg}], State0);
+ undefined ->
+ State0
+ end,
{next_state, StateName, State};
handle_event({request, ChannelPid, ChannelId, Type, Data}, StateName, State0) ->
@@ -683,8 +693,65 @@ handle_event({unknown, Data}, StateName, State) ->
sockname]} | {channel_info, channel_id(), [recv_window |
send_window]} |
{close, channel_id()} | stop, term(), state_name(), #state{})
- -> gen_fsm_state_return().
+ -> gen_fsm_sync_return().
%%--------------------------------------------------------------------
+handle_sync_event(get_print_info, _From, StateName, State) ->
+ Reply =
+ try
+ {inet:sockname(State#state.socket),
+ inet:peername(State#state.socket)
+ }
+ of
+ {{ok,Local}, {ok,Remote}} -> {{Local,Remote},io_lib:format("statename=~p",[StateName])};
+ _ -> {{"-",0},"-"}
+ catch
+ _:_ -> {{"?",0},"?"}
+ end,
+ {reply, Reply, StateName, State};
+
+handle_sync_event({connection_info, Options}, _From, StateName, State) ->
+ Info = ssh_info(Options, State, []),
+ {reply, Info, StateName, State};
+
+handle_sync_event({channel_info, ChannelId, Options}, _From, StateName,
+ #state{connection_state = #connection{channel_cache = Cache}} = State) ->
+ case ssh_channel:cache_lookup(Cache, ChannelId) of
+ #channel{} = Channel ->
+ Info = ssh_channel_info(Options, Channel, []),
+ {reply, Info, StateName, State};
+ undefined ->
+ {reply, [], StateName, State}
+ end;
+
+handle_sync_event({info, ChannelPid}, _From, StateName,
+ #state{connection_state =
+ #connection{channel_cache = Cache}} = State) ->
+ Result = ssh_channel:cache_foldl(
+ fun(Channel, Acc) when ChannelPid == all;
+ Channel#channel.user == ChannelPid ->
+ [Channel | Acc];
+ (_, Acc) ->
+ Acc
+ end, [], Cache),
+ {reply, {ok, Result}, StateName, State};
+
+handle_sync_event(stop, _, _StateName, #state{connection_state = Connection0,
+ role = Role,
+ opts = Opts} = State0) ->
+ {disconnect, Reason, {{replies, Replies}, Connection}} =
+ ssh_connection:handle_msg(#ssh_msg_disconnect{code = ?SSH_DISCONNECT_BY_APPLICATION,
+ description = "User closed down connection",
+ language = "en"}, Connection0, Role),
+ State = send_replies(Replies, State0),
+ SSHOpts = proplists:get_value(ssh_opts, Opts),
+ disconnect_fun(Reason, SSHOpts),
+ {stop, normal, ok, State#state{connection_state = Connection}};
+
+
+handle_sync_event(Event, From, StateName, State) when StateName /= connected ->
+ Events = [{sync, Event, From} | State#state.event_queue],
+ {next_state, StateName, State#state{event_queue = Events}};
+
handle_sync_event({request, ChannelPid, ChannelId, Type, Data, Timeout}, From, StateName, State0) ->
{{replies, Replies}, State1} = handle_request(ChannelPid,
ChannelId, Type, Data,
@@ -787,46 +854,6 @@ handle_sync_event({recv_window, ChannelId}, _From, StateName,
end,
{reply, Reply, StateName, next_packet(State)};
-handle_sync_event(get_print_info, _From, StateName, State) ->
- Reply =
- try
- {inet:sockname(State#state.socket),
- inet:peername(State#state.socket)
- }
- of
- {{ok,Local}, {ok,Remote}} -> {{Local,Remote},io_lib:format("statename=~p",[StateName])};
- _ -> {{"-",0},"-"}
- catch
- _:_ -> {{"?",0},"?"}
- end,
- {reply, Reply, StateName, State};
-
-handle_sync_event({connection_info, Options}, _From, StateName, State) ->
- Info = ssh_info(Options, State, []),
- {reply, Info, StateName, State};
-
-handle_sync_event({channel_info, ChannelId, Options}, _From, StateName,
- #state{connection_state = #connection{channel_cache = Cache}} = State) ->
- case ssh_channel:cache_lookup(Cache, ChannelId) of
- #channel{} = Channel ->
- Info = ssh_channel_info(Options, Channel, []),
- {reply, Info, StateName, State};
- undefined ->
- {reply, [], StateName, State}
- end;
-
-handle_sync_event({info, ChannelPid}, _From, StateName,
- #state{connection_state =
- #connection{channel_cache = Cache}} = State) ->
- Result = ssh_channel:cache_foldl(
- fun(Channel, Acc) when ChannelPid == all;
- Channel#channel.user == ChannelPid ->
- [Channel | Acc];
- (_, Acc) ->
- Acc
- end, [], Cache),
- {reply, {ok, Result}, StateName, State};
-
handle_sync_event({close, ChannelId}, _, StateName,
#state{connection_state =
#connection{channel_cache = Cache}} = State0) ->
@@ -841,19 +868,7 @@ handle_sync_event({close, ChannelId}, _, StateName,
undefined ->
State0
end,
- {reply, ok, StateName, next_packet(State)};
-
-handle_sync_event(stop, _, _StateName, #state{connection_state = Connection0,
- role = Role,
- opts = Opts} = State0) ->
- {disconnect, Reason, {{replies, Replies}, Connection}} =
- ssh_connection:handle_msg(#ssh_msg_disconnect{code = ?SSH_DISCONNECT_BY_APPLICATION,
- description = "User closed down connection",
- language = "en"}, Connection0, Role),
- State = send_replies(Replies, State0),
- SSHOpts = proplists:get_value(ssh_opts, Opts),
- disconnect_fun(Reason, SSHOpts),
- {stop, normal, ok, State#state{connection_state = Connection}}.
+ {reply, ok, StateName, next_packet(State)}.
%%--------------------------------------------------------------------
-spec handle_info({atom(), port(), binary()} | {atom(), port()} |
@@ -1282,8 +1297,17 @@ generate_event(<<?BYTE(Byte), _/binary>> = Msg, StateName,
ConnectionMsg = ssh_message:decode(Msg),
State1 = generate_event_new_state(State0, EncData),
try ssh_connection:handle_msg(ConnectionMsg, Connection0, Role) of
- {{replies, Replies}, Connection} ->
- State = send_replies(Replies, State1#state{connection_state = Connection}),
+ {{replies, Replies0}, Connection} ->
+ if StateName == connected ->
+ Replies = Replies0,
+ State2 = State1;
+ true ->
+ {ConnReplies, Replies} =
+ lists:splitwith(fun not_connected_filter/1, Replies0),
+ Q = State1#state.event_queue ++ ConnReplies,
+ State2 = State1#state{ event_queue = Q }
+ end,
+ State = send_replies(Replies, State2#state{connection_state = Connection}),
{next_state, StateName, next_packet(State)};
{noreply, Connection} ->
{next_state, StateName, next_packet(State1#state{connection_state = Connection})};
@@ -1456,15 +1480,43 @@ next_packet(#state{socket = Socket} = State) ->
State.
after_new_keys(#state{renegotiate = true} = State) ->
- {connected, State#state{renegotiate = false}};
+ State1 = State#state{renegotiate = false, event_queue = []},
+ lists:foldr(fun after_new_keys_events/2, {next_state, connected, State1}, State#state.event_queue);
after_new_keys(#state{renegotiate = false,
ssh_params = #ssh{role = client} = Ssh0} = State) ->
{Msg, Ssh} = ssh_auth:service_request_msg(Ssh0),
send_msg(Msg, State),
- {userauth, State#state{ssh_params = Ssh}};
+ {next_state, userauth, State#state{ssh_params = Ssh}};
after_new_keys(#state{renegotiate = false,
ssh_params = #ssh{role = server}} = State) ->
- {userauth, State}.
+ {next_state, userauth, State}.
+
+after_new_keys_events({sync, _Event, From}, {stop, _Reason, _StateData}=Terminator) ->
+ gen_fsm:reply(From, {error, closed}),
+ Terminator;
+after_new_keys_events(_, {stop, _Reason, _StateData}=Terminator) ->
+ Terminator;
+after_new_keys_events({sync, Event, From}, {next_state, StateName, StateData}) ->
+ case handle_sync_event(Event, From, StateName, StateData) of
+ {reply, Reply, NextStateName, NewStateData} ->
+ gen_fsm:reply(From, Reply),
+ {next_state, NextStateName, NewStateData};
+ {next_state, NextStateName, NewStateData}->
+ {next_state, NextStateName, NewStateData};
+ {stop, Reason, Reply, NewStateData} ->
+ gen_fsm:reply(From, Reply),
+ {stop, Reason, NewStateData}
+ end;
+after_new_keys_events({event, Event}, {next_state, StateName, StateData}) ->
+ case handle_event(Event, StateName, StateData) of
+ {next_state, NextStateName, NewStateData}->
+ {next_state, NextStateName, NewStateData};
+ {stop, Reason, NewStateData} ->
+ {stop, Reason, NewStateData}
+ end;
+after_new_keys_events({connection_reply, _Data} = Reply, {StateName, State}) ->
+ NewState = send_replies([Reply], State),
+ {next_state, StateName, NewState}.
handle_ssh_packet_data(RemainingSshPacketLen, DecData, EncData, StateName,
State) ->
@@ -1625,6 +1677,11 @@ log_error(Reason) ->
error_logger:error_report(Report),
"Internal error".
+not_connected_filter({connection_reply, _Data}) ->
+ true;
+not_connected_filter(_) ->
+ false.
+
send_replies([], State) ->
State;
send_replies([{connection_reply, Data} | Rest], #state{ssh_params = Ssh0} = State) ->
diff --git a/lib/ssh/test/Makefile b/lib/ssh/test/Makefile
index 740dbd0235..39b2f57d26 100644
--- a/lib/ssh/test/Makefile
+++ b/lib/ssh/test/Makefile
@@ -40,7 +40,8 @@ MODULES= \
ssh_connection_SUITE \
ssh_echo_server \
ssh_peername_sockname_server \
- ssh_test_cli
+ ssh_test_cli \
+ ssh_relay
HRL_FILES_NEEDED_IN_TEST= \
$(ERL_TOP)/lib/ssh/src/ssh.hrl \
diff --git a/lib/ssh/test/ssh_basic_SUITE.erl b/lib/ssh/test/ssh_basic_SUITE.erl
index d55d09f2a2..aaf0fa9905 100644
--- a/lib/ssh/test/ssh_basic_SUITE.erl
+++ b/lib/ssh/test/ssh_basic_SUITE.erl
@@ -29,6 +29,7 @@
-define(NEWLINE, <<"\r\n">>).
+-define(REKEY_DATA_TMO, 65000).
%%--------------------------------------------------------------------
%% Common Test interface functions -----------------------------------
%%--------------------------------------------------------------------
@@ -44,6 +45,7 @@ all() ->
{group, dsa_pass_key},
{group, rsa_pass_key},
{group, internal_error},
+ {group, renegotiate},
daemon_already_started,
server_password_option,
server_userpassword_option,
@@ -52,6 +54,8 @@ all() ->
ssh_connect_arg4_timeout,
packet_size_zero,
ssh_daemon_minimal_remote_max_packet_size_option,
+ ssh_msg_debug_fun_option_client,
+ ssh_msg_debug_fun_option_server,
id_string_no_opt_client,
id_string_own_string_client,
id_string_random_client,
@@ -67,6 +71,7 @@ groups() ->
{dsa_pass_key, [], [pass_phrase]},
{rsa_pass_key, [], [pass_phrase]},
{internal_error, [], [internal_error]},
+ {renegotiate, [], [rekey, rekey_limit, renegotiate1, renegotiate2]},
{hardening_tests, [], [ssh_connect_nonegtimeout_connected_parallel,
ssh_connect_nonegtimeout_connected_sequential,
ssh_connect_negtimeout_parallel,
@@ -82,8 +87,7 @@ groups() ->
basic_tests() ->
[send, close, peername_sockname,
exec, exec_compressed, shell, cli, known_hosts,
- idle_time, rekey, openssh_zlib_basic_test,
- misc_ssh_options, inet_option].
+ idle_time, openssh_zlib_basic_test, misc_ssh_options, inet_option].
%%--------------------------------------------------------------------
@@ -331,25 +335,175 @@ idle_time(Config) ->
rekey() ->
[{doc, "Idle timeout test"}].
rekey(Config) ->
- SystemDir = filename:join(?config(priv_dir, Config), system),
+ SystemDir = ?config(data_dir, Config),
UserDir = ?config(priv_dir, Config),
{Pid, Host, Port} = ssh_test_lib:daemon([{system_dir, SystemDir},
- {user_dir, UserDir},
+ {user_dir, UserDir},
{failfun, fun ssh_test_lib:failfun/2},
+ {user_passwords,
+ [{"simon", "says"}]},
{rekey_limit, 0}]),
+
ConnectionRef =
ssh_test_lib:connect(Host, Port, [{silently_accept_hosts, true},
{user_dir, UserDir},
+ {user, "simon"},
+ {password, "says"},
{user_interaction, false},
{rekey_limit, 0}]),
receive
- after 200000 ->
+ after ?REKEY_DATA_TMO ->
%%By this time rekeying would have been done
ssh:close(ConnectionRef),
ssh:stop_daemon(Pid)
end.
%%--------------------------------------------------------------------
+rekey_limit() ->
+ [{doc, "Test rekeying by data volume"}].
+rekey_limit(Config) ->
+ SystemDir = ?config(data_dir, Config),
+ UserDir = ?config(priv_dir, Config),
+ DataFile = filename:join(UserDir, "rekey.data"),
+
+ {Pid, Host, Port} = ssh_test_lib:daemon([{system_dir, SystemDir},
+ {user_dir, UserDir},
+ {user_passwords,
+ [{"simon", "says"}]}]),
+ {ok, SftpPid, ConnectionRef} =
+ ssh_sftp:start_channel(Host, Port, [{system_dir, SystemDir},
+ {user_dir, UserDir},
+ {user, "simon"},
+ {password, "says"},
+ {rekey_limit, 2500},
+ {user_interaction, false},
+ {silently_accept_hosts, true}]),
+
+ Kex1 = get_kex_init(ConnectionRef),
+
+ ct:sleep(?REKEY_DATA_TMO),
+ Kex1 = get_kex_init(ConnectionRef),
+
+ Data = lists:duplicate(9000,1),
+ ok = ssh_sftp:write_file(SftpPid, DataFile, Data),
+
+ ct:sleep(?REKEY_DATA_TMO),
+ Kex2 = get_kex_init(ConnectionRef),
+
+ false = (Kex2 == Kex1),
+
+ ct:sleep(?REKEY_DATA_TMO),
+ Kex2 = get_kex_init(ConnectionRef),
+
+ ok = ssh_sftp:write_file(SftpPid, DataFile, "hi\n"),
+
+ ct:sleep(?REKEY_DATA_TMO),
+ Kex2 = get_kex_init(ConnectionRef),
+
+ false = (Kex2 == Kex1),
+
+ ct:sleep(?REKEY_DATA_TMO),
+ Kex2 = get_kex_init(ConnectionRef),
+
+
+ ssh_sftp:stop_channel(SftpPid),
+ ssh:close(ConnectionRef),
+ ssh:stop_daemon(Pid).
+
+%%--------------------------------------------------------------------
+renegotiate1() ->
+ [{doc, "Test rekeying with simulataneous send request"}].
+renegotiate1(Config) ->
+ SystemDir = ?config(data_dir, Config),
+ UserDir = ?config(priv_dir, Config),
+ DataFile = filename:join(UserDir, "renegotiate1.data"),
+
+ {Pid, Host, DPort} = ssh_test_lib:daemon([{system_dir, SystemDir},
+ {user_dir, UserDir},
+ {user_passwords,
+ [{"simon", "says"}]}]),
+ RPort = ssh_test_lib:inet_port(),
+
+ {ok,RelayPid} = ssh_relay:start_link({0,0,0,0}, RPort, Host, DPort),
+
+ {ok, SftpPid, ConnectionRef} =
+ ssh_sftp:start_channel(Host, RPort, [{system_dir, SystemDir},
+ {user_dir, UserDir},
+ {user, "simon"},
+ {password, "says"},
+ {user_interaction, false},
+ {silently_accept_hosts, true}]),
+
+ Kex1 = get_kex_init(ConnectionRef),
+
+ {ok, Handle} = ssh_sftp:open(SftpPid, DataFile, [write]),
+
+ ok = ssh_sftp:write(SftpPid, Handle, "hi\n"),
+
+ ssh_relay:hold(RelayPid, rx, 20, 1000),
+ ssh_connection_handler:renegotiate(ConnectionRef),
+ spawn(fun() -> ok=ssh_sftp:write(SftpPid, Handle, "another hi\n") end),
+
+ ct:sleep(2000),
+
+ Kex2 = get_kex_init(ConnectionRef),
+
+ false = (Kex2 == Kex1),
+
+ ssh_relay:stop(RelayPid),
+ ssh_sftp:stop_channel(SftpPid),
+ ssh:close(ConnectionRef),
+ ssh:stop_daemon(Pid).
+
+%%--------------------------------------------------------------------
+renegotiate2() ->
+ [{doc, "Test rekeying with inflight messages from peer"}].
+renegotiate2(Config) ->
+ SystemDir = ?config(data_dir, Config),
+ UserDir = ?config(priv_dir, Config),
+ DataFile = filename:join(UserDir, "renegotiate1.data"),
+
+ {Pid, Host, DPort} = ssh_test_lib:daemon([{system_dir, SystemDir},
+ {user_dir, UserDir},
+ {user_passwords,
+ [{"simon", "says"}]}]),
+ RPort = ssh_test_lib:inet_port(),
+
+ {ok,RelayPid} = ssh_relay:start_link({0,0,0,0}, RPort, Host, DPort),
+
+ {ok, SftpPid, ConnectionRef} =
+ ssh_sftp:start_channel(Host, RPort, [{system_dir, SystemDir},
+ {user_dir, UserDir},
+ {user, "simon"},
+ {password, "says"},
+ {user_interaction, false},
+ {silently_accept_hosts, true}]),
+
+ Kex1 = get_kex_init(ConnectionRef),
+
+ {ok, Handle} = ssh_sftp:open(SftpPid, DataFile, [write]),
+
+ ok = ssh_sftp:write(SftpPid, Handle, "hi\n"),
+
+ ssh_relay:hold(RelayPid, rx, 20, infinity),
+ spawn(fun() -> ok=ssh_sftp:write(SftpPid, Handle, "another hi\n") end),
+ %% need a small pause here to ensure ssh_sftp:write is executed
+ ct:sleep(10),
+ ssh_connection_handler:renegotiate(ConnectionRef),
+ ssh_relay:release(RelayPid, rx),
+
+ ct:sleep(2000),
+
+ Kex2 = get_kex_init(ConnectionRef),
+
+ false = (Kex2 == Kex1),
+
+ ssh_relay:stop(RelayPid),
+ ssh_sftp:stop_channel(SftpPid),
+ ssh:close(ConnectionRef),
+ ssh:stop_daemon(Pid).
+
+%%--------------------------------------------------------------------
shell() ->
[{doc, "Test that ssh:shell/2 works"}].
shell(Config) when is_list(Config) ->
@@ -494,6 +648,94 @@ server_userpassword_option(Config) when is_list(Config) ->
ssh:stop_daemon(Pid).
%%--------------------------------------------------------------------
+ssh_msg_debug_fun_option_client() ->
+ [{doc, "validate client that uses the 'ssh_msg_debug_fun' option"}].
+ssh_msg_debug_fun_option_client(Config) ->
+ PrivDir = ?config(priv_dir, Config),
+ UserDir = filename:join(PrivDir, nopubkey), % to make sure we don't use public-key-auth
+ file:make_dir(UserDir),
+ SysDir = ?config(data_dir, Config),
+
+ {Pid, Host, Port} = ssh_test_lib:daemon([{system_dir, SysDir},
+ {user_dir, UserDir},
+ {password, "morot"},
+ {failfun, fun ssh_test_lib:failfun/2}]),
+ Parent = self(),
+ DbgFun = fun(ConnRef,Displ,Msg,Lang) -> Parent ! {msg_dbg,{ConnRef,Displ,Msg,Lang}} end,
+
+ ConnectionRef =
+ ssh_test_lib:connect(Host, Port, [{silently_accept_hosts, true},
+ {user, "foo"},
+ {password, "morot"},
+ {user_dir, UserDir},
+ {user_interaction, false},
+ {ssh_msg_debug_fun,DbgFun}]),
+ %% Beware, implementation knowledge:
+ gen_fsm:send_all_state_event(ConnectionRef,{ssh_msg_debug,false,<<"Hello">>,<<>>}),
+ receive
+ {msg_dbg,X={ConnectionRef,false,<<"Hello">>,<<>>}} ->
+ ct:log("Got expected dbg msg ~p",[X]),
+ ssh:stop_daemon(Pid);
+ {msg_dbg,X={_,false,<<"Hello">>,<<>>}} ->
+ ct:log("Got dbg msg but bad ConnectionRef (~p expected) ~p",[ConnectionRef,X]),
+ ssh:stop_daemon(Pid),
+ {fail, "Bad ConnectionRef received"};
+ {msg_dbg,X} ->
+ ct:log("Got bad dbg msg ~p",[X]),
+ ssh:stop_daemon(Pid),
+ {fail,"Bad msg received"}
+ after 1000 ->
+ ssh:stop_daemon(Pid),
+ {fail,timeout}
+ end.
+
+%%--------------------------------------------------------------------
+ssh_msg_debug_fun_option_server() ->
+ [{doc, "validate client that uses the 'ssh_msg_debug_fun' option"}].
+ssh_msg_debug_fun_option_server(Config) ->
+ PrivDir = ?config(priv_dir, Config),
+ UserDir = filename:join(PrivDir, nopubkey), % to make sure we don't use public-key-auth
+ file:make_dir(UserDir),
+ SysDir = ?config(data_dir, Config),
+
+ Parent = self(),
+ DbgFun = fun(ConnRef,Displ,Msg,Lang) -> Parent ! {msg_dbg,{ConnRef,Displ,Msg,Lang}} end,
+ ConnFun = fun(_,_,_) -> Parent ! {connection_pid,self()} end,
+
+ {Pid, Host, Port} = ssh_test_lib:daemon([{system_dir, SysDir},
+ {user_dir, UserDir},
+ {password, "morot"},
+ {failfun, fun ssh_test_lib:failfun/2},
+ {connectfun, ConnFun},
+ {ssh_msg_debug_fun, DbgFun}]),
+ _ConnectionRef =
+ ssh_test_lib:connect(Host, Port, [{silently_accept_hosts, true},
+ {user, "foo"},
+ {password, "morot"},
+ {user_dir, UserDir},
+ {user_interaction, false}]),
+ receive
+ {connection_pid,Server} ->
+ %% Beware, implementation knowledge:
+ gen_fsm:send_all_state_event(Server,{ssh_msg_debug,false,<<"Hello">>,<<>>}),
+ receive
+ {msg_dbg,X={_,false,<<"Hello">>,<<>>}} ->
+ ct:log("Got expected dbg msg ~p",[X]),
+ ssh:stop_daemon(Pid);
+ {msg_dbg,X} ->
+ ct:log("Got bad dbg msg ~p",[X]),
+ ssh:stop_daemon(Pid),
+ {fail,"Bad msg received"}
+ after 3000 ->
+ ssh:stop_daemon(Pid),
+ {fail,timeout2}
+ end
+ after 3000 ->
+ ssh:stop_daemon(Pid),
+ {fail,timeout1}
+ end.
+
+%%--------------------------------------------------------------------
known_hosts() ->
[{doc, "check that known_hosts is updated correctly"}].
known_hosts(Config) when is_list(Config) ->
@@ -1210,3 +1452,18 @@ fake_daemon(_Config) ->
{sockname,Server,ServerHost,ServerPort} -> {Server, ServerHost, ServerPort}
end.
+%% get_kex_init - helper function to get key_exchange_init_msg
+get_kex_init(Conn) ->
+ %% First, validate the key exchange is complete (StateName == connected)
+ {connected,S} = sys:get_state(Conn),
+ %% Next, walk through the elements of the #state record looking
+ %% for the #ssh_msg_kexinit record. This method is robust against
+ %% changes to either record. The KEXINIT message contains a cookie
+ %% unique to each invocation of the key exchange procedure (RFC4253)
+ SL = tuple_to_list(S),
+ case lists:keyfind(ssh_msg_kexinit, 1, SL) of
+ false ->
+ throw(not_found);
+ KexInit ->
+ KexInit
+ end.
diff --git a/lib/ssh/test/ssh_relay.erl b/lib/ssh/test/ssh_relay.erl
new file mode 100644
index 0000000000..a4f2bad2e2
--- /dev/null
+++ b/lib/ssh/test/ssh_relay.erl
@@ -0,0 +1,407 @@
+%%%-------------------------------------------------------------------
+%%% @author Simon Cornish <[email protected]>
+%%% @copyright (C) 2015, Simon Cornish
+%%% @doc
+%%% Provide manipulatable TCP-level relaying for testing SSH
+%%% @end
+%%% Created : 7 May 2015 by Simon Cornish <[email protected]>
+%%%-------------------------------------------------------------------
+-module(ssh_relay).
+
+-behaviour(gen_server).
+
+%% API
+-export([start_link/4]).
+-export([stop/1]).
+-export([hold/4, release/2, release_next/3]).
+
+%% gen_server callbacks
+-export([init/1, handle_call/3, handle_cast/2, handle_info/2,
+ terminate/2, code_change/3]).
+
+-record(hold, {
+ port,
+ n,
+ tmo,
+ tref,
+ q = []
+ }).
+
+-record(state, {
+ local_addr,
+ local_port,
+ peer_addr,
+ peer_port,
+ lpid,
+ local,
+ peer,
+ tx_hold,
+ rx_hold
+ }).
+
+-define(ACCEPT_TMO, 200).
+%%%===================================================================
+%%% API
+%%%===================================================================
+%%--------------------------------------------------------------------
+%% @doc
+%% Hold N (or 'all') messages in given direction.
+%% Messages will be released after the N+1th message or
+%% Tmo ms or 'infinity'
+%%
+%% Dir is 'tx' for direction local -> peer
+%% and 'rx' for direction peer -> local
+%%
+%% An Error, ealready, is returned if there is already a hold
+%% in the given direction
+%%
+%% @spec hold(Srv, Dir, N, Tmo) -> ok | {error, Error}
+%% @end
+%%--------------------------------------------------------------------
+hold(Srv, Dir, N, Tmo) ->
+ gen_server:call(Srv, {hold, Dir, N, Tmo}).
+
+%%--------------------------------------------------------------------
+%% @doc
+%% Release all held messages in given direction.
+%%
+%% An Error, enoent, is returned if there is no hold
+%% in the given direction
+%%
+%% @spec release(Srv, Dir) -> ok | {error, Error}
+%% @end
+%%--------------------------------------------------------------------
+release(Srv, Dir) ->
+ gen_server:call(Srv, {release, Dir}).
+
+%%--------------------------------------------------------------------
+%% @doc
+%% Release all held messages in given direction after the
+%% next message in the trigger direction
+%%
+%% An Error, enoent, is returned if there is no hold
+%% in the given direction
+%%
+%% @spec release_next(Srv, Dir, TriggerDir) -> ok | {error, Error}
+%% @end
+%%--------------------------------------------------------------------
+release_next(Srv, Dir, TriggerDir) ->
+ gen_server:call(Srv, {release_next, Dir, TriggerDir}).
+
+%%--------------------------------------------------------------------
+%% @doc
+%% Starts the server
+%%
+%% @spec start_link() -> {ok, Pid} | ignore | {error, Error}
+%% @end
+%%--------------------------------------------------------------------
+start_link(ListenAddr, ListenPort, PeerAddr, PeerPort) ->
+ gen_server:start_link(?MODULE, [ListenAddr, ListenPort, PeerAddr, PeerPort], []).
+
+stop(Srv) ->
+ unlink(Srv),
+ Srv ! stop.
+
+%%%===================================================================
+%%% gen_server callbacks
+%%%===================================================================
+
+%%--------------------------------------------------------------------
+%% @private
+%% @doc
+%% Initializes the server
+%%
+%% @spec init(Args) -> {ok, State} |
+%% {ok, State, Timeout} |
+%% ignore |
+%% {stop, Reason}
+%% @end
+%%--------------------------------------------------------------------
+init([ListenAddr, ListenPort, PeerAddr, PeerPort | Options]) ->
+ IfAddr = case ListenAddr of
+ {0,0,0,0} ->
+ [];
+ _ ->
+ [{ifaddr, ListenAddr}]
+ end,
+ case gen_tcp:listen(ListenPort, [{reuseaddr, true}, {backlog, 1}, {active, false}, binary | IfAddr]) of
+ {ok, LSock} ->
+ Parent = self(),
+ {LPid, _LMod} = spawn_monitor(fun() -> listen(Parent, LSock) end),
+ S = #state{local_addr = ListenAddr,
+ local_port = ListenPort,
+ lpid = LPid,
+ peer_addr = PeerAddr,
+ peer_port = PeerPort
+ },
+ {ok, S};
+ Error ->
+ {stop, Error}
+ end.
+
+%%--------------------------------------------------------------------
+%% @private
+%% @doc
+%% Handling call messages
+%%
+%% @spec handle_call(Request, From, State) ->
+%% {reply, Reply, State} |
+%% {reply, Reply, State, Timeout} |
+%% {noreply, State} |
+%% {noreply, State, Timeout} |
+%% {stop, Reason, Reply, State} |
+%% {stop, Reason, State}
+%% @end
+%%--------------------------------------------------------------------
+handle_call({hold, Dir, N, Tmo}, _From, State) ->
+ case Dir of
+ tx ->
+ do_hold(#state.tx_hold, State#state.peer, N, Tmo, State);
+ rx ->
+ do_hold(#state.rx_hold, State#state.local, N, Tmo, State);
+ _ ->
+ {reply, {error, einval}, State}
+ end;
+handle_call({release, Dir}, _From, State) ->
+ case Dir of
+ tx ->
+ do_release(#state.tx_hold, State);
+ rx ->
+ do_release(#state.rx_hold, State);
+ _ ->
+ {reply, {error, einval}, State}
+ end;
+handle_call({release_next, _Dir, _TriggerDir}, _From, State) ->
+ {reply, {error, nyi}, State};
+
+handle_call(Request, _From, State) ->
+ Reply = {unhandled, Request},
+ {reply, Reply, State}.
+
+%%--------------------------------------------------------------------
+%% @private
+%% @doc
+%% Handling cast messages
+%%
+%% @spec handle_cast(Msg, State) -> {noreply, State} |
+%% {noreply, State, Timeout} |
+%% {stop, Reason, State}
+%% @end
+%%--------------------------------------------------------------------
+handle_cast(_Msg, State) ->
+ {noreply, State}.
+
+%%--------------------------------------------------------------------
+%% @private
+%% @doc
+%% Handling all non call/cast messages
+%%
+%% @spec handle_info(Info, State) -> {noreply, State} |
+%% {noreply, State, Timeout} |
+%% {stop, Reason, State}
+%% @end
+%%--------------------------------------------------------------------
+handle_info({tcp, Local, Data}, S) when S#state.local == Local ->
+ S1 = do_local(Data, S),
+ {noreply, S1};
+
+handle_info({tcp_error, Local, Error}, S) when S#state.local == Local ->
+ S1 = do_local({error, Error}, S),
+ {noreply, S1};
+
+handle_info({tcp_closed, Local}, S) when S#state.local == Local ->
+ S1 = do_local(closed, S),
+ {noreply, S1};
+
+handle_info({tcp, Peer, Data}, S) when S#state.peer == Peer ->
+ S1 = do_peer(Data, S),
+ {noreply, S1};
+
+handle_info({tcp_error, Peer, Error}, S) when S#state.peer == Peer ->
+ S1 = do_peer({error, Error}, S),
+ {noreply, S1};
+
+handle_info({tcp_closed, Peer}, S) when S#state.peer == Peer ->
+ S1 = do_peer(closed, S),
+ {noreply, S1};
+
+handle_info({accept, Local}, S) ->
+ S1 = do_accept(Local, S),
+ {noreply, S1};
+
+handle_info({activate, Local}, State) ->
+ inet:setopts(Local, [{active, true}]),
+ {noreply, State};
+
+handle_info({release, Pos}, S) ->
+ {reply, _, S1} = do_release(Pos,S),
+ {noreply, S1};
+
+handle_info(stop, State) ->
+ {stop, normal, State};
+
+handle_info({'DOWN', _Ref, _process, LPid, Reason}, S) when S#state.lpid == LPid ->
+ io:format("Acceptor has finished: ~p~n", [Reason]),
+ {noreply, S};
+
+handle_info(_Info, State) ->
+ io:format("Unhandled info: ~p~n", [_Info]),
+ {noreply, State}.
+
+%%--------------------------------------------------------------------
+%% @private
+%% @doc
+%% This function is called by a gen_server when it is about to
+%% terminate. It should be the opposite of Module:init/1 and do any
+%% necessary cleaning up. When it returns, the gen_server terminates
+%% with Reason. The return value is ignored.
+%%
+%% @spec terminate(Reason, State) -> void()
+%% @end
+%%--------------------------------------------------------------------
+terminate(_Reason, _State) ->
+ ok.
+
+%%--------------------------------------------------------------------
+%% @private
+%% @doc
+%% Convert process state when code is changed
+%%
+%% @spec code_change(OldVsn, State, Extra) -> {ok, NewState}
+%% @end
+%%--------------------------------------------------------------------
+code_change(_OldVsn, State, _Extra) ->
+ {ok, State}.
+
+%%%===================================================================
+%%% Internal functions
+%%%===================================================================
+do_hold(Pos, _Port, _N, _Tmo, S) when element(Pos, S) /= undefined ->
+ {reply, {error, ealready}, S};
+do_hold(Pos, Port, N, Tmo, S) ->
+ TRef = if is_integer(Tmo) andalso Tmo > 0 ->
+ erlang:send_after(Tmo, self(), {release, Pos});
+ true ->
+ undefined
+ end,
+ Hold = #hold{port = Port, n = N, tmo = Tmo, tref = TRef},
+ {reply, ok, setelement(Pos, S, Hold)}.
+
+do_release(HPos, S) when element(HPos, S) == undefined ->
+ {reply, {error, enoent}, S};
+do_release(HPos, S) ->
+ #hold{port = Port, tref = TRef, q = Q} = element(HPos, S),
+ lists:foreach(fun(M) -> gen_tcp:send(Port, M), erlang:yield() end, Q),
+ catch erlang:cancel_timer(TRef),
+ receive
+ {release, HPos} -> ok
+ after 0 ->
+ ok
+ end,
+ {reply, ok, setelement(HPos, S, undefined)}.
+
+listen(Parent, LSock) ->
+ monitor(process, Parent),
+ do_listen(Parent, LSock).
+
+do_listen(Parent, LSock) ->
+ %% So annoying there is no select-like sematic for this
+ case gen_tcp:accept(LSock, ?ACCEPT_TMO) of
+ {ok, Sock} ->
+ Parent ! {accept, Sock},
+ gen_tcp:controlling_process(Sock, Parent),
+ Parent ! {activate, Sock},
+ do_flush(Parent, Sock),
+ gen_tcp:close(LSock);
+ {error, timeout} ->
+ receive
+ DOWN when element(1, DOWN) == 'DOWN' ->
+ ok;
+ stop ->
+ ok
+ after 1 ->
+ do_listen(Parent, LSock)
+ end;
+ Error ->
+ gen_tcp:close(LSock),
+ exit({accept,Error})
+ end.
+
+do_flush(Parent, Sock) ->
+ receive
+ {Tcp, Sock, _} = Msg when Tcp == tcp; Tcp == tcp_error ->
+ Parent ! Msg,
+ do_flush(Parent, Sock);
+ {tcp_closed, Sock} = Msg ->
+ Parent ! Msg,
+ do_flush(Parent, Sock)
+ after 1 ->
+ ok
+ end.
+
+do_accept(Local, S) ->
+ case gen_tcp:connect(S#state.peer_addr, S#state.peer_port, [{active, true}, binary]) of
+ {ok, Peer} ->
+ S#state{local = Local, peer = Peer};
+ Error ->
+ exit({connect, Error})
+ end.
+
+do_local(Data, S) when is_binary(Data) ->
+ TxH = S#state.tx_hold,
+ if TxH == undefined ->
+ gen_tcp:send(S#state.peer, Data),
+ S;
+ TxH#hold.n == 0 ->
+ lists:foreach(fun(M) -> gen_tcp:send(S#state.peer, M) end, TxH#hold.q),
+ gen_tcp:send(S#state.peer, Data),
+ catch erlang:cancel_timer(TxH#hold.tref),
+ TxP = #state.tx_hold,
+ receive
+ {release, TxP} ->
+ ok
+ after 0 ->
+ ok
+ end,
+ S#state{tx_hold = undefined};
+ true ->
+ Q = TxH#hold.q ++ [Data],
+ N = if is_integer(TxH#hold.n) ->
+ TxH#hold.n -1;
+ true ->
+ TxH#hold.n
+ end,
+ S#state{tx_hold = TxH#hold{q = Q, n = N}}
+ end;
+do_local(Error, _S) ->
+ exit({local, Error}).
+
+do_peer(Data, S) when is_binary(Data) ->
+ RxH = S#state.rx_hold,
+ if RxH == undefined ->
+ gen_tcp:send(S#state.local, Data),
+ S;
+ RxH#hold.n == 0 ->
+ lists:foreach(fun(M) -> gen_tcp:send(S#state.local, M) end, RxH#hold.q),
+ gen_tcp:send(S#state.local, Data),
+ catch erlang:cancel_timer(RxH#hold.tref),
+ RxP = #state.rx_hold,
+ receive
+ {release, RxP} ->
+ ok
+ after 0 ->
+ ok
+ end,
+ S#state{rx_hold = undefined};
+ true ->
+ Q = RxH#hold.q ++ [Data],
+ N = if is_integer(RxH#hold.n) ->
+ RxH#hold.n -1;
+ true ->
+ RxH#hold.n
+ end,
+ S#state{rx_hold = RxH#hold{q = Q, n = N}}
+ end;
+do_peer(Error, _S) ->
+ exit({peer, Error}).
+
diff --git a/lib/ssl/doc/src/notes.xml b/lib/ssl/doc/src/notes.xml
index e0992d317c..352563700b 100644
--- a/lib/ssl/doc/src/notes.xml
+++ b/lib/ssl/doc/src/notes.xml
@@ -25,68 +25,7 @@
<file>notes.xml</file>
</header>
<p>This document describes the changes made to the SSL application.</p>
- <section><title>SSL 7.0</title>
-
- <section><title>Fixed Bugs and Malfunctions</title>
- <list>
- <item>
- <p>
- Ignore signature_algorithm (TLS 1.2 extension) sent to
- TLS 1.0 or TLS 1.1 server</p>
- <p>
- Own Id: OTP-12670</p>
- </item>
- </list>
- </section>
-
-
- <section><title>Improvements and New Features</title>
- <list>
- <item>
- <p>
- Add new API functions to handle CRL-verification</p>
- <p>
- Own Id: OTP-10362 Aux Id: kunagi-215 [126] </p>
- </item>
- <item>
- <p>
- Remove default support for SSL-3.0, due to Poodle
- vunrability in protocol specification.</p>
- <p>
- Add padding check for TLS-1.0 to remove Poodle
- vunrability from TLS 1.0, also add the option
- padding_check. This option only affects TLS-1.0
- connections and if set to false it disables the block
- cipher padding check to be able to interoperate with
- legacy software.</p>
- <p>
- Remove default support for RC4 cipher suites, as they are
- consider too weak.</p>
- <p>
- *** POTENTIAL INCOMPATIBILITY ***</p>
- <p>
- Own Id: OTP-12390</p>
- </item>
- <item>
- <p>
- Add support for TLS ALPN (Application-Layer Protocol
- Negotiation) extension.</p>
- <p>
- Own Id: OTP-12580</p>
- </item>
- <item>
- <p>
- Add SNI (Server Name Indication) support for the server
- side.</p>
- <p>
- Own Id: OTP-12736</p>
- </item>
- </list>
- </section>
-
-</section>
-
-<section><title>SSL 6.0</title>
+ <section><title>SSL 6.0</title>
<section><title>Fixed Bugs and Malfunctions</title>
<list>
diff --git a/lib/ssl/doc/src/ssl.xml b/lib/ssl/doc/src/ssl.xml
index 8a0bf69be4..18d98e5efb 100644
--- a/lib/ssl/doc/src/ssl.xml
+++ b/lib/ssl/doc/src/ssl.xml
@@ -123,13 +123,13 @@
The callback <c>gen_tcp</c> is treated specially and calls <c>inet</c>
directly.</p>
<taglist>
- <tag><c>CallbackModule</c></tag>
- <item><p><c>= atom()</c></p></item>
- <tag><c>DataTag</c></tag>
- <item><p><c>= atom()</c></p>
+ <tag><c>CallbackModule =</c></tag>
+ <item><p><c>atom()</c></p></item>
+ <tag><c>DataTag =</c></tag>
+ <item><p><c>atom()</c></p>
<p>Used in socket data message.</p></item>
- <tag><c>ClosedTag</c></tag>
- <item><p><c>= atom()</c></p>
+ <tag><c>ClosedTag =</c></tag>
+ <item><p><c>atom()</c></p>
<p>Used in socket close message.</p></item>
</taglist>
</item>
diff --git a/lib/ssl/doc/src/ssl_crl_cache_api.xml b/lib/ssl/doc/src/ssl_crl_cache_api.xml
index 90aa895aff..9230442ae0 100644
--- a/lib/ssl/doc/src/ssl_crl_cache_api.xml
+++ b/lib/ssl/doc/src/ssl_crl_cache_api.xml
@@ -47,10 +47,10 @@
<taglist>
- <tag><c>cache_ref()</c></tag>
- <item> = opaque()</item>
- <tag><c>dist_point()</c></tag>
- <item><p> = #'DistributionPoint'{} see <seealso
+ <tag><c>cache_ref() =</c></tag>
+ <item>opaque()</item>
+ <tag><c>dist_point() =</c></tag>
+ <item><p>#'DistributionPoint'{} see <seealso
marker="public_key:public_key_records"> X509 certificates records</seealso></p></item>
</taglist>
diff --git a/lib/ssl/doc/src/ssl_session_cache_api.xml b/lib/ssl/doc/src/ssl_session_cache_api.xml
index c89d3874a1..28b5f4ce23 100644
--- a/lib/ssl/doc/src/ssl_session_cache_api.xml
+++ b/lib/ssl/doc/src/ssl_session_cache_api.xml
@@ -40,20 +40,20 @@
<c>ssl_session_cache_api</c>:</p>
<taglist>
- <tag><c>cache_ref()</c></tag>
- <item><p>= <c>opaque()</c></p></item>
+ <tag><c>cache_ref() =</c></tag>
+ <item><p><c>opaque()</c></p></item>
- <tag><c>key()</c></tag>
- <item><p>= <c>{partialkey(), session_id()}</c></p></item>
+ <tag><c>key() =</c></tag>
+ <item><p><c>{partialkey(), session_id()}</c></p></item>
- <tag><c>partialkey()</c></tag>
- <item><p>= <c>opaque()</c></p></item>
+ <tag><c>partialkey() =</c></tag>
+ <item><p><c>opaque()</c></p></item>
- <tag><c>session_id()</c></tag>
- <item><p>= <c>binary()</c></p></item>
+ <tag><c>session_id() =</c></tag>
+ <item><p><c>binary()</c></p></item>
- <tag><c>session()</c></tag>
- <item><p>= <c>opaque()</c></p></item>
+ <tag><c>session()</c> =</tag>
+ <item><p><c>opaque()</c></p></item>
</taglist>
</section>
diff --git a/lib/ssl/test/ssl_alpn_handshake_SUITE.erl b/lib/ssl/test/ssl_alpn_handshake_SUITE.erl
index ccd70fa605..ae76f5849e 100644
--- a/lib/ssl/test/ssl_alpn_handshake_SUITE.erl
+++ b/lib/ssl/test/ssl_alpn_handshake_SUITE.erl
@@ -384,7 +384,7 @@ ssl_receive_and_assert_alpn(Socket, Protocol, Data) ->
ssl_send(Socket, Data) ->
ct:log("Connection info: ~p~n",
- [ssl:connection_info(Socket)]),
+ [ssl:connection_information(Socket)]),
ssl:send(Socket, Data).
ssl_receive(Socket, Data) ->
@@ -392,7 +392,7 @@ ssl_receive(Socket, Data) ->
ssl_receive(Socket, Data, Buffer) ->
ct:log("Connection info: ~p~n",
- [ssl:connection_info(Socket)]),
+ [ssl:connection_information(Socket)]),
receive
{ssl, Socket, MoreData} ->
ct:log("Received ~p~n",[MoreData]),
@@ -411,4 +411,4 @@ ssl_receive(Socket, Data, Buffer) ->
end.
connection_info_result(Socket) ->
- ssl:connection_info(Socket).
+ ssl:connection_information(Socket).
diff --git a/lib/ssl/test/ssl_basic_SUITE.erl b/lib/ssl/test/ssl_basic_SUITE.erl
index 50d5fb411f..e1a36dbbd4 100644
--- a/lib/ssl/test/ssl_basic_SUITE.erl
+++ b/lib/ssl/test/ssl_basic_SUITE.erl
@@ -384,7 +384,7 @@ new_options_in_accept(Config) when is_list(Config) ->
%%--------------------------------------------------------------------
connection_info() ->
- [{doc,"Test the API function ssl:connection_info/1"}].
+ [{doc,"Test the API function ssl:connection_information/1"}].
connection_info(Config) when is_list(Config) ->
ClientOpts = ?config(client_opts, Config),
ServerOpts = ?config(server_opts, Config),
@@ -2831,7 +2831,7 @@ listen_socket(Config) ->
{error, enotconn} = ssl:send(ListenSocket, <<"data">>),
{error, enotconn} = ssl:recv(ListenSocket, 0),
- {error, enotconn} = ssl:connection_info(ListenSocket),
+ {error, enotconn} = ssl:connection_information(ListenSocket),
{error, enotconn} = ssl:peername(ListenSocket),
{error, enotconn} = ssl:peercert(ListenSocket),
{error, enotconn} = ssl:session_info(ListenSocket),
@@ -3445,7 +3445,7 @@ renegotiate_immediately(Socket) ->
end,
ok = ssl:renegotiate(Socket),
{error, renegotiation_rejected} = ssl:renegotiate(Socket),
- ct:sleep(?RENEGOTIATION_DISABLE_TIME +1),
+ ct:sleep(?RENEGOTIATION_DISABLE_TIME + ?SLEEP),
ok = ssl:renegotiate(Socket),
ct:log("Renegotiated again"),
ssl:send(Socket, "Hello world"),
@@ -3836,10 +3836,10 @@ cipher(CipherSuite, Version, Config, ClientOpts, ServerOpts) ->
end.
connection_info_result(Socket) ->
- ssl:connection_info(Socket).
-
+ {ok, Info} = ssl:connection_information(Socket, [protocol, cipher_suite]),
+ {ok, {proplists:get_value(protocol, Info), proplists:get_value(cipher_suite, Info)}}.
version_info_result(Socket) ->
- {ok, {Version, _}} = ssl:connection_info(Socket),
+ {ok, [{version, Version}]} = ssl:connection_information(Socket, [version]),
{ok, Version}.
connect_dist_s(S) ->
diff --git a/lib/ssl/test/ssl_npn_handshake_SUITE.erl b/lib/ssl/test/ssl_npn_handshake_SUITE.erl
index 326f907e66..8e95679306 100644
--- a/lib/ssl/test/ssl_npn_handshake_SUITE.erl
+++ b/lib/ssl/test/ssl_npn_handshake_SUITE.erl
@@ -332,7 +332,7 @@ ssl_receive_and_assert_npn(Socket, Protocol, Data) ->
ssl_send(Socket, Data) ->
ct:log("Connection info: ~p~n",
- [ssl:connection_info(Socket)]),
+ [ssl:connection_information(Socket)]),
ssl:send(Socket, Data).
ssl_receive(Socket, Data) ->
@@ -340,7 +340,7 @@ ssl_receive(Socket, Data) ->
ssl_receive(Socket, Data, Buffer) ->
ct:log("Connection info: ~p~n",
- [ssl:connection_info(Socket)]),
+ [ssl:connection_information(Socket)]),
receive
{ssl, Socket, MoreData} ->
ct:log("Received ~p~n",[MoreData]),
@@ -360,4 +360,4 @@ ssl_receive(Socket, Data, Buffer) ->
connection_info_result(Socket) ->
- ssl:connection_info(Socket).
+ ssl:connection_information(Socket).
diff --git a/lib/ssl/test/ssl_sni_SUITE.erl b/lib/ssl/test/ssl_sni_SUITE.erl
index 46cd644e4d..b059ff991b 100644
--- a/lib/ssl/test/ssl_sni_SUITE.erl
+++ b/lib/ssl/test/ssl_sni_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2015. All Rights Reserved.
+%% Copyright Ericsson AB 2015-2015. 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,7 +16,6 @@
%%
%% %CopyrightEnd%
%%
-
%%
-module(ssl_sni_SUITE).
@@ -31,7 +30,12 @@
%%--------------------------------------------------------------------
suite() -> [{ct_hooks,[ts_install_cth]}].
-all() -> [no_sni_header, sni_match, sni_no_match] ++ [no_sni_header_fun, sni_match_fun, sni_no_match_fun].
+all() -> [no_sni_header,
+ sni_match,
+ sni_no_match,
+ no_sni_header_fun,
+ sni_match_fun,
+ sni_no_match_fun].
init_per_suite(Config0) ->
catch crypto:stop(),
@@ -39,11 +43,11 @@ init_per_suite(Config0) ->
ok ->
ssl:start(),
Result =
- (catch make_certs:all(?config(data_dir, Config0),
- ?config(priv_dir, Config0))),
+ (catch make_certs:all(?config(data_dir, Config0),
+ ?config(priv_dir, Config0))),
ct:log("Make certs ~p~n", [Result]),
ssl_test_lib:cert_options(Config0)
- catch _:_ ->
+ catch _:_ ->
{skip, "Crypto did not start"}
end.
@@ -76,8 +80,6 @@ sni_no_match_fun(Config) ->
%%--------------------------------------------------------------------
%% Internal Functions ------------------------------------------------
%%--------------------------------------------------------------------
-
-
ssl_recv(SSLSocket, Expect) ->
ssl_recv(SSLSocket, "", Expect).
@@ -93,20 +95,21 @@ ssl_recv(SSLSocket, CurrentData, ExpectedData) ->
end;
Other ->
ct:fail({unexpected_message, Other})
- after 4000 ->
+ after 4000 ->
ct:fail({timeout, CurrentData, ExpectedData})
end.
-
-
send_and_hostname(SSLSocket) ->
ssl:send(SSLSocket, "OK"),
{ok, [{sni_hostname, Hostname}]} = ssl:connection_information(SSLSocket, [sni_hostname]),
Hostname.
-rdnPart([[#'AttributeTypeAndValue'{type=Type, value=Value} | _] | _], Type) -> Value;
-rdnPart([_ | Tail], Type) -> rdnPart(Tail, Type);
-rdnPart([], _) -> unknown.
+rdnPart([[#'AttributeTypeAndValue'{type=Type, value=Value} | _] | _], Type) ->
+ Value;
+rdnPart([_ | Tail], Type) ->
+ rdnPart(Tail, Type);
+rdnPart([], _) ->
+ unknown.
rdn_to_string({utf8String, Binary}) ->
erlang:binary_to_list(Binary);
@@ -116,12 +119,15 @@ rdn_to_string({printableString, String}) ->
recv_and_certificate(SSLSocket) ->
ssl_recv(SSLSocket, "OK"),
{ok, PeerCert} = ssl:peercert(SSLSocket),
- #'OTPCertificate'{tbsCertificate = #'OTPTBSCertificate'{subject = {rdnSequence, Subject}}} = public_key:pkix_decode_cert(PeerCert, otp),
+ #'OTPCertificate'{tbsCertificate = #'OTPTBSCertificate'{subject = {rdnSequence, Subject}}}
+ = public_key:pkix_decode_cert(PeerCert, otp),
ct:log("Subject of certificate received from server: ~p", [Subject]),
rdn_to_string(rdnPart(Subject, ?'id-at-commonName')).
run_sni_fun_handshake(Config, SNIHostname, ExpectedSNIHostname, ExpectedCN) ->
- ct:log("Start running handshake for sni_fun, Config: ~p, SNIHostname: ~p, ExpectedSNIHostname: ~p, ExpectedCN: ~p", [Config, SNIHostname, ExpectedSNIHostname, ExpectedCN]),
+ ct:log("Start running handshake for sni_fun, Config: ~p, SNIHostname: ~p, "
+ "ExpectedSNIHostname: ~p, ExpectedCN: ~p",
+ [Config, SNIHostname, ExpectedSNIHostname, ExpectedCN]),
[{sni_hosts, ServerSNIConf}] = ?config(sni_server_opts, Config),
SNIFun = fun(Domain) -> proplists:get_value(Domain, ServerSNIConf, undefined) end,
ServerOptions = ?config(server_opts, Config) ++ [{sni_fun, SNIFun}],
@@ -142,11 +148,14 @@ run_sni_fun_handshake(Config, SNIHostname, ExpectedSNIHostname, ExpectedCN) ->
{host, Hostname}, {from, self()},
{mfa, {?MODULE, recv_and_certificate, []}},
{options, ClientOptions}]),
- ssl_test_lib:check_result(Server, ExpectedSNIHostname, Client, ExpectedCN).
-
+ ssl_test_lib:check_result(Server, ExpectedSNIHostname, Client, ExpectedCN),
+ ssl_test_lib:close(Server),
+ ssl_test_lib:close(Client).
run_handshake(Config, SNIHostname, ExpectedSNIHostname, ExpectedCN) ->
- ct:log("Start running handshake, Config: ~p, SNIHostname: ~p, ExpectedSNIHostname: ~p, ExpectedCN: ~p", [Config, SNIHostname, ExpectedSNIHostname, ExpectedCN]),
+ ct:log("Start running handshake, Config: ~p, SNIHostname: ~p, "
+ "ExpectedSNIHostname: ~p, ExpectedCN: ~p",
+ [Config, SNIHostname, ExpectedSNIHostname, ExpectedCN]),
ServerOptions = ?config(sni_server_opts, Config) ++ ?config(server_opts, Config),
ClientOptions =
case SNIHostname of
@@ -165,4 +174,6 @@ run_handshake(Config, SNIHostname, ExpectedSNIHostname, ExpectedCN) ->
{host, Hostname}, {from, self()},
{mfa, {?MODULE, recv_and_certificate, []}},
{options, ClientOptions}]),
- ssl_test_lib:check_result(Server, ExpectedSNIHostname, Client, ExpectedCN).
+ ssl_test_lib:check_result(Server, ExpectedSNIHostname, Client, ExpectedCN),
+ ssl_test_lib:close(Server),
+ ssl_test_lib:close(Client).
diff --git a/lib/ssl/test/ssl_test_lib.erl b/lib/ssl/test/ssl_test_lib.erl
index 8b98e6f16b..a3bfdf8893 100644
--- a/lib/ssl/test/ssl_test_lib.erl
+++ b/lib/ssl/test/ssl_test_lib.erl
@@ -949,7 +949,8 @@ der_to_pem(File, Entries) ->
file:write_file(File, PemBin).
cipher_result(Socket, Result) ->
- Result = ssl:connection_info(Socket),
+ {ok, Info} = ssl:connection_information(Socket),
+ Result = {ok, {proplists:get_value(protocol, Info), proplists:get_value(cipher_suite, Info)}},
ct:log("~p:~p~nSuccessfull connect: ~p~n", [?MODULE,?LINE, Result]),
%% Importante to send two packets here
%% to properly test "cipher state" handling
diff --git a/lib/ssl/test/ssl_to_openssl_SUITE.erl b/lib/ssl/test/ssl_to_openssl_SUITE.erl
index 0413415e49..aca34cb6e9 100644
--- a/lib/ssl/test/ssl_to_openssl_SUITE.erl
+++ b/lib/ssl/test/ssl_to_openssl_SUITE.erl
@@ -1243,15 +1243,16 @@ run_suites(Ciphers, Version, Config, Type) ->
ct:fail(cipher_suite_failed_see_test_case_log)
end.
-client_read_check([], _NewData) -> ok;
-client_read_check([Hd | T], NewData) ->
- case binary:match(NewData, list_to_binary(Hd)) of
+client_read_check([], _Data) ->
+ ok;
+client_read_check([Hd | T], Data) ->
+ case binary:match(Data, list_to_binary(Hd)) of
nomatch ->
nomatch;
_ ->
- client_read_check(T, NewData)
+ client_read_check(T, Data)
end.
-client_read_bulk(Port, DataExpected, DataReceived) ->
+client_check_result(Port, DataExpected, DataReceived) ->
receive
{Port, {data, TheData}} ->
Data = list_to_binary(TheData),
@@ -1261,15 +1262,14 @@ client_read_bulk(Port, DataExpected, DataReceived) ->
ok ->
ok;
_ ->
- client_read_bulk(Port, DataExpected, NewData)
- end;
- _ ->
- ct:fail("unexpected_message")
- after 4000 ->
- ct:fail("timeout")
+ client_check_result(Port, DataExpected, NewData)
+ end
+ after 3000 ->
+ ct:fail({"Time out on opensssl Client", {expected, DataExpected},
+ {got, DataReceived}})
end.
-client_read_bulk(Port, DataExpected) ->
- client_read_bulk(Port, DataExpected, <<"">>).
+client_check_result(Port, DataExpected) ->
+ client_check_result(Port, DataExpected, <<"">>).
send_and_hostname(SSLSocket) ->
ssl:send(SSLSocket, "OK"),
@@ -1292,9 +1292,12 @@ erlang_server_openssl_client_sni_test(Config, SNIHostname, ExpectedSNIHostname,
end,
ct:log("Options: ~p", [[ServerOptions, ClientCommand]]),
ClientPort = open_port({spawn, ClientCommand}, [stderr_to_stdout]),
- ssl_test_lib:check_result(Server, ExpectedSNIHostname),
+
+ %% Client check needs to be done befor server check,
+ %% or server check might consume client messages
ExpectedClientOutput = ["OK", "/CN=" ++ ExpectedCN ++ "/"],
- ok = client_read_bulk(ClientPort, ExpectedClientOutput),
+ client_check_result(ClientPort, ExpectedClientOutput),
+ ssl_test_lib:check_result(Server, ExpectedSNIHostname),
ssl_test_lib:close_port(ClientPort),
ssl_test_lib:close(Server),
ok.
@@ -1318,12 +1321,14 @@ erlang_server_openssl_client_sni_test_sni_fun(Config, SNIHostname, ExpectedSNIHo
end,
ct:log("Options: ~p", [[ServerOptions, ClientCommand]]),
ClientPort = open_port({spawn, ClientCommand}, [stderr_to_stdout]),
- ssl_test_lib:check_result(Server, ExpectedSNIHostname),
+
+ %% Client check needs to be done befor server check,
+ %% or server check might consume client messages
ExpectedClientOutput = ["OK", "/CN=" ++ ExpectedCN ++ "/"],
- ok = client_read_bulk(ClientPort, ExpectedClientOutput),
+ client_check_result(ClientPort, ExpectedClientOutput),
+ ssl_test_lib:check_result(Server, ExpectedSNIHostname),
ssl_test_lib:close_port(ClientPort),
- ssl_test_lib:close(Server),
- ok.
+ ssl_test_lib:close(Server).
cipher(CipherSuite, Version, Config, ClientOpts, ServerOpts) ->
@@ -1664,7 +1669,7 @@ erlang_ssl_receive_and_assert_negotiated_protocol(Socket, Protocol, Data) ->
erlang_ssl_receive(Socket, Data) ->
ct:log("Connection info: ~p~n",
- [ssl:connection_info(Socket)]),
+ [ssl:connection_information(Socket)]),
receive
{ssl, Socket, Data} ->
io:format("Received ~p~n",[Data]),
@@ -1683,16 +1688,16 @@ erlang_ssl_receive(Socket, Data) ->
end.
connection_info(Socket, Version) ->
- case ssl:connection_info(Socket) of
- {ok, {Version, _} = Info} ->
+ case ssl:connection_information(Socket, [version]) of
+ {ok, [{version, Version}] = Info} ->
ct:log("Connection info: ~p~n", [Info]),
ok;
- {ok, {OtherVersion, _}} ->
+ {ok, [{version, OtherVersion}]} ->
{wrong_version, OtherVersion}
end.
connection_info_result(Socket) ->
- ssl:connection_info(Socket).
+ ssl:connection_information(Socket).
delayed_send(Socket, [ErlData, OpenSslData]) ->
diff --git a/lib/stdlib/doc/src/c.xml b/lib/stdlib/doc/src/c.xml
index b49fa6ad67..b43d4786ae 100644
--- a/lib/stdlib/doc/src/c.xml
+++ b/lib/stdlib/doc/src/c.xml
@@ -232,6 +232,14 @@ compile:file(<anno>File</anno>, <anno>Options</anno> ++ [report_errors, report_w
</desc>
</func>
<func>
+ <name name="uptime" arity="0"/>
+ <fsummary>Print node uptime</fsummary>
+ <desc>
+ <p>Prints the node uptime (as given by
+ <c>erlang:statistics(wall_clock)</c>), in human-readable form.</p>
+ </desc>
+ </func>
+ <func>
<name>xm(ModSpec) -> void()</name>
<fsummary>Cross reference check a module</fsummary>
<type>
diff --git a/lib/stdlib/doc/src/ets.xml b/lib/stdlib/doc/src/ets.xml
index 6b9524ef63..2bfe074c3e 100644
--- a/lib/stdlib/doc/src/ets.xml
+++ b/lib/stdlib/doc/src/ets.xml
@@ -1435,7 +1435,9 @@ is_integer(X), is_integer(Y), X + Y < 4711]]></code>
<p>Whenever the <c>extended_info</c> option is used, it
results in a file not readable by versions of ets prior to
that in stdlib-1.15.1</p>
-
+ <p>The <c>sync</c> option, if set to <c>true</c>, ensures that
+ the content of the file is actually written to the disk before
+ <c>tab2file</c> returns. Default is <c>{sync, false}</c>.</p>
</desc>
</func>
<func>
diff --git a/lib/stdlib/doc/src/gb_sets.xml b/lib/stdlib/doc/src/gb_sets.xml
index ea96c14472..405bae5698 100644
--- a/lib/stdlib/doc/src/gb_sets.xml
+++ b/lib/stdlib/doc/src/gb_sets.xml
@@ -4,7 +4,7 @@
<erlref>
<header>
<copyright>
- <year>2001</year><year>2014</year>
+ <year>2001</year><year>2015</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -306,6 +306,17 @@
</desc>
</func>
<func>
+ <name name="iterator_from" arity="2"/>
+ <fsummary>Return an iterator for a set starting from a specified element</fsummary>
+ <desc>
+ <p>Returns an iterator that can be used for traversing the
+ entries of <c><anno>Set</anno></c>; see <c>next/1</c>.
+ The difference as compared to the iterator returned by
+ <c>iterator/1</c> is that the first element greater than
+ or equal to <c><anno>Element</anno></c> is returned.</p>
+ </desc>
+ </func>
+ <func>
<name name="largest" arity="1"/>
<fsummary>Return largest element</fsummary>
<desc>
diff --git a/lib/stdlib/doc/src/gb_trees.xml b/lib/stdlib/doc/src/gb_trees.xml
index b2f237e1d7..82167e1083 100644
--- a/lib/stdlib/doc/src/gb_trees.xml
+++ b/lib/stdlib/doc/src/gb_trees.xml
@@ -4,7 +4,7 @@
<erlref>
<header>
<copyright>
- <year>2001</year><year>2014</year>
+ <year>2001</year><year>2015</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -183,6 +183,17 @@
</desc>
</func>
<func>
+ <name name="iterator_from" arity="2"/>
+ <fsummary>Return an iterator for a tree starting from specified key</fsummary>
+ <desc>
+ <p>Returns an iterator that can be used for traversing the
+ entries of <c><anno>Tree</anno></c>; see <c>next/1</c>.
+ The difference as compared to the iterator returned by
+ <c>iterator/1</c> is that the first key greater than
+ or equal to <c><anno>Key</anno></c> is returned.</p>
+ </desc>
+ </func>
+ <func>
<name name="keys" arity="1"/>
<fsummary>Return a list of the keys in a tree</fsummary>
<desc>
diff --git a/lib/stdlib/doc/src/maps.xml b/lib/stdlib/doc/src/maps.xml
index e46068230a..7345a9357a 100644
--- a/lib/stdlib/doc/src/maps.xml
+++ b/lib/stdlib/doc/src/maps.xml
@@ -33,6 +33,28 @@
<funcs>
<func>
+ <name name="filter" arity="2"/>
+ <fsummary>Choose pairs which satisfy a predicate</fsummary>
+ <desc>
+ <p>
+ Returns a map <c><anno>Map2</anno></c> for which predicate
+ <c><anno>Pred</anno></c> holds true in <c><anno>Map1</anno></c>.
+ </p>
+ <p>
+ The call will fail with a <c>{badmap,Map}</c> exception if
+ <c><anno>Map1</anno></c> is not a map or with <c>badarg</c> if
+ <c><anno>Pred</anno></c> is not a function of arity 2.
+ </p>
+ <p>Example:</p>
+ <code type="none">
+> M = #{a => 2, b => 3, c=> 4, "a" => 1, "b" => 2, "c" => 4},
+ Pred = fun(K,V) -> is_atom(K) andalso (V rem 2) =:= 0 end,
+ maps:filter(Pred,M).
+#{a => 2,c => 4} </code>
+ </desc>
+ </func>
+
+ <func>
<name name="find" arity="2"/>
<fsummary></fsummary>
<desc>
diff --git a/lib/stdlib/doc/src/notes.xml b/lib/stdlib/doc/src/notes.xml
index 3914a9bc0e..301a5ee2e8 100644
--- a/lib/stdlib/doc/src/notes.xml
+++ b/lib/stdlib/doc/src/notes.xml
@@ -30,224 +30,6 @@
</header>
<p>This document describes the changes made to the STDLIB application.</p>
-<section><title>STDLIB 2.5</title>
-
- <section><title>Fixed Bugs and Malfunctions</title>
- <list>
- <item>
- <p>
- Fix handling of single dot in filename:join/2</p>
- <p>
- The reference manual says that filename:join(A,B) is
- equivalent to filename:join([A,B]). In some rare cases
- this turns out not to be true. For example:</p>
- <p>
- <c>filename:join("/a/.","b") -&gt; "/a/./b"</c> vs
- <c>filename:join(["/a/.","b"]) -&gt; "/a/b"</c>.</p>
- <p>
- This has been corrected. A single dot is now only kept if
- it occurs at the very beginning or the very end of the
- resulting path.</p>
- <p>
- *** POTENTIAL INCOMPATIBILITY ***</p>
- <p>
- Own Id: OTP-12158</p>
- </item>
- <item>
- <p>
- The undocumented option <c>generic_debug</c> for
- <c>gen_server</c> has been removed.</p>
- <p>
- Own Id: OTP-12183</p>
- </item>
- <item>
- <p>
- erl_lint:icrt_export/4 has been rewritten to make the
- code really follow the scoping rules of Erlang, and not
- just in most situations by accident.</p>
- <p>
- Own Id: OTP-12186</p>
- </item>
- <item>
- <p>
- Add 'trim_all' option to binary:split/3</p>
- <p>
- This option can be set to remove _ALL_ empty parts of the
- result of a call to binary:split/3.</p>
- <p>
- Own Id: OTP-12301</p>
- </item>
- <item>
- <p> Correct orddict(3) regarding evaluation order of
- <c>fold()</c> and <c>map()</c>. </p>
- <p>
- Own Id: OTP-12651 Aux Id: seq12832 </p>
- </item>
- <item>
- <p>
- Correct <c>maps</c> module error exceptions </p>
- <p>
- Bad input to maps module function will now yield the
- following exceptions: <list> <item>{badmap,NotMap}
- or,</item> <item>badarg</item> </list></p>
- <p>
- Own Id: OTP-12657</p>
- </item>
- <item>
- <p>
- It is now possible to paste text in JCL mode (using
- Ctrl-Y) that has been copied in the previous shell
- session. Also a bug that caused the JCL mode to crash
- when pasting text has been fixed.</p>
- <p>
- Own Id: OTP-12673</p>
- </item>
- </list>
- </section>
-
-
- <section><title>Improvements and New Features</title>
- <list>
- <item>
- <p>
- Allow maps for supervisor flags and child specs</p>
- <p>
- Earlier, supervisor flags and child specs were given as
- tuples. While this is kept for backwards compatibility,
- it is now also allowed to give these parameters as maps,
- see <seealso
- marker="stdlib:supervisor#sup_flags">sup_flags</seealso>
- and <seealso
- marker="stdlib:supervisor#child_spec">child_spec</seealso>.</p>
- <p>
- Own Id: OTP-11043</p>
- </item>
- <item>
- <p>
- A new system message, <c>terminate</c>, is added. This
- can be sent with <c>sys:terminate/2,3</c>. If the
- receiving process handles system messages properly it
- will terminate shortly after receiving this message.</p>
- <p>
- The new function <c>proc_lib:stop/1,3</c> utilizes this
- new system message and monitors the receiving process in
- order to facilitate a synchronous stop mechanism for
- 'special processes'.</p>
- <p>
- <c>proc_lib:stop/1,3</c> is used by the following
- functions:</p>
- <p>
- <list> <item><c>gen_server:stop/1,3</c> (new)</item>
- <item><c>gen_fsm:stop/1,3</c> (new)</item>
- <item><c>gen_event:stop/1,3</c> (modified to be
- synchronous)</item> <item><c>wx_object:stop/1,3</c>
- (new)</item> </list></p>
- <p>
- Own Id: OTP-11173 Aux Id: seq12353 </p>
- </item>
- <item>
- <p>
- Remove the <c>pg</c> module, which has been deprecated
- through OTP-17, is now removed from the STDLIB
- application. This module has been marked experimental for
- more than 15 years, and has largely been superseded by
- the <c>pg2</c> module from the Kernel application.</p>
- <p>
- Own Id: OTP-11907</p>
- </item>
- <item>
- <p>
- New BIF: <c>erlang:get_keys/0</c>, lists all keys
- associated with the process dictionary. Note:
- <c>erlang:get_keys/0</c> is auto-imported.</p>
- <p>
- *** POTENTIAL INCOMPATIBILITY ***</p>
- <p>
- Own Id: OTP-12151 Aux Id: seq12521 </p>
- </item>
- <item>
- <p> Add three new functions to <c>io_lib</c>--
- <c>scan_format/2</c>, <c>unscan_format/1</c>, and
- <c>build_text/1</c>-- which expose the parsed form of the
- format control sequences to make it possible to easily
- modify or filter the input to <c>io_lib:format/2</c>.
- This can e.g. be used in order to replace unbounded-size
- control sequences like <c>~w</c> or <c>~p</c> with
- corresponding depth-limited <c>~W</c> and <c>~P</c>
- before doing the actual formatting. </p>
- <p>
- Own Id: OTP-12167</p>
- </item>
- <item>
- <p> Introduce the <c>erl_anno</c> module, an abstraction
- of the second element of tokens and tuples in the
- abstract format. </p>
- <p>
- Own Id: OTP-12195</p>
- </item>
- <item>
- <p>
- Support variables as Map keys in expressions and patterns</p>
- <p>Erlang will accept any expression as keys in Map
- expressions and it will accept literals or bound
- variables as keys in Map patterns.</p>
- <p>
- Own Id: OTP-12218</p>
- </item>
- <item>
- <p> The last traces of Mnemosyne Rules have been removed.
- </p>
- <p>
- Own Id: OTP-12257</p>
- </item>
- <item>
- <p>
- Properly support maps in match_specs</p>
- <p>
- Own Id: OTP-12270</p>
- </item>
- <item>
- <p>
- New function <c>ets:take/2</c>. Works the same as
- <c>ets:delete/2</c> but also returns the deleted
- object(s).</p>
- <p>
- Own Id: OTP-12309</p>
- </item>
- <item>
- <p><c>string:tokens/2</c> is somewhat faster, especially
- if the list of separators only contains one separator
- character.</p>
- <p>
- Own Id: OTP-12422 Aux Id: seq12774 </p>
- </item>
- <item>
- <p>
- Prevent zip:zip_open/[12] from leaking file descriptors
- if parent process dies.</p>
- <p>
- Own Id: OTP-12566</p>
- </item>
- <item>
- <p>
- Add a new random number generator, see <c>rand</c>
- module. It have better characteristics and an improved
- interface.</p>
- <p>
- Own Id: OTP-12586 Aux Id: OTP-12501, OTP-12502 </p>
- </item>
- <item>
- <p><c>filename:split/1</c> when given an empty binary
- will now return an empty list, to make it consistent with
- return value when given an empty list.</p>
- <p>
- Own Id: OTP-12716</p>
- </item>
- </list>
- </section>
-
-</section>
-
<section><title>STDLIB 2.4</title>
<section><title>Fixed Bugs and Malfunctions</title>
diff --git a/lib/stdlib/src/c.erl b/lib/stdlib/src/c.erl
index 9860adf04d..d5b24d3c32 100644
--- a/lib/stdlib/src/c.erl
+++ b/lib/stdlib/src/c.erl
@@ -27,7 +27,7 @@
lc_batch/0, lc_batch/1,
i/3,pid/3,m/0,m/1,
bt/1, q/0,
- erlangrc/0,erlangrc/1,bi/1, flush/0, regs/0,
+ erlangrc/0,erlangrc/1,bi/1, flush/0, regs/0, uptime/0,
nregs/0,pwd/0,ls/0,ls/1,cd/1,memory/1,memory/0, xm/1]).
-export([display_info/1]).
@@ -65,6 +65,7 @@ help() ->
"q() -- quit - shorthand for init:stop()\n"
"regs() -- information about registered processes\n"
"nregs() -- information about all registered processes\n"
+ "uptime() -- print node uptime\n"
"xm(M) -- cross reference check a module\n"
"y(File) -- generate a Yecc parser\n">>).
@@ -774,6 +775,26 @@ memory() -> erlang:memory().
memory(TypeSpec) -> erlang:memory(TypeSpec).
%%
+%% uptime/0
+%%
+
+-spec uptime() -> 'ok'.
+
+uptime() ->
+ io:format("~s~n", [uptime(get_uptime())]).
+
+uptime({D, {H, M, S}}) ->
+ lists:flatten(
+ [[ io_lib:format("~p days, ", [D]) || D > 0 ],
+ [ io_lib:format("~p hours, ", [H]) || D+H > 0 ],
+ [ io_lib:format("~p minutes and ", [M]) || D+H+M > 0 ],
+ io_lib:format("~p seconds", [S])]).
+
+get_uptime() ->
+ {UpTime, _} = erlang:statistics(wall_clock),
+ calendar:seconds_to_daystime(UpTime div 1000).
+
+%%
%% Cross Reference Check
%%
%%-spec xm(module() | file:filename()) -> xref:m/1 return
diff --git a/lib/stdlib/src/erl_anno.erl b/lib/stdlib/src/erl_anno.erl
index 963b7278a6..9fb767fc93 100644
--- a/lib/stdlib/src/erl_anno.erl
+++ b/lib/stdlib/src/erl_anno.erl
@@ -147,7 +147,7 @@ is_anno2(_, _) ->
false.
is_filename(T) ->
- is_string(T) orelse is_binary(T).
+ is_list(T) orelse is_binary(T).
is_string(T) ->
try lists:all(fun(C) when is_integer(C), C >= 0 -> true end, T)
diff --git a/lib/stdlib/src/erl_lint.erl b/lib/stdlib/src/erl_lint.erl
index 821d81a6b4..714c260bda 100644
--- a/lib/stdlib/src/erl_lint.erl
+++ b/lib/stdlib/src/erl_lint.erl
@@ -120,13 +120,13 @@ value_option(Flag, Default, On, OnVal, Off, OffVal, Opts) ->
func=[], %Current function
warn_format=0, %Warn format calls
enabled_warnings=[], %All enabled warnings (ordset).
+ nowarn_bif_clash=[], %All no warn bif clashes (ordset).
errors=[], %Current errors
warnings=[], %Current warnings
file = "" :: string(), %From last file attribute
recdef_top=false :: boolean(), %true in record initialisation
%outside any fun or lc
xqlc= false :: boolean(), %true if qlc.hrl included
- new = false :: boolean(), %Has user-defined 'new/N'
called= [] :: [{fa(),line()}], %Called functions
usage = #usage{} :: #usage{},
specs = dict:new() %Type specifications
@@ -569,6 +569,7 @@ start(File, Opts) ->
warn_format = value_option(warn_format, 1, warn_format, 1,
nowarn_format, 0, Opts),
enabled_warnings = Enabled,
+ nowarn_bif_clash = nowarn_function(nowarn_bif_clash, Opts),
file = File
}.
@@ -640,8 +641,6 @@ forms(Forms0, St0) ->
St4 = foldl(fun form/2, pre_scan(Forms, St3), Forms),
post_traversal_check(Forms, St4).
-pre_scan([{function,_L,new,_A,_Cs} | Fs], St) ->
- pre_scan(Fs, St#lint{new=true});
pre_scan([{attribute,L,compile,C} | Fs], St) ->
case is_warn_enabled(export_all, St) andalso
member(export_all, lists:flatten([C])) of
@@ -772,8 +771,7 @@ eof(_Line, St0) ->
%% bif_clashes(Forms, State0) -> State.
-bif_clashes(Forms, St) ->
- Nowarn = nowarn_function(nowarn_bif_clash, St#lint.compile),
+bif_clashes(Forms, #lint{nowarn_bif_clash=Nowarn} = St) ->
Clashes0 = [{Name,Arity} || {function,_L,Name,Arity,_Cs} <- Forms,
erl_internal:bif(Name, Arity)],
Clashes = ordsets:subtract(ordsets:from_list(Clashes0), Nowarn),
@@ -3781,8 +3779,7 @@ is_autoimport_suppressed(NoAutoSet,{Func,Arity}) ->
gb_sets:is_element({Func,Arity},NoAutoSet).
%% Predicate to find out if a function specific bif-clash suppression (old deprecated) is present
bif_clash_specifically_disabled(St,{F,A}) ->
- Nowarn = nowarn_function(nowarn_bif_clash, St#lint.compile),
- lists:member({F,A},Nowarn).
+ lists:member({F,A},St#lint.nowarn_bif_clash).
%% Predicate to find out if an autoimported guard_bif is not overriden in some way
%% Guard Bif without module name is disallowed if
diff --git a/lib/stdlib/src/ets.erl b/lib/stdlib/src/ets.erl
index 1df069755d..0e2d59d0c3 100644
--- a/lib/stdlib/src/ets.erl
+++ b/lib/stdlib/src/ets.erl
@@ -739,7 +739,8 @@ do_filter(Tab, Key, F, A, Ack) ->
-record(filetab_options,
{
object_count = false :: boolean(),
- md5sum = false :: boolean()
+ md5sum = false :: boolean(),
+ sync = false :: boolean()
}).
-spec tab2file(Tab, Filename) -> 'ok' | {'error', Reason} when
@@ -754,7 +755,7 @@ tab2file(Tab, File) ->
Tab :: tab(),
Filename :: file:name(),
Options :: [Option],
- Option :: {'extended_info', [ExtInfo]},
+ Option :: {'extended_info', [ExtInfo]} | {'sync', boolean()},
ExtInfo :: 'md5sum' | 'object_count',
Reason :: term().
@@ -835,6 +836,15 @@ tab2file(Tab, File, Options) ->
List ->
LogFun(NewState1,[['$end_of_table',List]])
end,
+ case FtOptions#filetab_options.sync of
+ true ->
+ case disk_log:sync(Name) of
+ ok -> ok;
+ {error, Reason2} -> throw(Reason2)
+ end;
+ false ->
+ ok
+ end,
disk_log:close(Name)
catch
throw:TReason ->
@@ -887,23 +897,24 @@ md5terms(State, [H|T]) ->
{FinState, [B|TL]}.
parse_ft_options(Options) when is_list(Options) ->
- {Opt,Rest} = case (catch lists:keytake(extended_info,1,Options)) of
- false ->
- {[],Options};
- {value,{extended_info,L},R} when is_list(L) ->
- {L,R}
- end,
- case Rest of
- [] ->
- parse_ft_info_options(#filetab_options{}, Opt);
- Other ->
- throw({unknown_option, Other})
- end;
-parse_ft_options(Malformed) ->
+ {ok, parse_ft_options(Options, #filetab_options{}, false)}.
+
+parse_ft_options([], FtOpt, _) ->
+ FtOpt;
+parse_ft_options([{sync,true} | Rest], FtOpt, EI) ->
+ parse_ft_options(Rest, FtOpt#filetab_options{sync = true}, EI);
+parse_ft_options([{sync,false} | Rest], FtOpt, EI) ->
+ parse_ft_options(Rest, FtOpt, EI);
+parse_ft_options([{extended_info,L} | Rest], FtOpt0, false) ->
+ FtOpt1 = parse_ft_info_options(FtOpt0, L),
+ parse_ft_options(Rest, FtOpt1, true);
+parse_ft_options([Other | _], _, _) ->
+ throw({unknown_option, Other});
+parse_ft_options(Malformed, _, _) ->
throw({malformed_option, Malformed}).
parse_ft_info_options(FtOpt,[]) ->
- {ok,FtOpt};
+ FtOpt;
parse_ft_info_options(FtOpt,[object_count | T]) ->
parse_ft_info_options(FtOpt#filetab_options{object_count = true}, T);
parse_ft_info_options(FtOpt,[md5sum | T]) ->
diff --git a/lib/stdlib/src/gb_sets.erl b/lib/stdlib/src/gb_sets.erl
index 393fb07229..d3fbd542f7 100644
--- a/lib/stdlib/src/gb_sets.erl
+++ b/lib/stdlib/src/gb_sets.erl
@@ -137,6 +137,10 @@
%% approach is that it does not require the complete list of all
%% elements to be built in memory at one time.
%%
+%% - iterator_from(X, S): returns an iterator that can be used for
+%% traversing the elements of set S greater than or equal to X;
+%% see `next'.
+%%
%% - next(T): returns {X, T1} where X is the smallest element referred
%% to by the iterator T, and T1 is the new iterator to be used for
%% traversing the remaining elements, or the atom `none' if no
@@ -157,8 +161,8 @@
insert/2, add/2, delete/2, delete_any/2, balance/1, union/2,
union/1, intersection/2, intersection/1, is_disjoint/2, difference/2,
is_subset/2, to_list/1, from_list/1, from_ordset/1, smallest/1,
- largest/1, take_smallest/1, take_largest/1, iterator/1, next/1,
- filter/2, fold/3, is_set/1]).
+ largest/1, take_smallest/1, take_largest/1, iterator/1,
+ iterator_from/2, next/1, filter/2, fold/3, is_set/1]).
%% `sets' compatibility aliases:
@@ -500,6 +504,22 @@ iterator({_, L, _} = T, As) ->
iterator(nil, As) ->
As.
+-spec iterator_from(Element, Set) -> Iter when
+ Set :: set(Element),
+ Iter :: iter(Element).
+
+iterator_from(S, {_, T}) ->
+ iterator_from(S, T, []).
+
+iterator_from(S, {K, _, T}, As) when K < S ->
+ iterator_from(S, T, As);
+iterator_from(_, {_, nil, _} = T, As) ->
+ [T | As];
+iterator_from(S, {_, L, _} = T, As) ->
+ iterator_from(S, L, [T | As]);
+iterator_from(_, nil, As) ->
+ As.
+
-spec next(Iter1) -> {Element, Iter2} | 'none' when
Iter1 :: iter(Element),
Iter2 :: iter(Element).
diff --git a/lib/stdlib/src/gb_trees.erl b/lib/stdlib/src/gb_trees.erl
index 7069b61873..259e8f718b 100644
--- a/lib/stdlib/src/gb_trees.erl
+++ b/lib/stdlib/src/gb_trees.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2001-2014. All Rights Reserved.
+%% Copyright Ericsson AB 2001-2015. 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
@@ -102,6 +102,10 @@
%% approach is that it does not require the complete list of all
%% elements to be built in memory at one time.
%%
+%% - iterator_from(K, T): returns an iterator that can be used for
+%% traversing the entries of tree T with key greater than or
+%% equal to K; see `next'.
+%%
%% - next(S): returns {X, V, S1} where X is the smallest key referred to
%% by the iterator S, and S1 is the new iterator to be used for
%% traversing the remaining entries, or the atom `none' if no entries
@@ -117,7 +121,7 @@
update/3, enter/3, delete/2, delete_any/2, balance/1,
is_defined/2, keys/1, values/1, to_list/1, from_orddict/1,
smallest/1, largest/1, take_smallest/1, take_largest/1,
- iterator/1, next/1, map/2]).
+ iterator/1, iterator_from/2, next/1, map/2]).
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@@ -529,6 +533,29 @@ iterator({_, _, L, _} = T, As) ->
iterator(nil, As) ->
As.
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+-spec iterator_from(Key, Tree) -> Iter when
+ Tree :: tree(Key, Value),
+ Iter :: iter(Key, Value).
+
+iterator_from(S, {_, T}) ->
+ iterator_1_from(S, T).
+
+iterator_1_from(S, T) ->
+ iterator_from(S, T, []).
+
+iterator_from(S, {K, _, _, T}, As) when K < S ->
+ iterator_from(S, T, As);
+iterator_from(_, {_, _, nil, _} = T, As) ->
+ [T | As];
+iterator_from(S, {_, _, L, _} = T, As) ->
+ iterator_from(S, L, [T | As]);
+iterator_from(_, nil, As) ->
+ As.
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
-spec next(Iter1) -> 'none' | {Key, Value, Iter2} when
Iter1 :: iter(Key, Value),
Iter2 :: iter(Key, Value).
diff --git a/lib/stdlib/src/maps.erl b/lib/stdlib/src/maps.erl
index 3877c150ec..533ff08726 100644
--- a/lib/stdlib/src/maps.erl
+++ b/lib/stdlib/src/maps.erl
@@ -19,7 +19,8 @@
-module(maps).
--export([get/3,fold/3, map/2, size/1,
+-export([get/3,filter/2,fold/3, map/2,
+ size/1,
without/2, with/2]).
@@ -145,6 +146,19 @@ get(Key,Map,Default) ->
erlang:error({badmap,Map},[Key,Map,Default]).
+-spec filter(Pred,Map1) -> Map2 when
+ Pred :: fun((Key, Value) -> boolean()),
+ Key :: term(),
+ Value :: term(),
+ Map1 :: map(),
+ Map2 :: map().
+
+filter(Pred,Map) when is_function(Pred,2), is_map(Map) ->
+ maps:from_list([{K,V}||{K,V}<-maps:to_list(Map),Pred(K,V)]);
+filter(Pred,Map) ->
+ erlang:error(error_type(Map),[Pred,Map]).
+
+
-spec fold(Fun,Init,Map) -> Acc when
Fun :: fun((K, V, AccIn) -> AccOut),
Init :: term(),
@@ -169,10 +183,7 @@ fold(Fun,Init,Map) ->
V2 :: term().
map(Fun,Map) when is_function(Fun, 2), is_map(Map) ->
- maps:from_list(lists:map(fun
- ({K,V}) ->
- {K,Fun(K,V)}
- end,maps:to_list(Map)));
+ maps:from_list([{K,Fun(K,V)}||{K,V}<-maps:to_list(Map)]);
map(Fun,Map) ->
erlang:error(error_type(Map),[Fun,Map]).
diff --git a/lib/stdlib/src/shell_default.erl b/lib/stdlib/src/shell_default.erl
index 3fe359af0e..0fca7ff8c7 100644
--- a/lib/stdlib/src/shell_default.erl
+++ b/lib/stdlib/src/shell_default.erl
@@ -23,7 +23,7 @@
-module(shell_default).
-export([help/0,lc/1,c/1,c/2,nc/1,nl/1,l/1,i/0,pid/3,i/3,m/0,m/1,
- memory/0,memory/1,
+ memory/0,memory/1,uptime/0,
erlangrc/1,bi/1, regs/0, flush/0,pwd/0,ls/0,ls/1,cd/1,
y/1, y/2,
xm/1, bt/1, q/0,
@@ -92,6 +92,7 @@ pid(X,Y,Z) -> c:pid(X,Y,Z).
pwd() -> c:pwd().
q() -> c:q().
regs() -> c:regs().
+uptime() -> c:uptime().
xm(Mod) -> c:xm(Mod).
y(File) -> c:y(File).
y(File, Opts) -> c:y(File, Opts).
diff --git a/lib/stdlib/src/stdlib.app.src b/lib/stdlib/src/stdlib.app.src
index a27a35dca2..c33130cf8c 100644
--- a/lib/stdlib/src/stdlib.app.src
+++ b/lib/stdlib/src/stdlib.app.src
@@ -104,7 +104,7 @@
dets]},
{applications, [kernel]},
{env, []},
- {runtime_dependencies, ["sasl-2.4","kernel-3.0.2","erts-7.0","crypto-3.3",
+ {runtime_dependencies, ["sasl-2.4","kernel-4.0","erts-7.0","crypto-3.3",
"compiler-5.0"]}
]}.
diff --git a/lib/stdlib/test/dict_SUITE.erl b/lib/stdlib/test/dict_SUITE.erl
index 69814e12ce..ab624e8dd2 100644
--- a/lib/stdlib/test/dict_SUITE.erl
+++ b/lib/stdlib/test/dict_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2013. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2015. 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,16 +25,16 @@
-export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1,
init_per_group/2,end_per_group/2,
init_per_testcase/2,end_per_testcase/2,
- create/1,store/1]).
+ create/1,store/1,iterate/1]).
-include_lib("test_server/include/test_server.hrl").
--import(lists, [foldl/3,reverse/1]).
+-import(lists, [foldl/3]).
suite() -> [{ct_hooks,[ts_install_cth]}].
all() ->
- [create, store].
+ [create, store, iterate].
groups() ->
[].
@@ -93,6 +93,48 @@ store_1(List, M) ->
D0.
%%%
+%%% Test specifics for gb_trees.
+%%%
+
+iterate(Config) when is_list(Config) ->
+ test_all(fun iterate_1/1).
+
+iterate_1(M) ->
+ case M(module, []) of
+ gb_trees -> iterate_2(M);
+ _ -> ok
+ end,
+ M(empty, []).
+
+iterate_2(M) ->
+ random:seed(1, 2, 42),
+ iter_tree(M, 1000).
+
+iter_tree(_M, 0) ->
+ ok;
+iter_tree(M, N) ->
+ L = [{I, I} || I <- lists:seq(1, N)],
+ T = M(from_list, L),
+ L = lists:reverse(iterate_tree(M, T)),
+ R = random:uniform(N),
+ KV = lists:reverse(iterate_tree_from(M, R, T)),
+ KV = [P || P={K,_} <- L, K >= R],
+ iter_tree(M, N-1).
+
+iterate_tree(M, Tree) ->
+ I = M(iterator, Tree),
+ iterate_tree_1(M, M(next, I), []).
+
+iterate_tree_from(M, Start, Tree) ->
+ I = M(iterator_from, {Start, Tree}),
+ iterate_tree_1(M, M(next, I), []).
+
+iterate_tree_1(_, none, R) ->
+ R;
+iterate_tree_1(M, {K, V, I}, R) ->
+ iterate_tree_1(M, M(next, I), [{K, V} | R]).
+
+%%%
%%% Helper functions.
%%%
diff --git a/lib/stdlib/test/dict_test_lib.erl b/lib/stdlib/test/dict_test_lib.erl
index 4fdb4fa0bd..81d26ce5f8 100644
--- a/lib/stdlib/test/dict_test_lib.erl
+++ b/lib/stdlib/test/dict_test_lib.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2013. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2015. 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
@@ -29,6 +29,9 @@ new(Mod, Eq) ->
(module, []) -> Mod;
(size, D) -> Mod:size(D);
(is_empty, D) -> Mod:is_empty(D);
+ (iterator, S) -> Mod:iterator(S);
+ (iterator_from, {Start, S}) -> Mod:iterator_from(Start, S);
+ (next, I) -> Mod:next(I);
(to_list, D) -> to_list(Mod, D)
end.
diff --git a/lib/stdlib/test/ets_SUITE.erl b/lib/stdlib/test/ets_SUITE.erl
index 41bd4af241..a88843bb6e 100644
--- a/lib/stdlib/test/ets_SUITE.erl
+++ b/lib/stdlib/test/ets_SUITE.erl
@@ -4078,12 +4078,22 @@ tab2file(doc) -> ["Check the ets:tab2file function on an empty "
"ets table."];
tab2file(suite) -> [];
tab2file(Config) when is_list(Config) ->
+ ?line FName = filename:join([?config(priv_dir, Config),"tab2file_case"]),
+ tab2file_do(FName, []),
+ tab2file_do(FName, [{sync,true}]),
+ tab2file_do(FName, [{sync,false}]),
+ {'EXIT',{{badmatch,{error,_}},_}} = (catch tab2file_do(FName, [{sync,yes}])),
+ {'EXIT',{{badmatch,{error,_}},_}} = (catch tab2file_do(FName, [sync])),
+ ok.
+
+tab2file_do(FName, Opts) ->
%% Write an empty ets table to a file, read back and check properties.
?line Tab = ets_new(ets_SUITE_foo_tab, [named_table, set, private,
{keypos, 2}]),
- ?line FName = filename:join([?config(priv_dir, Config),"tab2file_case"]),
- ?line ok = ets:tab2file(Tab, FName),
- ?line true = ets:delete(Tab),
+ catch file:delete(FName),
+ Res = ets:tab2file(Tab, FName, Opts),
+ true = ets:delete(Tab),
+ ok = Res,
%
?line EtsMem = etsmem(),
?line {ok, Tab2} = ets:file2tab(FName),
@@ -4093,6 +4103,7 @@ tab2file(Config) when is_list(Config) ->
?line set = ets:info(Tab2, type),
?line true = ets:delete(Tab2),
?line verify_etsmem(EtsMem).
+
tab2file2(doc) -> ["Check the ets:tab2file function on a ",
"filled set/bag type ets table."];
diff --git a/lib/stdlib/test/maps_SUITE.erl b/lib/stdlib/test/maps_SUITE.erl
index 1d9c041a74..f8f241d834 100644
--- a/lib/stdlib/test/maps_SUITE.erl
+++ b/lib/stdlib/test/maps_SUITE.erl
@@ -34,18 +34,21 @@
-export([init_per_testcase/2]).
-export([end_per_testcase/2]).
--export([t_get_3/1,
+-export([t_get_3/1, t_filter_2/1,
t_fold_3/1,t_map_2/1,t_size_1/1,
t_with_2/1,t_without_2/1]).
--define(badmap(V,F,Args), {'EXIT', {{badmap,V}, [{maps,F,Args,_}|_]}}).
--define(badarg(F,Args), {'EXIT', {badarg, [{maps,F,Args,_}|_]}}).
+%-define(badmap(V,F,Args), {'EXIT', {{badmap,V}, [{maps,F,Args,_}|_]}}).
+%-define(badarg(F,Args), {'EXIT', {badarg, [{maps,F,Args,_}|_]}}).
+% silly broken hipe
+-define(badmap(V,F,_Args), {'EXIT', {{badmap,V}, [{maps,F,_,_}|_]}}).
+-define(badarg(F,_Args), {'EXIT', {badarg, [{maps,F,_,_}|_]}}).
suite() ->
[{ct_hooks, [ts_install_cth]}].
all() ->
- [t_get_3,
+ [t_get_3,t_filter_2,
t_fold_3,t_map_2,t_size_1,
t_with_2,t_without_2].
@@ -99,6 +102,16 @@ t_with_2(_Config) ->
?badarg(with,[a,#{}]) = (catch maps:with(a,#{})),
ok.
+t_filter_2(Config) when is_list(Config) ->
+ M = #{a => 2, b => 3, c=> 4, "a" => 1, "b" => 2, "c" => 4},
+ Pred1 = fun(K,V) -> is_atom(K) andalso (V rem 2) =:= 0 end,
+ Pred2 = fun(K,V) -> is_list(K) andalso (V rem 2) =:= 0 end,
+ #{a := 2,c := 4} = maps:filter(Pred1,M),
+ #{"b" := 2,"c" := 4} = maps:filter(Pred2,M),
+ %% error case
+ ?badmap(a,filter,[_,a]) = (catch maps:filter(fun(_,_) -> ok end,id(a))),
+ ?badarg(filter,[<<>>,#{}]) = (catch maps:filter(id(<<>>),#{})),
+ ok.
t_fold_3(Config) when is_list(Config) ->
Vs = lists:seq(1,200),
diff --git a/lib/stdlib/test/sets_SUITE.erl b/lib/stdlib/test/sets_SUITE.erl
index c0cf1fc7e8..24f5d65f82 100644
--- a/lib/stdlib/test/sets_SUITE.erl
+++ b/lib/stdlib/test/sets_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2004-2013. All Rights Reserved.
+%% Copyright Ericsson AB 2004-2015. 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
@@ -28,7 +28,7 @@
create/1,add_element/1,del_element/1,
subtract/1,intersection/1,union/1,is_subset/1,
is_set/1,fold/1,filter/1,
- take_smallest/1,take_largest/1]).
+ take_smallest/1,take_largest/1, iterate/1]).
-include_lib("test_server/include/test_server.hrl").
@@ -48,7 +48,7 @@ suite() -> [{ct_hooks,[ts_install_cth]}].
all() ->
[create, add_element, del_element, subtract,
intersection, union, is_subset, is_set, fold, filter,
- take_smallest, take_largest].
+ take_smallest, take_largest, iterate].
groups() ->
[].
@@ -426,6 +426,44 @@ take_largest_3(S0, List0, M) ->
take_largest_3(S, List, M)
end.
+iterate(Config) when is_list(Config) ->
+ test_all(fun iterate_1/1).
+
+iterate_1(M) ->
+ case M(module, []) of
+ gb_sets -> iterate_2(M);
+ _ -> ok
+ end,
+ M(empty, []).
+
+iterate_2(M) ->
+ random:seed(1, 2, 42),
+ iter_set(M, 1000).
+
+iter_set(_M, 0) ->
+ ok;
+iter_set(M, N) ->
+ L = [I || I <- lists:seq(1, N)],
+ T = M(from_list, L),
+ L = lists:reverse(iterate_set(M, T)),
+ R = random:uniform(N),
+ S = lists:reverse(iterate_set(M, R, T)),
+ S = [E || E <- L, E >= R],
+ iter_set(M, N-1).
+
+iterate_set(M, Set) ->
+ I = M(iterator, Set),
+ iterate_set_1(M, M(next, I), []).
+
+iterate_set(M, Start, Set) ->
+ I = M(iterator_from, {Start, Set}),
+ iterate_set_1(M, M(next, I), []).
+
+iterate_set_1(_, none, R) ->
+ R;
+iterate_set_1(M, {E, I}, R) ->
+ iterate_set_1(M, M(next, I), [E | R]).
+
%%%
%%% Helper functions.
%%%
diff --git a/lib/stdlib/test/sets_test_lib.erl b/lib/stdlib/test/sets_test_lib.erl
index 86f009a8f9..772139406d 100644
--- a/lib/stdlib/test/sets_test_lib.erl
+++ b/lib/stdlib/test/sets_test_lib.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2004-2013. All Rights Reserved.
+%% Copyright Ericsson AB 2004-2015. 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 +34,10 @@ new(Mod, Eq) ->
(is_empty, S) -> is_empty(Mod, S);
(is_set, S) -> Mod:is_set(S);
(is_subset, {S,Set}) -> is_subset(Mod, Eq, S, Set);
+ (iterator, S) -> Mod:iterator(S);
+ (iterator_from, {Start, S}) -> Mod:iterator_from(Start, S);
(module, []) -> Mod;
+ (next, I) -> Mod:next(I);
(singleton, E) -> singleton(Mod, E);
(size, S) -> Mod:size(S);
(subtract, {S1,S2}) -> subtract(Mod, S1, S2);
diff --git a/lib/stdlib/vsn.mk b/lib/stdlib/vsn.mk
index a1f2a946b1..f57f31c8de 100644
--- a/lib/stdlib/vsn.mk
+++ b/lib/stdlib/vsn.mk
@@ -1 +1 @@
-STDLIB_VSN = 2.5
+STDLIB_VSN = 2.4
diff --git a/lib/syntax_tools/doc/src/notes.xml b/lib/syntax_tools/doc/src/notes.xml
index 8f245083c4..408f6d5bac 100644
--- a/lib/syntax_tools/doc/src/notes.xml
+++ b/lib/syntax_tools/doc/src/notes.xml
@@ -31,20 +31,6 @@
<p>This document describes the changes made to the Syntax_Tools
application.</p>
-<section><title>Syntax_Tools 1.7</title>
-
- <section><title>Improvements and New Features</title>
- <list>
- <item>
- <p>Use the new <c>erl_anno</c> module.</p>
- <p>
- Own Id: OTP-12732</p>
- </item>
- </list>
- </section>
-
-</section>
-
<section><title>Syntax_Tools 1.6.18</title>
<section><title>Fixed Bugs and Malfunctions</title>
diff --git a/lib/syntax_tools/vsn.mk b/lib/syntax_tools/vsn.mk
index 403e90196e..1c42ef0ddb 100644
--- a/lib/syntax_tools/vsn.mk
+++ b/lib/syntax_tools/vsn.mk
@@ -1 +1 @@
-SYNTAX_TOOLS_VSN = 1.7
+SYNTAX_TOOLS_VSN = 1.6.18
diff --git a/lib/test_server/doc/src/notes.xml b/lib/test_server/doc/src/notes.xml
index 6cf7a2b52d..e996d2b4a3 100644
--- a/lib/test_server/doc/src/notes.xml
+++ b/lib/test_server/doc/src/notes.xml
@@ -32,55 +32,6 @@
<file>notes.xml</file>
</header>
-<section><title>Test_Server 3.9</title>
-
- <section><title>Fixed Bugs and Malfunctions</title>
- <list>
- <item>
- <p>
- The status of an aborted test due to test suite
- compilation error has changed from 'auto_skipped' to
- 'failed'. This affects both the textual log file, event
- handling and CT hook callbacks. The logging of
- compilation failures has also been improved, especially
- in the case of multiple test suites failing compilation.</p>
- <p>
- Own Id: OTP-10816</p>
- </item>
- </list>
- </section>
-
-
- <section><title>Improvements and New Features</title>
- <list>
- <item>
- <p>
- The Test Server application has been marked as obsolete
- and will be removed from OTP in the next major release
- (OTP 19.0).</p>
- <p>
- Own Id: OTP-10923 Aux Id: OTP-12705 </p>
- </item>
- <item>
- <p>
- When running OTP tests using the ts interface, it is now
- possible to specify so called test categories per OTP
- application. A test category is represented by a CT test
- specification and defines an arbitrary subset of existing
- test suites, groups and cases. Examples of test
- categories are 'smoke' (smoke tests) and 'bench'
- (benchmarks). (Call ts:help() for more info). Also,
- functions for reading terms from the current test
- specification during test, ct:get_testspec_terms/0 and
- ct:get_testspec_terms/1, have been implemented.</p>
- <p>
- Own Id: OTP-11962</p>
- </item>
- </list>
- </section>
-
-</section>
-
<section><title>Test_Server 3.8.1</title>
<section><title>Fixed Bugs and Malfunctions</title>
diff --git a/lib/test_server/src/erl2html2.erl b/lib/test_server/src/erl2html2.erl
index 9101212852..b0b5c40965 100644
--- a/lib/test_server/src/erl2html2.erl
+++ b/lib/test_server/src/erl2html2.erl
@@ -170,7 +170,11 @@ get_line(Anno) ->
%%% Find the line number of the last expression in the function
find_clause_lines([{clause,CL,_Params,_Op,Exprs}], CLs) -> % last clause
try tuple_to_list(lists:last(Exprs)) of
- [_Type,ExprLine | _] ->
+ [_Type,ExprLine | _] when is_integer(ExprLine) ->
+ {lists:reverse([{clause,get_line(CL)}|CLs]), get_line(ExprLine)};
+ [tree,_ | Exprs1] ->
+ find_clause_lines([{clause,CL,undefined,undefined,Exprs1}], CLs);
+ [macro,{_var,ExprLine,_MACRO} | _] when is_integer(ExprLine) ->
{lists:reverse([{clause,get_line(CL)}|CLs]), get_line(ExprLine)};
_ ->
{lists:reverse([{clause,get_line(CL)}|CLs]), get_line(CL)}
@@ -188,18 +192,18 @@ build_html(SFd,DFd,Encoding,FuncsAndCs) ->
build_html(SFd,DFd,Encoding,file:read_line(SFd),1,FuncsAndCs,
false,undefined).
-%% function start line found
-build_html(SFd,DFd,Enc,{ok,Str},L0,[{F,A,L0,LastL}|FuncsAndCs],
- _IsFuncDef,_FAndLastL) ->
- FALink = test_server_ctrl:uri_encode(F++"-"++integer_to_list(A),utf8),
- file:write(DFd,["<a name=\"",to_raw_list(FALink,Enc),"\"/>"]),
- build_html(SFd,DFd,Enc,{ok,Str},L0,FuncsAndCs,true,{F,LastL});
%% line of last expression in function found
build_html(SFd,DFd,Enc,{ok,Str},LastL,FuncsAndCs,_IsFuncDef,{F,LastL}) ->
LastLineLink = test_server_ctrl:uri_encode(F++"-last_expr",utf8),
file:write(DFd,["<a name=\"",
to_raw_list(LastLineLink,Enc),"\"/>"]),
build_html(SFd,DFd,Enc,{ok,Str},LastL,FuncsAndCs,true,undefined);
+%% function start line found
+build_html(SFd,DFd,Enc,{ok,Str},L0,[{F,A,L0,LastL}|FuncsAndCs],
+ _IsFuncDef,_FAndLastL) ->
+ FALink = test_server_ctrl:uri_encode(F++"-"++integer_to_list(A),utf8),
+ file:write(DFd,["<a name=\"",to_raw_list(FALink,Enc),"\"/>"]),
+ build_html(SFd,DFd,Enc,{ok,Str},L0,FuncsAndCs,true,{F,LastL});
build_html(SFd,DFd,Enc,{ok,Str},L,[{clause,L}|FuncsAndCs],
_IsFuncDef,FAndLastL) ->
build_html(SFd,DFd,Enc,{ok,Str},L,FuncsAndCs,true,FAndLastL);
diff --git a/lib/test_server/test/erl2html2_SUITE.erl b/lib/test_server/test/erl2html2_SUITE.erl
index 908985c879..796b84dedd 100644
--- a/lib/test_server/test/erl2html2_SUITE.erl
+++ b/lib/test_server/test/erl2html2_SUITE.erl
@@ -130,15 +130,7 @@ groups() ->
%% @end
%%--------------------------------------------------------------------
all() ->
- [m1].
-
-%%--------------------------------------------------------------------
-%% @spec TestCase() -> Info
-%% Info = [tuple()]
-%% @end
-%%--------------------------------------------------------------------
-m1() ->
- [].
+ [macros_defined, macros_undefined].
%%--------------------------------------------------------------------
%% @spec TestCase(Config0) ->
@@ -149,19 +141,29 @@ m1() ->
%% Comment = term()
%% @end
%%--------------------------------------------------------------------
-m1(Config) ->
- {Src,Dst} = convert_module("m1",Config),
+macros_defined(Config) ->
+ %% let erl2html2 use epp as parser
+ DataDir = ?config(data_dir,Config),
+ InclDir = filename:join(DataDir, "include"),
+ {Src,Dst} = convert_module("m1",[InclDir],Config),
{true,L} = check_line_numbers(Src,Dst),
- ok = check_link_targets(Src,Dst,L,[{baz,0}]),
+ ok = check_link_targets(Src,Dst,L,[{baz,0}],[]),
ok.
-convert_module(Mod,Config) ->
+macros_undefined(Config) ->
+ %% let erl2html2 use epp_dodger as parser
+ {Src,Dst} = convert_module("m1",[],Config),
+ {true,L} = check_line_numbers(Src,Dst),
+ ok = check_link_targets(Src,Dst,L,[{baz,0}],[{quux,0}]),
+ ok.
+
+convert_module(Mod,InclDirs,Config) ->
DataDir = ?config(data_dir,Config),
PrivDir = ?config(priv_dir,Config),
Src = filename:join(DataDir,Mod++".erl"),
Dst = filename:join(PrivDir,Mod++".erl.html"),
io:format("<a href=\"~s\">~s</a>\n",[Src,filename:basename(Src)]),
- ok = erl2html2:convert(Src, Dst, [], "<html><body>"),
+ ok = erl2html2:convert(Src, Dst, InclDirs, "<html><body>"),
io:format("<a href=\"~s\">~s</a>\n",[Dst,filename:basename(Dst)]),
{Src,Dst}.
@@ -229,36 +231,46 @@ check_line_number(Last,Line,OrigLine) ->
%% function.
%% The test module has -compile(export_all), so all functions are
%% found by listing the exported ones.
-check_link_targets(Src,Dst,L,RmFncs) ->
+check_link_targets(Src,Dst,L,RmFncs,ShouldRemain) ->
Mod = list_to_atom(filename:basename(filename:rootname(Src))),
Exports = Mod:module_info(exports)--[{module_info,0},{module_info,1}|RmFncs],
- {ok,{[],L},_} = xmerl_sax_parser:file(Dst,
- [{event_fun,fun sax_event/3},
- {event_state,{Exports,0}}]),
+ LastExprFuncs = [Func || {Func,_A} <- Exports],
+ {ok,{FAs,Fs,L},_} =
+ xmerl_sax_parser:file(Dst,
+ [{event_fun,fun sax_event/3},
+ {event_state,{Exports,LastExprFuncs,0}}]),
+ true = (length(FAs) == length(ShouldRemain)),
+ [] = [FA || FA <- FAs, not lists:member(FA,ShouldRemain)],
+ [] = [F || F <- Fs, not lists:keymember(F,1,ShouldRemain)],
ok.
sax_event(Event,_Loc,State) ->
sax_event(Event,State).
-sax_event({startElement,_Uri,"a",_QN,Attrs},{Exports,PrevLine}) ->
+sax_event({startElement,_Uri,"a",_QN,Attrs},{Exports,LastExprFuncs,PrevLine}) ->
{_,_,"name",Name} = lists:keyfind("name",3,Attrs),
case catch list_to_integer(Name) of
Line when is_integer(Line) ->
case PrevLine + 1 of
Line ->
-% erlang:display({found_line,Line}),
- {Exports,Line};
+ {Exports,LastExprFuncs,Line};
Other ->
ct:fail({unexpected_line_number_target,Other})
end;
{'EXIT',_} ->
- {match,[FStr,AStr]} =
- re:run(Name,"^(.*)-([0-9]+)$",[{capture,all_but_first,list}]),
+ {match,[FStr,EndStr]} =
+ re:run(Name,"^(.*)-(last_expr|[0-9]+)$",
+ [{capture,all_but_first,list}]),
F = list_to_atom(http_uri:decode(FStr)),
- A = list_to_integer(AStr),
-% erlang:display({found_fnc,F,A}),
- A = proplists:get_value(F,Exports),
- {lists:delete({F,A},Exports),PrevLine}
+ case EndStr of
+ "last_expr" ->
+ true = lists:member(F,LastExprFuncs),
+ {Exports,lists:delete(F,LastExprFuncs),PrevLine};
+ _ ->
+ A = list_to_integer(EndStr),
+ A = proplists:get_value(F,Exports),
+ {lists:delete({F,A},Exports),LastExprFuncs,PrevLine}
+ end
end;
sax_event(_,State) ->
State.
diff --git a/lib/test_server/test/erl2html2_SUITE_data/include/header3.hrl b/lib/test_server/test/erl2html2_SUITE_data/include/header3.hrl
new file mode 100644
index 0000000000..2a20850a3a
--- /dev/null
+++ b/lib/test_server/test/erl2html2_SUITE_data/include/header3.hrl
@@ -0,0 +1 @@
+-define(EPP_SWITCH, on).
diff --git a/lib/test_server/test/erl2html2_SUITE_data/m1.erl b/lib/test_server/test/erl2html2_SUITE_data/m1.erl
index 156f1d0a51..1d405963a5 100644
--- a/lib/test_server/test/erl2html2_SUITE_data/m1.erl
+++ b/lib/test_server/test/erl2html2_SUITE_data/m1.erl
@@ -7,9 +7,15 @@
-include("header1.hrl").
-include("header2.hrl").
+-include("header3.hrl").
-define(MACRO1,value).
+%% This macro is used to select parser in erl2html2.
+%% If EPP_SWITCH is defined epp is used, else epp_dodger.
+epp_switch() ->
+ ?EPP_SWITCH.
+
%%% Comment
foo(x) ->
%% Comment
diff --git a/lib/tools/doc/src/cprof.xml b/lib/tools/doc/src/cprof.xml
index 553597837e..bfddb9f5a8 100644
--- a/lib/tools/doc/src/cprof.xml
+++ b/lib/tools/doc/src/cprof.xml
@@ -66,7 +66,7 @@
<func>
<name>analyse() -> {AllCallCount, ModAnalysisList}</name>
<name>analyse(Limit) -> {AllCallCount, ModAnalysisList}</name>
- <name>analyse(Mod) -> ModAnlysis</name>
+ <name>analyse(Mod) -> ModAnalysis</name>
<name>analyse(Mod, Limit) -> ModAnalysis</name>
<fsummary>Collect and analyse call counters.</fsummary>
<type>
diff --git a/lib/tools/doc/src/notes.xml b/lib/tools/doc/src/notes.xml
index 85610d623a..38b57b73a9 100644
--- a/lib/tools/doc/src/notes.xml
+++ b/lib/tools/doc/src/notes.xml
@@ -30,65 +30,6 @@
</header>
<p>This document describes the changes made to the Tools application.</p>
-<section><title>Tools 2.8</title>
-
- <section><title>Fixed Bugs and Malfunctions</title>
- <list>
- <item>
- <p>
- In order to improve performance of the cover tool, new
- functions are added for cover compilation and analysis on
- multiple files. This allows for more parallelisation.</p>
- <p>
- Some improvements of the data base access is also done in
- order to improve the performance when analysing and
- resetting cover data.</p>
- <p>
- Minor incompatibility: An error reason from
- analyse_to_file is changed from no_source_code_found to
- {no_source_code_found,Module}.</p>
- <p>
- *** POTENTIAL INCOMPATIBILITY ***</p>
- <p>
- Own Id: OTP-12330 Aux Id: seq12757 </p>
- </item>
- </list>
- </section>
-
-
- <section><title>Improvements and New Features</title>
- <list>
- <item>
- <p>
- Allow maps for supervisor flags and child specs</p>
- <p>
- Earlier, supervisor flags and child specs were given as
- tuples. While this is kept for backwards compatibility,
- it is now also allowed to give these parameters as maps,
- see <seealso
- marker="stdlib:supervisor#sup_flags">sup_flags</seealso>
- and <seealso
- marker="stdlib:supervisor#child_spec">child_spec</seealso>.</p>
- <p>
- Own Id: OTP-11043</p>
- </item>
- <item>
- <p>
- Remove Mnemosyne rules support.</p>
- <p>
- Own Id: OTP-12511</p>
- </item>
- <item>
- <p>
- Add printout of total number of calls and time in eprof</p>
- <p>
- Own Id: OTP-12681</p>
- </item>
- </list>
- </section>
-
-</section>
-
<section><title>Tools 2.7.2</title>
<section><title>Fixed Bugs and Malfunctions</title>
diff --git a/lib/tools/vsn.mk b/lib/tools/vsn.mk
index 68c3f6e29c..3b3202d38b 100644
--- a/lib/tools/vsn.mk
+++ b/lib/tools/vsn.mk
@@ -1 +1 @@
-TOOLS_VSN = 2.8
+TOOLS_VSN = 2.7.2
diff --git a/lib/typer/doc/src/notes.xml b/lib/typer/doc/src/notes.xml
index 045b55ffe4..23e22759d6 100644
--- a/lib/typer/doc/src/notes.xml
+++ b/lib/typer/doc/src/notes.xml
@@ -30,20 +30,6 @@
</header>
<p>This document describes the changes made to TypEr.</p>
-<section><title>TypEr 0.9.9</title>
-
- <section><title>Fixed Bugs and Malfunctions</title>
- <list>
- <item>
- <p> Properly extract annotations from core code. </p>
- <p>
- Own Id: OTP-12727</p>
- </item>
- </list>
- </section>
-
-</section>
-
<section><title>TypEr 0.9.8</title>
<section><title>Fixed Bugs and Malfunctions</title>
diff --git a/lib/typer/vsn.mk b/lib/typer/vsn.mk
index 74c0ccfc59..ce658e257b 100644
--- a/lib/typer/vsn.mk
+++ b/lib/typer/vsn.mk
@@ -1 +1 @@
-TYPER_VSN = 0.9.9
+TYPER_VSN = 0.9.8
diff --git a/lib/webtool/doc/src/notes.xml b/lib/webtool/doc/src/notes.xml
index 4800dd6df4..e571668c91 100644
--- a/lib/webtool/doc/src/notes.xml
+++ b/lib/webtool/doc/src/notes.xml
@@ -31,23 +31,6 @@
<p>This document describes the changes made to the Webtool
application.</p>
-<section><title>WebTool 0.9</title>
-
- <section><title>Improvements and New Features</title>
- <list>
- <item>
- <p>
- The Webtool application has been marked as obsolete and
- will be removed from OTP in the next major release (OTP
- 19.0).</p>
- <p>
- Own Id: OTP-10922 Aux Id: OTP-12705 </p>
- </item>
- </list>
- </section>
-
-</section>
-
<section><title>WebTool 0.8.10</title>
<section><title>Fixed Bugs and Malfunctions</title>
diff --git a/lib/wx/c_src/wxe_driver.c b/lib/wx/c_src/wxe_driver.c
index ea52737fa2..ec1ba7f566 100644
--- a/lib/wx/c_src/wxe_driver.c
+++ b/lib/wx/c_src/wxe_driver.c
@@ -146,7 +146,12 @@ wxe_driver_stop(ErlDrvData handle)
if(sd->port_handle != WXE_DRV_PORT_HANDLE) {
// fprintf(stderr, "%s:%d: STOP \r\n", __FILE__,__LINE__);
meta_command(DELETE_PORT,sd);
- free(handle);
+ } else {
+ // fprintf(stderr, "%s:%d: STOP \r\n", __FILE__,__LINE__);
+ stop_native_gui(wxe_master);
+ unload_native_gui();
+ free(wxe_master);
+ wxe_master = NULL;
}
}
@@ -154,10 +159,6 @@ static void
wxe_driver_unload(void)
{
// fprintf(stderr, "%s:%d: UNLOAD \r\n", __FILE__,__LINE__);
- stop_native_gui(wxe_master);
- unload_native_gui();
- free(wxe_master);
- wxe_master = NULL;
}
static ErlDrvSSizeT
diff --git a/lib/wx/c_src/wxe_impl.cpp b/lib/wx/c_src/wxe_impl.cpp
index ef648e008c..2fd5f0c52c 100644
--- a/lib/wx/c_src/wxe_impl.cpp
+++ b/lib/wx/c_src/wxe_impl.cpp
@@ -89,7 +89,7 @@ void push_command(int op,char * buf,int len, wxe_data *sd)
}
void meta_command(int what, wxe_data *sd) {
- if(what == PING_PORT) {
+ if(what == PING_PORT && wxe_status == WXE_INITIATED) {
erl_drv_mutex_lock(wxe_batch_locker_m);
if(wxe_batch_caller > 0) {
wxe_queue->Add(WXE_DEBUG_PING, NULL, 0, sd);
@@ -98,9 +98,12 @@ void meta_command(int what, wxe_data *sd) {
wxWakeUpIdle();
erl_drv_mutex_unlock(wxe_batch_locker_m);
} else {
- if(sd) {
+ if(sd && wxe_status == WXE_INITIATED) {
wxeMetaCommand Cmd(sd, what);
wxTheApp->AddPendingEvent(Cmd);
+ if(what == DELETE_PORT) {
+ free(sd);
+ }
}
}
}
@@ -169,6 +172,7 @@ void WxeApp::MacOpenFile(const wxString &filename) {
#endif
void WxeApp::shutdown(wxeMetaCommand& Ecmd) {
+ wxe_status = WXE_EXITING;
ExitMainLoop();
delete wxe_queue;
delete wxe_queue_cb_saved;
@@ -200,6 +204,10 @@ void handle_event_callback(ErlDrvPort port, ErlDrvTermData process)
{
WxeApp * app = (WxeApp *) wxTheApp;
ErlDrvMonitor monitor;
+
+ if(wxe_status != WXE_INITIATED)
+ return;
+
// Is thread safe if pdl have been incremented
if(driver_monitor_process(port, process, &monitor) == 0) {
// Should we be able to handle commands when recursing? probably
@@ -217,6 +225,8 @@ void handle_event_callback(ErlDrvPort port, ErlDrvTermData process)
void WxeApp::dispatch_cmds()
{
+ if(wxe_status != WXE_INITIATED)
+ return;
erl_drv_mutex_lock(wxe_batch_locker_m);
recurse_level++;
int level = dispatch(wxe_queue_cb_saved, 0, WXE_STORED);
diff --git a/lib/wx/c_src/wxe_impl.h b/lib/wx/c_src/wxe_impl.h
index a0a1c84718..b251d5f0f9 100644
--- a/lib/wx/c_src/wxe_impl.h
+++ b/lib/wx/c_src/wxe_impl.h
@@ -46,7 +46,8 @@ typedef wxString wxeLocaleC;
#define WXE_NOT_INITIATED 0
#define WXE_INITIATED 1
-#define WXE_EXITED 2
+#define WXE_EXITING 2
+#define WXE_EXITED 3
#define WXE_ERROR -1
void send_msg(const char *, const wxString *); // For debugging and error msgs
diff --git a/lib/wx/doc/src/notes.xml b/lib/wx/doc/src/notes.xml
index d31e927458..682ab48ca0 100644
--- a/lib/wx/doc/src/notes.xml
+++ b/lib/wx/doc/src/notes.xml
@@ -31,55 +31,6 @@
<p>This document describes the changes made to the wxErlang
application.</p>
-<section><title>Wx 1.4</title>
-
- <section><title>Fixed Bugs and Malfunctions</title>
- <list>
- <item>
- <p>
- The undocumented option <c>generic_debug</c> for
- <c>gen_server</c> has been removed.</p>
- <p>
- Own Id: OTP-12183</p>
- </item>
- </list>
- </section>
-
-
- <section><title>Improvements and New Features</title>
- <list>
- <item>
- <p>
- Use wxWidgets-3.0, if found, as default backend on
- windows.</p>
- <p>
- Own Id: OTP-12632</p>
- </item>
- <item>
- <p>
- Add missing fields in some events records. May require a
- recompilation of user applications.</p>
- <p>
- Own Id: OTP-12660</p>
- </item>
- </list>
- </section>
-
-
- <section><title>Known Bugs and Problems</title>
- <list>
- <item>
- <p>
- Remove raise condition where <c>wx</c> could crash during
- emulator stoppage.</p>
- <p>
- Own Id: OTP-12734</p>
- </item>
- </list>
- </section>
-
-</section>
-
<section><title>Wx 1.3.3</title>
<section><title>Fixed Bugs and Malfunctions</title>
diff --git a/lib/wx/vsn.mk b/lib/wx/vsn.mk
index 09fb9f384c..942d4c0d6f 100644
--- a/lib/wx/vsn.mk
+++ b/lib/wx/vsn.mk
@@ -1 +1 @@
-WX_VSN = 1.4
+WX_VSN = 1.3.3
diff --git a/lib/xmerl/doc/src/notes.xml b/lib/xmerl/doc/src/notes.xml
index b9cc2bd329..3fa1f01a79 100644
--- a/lib/xmerl/doc/src/notes.xml
+++ b/lib/xmerl/doc/src/notes.xml
@@ -31,20 +31,6 @@
<p>This document describes the changes made to the Xmerl application.</p>
-<section><title>Xmerl 1.3.8</title>
-
- <section><title>Fixed Bugs and Malfunctions</title>
- <list>
- <item>
- <p> Remove compiler warnings in xmerl. </p>
- <p>
- Own Id: OTP-12689</p>
- </item>
- </list>
- </section>
-
-</section>
-
<section><title>Xmerl 1.3.7</title>
<section><title>Fixed Bugs and Malfunctions</title>
diff --git a/otp_versions.table b/otp_versions.table
index 12790c88a8..fbed2ce427 100644
--- a/otp_versions.table
+++ b/otp_versions.table
@@ -1,3 +1,4 @@
+OTP-17.5.4 : inets-5.10.8 ssh-3.2.3 # asn1-3.0.4 common_test-1.10.1 compiler-5.0.4 cosEvent-2.1.15 cosEventDomain-1.1.14 cosFileTransfer-1.1.16 cosNotification-1.1.21 cosProperty-1.1.17 cosTime-1.1.14 cosTransactions-1.2.14 crypto-3.5 debugger-4.0.3 dialyzer-2.7.4 diameter-1.9.1 edoc-0.7.16 eldap-1.1.1 erl_docgen-0.3.7 erl_interface-3.7.20 erts-6.4.1 et-1.5 eunit-2.2.9 gs-1.5.16 hipe-3.11.3 ic-4.3.6 jinterface-1.5.12 kernel-3.2 megaco-3.17.3 mnesia-4.12.5 observer-2.0.4 odbc-2.10.22 orber-3.7.1 os_mon-2.3.1 ose-1.0.2 otp_mibs-1.0.10 parsetools-2.0.12 percept-0.8.10 public_key-0.23 reltool-0.6.6 runtime_tools-1.8.16 sasl-2.4.1 snmp-5.1.2 ssl-6.0 stdlib-2.4 syntax_tools-1.6.18 test_server-3.8.1 tools-2.7.2 typer-0.9.8 webtool-0.8.10 wx-1.3.3 xmerl-1.3.7 :
OTP-17.5.3 : common_test-1.10.1 diameter-1.9.1 erts-6.4.1 snmp-5.1.2 test_server-3.8.1 # asn1-3.0.4 compiler-5.0.4 cosEvent-2.1.15 cosEventDomain-1.1.14 cosFileTransfer-1.1.16 cosNotification-1.1.21 cosProperty-1.1.17 cosTime-1.1.14 cosTransactions-1.2.14 crypto-3.5 debugger-4.0.3 dialyzer-2.7.4 edoc-0.7.16 eldap-1.1.1 erl_docgen-0.3.7 erl_interface-3.7.20 et-1.5 eunit-2.2.9 gs-1.5.16 hipe-3.11.3 ic-4.3.6 inets-5.10.7 jinterface-1.5.12 kernel-3.2 megaco-3.17.3 mnesia-4.12.5 observer-2.0.4 odbc-2.10.22 orber-3.7.1 os_mon-2.3.1 ose-1.0.2 otp_mibs-1.0.10 parsetools-2.0.12 percept-0.8.10 public_key-0.23 reltool-0.6.6 runtime_tools-1.8.16 sasl-2.4.1 ssh-3.2.2 ssl-6.0 stdlib-2.4 syntax_tools-1.6.18 tools-2.7.2 typer-0.9.8 webtool-0.8.10 wx-1.3.3 xmerl-1.3.7 :
OTP-17.5.2 : inets-5.10.7 ssh-3.2.2 # asn1-3.0.4 common_test-1.10 compiler-5.0.4 cosEvent-2.1.15 cosEventDomain-1.1.14 cosFileTransfer-1.1.16 cosNotification-1.1.21 cosProperty-1.1.17 cosTime-1.1.14 cosTransactions-1.2.14 crypto-3.5 debugger-4.0.3 dialyzer-2.7.4 diameter-1.9 edoc-0.7.16 eldap-1.1.1 erl_docgen-0.3.7 erl_interface-3.7.20 erts-6.4 et-1.5 eunit-2.2.9 gs-1.5.16 hipe-3.11.3 ic-4.3.6 jinterface-1.5.12 kernel-3.2 megaco-3.17.3 mnesia-4.12.5 observer-2.0.4 odbc-2.10.22 orber-3.7.1 os_mon-2.3.1 ose-1.0.2 otp_mibs-1.0.10 parsetools-2.0.12 percept-0.8.10 public_key-0.23 reltool-0.6.6 runtime_tools-1.8.16 sasl-2.4.1 snmp-5.1.1 ssl-6.0 stdlib-2.4 syntax_tools-1.6.18 test_server-3.8 tools-2.7.2 typer-0.9.8 webtool-0.8.10 wx-1.3.3 xmerl-1.3.7 :
OTP-17.5.1 : ssh-3.2.1 # asn1-3.0.4 common_test-1.10 compiler-5.0.4 cosEvent-2.1.15 cosEventDomain-1.1.14 cosFileTransfer-1.1.16 cosNotification-1.1.21 cosProperty-1.1.17 cosTime-1.1.14 cosTransactions-1.2.14 crypto-3.5 debugger-4.0.3 dialyzer-2.7.4 diameter-1.9 edoc-0.7.16 eldap-1.1.1 erl_docgen-0.3.7 erl_interface-3.7.20 erts-6.4 et-1.5 eunit-2.2.9 gs-1.5.16 hipe-3.11.3 ic-4.3.6 inets-5.10.6 jinterface-1.5.12 kernel-3.2 megaco-3.17.3 mnesia-4.12.5 observer-2.0.4 odbc-2.10.22 orber-3.7.1 os_mon-2.3.1 ose-1.0.2 otp_mibs-1.0.10 parsetools-2.0.12 percept-0.8.10 public_key-0.23 reltool-0.6.6 runtime_tools-1.8.16 sasl-2.4.1 snmp-5.1.1 ssl-6.0 stdlib-2.4 syntax_tools-1.6.18 test_server-3.8 tools-2.7.2 typer-0.9.8 webtool-0.8.10 wx-1.3.3 xmerl-1.3.7 :