aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.gitignore2
-rw-r--r--HOWTO/INSTALL-CROSS.md8
-rw-r--r--HOWTO/INSTALL-WIN32.md10
-rw-r--r--HOWTO/INSTALL.md895
-rw-r--r--Makefile.in5
-rw-r--r--OTP_VERSION2
-rw-r--r--README.md11
-rw-r--r--bootstrap/lib/compiler/ebin/beam_disasm.beambin26316 -> 26320 bytes
-rw-r--r--bootstrap/lib/compiler/ebin/compiler.appup2
-rw-r--r--bootstrap/lib/compiler/ebin/core_lib.beambin5740 -> 5980 bytes
-rw-r--r--bootstrap/lib/compiler/ebin/core_pp.beambin13084 -> 13196 bytes
-rw-r--r--bootstrap/lib/compiler/ebin/sys_core_fold.beambin50332 -> 50208 bytes
-rw-r--r--bootstrap/lib/compiler/ebin/sys_pre_expand.beambin14252 -> 14244 bytes
-rw-r--r--bootstrap/lib/compiler/ebin/v3_codegen.beambin54556 -> 54516 bytes
-rw-r--r--bootstrap/lib/compiler/ebin/v3_core.beambin53216 -> 53472 bytes
-rw-r--r--bootstrap/lib/compiler/ebin/v3_kernel.beambin47480 -> 47460 bytes
-rw-r--r--bootstrap/lib/compiler/ebin/v3_life.beambin20708 -> 20696 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/application.beambin4676 -> 4524 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/inet_config.beambin7784 -> 7812 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/erl_expand_records.beambin22504 -> 22504 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/erl_lint.beambin89540 -> 89740 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/erl_pp.beambin26316 -> 26656 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/otp_internal.beambin10156 -> 10172 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/pg.beambin2064 -> 2096 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/slave.beambin4860 -> 5200 bytes
-rw-r--r--erts/doc/src/erlang.xml20
-rw-r--r--erts/doc/src/notes.xml732
-rw-r--r--erts/emulator/Makefile.in1
-rw-r--r--erts/emulator/beam/beam_emu.c2
-rw-r--r--erts/emulator/beam/erl_nif.c52
-rw-r--r--erts/emulator/beam/erl_process.c15
-rw-r--r--erts/emulator/beam/erl_term.h12
-rw-r--r--erts/emulator/beam/erl_trace.c4
-rw-r--r--erts/emulator/test/binary_SUITE.erl4
-rw-r--r--erts/emulator/test/match_spec_SUITE.erl14
-rw-r--r--erts/emulator/test/port_SUITE.erl9
-rw-r--r--erts/preloaded/ebin/erl_prim_loader.beambin54792 -> 54768 bytes
-rw-r--r--erts/preloaded/ebin/erlang.beambin98276 -> 98248 bytes
-rw-r--r--erts/preloaded/ebin/erts_internal.beambin4296 -> 4276 bytes
-rw-r--r--erts/preloaded/ebin/init.beambin48816 -> 48796 bytes
-rw-r--r--erts/preloaded/ebin/otp_ring0.beambin1480 -> 1460 bytes
-rw-r--r--erts/preloaded/ebin/prim_eval.beambin1360 -> 1340 bytes
-rw-r--r--erts/preloaded/ebin/prim_file.beambin44916 -> 44892 bytes
-rw-r--r--erts/preloaded/ebin/prim_inet.beambin72932 -> 72912 bytes
-rw-r--r--erts/preloaded/ebin/prim_zip.beambin23448 -> 23424 bytes
-rw-r--r--erts/preloaded/ebin/zlib.beambin13196 -> 13176 bytes
-rw-r--r--erts/preloaded/src/erlang.erl7
-rw-r--r--erts/test/otp_SUITE.erl80
-rw-r--r--erts/vsn.mk2
-rw-r--r--lib/asn1/doc/src/asn1_ug.xml796
-rw-r--r--lib/asn1/doc/src/asn1ct.xml9
-rw-r--r--lib/asn1/doc/src/notes.xml106
-rw-r--r--lib/common_test/doc/src/ct_hooks.xml50
-rw-r--r--lib/common_test/doc/src/ct_run.xml3
-rw-r--r--lib/common_test/doc/src/event_handler_chapter.xml29
-rw-r--r--lib/common_test/doc/src/notes.xml178
-rw-r--r--lib/common_test/doc/src/run_test_chapter.xml18
-rw-r--r--lib/common_test/src/ct.erl5
-rw-r--r--lib/common_test/src/ct_framework.erl17
-rw-r--r--lib/common_test/src/ct_netconfc.erl10
-rw-r--r--lib/common_test/src/ct_telnet.erl141
-rw-r--r--lib/common_test/src/ct_util.erl25
-rw-r--r--lib/common_test/src/cth_conn_log.erl11
-rw-r--r--lib/common_test/src/unix_telnet.erl23
-rw-r--r--lib/common_test/test/ct_telnet_SUITE.erl26
-rw-r--r--lib/common_test/test/ct_telnet_SUITE_data/ct_telnet_own_server_SUITE.erl42
-rw-r--r--lib/common_test/test/telnet_server.erl8
-rw-r--r--lib/compiler/doc/src/notes.xml227
-rw-r--r--lib/compiler/src/beam_disasm.erl9
-rw-r--r--lib/compiler/src/cerl.erl6
-rw-r--r--lib/compiler/src/core_lib.erl11
-rw-r--r--lib/compiler/src/core_pp.erl6
-rw-r--r--lib/compiler/src/sys_core_fold.erl12
-rw-r--r--lib/compiler/src/sys_pre_expand.erl2
-rw-r--r--lib/compiler/src/v3_core.erl29
-rw-r--r--lib/compiler/test/map_SUITE.erl5
-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.xml104
-rw-r--r--lib/debugger/doc/src/notes.xml66
-rw-r--r--lib/dialyzer/doc/src/notes.xml167
-rw-r--r--lib/dialyzer/src/Makefile2
-rw-r--r--lib/dialyzer/src/dialyzer_analysis_callgraph.erl10
-rw-r--r--lib/dialyzer/src/dialyzer_cl.erl4
-rw-r--r--lib/dialyzer/src/dialyzer_dataflow.erl51
-rw-r--r--lib/dialyzer/src/dialyzer_dep.erl6
-rw-r--r--lib/dialyzer/src/dialyzer_gui_wx.erl31
-rw-r--r--lib/dialyzer/src/dialyzer_races.erl16
-rw-r--r--lib/dialyzer/test/small_SUITE_data/results/funs_from_outside7
-rw-r--r--lib/dialyzer/test/small_SUITE_data/src/ddfs_master/common_types.hrl6
-rw-r--r--lib/dialyzer/test/small_SUITE_data/src/ddfs_master/config.hrl148
-rw-r--r--lib/dialyzer/test/small_SUITE_data/src/ddfs_master/ddfs.hrl9
-rw-r--r--lib/dialyzer/test/small_SUITE_data/src/ddfs_master/ddfs_gc.hrl17
-rw-r--r--lib/dialyzer/test/small_SUITE_data/src/ddfs_master/ddfs_master.erl531
-rw-r--r--lib/dialyzer/test/small_SUITE_data/src/ddfs_master/ddfs_tag.hrl19
-rw-r--r--lib/dialyzer/test/small_SUITE_data/src/ddfs_master/gs_util.hrl16
-rw-r--r--lib/dialyzer/test/small_SUITE_data/src/funs_from_outside.erl83
-rw-r--r--lib/diameter/doc/src/diameter_make.xml2
-rw-r--r--lib/diameter/doc/src/notes.xml166
-rw-r--r--lib/diameter/include/diameter.hrl6
-rw-r--r--lib/diameter/src/Makefile24
-rw-r--r--lib/diameter/src/app.sed40
-rw-r--r--lib/diameter/src/base/diameter_service.erl2
-rw-r--r--lib/diameter/src/compiler/diameter_codegen.erl8
-rw-r--r--lib/diameter/src/compiler/diameter_forms.hrl6
-rw-r--r--lib/diameter/src/compiler/diameter_make.erl32
-rw-r--r--lib/diameter/src/diameter.app.src26
-rw-r--r--lib/diameter/src/info/diameter_dbg.erl (renamed from lib/diameter/src/base/diameter_dbg.erl)163
-rw-r--r--lib/diameter/src/info/diameter_info.erl (renamed from lib/diameter/src/base/diameter_info.erl)14
-rw-r--r--lib/diameter/src/modules.mk12
-rw-r--r--lib/diameter/test/diameter_app_SUITE.erl66
-rw-r--r--lib/diameter/test/diameter_compiler_SUITE.erl10
-rw-r--r--lib/edoc/doc/src/notes.xml29
-rw-r--r--lib/edoc/src/edoc_types.erl1
-rw-r--r--lib/eldap/doc/src/notes.xml46
-rw-r--r--lib/erl_docgen/doc/src/notes.xml43
-rw-r--r--lib/erl_interface/doc/src/notes.xml16
-rw-r--r--lib/et/doc/src/notes.xml45
-rw-r--r--lib/eunit/doc/src/notes.xml29
-rw-r--r--lib/gs/doc/src/notes.xml31
-rw-r--r--lib/hipe/cerl/erl_types.erl69
-rw-r--r--lib/hipe/doc/src/notes.xml118
-rw-r--r--lib/hipe/icode/hipe_beam_to_icode.erl4
-rw-r--r--lib/hipe/icode/hipe_icode.hrl7
-rw-r--r--lib/hipe/icode/hipe_icode_type.erl47
-rw-r--r--lib/hipe/llvm/hipe_llvm_main.erl30
-rw-r--r--lib/hipe/llvm/hipe_rtl_to_llvm.erl9
-rw-r--r--lib/hipe/main/hipe.erl32
-rw-r--r--lib/hipe/rtl/hipe_icode2rtl.erl2
-rw-r--r--lib/hipe/rtl/hipe_tagscheme.erl21
-rw-r--r--lib/hipe/test/Makefile6
-rw-r--r--lib/hipe/test/hipe_testsuite_driver.erl25
-rw-r--r--lib/ic/doc/src/notes.xml18
-rw-r--r--lib/inets/doc/src/notes.xml93
-rw-r--r--lib/inets/src/http_server/httpd_util.erl9
-rw-r--r--lib/inets/test/httpd_SUITE.erl10
-rw-r--r--lib/inets/test/inets_sup_SUITE.erl130
-rw-r--r--lib/inets/test/inets_sup_SUITE_data/mime.types3
-rw-r--r--lib/inets/test/inets_sup_SUITE_data/simple.conf6
-rw-r--r--lib/jinterface/doc/src/notes.xml19
-rw-r--r--lib/kernel/doc/src/application.xml5
-rw-r--r--lib/kernel/doc/src/kernel_app.xml43
-rw-r--r--lib/kernel/doc/src/notes.xml197
-rw-r--r--lib/kernel/src/application.erl5
-rw-r--r--lib/kernel/src/application_controller.erl31
-rw-r--r--lib/kernel/test/application_SUITE.erl20
-rw-r--r--lib/kernel/test/application_SUITE_data/t4.config1
-rw-r--r--lib/kernel/test/sendfile_SUITE.erl7
-rw-r--r--lib/megaco/doc/src/notes.xml18
-rw-r--r--lib/mnesia/doc/src/notes.xml64
-rw-r--r--lib/observer/doc/src/notes.xml62
-rw-r--r--lib/observer/test/crashdump_viewer_SUITE.erl19
-rw-r--r--lib/odbc/doc/src/notes.xml52
-rw-r--r--lib/orber/doc/src/notes.xml21
-rw-r--r--lib/os_mon/doc/src/notes.xml42
-rw-r--r--lib/otp_mibs/doc/src/notes.xml49
-rw-r--r--lib/parsetools/doc/src/notes.xml36
-rw-r--r--lib/percept/doc/src/notes.xml29
-rw-r--r--lib/public_key/doc/src/cert_records.xml4
-rw-r--r--lib/public_key/doc/src/notes.xml64
-rw-r--r--lib/public_key/doc/src/part.xml4
-rw-r--r--lib/public_key/doc/src/public_key.xml41
-rw-r--r--lib/reltool/doc/src/notes.xml48
-rw-r--r--lib/reltool/test/reltool_server_SUITE.erl9
-rw-r--r--lib/reltool/test/reltool_test_lib.erl7
-rw-r--r--lib/runtime_tools/doc/src/notes.xml89
-rw-r--r--lib/sasl/doc/src/appup.xml23
-rw-r--r--lib/sasl/doc/src/notes.xml58
-rw-r--r--lib/sasl/examples/src/target_system.erl16
-rw-r--r--lib/sasl/test/release_handler_SUITE.erl62
-rw-r--r--lib/sasl/test/systools_SUITE.erl24
-rw-r--r--lib/snmp/doc/src/notes.xml31
-rw-r--r--lib/ssh/doc/src/notes.xml140
-rw-r--r--lib/ssh/doc/src/ssh.xml21
-rw-r--r--lib/ssh/doc/src/using_ssh.xml4
-rw-r--r--lib/ssh/src/ssh.erl4
-rw-r--r--lib/ssh/src/ssh_acceptor.erl47
-rw-r--r--lib/ssh/src/ssh_auth.erl4
-rw-r--r--lib/ssh/src/ssh_connection_handler.erl3
-rw-r--r--lib/ssh/test/ssh_basic_SUITE.erl56
-rw-r--r--lib/ssl/doc/src/notes.xml159
-rw-r--r--lib/ssl/doc/src/ssl.xml69
-rw-r--r--lib/ssl/internal_doc/ssl-implementation.txt52
-rw-r--r--lib/ssl/src/dtls_connection.erl3
-rw-r--r--lib/ssl/src/ssl.erl20
-rw-r--r--lib/ssl/src/ssl_cipher.erl8
-rw-r--r--lib/ssl/src/ssl_connection.erl122
-rw-r--r--lib/ssl/src/ssl_handshake.erl79
-rw-r--r--lib/ssl/src/ssl_internal.hrl1
-rw-r--r--lib/ssl/src/ssl_record.erl2
-rw-r--r--lib/ssl/src/tls_connection.erl13
-rw-r--r--lib/ssl/src/tls_record.erl33
-rw-r--r--lib/ssl/test/make_certs.erl9
-rw-r--r--lib/ssl/test/ssl_basic_SUITE.erl176
-rw-r--r--lib/ssl/test/ssl_crl_SUITE.erl42
-rw-r--r--lib/ssl/test/ssl_handshake_SUITE.erl14
-rw-r--r--lib/ssl/test/ssl_test_lib.erl25
-rw-r--r--lib/stdlib/doc/src/notes.xml384
-rw-r--r--lib/stdlib/doc/src/pg.xml5
-rw-r--r--lib/stdlib/examples/erl_id_trans.erl2
-rw-r--r--lib/stdlib/src/erl_expand_records.erl6
-rw-r--r--lib/stdlib/src/erl_lint.erl41
-rw-r--r--lib/stdlib/src/erl_pp.erl13
-rw-r--r--lib/stdlib/src/io_lib_pretty.erl2
-rw-r--r--lib/stdlib/src/maps.erl2
-rw-r--r--lib/stdlib/src/otp_internal.erl26
-rw-r--r--lib/stdlib/src/pg.erl3
-rw-r--r--lib/stdlib/test/erl_lint_SUITE.erl41
-rw-r--r--lib/stdlib/test/erl_pp_SUITE.erl10
-rw-r--r--lib/syntax_tools/doc/src/notes.xml50
-rw-r--r--lib/test_server/doc/src/notes.xml42
-rw-r--r--lib/test_server/doc/src/test_server_ctrl.xml11
-rw-r--r--lib/test_server/src/test_server.erl4
-rw-r--r--lib/test_server/test/test_server_SUITE_data/test_server_parallel01_SUITE.erl16
-rw-r--r--lib/tools/doc/src/notes.xml76
-rw-r--r--lib/tools/test/eprof_SUITE.erl10
-rw-r--r--lib/typer/Makefile2
-rw-r--r--lib/typer/doc/Makefile39
-rw-r--r--lib/typer/doc/html/.gitignore0
-rw-r--r--lib/typer/doc/pdf/.gitignore0
-rw-r--r--lib/typer/doc/src/Makefile117
-rw-r--r--lib/typer/doc/src/book.xml41
-rw-r--r--lib/typer/doc/src/fascicules.xml12
-rw-r--r--lib/typer/doc/src/notes.xml51
-rw-r--r--lib/typer/doc/src/part_notes.xml35
-rw-r--r--lib/typer/doc/src/ref_man.xml35
-rw-r--r--lib/typer/doc/src/typer_app.xml43
-rw-r--r--lib/typer/info2
-rw-r--r--lib/typer/src/Makefile2
-rw-r--r--lib/typer/vsn.mk2
-rw-r--r--lib/webtool/doc/src/notes.xml29
-rw-r--r--lib/wx/doc/src/notes.xml53
-rw-r--r--lib/xmerl/doc/src/notes.xml29
-rwxr-xr-xotp_build141
-rw-r--r--otp_versions.table2
-rw-r--r--system/doc/design_principles/applications.xml7
-rw-r--r--system/doc/design_principles/release_handling.xml17
-rw-r--r--system/doc/getting_started/seq_prog.xml123
-rw-r--r--system/doc/installation_guide/Makefile8
-rw-r--r--system/doc/installation_guide/install-binary.xml127
-rw-r--r--system/doc/installation_guide/part.xml4
-rw-r--r--system/doc/installation_guide/verification.xml102
-rw-r--r--system/doc/installation_guide/xmlfiles.mk6
-rw-r--r--system/doc/reference_manual/data_types.xml32
-rw-r--r--system/doc/reference_manual/expressions.xml8
-rw-r--r--system/doc/reference_manual/maps.xml274
-rw-r--r--system/doc/reference_manual/modules.xml8
-rw-r--r--system/doc/reference_manual/part.xml1
-rw-r--r--system/doc/reference_manual/typespec.xml12
-rw-r--r--system/doc/reference_manual/xmlfiles.mk1
-rw-r--r--system/doc/system_principles/create_target.xmlsrc248
-rw-r--r--system/doc/system_principles/part.xml4
-rw-r--r--system/doc/system_principles/system_principles.xml9
-rw-r--r--system/doc/system_principles/upgrade.xml118
-rw-r--r--system/doc/system_principles/versions.xml11
-rw-r--r--system/doc/system_principles/xmlfiles.mk3
261 files changed, 8928 insertions, 2448 deletions
diff --git a/.gitignore b/.gitignore
index b391ecbe57..d40f49b56f 100644
--- a/.gitignore
+++ b/.gitignore
@@ -98,6 +98,8 @@ lib/wx/c_src/win32/
lib/wx/priv/win32/
lib/wx/win32/
make/win32/
+make/otp_built
+make/otp_doc_built
# OSE
*.d
diff --git a/HOWTO/INSTALL-CROSS.md b/HOWTO/INSTALL-CROSS.md
index 10f463c06d..af4b38f292 100644
--- a/HOWTO/INSTALL-CROSS.md
+++ b/HOWTO/INSTALL-CROSS.md
@@ -563,12 +563,6 @@ under the License.
%CopyrightEnd%
-Modifying This Document
------------------------
-
-Before modifying this document you need to have a look at the
-[$ERL_TOP/HOWTO/MARKDOWN.md][] document.
-
[$ERL_TOP/HOWTO/INSTALL.md]: INSTALL.md
@@ -576,6 +570,4 @@ Before modifying this document you need to have a look at the
[How to Build the Documentation]: INSTALL.md#The-ErlangOTP-Documentation_How-to-Build-the-Documentation
[cross configuration variables]: #Currently-Used-Configuration-Variables
[DESTDIR]: http://www.gnu.org/prep/standards/html_node/DESTDIR.html
- [$ERL_TOP/HOWTO/MARKDOWN.md]: MARKDOWN.md
-
[?TOC]: true
diff --git a/HOWTO/INSTALL-WIN32.md b/HOWTO/INSTALL-WIN32.md
index 94d3688f23..0387572dd3 100644
--- a/HOWTO/INSTALL-WIN32.md
+++ b/HOWTO/INSTALL-WIN32.md
@@ -1018,7 +1018,7 @@ Copyright and License
%CopyrightBegin%
-Copyright Ericsson AB 2003-2012. All Rights Reserved.
+Copyright Ericsson AB 2003-2014. All Rights Reserved.
The contents of this file are subject to the Erlang Public License,
Version 1.1, (the "License"); you may not use this file except in
@@ -1033,15 +1033,7 @@ under the License.
%CopyrightEnd%
-Modifying This Document
------------------------
-
-Before modifying this document you need to have a look at the
-[$ERL_TOP/HOWTO/MARKDOWN.md][] document.
-
-
[1]: http://www.erlang.org/faq.html "mailing lists"
- [$ERL_TOP/HOWTO/MARKDOWN.md]: MARKDOWN.md
[?TOC]: true
diff --git a/HOWTO/INSTALL.md b/HOWTO/INSTALL.md
index 368947b36c..5b3a09df2b 100644
--- a/HOWTO/INSTALL.md
+++ b/HOWTO/INSTALL.md
@@ -4,174 +4,109 @@ Building and Installing Erlang/OTP
Introduction
------------
-This document describes how to build and install Erlang/OTP-%OTP-REL%. You
-are advised to read the whole document before attempting to build and install
-Erlang/OTP. You can find more information about Open Source Erlang/OTP at:
+This document describes how to build and install Erlang/OTP-%OTP-REL%.
+Erlang/OTP should be possible to build from source on any Unix/Linux system,
+including OS X. You are advised to read the whole document
+before attempting to build and install Erlang/OTP.
- <http://www.erlang.org/>
+The source code can be downloaded from the official site of Erlang/OTP or GitHub.
+* <http://www.erlang.org>
+* <https://github.com/erlang/otp>
-The source code for Erlang/OTP can also be found in a Git repository:
-
- <http://github.com/erlang/otp>
-
-Erlang/OTP should be possible to build from source on any Unix system,
-including Mac OS X. This document describes how to native compile Erlang/OTP
-on Unix. For detailed instructions on how to
-
-* cross compile Erlang/OTP, see the [$ERL_TOP/HOWTO/INSTALL-CROSS.md][]
- document.
-
-* build Erlang/OTP on Windows, see the [$ERL_TOP/HOWTO/INSTALL-WIN32.md][]
- document.
+Required Utilities
+------------------
- Binary releases for Windows can be found at
- <http://www.erlang.org/download.html>.
+These are the tools you need in order to unpack and build Erlang/OTP.
-Before reading the above mentioned documents you are in any case advised to
-read this document first, since it covers building Erlang/OTP in general as
-well as other important information.
+> *WARNING*: Please have a look at the [Known platform issues][] chapter
+> before you start.
-Daily Build and Test
---------------------
-At Ericsson we have a "Daily Build and Test" that runs on:
-
-* Solaris 8, 9
- * Sparc32
- * Sparc64
-* Solaris 10
- * Sparc32
- * Sparc64
- * x86
-* SuSE Linux/GNU 9.4, 10.1
- * x86
-* SuSE Linux/GNU 10.0, 10.1, 11.0
- * x86
- * x86\_64
-* openSuSE 11.4 (Celadon)
- * x86\_64 (valgrind)
-* Fedora 7
- * PowerPC
-* Fedora 14
- * x86\_64
-* Gentoo Linux/GNU 1.12.11.1
- * x86
-* Ubuntu Linux/GNU 7.04, 10.04, 10.10, 11.0
- * x86\_64
-* MontaVista Linux/GNU 4.0.1
- * PowerPC
-* FreeBSD 8.2
- * x86
-* OpenBSD 5.0
- * x86\_64
-* Mac OS X 10.5.8 (Leopard), 10.7.3 (Lion), 10.9 (Mavericks)
- * x86
-* Windows XP SP3, 2003, Vista, 7
- * x86
-* Windows 7
- * x86\_64
+### Unpacking ###
-We also have the following "Daily Cross Builds":
+* GNU unzip, or a modern uncompress.
+* A TAR program that understands the GNU TAR format for long filenames.
-* SuSE Linux/GNU 10.1 x86 -> SuSE Linux/GNU 10.1 x86\_64
-* SuSE Linux/GNU 10.1 x86\_64 -> Linux/GNU TILEPro64
+### Building ###
-and the following "Daily Cross Build Tests":
+* GNU `make`
+* Compiler -- GNU C Compiler, `gcc` or the C compiler frontend for LLVM, `clang`.
+* Perl 5
+* GNU `m4` -- If HiPE (native code) support is enabled. HiPE can be
+ disabled using `--disable-hipe`
+* `ncurses`, `termcap`, or `termlib` -- The development headers and
+ libraries are needed, often known as `ncurses-devel`. Use
+ `--without-termcap` to build without any of these libraries. Note that
+ in this case only the old shell (without any line editing) can be used.
+* `sed` -- Stream Editor for basic text transformation.
-* SuSE Linux/GNU 10.1 x86\_64
+#### Building in Git ####
-Versions Known NOT to Work
---------------------------
+* GNU `autoconf` of at least version 2.59. Note that `autoconf` is not
+ needed when building an unmodified version of the released source.
-* Suse linux 9.1 is shipped with a patched GCC version 3.3.3, having the
- rpm named `gcc-3.3.3-41`. That version has a serious optimization bug
- that makes it unusable for building the Erlang emulator. Please
- upgrade GCC to a newer version before building on Suse 9.1. Suse Linux
- Enterprise edition 9 (SLES9) has `gcc-3.3.3-43` and is not affected.
+#### Building on OS X ####
-* `gcc-4.3.0` has a serious optimizer bug. It produces an Erlang emulator
- that will crash immediately. The bug is supposed to be fixed in
- `gcc-4.3.1`.
+* Xcode -- Download and install via the Mac App Store.
+ Read about [Building on a Mac][] before proceeding.
-* FreeBSD had a bug which caused `kqueue`/`poll`/`select` to fail to detect
- that a `writev()` on a pipe has been made. This bug should have been fixed
- in FreeBSD 6.3 and FreeBSD 7.0. NetBSD and DragonFlyBSD probably have or
- have had the same bug. More information can be found at:
+### Installing ###
- * <http://www.freebsd.org/cgi/cvsweb.cgi/src/sys/kern/sys_pipe.c>
- * <http://lists.freebsd.org/pipermail/freebsd-arch/2007-September/006790.html>
+* An `install` program that can take multiple file names.
-* `getcwd()` on Solaris 9 can cause an emulator crash. If you have
- async-threads enabled you can increase the stack size of the
- async-threads as a temporary workaround. See the `+a` command-line
- argument in the documentation of `erl(1)`. Without async-threads the
- emulator is not as vulnerable to this bug, but if you hit it without
- async-threads the only workaround available is to enable async-threads
- and increase the stack size of the async-threads. Sun has however
- released patches that fixes the issue:
- > Problem Description: 6448300 large mnttab can cause stack overrun
- > during Solaris 9 getcwd
+Optional Utilities
+------------------
- More information can be found at:
+Some applications are automatically skipped if the dependencies aren't met.
+Here is a list of utilities needed for those applications. You will
+also find the utilities needed for building the documentation.
- * <http://sunsolve.sun.com/search/document.do?assetkey=1-21-112874-40-1&searchclause=6448300>
- * <http://sunsolve.sun.com/search/document.do?assetkey=1-21-114432-29-1&searchclause=6448300>
+### Building ###
-Required Utilities
-------------------
+* OpenSSL -- The opensource toolkit for Secure Socket Layer
+ and Transport Layer Security.
+ Required for building the application `crypto`.
+ Further, `ssl` and `ssh` require a working crypto application and
+ will also be skipped if OpenSSL is missing. The `public_key`
+ application will available without `crypto`, but the functionality
+ will be very limited.
+
+ The development package of OpenSSL including the header files are needed as well
+ as the binary command program `openssl`. At least version 0.9.8 of OpenSSL is required.
+ Read more and download from <http://www.openssl.org>.
+* Oracle Java SE JDK -- The Java Development Kit (Standard Edition).
+ Required for building the application `jinterface` and parts of `ic` and `orber`.
+ At least version 1.5.0 of the JDK is required.
+
+ Download from <http://www.oracle.com/technetwork/java/javase/downloads>.
+ We have also tested with IBM's JDK 1.5.0.
+* X Windows -- Development headers and libraries are needed
+ to build the Erlang/OTP application `gs` on Unix/Linux.
+* `flex` -- Headers and libraries are needed to build the flex
+ scanner for the `megaco` application on Unix/Linux.
+* wxWidgets -- Toolkit for GUI applications.
+ Required for building the `wx` application. At least
+ version 3.0 of wxWidgets is required.
-These are the tools you will need in order to unpack and build Erlang/OTP.
+ Download from <http://sourceforge.net/projects/wxwindows/files/3.0.0/>
+ or get it from GitHub: <https://github.com/wxWidgets/wxWidgets>
-### Unpacking ###
+ Further instructions on wxWidgets, read [Building with wxErlang][].
-* GNU unzip, or a modern uncompress.
-* A TAR program that understands the GNU TAR format for long filenames
- (such as GNU TAR).
-### Building ###
-* GNU `make`
-* `gcc` -- GNU C compiler
-* Perl 5
-* GNU `m4` -- If HiPE (native code) support is enabled. HiPE can be
- disabled using `--disable-hipe`
-* `ncurses`, `termcap`, or `termlib` -- The development headers and
- libraries are needed, often known as `ncurses-devel`. Use
- `--without-termcap` to build without any of these libraries. Note that
- in this case only the old shell (without any line editing) can be used.
-* OpenSSL -- Optional, but needed for building the Erlang/OTP applications
- `ssl` and `crypto`. You need the "development package" of OpenSSL, i.e.
- including the header files. For building the application `ssl` the OpenSSL
- binary command program `openssl` is also needed. At least version 0.9.8
- of OpenSSL is required. Can be downloaded from <http://www.openssl.org>.
-* Sun Java jdk-1.5.0 or higher -- Optional but needed for building the
- Erlang/OTP application `jinterface` and parts of `ic` and `orber`. Can
- be downloaded from <http://java.sun.com>. We have also tested IBM's
- JDK 1.5.0.
-* X Windows -- Optional, but development headers and libraries are needed
- to build the Erlang/OTP application `gs` on Unix/Linux.
-* `sed` -- There seem to be some problems with some of the `sed` version on
- Solaris. Make sure `/bin/sed` or `/usr/bin/sed` is used on the Solaris
- platform.
-* `flex` -- Optional, headers and libraries are needed to build the `flex`
- scanner for the `megaco` application on Unix/Linux.
+### Building Documentation ###
-#### Building Documentation ####
+* `xsltproc` -- A command line XSLT processor.
-* `xsltproc` -- XSLT processor. A tool for applying XSLT stylesheets
- to XML documents. Can be downloaded from
+ A tool for applying XSLT stylesheets
+ to XML documents. Download xsltproc from
<http://xmlsoft.org/XSLT/xsltproc2.html>.
+
* `fop` -- Apache FOP print formatter (requires Java). Can be downloaded
from <http://xmlgraphics.apache.org/fop>.
-#### Building in Git ####
-* GNU `autoconf` of at least version 2.59. Note that `autoconf` is not
- needed when building an unmodified version of the released source.
-
-### Installing ###
-
-* An `install` program that can take multiple file names.
How to Build and Install Erlang/OTP
-----------------------------------
@@ -186,65 +121,205 @@ section below before proceeding.
### Unpacking ###
-Step 1: Start by unpacking the Erlang/OTP distribution file with your GNU
+Start by unpacking the Erlang/OTP distribution file with your GNU
compatible TAR program.
- $ gunzip -c otp_src_%OTP-VSN%.tar.gz | tar xf -
+ $ tar -zxf otp_src_%OTP-VSN%.tar.gz # Assuming bash/sh
-alternatively:
-
- $ zcat otp_src_%OTP-VSN%.tar.gz | tar xf -
-
-
-Step 2: Now cd into the base directory (`$ERL_TOP`).
+Now change directory into the base directory and set the `$ERL_TOP` variable.
$ cd otp_src_%OTP-VSN%
+ $ export ERL_TOP=`pwd` # Assuming bash/sh
### Configuring ###
-Step 3: On some platforms Perl may behave strangely if certain locales are
-set, so optionally you may need to set the LANG variable:
-
- # Bourne shell
- $ LANG=C; export LANG
+Run the following commands to configure the build:
-or
+ $ ./configure [ options ]
- # C-Shell
- $ setenv LANG C
+> *NOTE*: If you are building Erlang/OTP from git you will need to run `./otp_build autoconf` to generate
+> the configure scripts.
-Step 4: Run the following commands to configure the build:
+By default, Erlang/OTP release will be installed in `/usr/local/{bin,lib/erlang}`.
+If you for instance don't have the permission to install in the standard location,
+ you can install Erlang/OTP somewhere else. For example, to install in
+`/opt/erlang/%OTP-VSN%/{bin,lib/erlang}`, use the `--prefix=/opt/erlang/%OTP-VSN%` option.
- $ ./configure [ options ]
+On some platforms Perl may behave strangely if certain locales are
+set. If you get errors when building, try setting the LANG variable:
-If you are building it from git you will need to run `./otp_build autoconf` to generate configure file.
-By default, Erlang/OTP will be installed in `/usr/local/{bin,lib/erlang}`.
-To instead install in `<BaseDir>/{bin,lib/erlang}`, use the
-`--prefix=<BaseDir>` option.
+ $ export LANG=C # Assuming bash/sh
-If you upgraded the source with some patch you may need to clean up
-from previous builds before the new build. Before doing a `make clean`,
-be sure to read the [Pre-built Source Release][] section below.
### Building ###
-Step 5: Build the Erlang/OTP package.
+Build the Erlang/OTP release.
$ make
+
+### Testing ###
+
+Before installation you should test whether your build is working properly
+by running our smoke test. The smoke test is a subset of the complete Erlang/OTP test suites.
+First you will need to build and release the test suites.
+
+ $ make release_tests
+
+This creates an additional folder in `$ERL_TOP/release` called `tests`.
+Now, it's time to start the smoke test.
+
+ $ cd release/tests/test_server
+ $ $ERL_TOP/bin/erl -s ts install -s ts smoke_test batch -s init stop
+
+To verify that everything is ok you should open `$ERL_TOP/release/tests/test_server/index.html`
+in your web browser and make sure that there are zero failed test cases.
+
+> *NOTE*: On builds without `crypto`, `ssl` and `ssh` there is a failed test case
+> for undefined functions. Verify that the failed test case log only shows calls
+> to skipped applications.
+
### Installing ###
-Step 6: Install then Erlang/OTP package
+You are now ready to install the Erlang/OTP release!
+The following command will install the release on your system.
$ make install
-### A Closer Look at the individual Steps ###
-Let us go through them in some detail.
+### Running ###
+
+You should now have a working release of Erlang/OTP!
+Jump to [System Principles][] for instructions on running Erlang/OTP.
+
+
+### How to Build the Documentation ###
+
+Make sure you're in the top directory in the source tree.
+
+ $ cd $ERL_TOP
+
+If you have just built Erlang/OTP in the current source tree, you have
+already ran `configure` and do not need to do this again; otherwise, run
+`configure`.
+
+ $ ./configure [Configure Args]
+
+When building the documentation you need a full Erlang/OTP-%OTP-VSN% system in
+the `$PATH`.
+
+ $ export PATH=$ERL_TOP/bin:$PATH # Assuming bash/sh
+
+Build the documentation.
-#### Configuring ####
+ $ make docs
+
+#### Build Issues ####
+
+We have sometimes experienced problems with Oracle's `java` running out of
+memory when running `fop`. Increasing the amount of memory available
+as follows has in our case solved the problem.
+
+ $ export FOP_OPTS="-Xmx<Installed amount of RAM in MB>m"
+
+More information can be found at
+* <http://xmlgraphics.apache.org/fop/0.95/running.html#memory>.
+
+
+### How to Install the Documentation ###
+
+The documentation can be installed either using the `install-docs` target,
+or using the `release_docs` target.
+
+* If you have installed Erlang/OTP using the `install` target, install
+ the documentation using the `install-docs` target. Install locations
+ determined by `configure` will be used. `$DESTDIR` can be used the
+ same way as when doing `make install`.
+
+ $ make install-docs
+
+* If you have installed Erlang/OTP using the `release` target, install
+ the documentation using the `release_docs` target. You typically want
+ to use the same `RELEASE_ROOT` as when invoking `make release`.
+
+ $ make release_docs RELEASE_ROOT=<release dir>
+
+
+### Accessing the Documentation ###
+
+After installation you can access the documentation by
+
+* Reading man pages. Make sure that `erl` is referring to the
+ installed version. For example `/usr/local/bin/erl`.
+ Try viewing at the man page for Mnesia
+
+ $ erl -man mnesia
+
+* Browsing the html pages by loading the page `/usr/local/lib/erlang/doc/erlang/index.html`
+ or `<BaseDir>/lib/erlang/doc/erlang/index.html` if the prefix option has been used.
+
+
+### How to Install the Pre-formatted Documentation ###
+
+Pre-formatted [html documentation][] and [man pages][] can be downloaded from
+* <http://www.erlang.org/download.html>.
+
+Extract the html archive in the installation directory.
+
+ $ cd <ReleaseDir>
+ $ tar -zxf otp_html_%OTP-VSN%.tar.gz
+
+For `erl -man <page>` to work the Unix manual pages have to be
+installed in the same way, i.e.
+
+ $ cd <ReleaseDir>
+ $ tar -zxf otp_man_%OTP-VSN%.tar.gz
+
+Where `<ReleaseDir>` is
+
+* `<PrefixDir>/lib/erlang` if you have installed Erlang/OTP using
+ `make install`.
+* `$DESTDIR<PrefixDir>/lib/erlang` if you have installed Erlang/OTP
+ using `make install DESTDIR=<TmpInstallDir>`.
+* `RELEASE_ROOT` if you have installed using
+ `make release RELEASE_ROOT=<ReleaseDir>`.
+
+
+Advanced configuration and build of Erlang/OTP
+----------------------------------------------
+
+If you want to tailor your Erlang/OTP build and installation, please read
+on for detailed information about the individual steps.
+
+### make and $ERL\_TOP ###
+
+All the makefiles in the entire directory tree use the environment
+variable `ERL_TOP` to find the absolute path of the installation. The
+`configure` script will figure this out and set it in the top level
+Makefile (which, when building, it will pass on). However, when
+developing it is sometimes convenient to be able to run make in a
+subdirectory. To do this you must set the `ERL_TOP` variable
+before you run make.
-Step 4 runs a configuration script created by the GNU autoconf utility, which
+For example, assume your GNU make program is called `make` and you
+want to rebuild the application `STDLIB`, then you could do:
+
+ $ cd lib/stdlib; env ERL_TOP=<Dir> make
+
+where `<Dir>` would be what you find `ERL_TOP` is set to in the top level
+Makefile.
+
+### otp\_build vs configure/make ###
+
+Building Erlang/OTP can be done either by using the `$ERL_TOP/otp_build`
+script, or by invoking `$ERL_TOP/configure` and `make` directly. Building using
+`otp_build` is easier since it involves fewer steps, but the `otp_build` build
+procedure is not as flexible as the `configure`/`make` build procedure. The binary
+releases for Windows that we deliver are built using `otp_build`.
+
+### Configuring ###
+
+The configure script is created by the GNU autoconf utility, which
checks for system specific features and then creates a number of makefiles.
The configure script allows you to customize a number of parameters;
@@ -260,10 +335,10 @@ use the `--prefix` argument like this: `./configure --prefix=<Dir>`.
Some of the available `configure` options are:
* `--prefix=PATH` - Specify installation prefix.
-* `--{enable,disable}-threads` - Thread support (enabled by default if
- possible)
+
+* `--{enable,disable}-threads` - Thread support. This is enabled by default if possible.
* `--{enable,disable}-smp-support` - SMP support (enabled by default if
- possible)
+ a usable POSIX thread library or native Windows threads is found)
* `--{enable,disable}-kernel-poll` - Kernel poll support (enabled by
default if possible)
* `--{enable,disable}-hipe` - HiPE support (enabled by default on supported
@@ -290,7 +365,7 @@ Some of the available `configure` options are:
* `--{with,without}-javac` - Java compiler (without implies that the
`jinterface` application won't be built)
* `--{enable,disable}-dynamic-ssl-lib` - Dynamic OpenSSL libraries
-* `--{enable,disable}-shared-zlib` - Shared zlib library
+* `--{enable,disable}-builtin-zlib` - Use the built-in source for zlib.
* `--with-ssl=PATH` - Specify location of OpenSSL include and lib
* `--{with,without}-ssl` - OpenSSL (without implies that the `crypto`,
`ssh`, and `ssl` won't be built)
@@ -321,9 +396,9 @@ Some of the available `configure` options are:
to configure.
* `--without-$app` - By default all applications in Erlang/OTP will be included
in a release. If this is not wanted it is possible to specify that Erlang/OTP
- should be compiled without that applications, i.e. `--without-wx`. There is
- no automatic dependency handling inbetween applications. So if you disable
- an application that another depends on, you also have to disable the
+ should be compiled without one or more applications, i.e. `--without-wx`. There is
+ no automatic dependency handling between applications. If you disable
+ an application that another application depends on, you also have to disable the
dependant application.
* `--enable-dirty-schedulers` - Enable the **experimental** dirty schedulers
functionality. Note that the dirty schedulers functionality is experimental,
@@ -334,26 +409,138 @@ Some of the available `configure` options are:
If you or your system has special requirements please read the `Makefile` for
additional configuration information.
-#### Building ####
-Step 5 builds the Erlang/OTP system. On a fast computer, this will take about
-5 minutes. After completion of this step, you should have a working
-Erlang/OTP system which you can try by typing `bin/erl`. This should start
-up Erlang/OTP and give you a prompt:
+### Building ###
+
+Building Erlang/OTP on a relatively fast computer takes approximately
+5 minutes. To speed it up, you can utilize parallel make with the `-j<num_jobs>` option.
+
+ $ export MAKEFLAGS=-j8 # Assuming bash/sh
+ $ make
+
+If you've upgraded the source with a patch you may need to clean up from previous
+builds before the new build.
+Make sure to read the [Pre-built Source Release][] section below before doing a `make clean`.
+
+#### Within Git ####
+
+When building in a Git working directory you also have to have a GNU `autoconf`
+of at least version 2.59 on your system, because you need to generate the
+`configure` scripts before you can start building.
+
+The `configure` scripts are generated by invoking `./otp_build autoconf` in
+the `$ERL_TOP` directory. The `configure` scripts also have to be regenerated
+when a `configure.in` or `aclocal.m4` file has been modified. Note that when
+checking out a branch a `configure.in` or `aclocal.m4` file may change
+content, and you may therefore have to regenerate the `configure` scripts
+when checking out a branch. Regenerated `configure` scripts imply that you
+have to run `configure` and build again.
+
+> *NOTE*: Running `./otp_build autoconf` is **not** needed when building
+> an unmodified version of the released source.
+
+Other useful information can be found at our GitHub wiki:
+* <http://wiki.github.com/erlang/otp>
+
+#### OS X (Darwin) ####
+
+Make sure that the command `hostname` returns a valid fully qualified host
+name (this is configured in `/etc/hostconfig`). Otherwise you might experience
+problems when running distributed systems.
+
+If you develop linked-in drivers (shared library) you need to link using
+`gcc` and the flags `-bundle -flat_namespace -undefined suppress`. You also
+include `-fno-common` in `CFLAGS` when compiling. Use `.so` as the library
+suffix.
+
+If you have Xcode 4.3, or later, you will also need to download
+"Command Line Tools" via the Downloads preference pane in Xcode.
+
+#### Building with wxErlang ####
+
+If you want to build the `wx` application, you will need to get wxWidgets-3.0
+(`wxWidgets-3.0.0.tar.bz2` from <http://sourceforge.net/projects/wxwindows/files/3.0.0/>) or get it from github with bug fixes:
+
+ $ git clone --branch WX_3_0_branch [email protected]:wxWidgets/wxWidgets.git
+
+Be aware that the wxWidgets-3.0 is a new release of wxWidgets, it is not as
+mature as the old releases and the OS X port still lags behind the other ports.
+
+Configure and build wxWidgets (on Mavericks - 10.9):
- $ bin/erl
- Erlang/OTP %OTP-REL% [erts-%ERTS-VSN%] [source] [smp:4:4] [async-threads:0] [kernel-poll:false]
+ $ ./configure --with-cocoa --prefix=/usr/local
+ or without support for old versions and with static libs
+ $ ./configure --with-cocoa --prefix=/usr/local --with-macosx-version-min=10.9 --disable-shared
+ $ make
+ $ sudo make install
+ $ export PATH=/usr/local/bin:$PATH
- Eshell V%ERTS-VSN% (abort with ^G)
- 1> _
+Check that you got the correct wx-config
-#### Installing ####
+ $ which wx-config && wx-config --version-full
-Step 6 is optional. It installs Erlang/OTP at a standardized location (if you
-change your mind about where you wish to install you can rerun step 4,
-without having to do step 5 again).
+Build Erlang/OTP
+
+ $ export PATH=/usr/local/bin:$PATH
+ $ cd $ERL_TOP
+ $ ./configure
+ $ make
+ $ sudo make install
-##### Alternative Installation Procedures #####
+
+#### Pre-built Source Release ####
+
+The source release is delivered with a lot of platform independent
+build results already pre-built. If you want to remove these pre-built
+files, invoke `./otp_build remove_prebuilt_files` from the `$ERL_TOP`
+directory. After you have done this, you can build exactly the same way
+as before, but the build process will take a much longer time.
+
+> *WARNING*: Doing `make clean` in an arbitrary directory of the source
+> tree, may remove files needed for bootstrapping the build.
+>
+> Doing `./otp_build save_bootstrap` from the `$ERL_TOP` directory before
+> doing `make clean` will ensure that it will be possible to build after
+> doing `make clean`. `./otp_build save_bootstrap` will be invoked
+> automatically when `make` is invoked from `$ERL_TOP` with either the
+> `clean` target, or the default target. It is also automatically invoked
+> if `./otp_build remove_prebuilt_files` is invoked.
+
+#### How to Build a Debug Enabled Erlang RunTime System ####
+
+After completing all the normal building steps described above a debug
+enabled runtime system can be built. To do this you have to change
+directory to `$ERL_TOP/erts/emulator`.
+
+In this directory execute:
+
+ $ make debug FLAVOR=$FLAVOR
+
+where `$FLAVOR` is either `plain` or `smp`. The flavor options will
+produce a beam.debug and beam.smp.debug executable respectively. The
+files are installed along side with the normal (opt) versions `beam.smp`
+and `beam`.
+
+To start the debug enabled runtime system execute:
+
+ $ $ERL_TOP/bin/cerl -debug
+
+The debug enabled runtime system features lock violation checking,
+assert checking and various sanity checks to help a developer ensure
+correctness. Some of these features can be enabled on a normal beam
+using appropriate configure options.
+
+There are other types of runtime systems that can be built as well
+using the similar steps just described.
+
+ $ make $TYPE FLAVOR=$FLAVOR
+
+where `$TYPE` is `opt`, `gcov`, `gprof`, `debug`, `valgrind`, or `lcnt`.
+These different beam types are useful for debugging and profiling
+purposes.
+
+
+### Installing ###
* Staged install using [DESTDIR][]. You can perform the install
phase in a temporary directory and later move the installation into
@@ -435,7 +622,7 @@ without having to do step 5 again).
if you want to try the system out, running test suites, etc, before doing
the real install without `EXTRA_PREFIX`.
-### Symbolic Links in --bindir ###
+#### Symbolic Links in --bindir ####
When doing `make install` and the default installation prefix is used,
relative symbolic links will be created from `/usr/local/bin` to all public
@@ -449,156 +636,10 @@ passed to `configure`. One can force relative, or absolute links by passing
phase. Note that such a request might cause a failure if the request cannot
be satisfied.
-### Pre-built Source Release ###
-
-The source release is delivered with a lot of platform independent
-build results already pre-built. If you want to remove these pre-built
-files, invoke `./otp_build remove_prebuilt_files` from the `$ERL_TOP`
-directory. After you have done this, you can build exactly the same way
-as before, but the build process will take a much longer time.
-
-> *WARNING*: Doing `make clean` in an arbitrary directory of the source
-> tree, may remove files needed for bootstrapping the build.
->
-> Doing `./otp_build save_bootstrap` from the `$ERL_TOP` directory before
-> doing `make clean` will ensure that it will be possible to build after
-> doing `make clean`. `./otp_build save_bootstrap` will be invoked
-> automatically when `make` is invoked from `$ERL_TOP` with either the
-> `clean` target, or the default target. It is also automatically invoked
-> if `./otp_build remove_prebuilt_files` is invoked.
-
-### Building in Git ###
-
-When building in a Git working directory you also have to have a GNU `autoconf`
-of at least version 2.59 on your system, because you need to generate the
-`configure` scripts before you can start building.
-
-The `configure` scripts are generated by invoking `./otp_build autoconf` in
-the `$ERL_TOP` directory. The `configure` scripts also have to be regenerated
-when a `configure.in` or `aclocal.m4` file has been modified. Note that when
-checking out a branch a `configure.in` or `aclocal.m4` file may change
-content, and you may therefore have to regenerate the `configure` scripts
-when checking out a branch. Regenerated `configure` scripts imply that you
-have to run `configure` and build again.
-
-> *NOTE*: Running `./otp_build autoconf` is **not** needed when building
-> an unmodified version of the released source.
-
-Other useful information can be found at our github wiki:
-<http://wiki.github.com/erlang/otp>
-
-### make and $ERL\_TOP ###
-
-All the makefiles in the entire directory tree use the environment
-variable `ERL_TOP` to find the absolute path of the installation. The
-`configure` script will figure this out and set it in the top level
-Makefile (which, when building, it will pass on). However, when
-developing it is sometimes convenient to be able to run make in a
-subdirectory. To do this you must set the `ERL_TOP` variable
-before you run make.
-
-For example, assume your GNU make program is called `make` and you
-want to rebuild the application `STDLIB`, then you could do:
-
- $ cd lib/stdlib; env ERL_TOP=<Dir> make
-
-where `<Dir>` would be what you find `ERL_TOP` is set to in the top level
-Makefile.
-
-The Erlang/OTP Documentation
-----------------------------
-
-### How to Build the Documentation ###
-
-Before you can build the documentation you need to either [native build][]
-or [cross build][] the Erlang/OTP system. After this you can build the
-documentation as follows.
-
- $ cd $ERL_TOP
- $ make docs
-
-The documentation can be installed either using the `install-docs` target,
-or using the `release_docs` target.
-
-* If you have installed Erlang/OTP using the `install` target, install
- the documentation using the `install-docs` target. Install locations
- determined by `configure` will be used. `$DESTDIR` can be used the
- same way as when doing `make install`.
-
- $ make install-docs
-
-* If you have installed Erlang/OTP using the `release` target, install
- the documentation using the `release_docs` target. You typically want
- to use the same `RELEASE_ROOT` as when invoking `make release`.
-
- $ make release_docs RELEASE_ROOT=<release dir>
-#### Build Issues ####
+### Running ###
-We have sometimes experienced problems with Sun's `java` running out of
-memory when running `fop`. Increasing the amount of memory available
-as follows has in our case solved the problem.
-
- $ export FOP_OPTS="-Xmx<Installed amount of RAM in MB>m"
-
-More information can be found at
-<http://xmlgraphics.apache.org/fop/0.95/running.html#memory>.
-
-### How to Install the Pre-formatted Documentation ###
-
-Pre-formatted [html documentation][] and [man pages][] can be downloaded at
-<http://www.erlang.org/download.html>.
-
-For some graphical tools to find the on-line help you have to install
-the HTML documentation on top of the installed OTP applications, i.e.
-
- $ cd <ReleaseDir>
- $ gunzip -c otp_html_%OTP-VSN%.tar.gz | tar xf -
-
-For `erl -man <page>` to work the Unix manual pages have to be
-installed in the same way, i.e.
-
- $ cd <ReleaseDir>
- $ gunzip -c otp_man_%OTP-VSN%.tar.gz | tar xf -
-
-Where `<ReleaseDir>` is
-
-* `<PrefixDir>/lib/erlang` if you have installed Erlang/OTP using
- `make install`.
-* `$DESTDIR<PrefixDir>/lib/erlang` if you have installed Erlang/OTP
- using `make install DESTDIR=<TmpInstallDir>`.
-* `RELEASE_ROOT` if you have installed using
- `make release RELEASE_ROOT=<ReleaseDir>`.
-
-Support for SMP (Symmetric Multi Processing)
---------------------------------------------
-
-An emulator with SMP support will be built by default on most platforms
-if a usable POSIX thread library or native Windows threads is found.
-
-You can force building of an SMP emulator, by using
-`./configure --enable-smp-support`. However, if configure does not
-automatically enable SMP support, the build is very likely to fail.
-
-Use `./configure --disable-smp-support` if you for some reason do not
-want to have the emulator with SMP support built.
-
-If SMP support is enabled, support for threaded I/O will also be turned on
-(also in the emulator without SMP support).
-
-The `erl` command will automatically start the SMP emulator if the
-computer has more than one logical processor. You can force a start
-of the emulator with SMP support by passing `-smp enable` as
-command line arguments to erl, and you can force a start of the
-emulator without SMP support by passing `-smp disable`.
-
-GS (Graphic System)
--------------------
-
-GS now Tcl/Tk 8.4. It will be searched for when starting GS.
-
-Using HiPE
-----------
+#### Using HiPE ####
HiPE supports the following system configurations:
@@ -619,12 +660,12 @@ HiPE supports the following system configurations:
* FreeBSD: FreeBSD 6.1 and 6.2 in 32-bit and 64-bit modes should work.
- * MacOSX/Darwin: Darwin 9.8.0 in 32-bit mode should work.
+ * OS X/Darwin: Darwin 9.8.0 in 32-bit mode should work.
* PowerPC: All 32-bit 6xx/7xx(G3)/74xx(G4) processors should work. 32-bit
mode on 970 (G5) and POWER5 processors should work.
- * Linux (Yellow Dog) and Mac OSX 10.4 are supported.
+ * Linux (Yellow Dog) and OS X 10.4 are supported.
* SPARC: All UltraSPARC processors running 32-bit user code should work.
@@ -643,11 +684,11 @@ HiPE is automatically enabled on the following systems:
* x86 in 32-bit mode: Linux, Solaris, FreeBSD
* x86 in 64-bit mode: Linux, Solaris, FreeBSD
-* PowerPC: Linux, MacOSX
+* PowerPC: Linux, Mac OSX
* SPARC: Linux
* ARM: Linux
-On other supported systems you need to `./configure --enable-hipe`.
+On other supported systems, see [Advanced Configure][] on how to enable HiPE.
If you are running on a platform supporting HiPE and if you have not disabled
HiPE, you can compile a module into native code like this from the Erlang
@@ -659,7 +700,7 @@ or
1> c(Module, [native|OtherOptions]).
-Using the erlc program, write like this:
+Using the erlc program, write like this
$ erlc +native Module.erl
@@ -674,88 +715,102 @@ Use `hipe:help_options/0` to print out the available options.
1> hipe:help_options().
-Mac OS X (Darwin)
------------------
-
-Make sure that the command `hostname` returns a valid fully qualified host
-name (this is configured in `/etc/hostconfig`).
-
-If you develop linked-in drivers (shared library) you need to link using
-`gcc` and the flags `-bundle -flat_namespace -undefined suppress`. You also
-include `-fno-common` in `CFLAGS` when compiling. Use `.so` as the library
-suffix.
-
-Install `Xcode` from the `AppStore` if it is not already installed.
-
-If you have Xcode 4.3, or later, you will also need to download
-"Command Line Tools" via the Downloads preference pane in Xcode.
-
-### Building with wxErlang ###
+#### Running with GS ####
-If you want to build the `wx` application, you will need to get wxWidgets-3.0 (or later)
-(`wxWidgets-3.0.0.tar.bz2` from <http://sourceforge.net/projects/wxwindows/files/3.0.0/>)
-or get it from github:
- $ git clone [email protected]:wxWidgets/wxWidgets.git
+The `gs` application requires the GUI toolkit Tcl/Tk to run. At least
+version 8.4 is required.
-Be aware that the wxWidgets-3.0 is a new release of wxWidgets, it is not as matured
-as the old releases and the MacOsX port still lags behind the other ports.
-
-Configure and build wxWidgets (on Mavericks - 10.9):
-
- $ ./configure --with-cocoa --prefix=/usr/local
- or without support for old versions and with static libs
- $ ./configure --with-cocoa --prefix=/usr/local --with-macosx-version-min=10.9 --disable-shared
- $ make
- $ sudo make install
- $ export PATH=/usr/local/bin:$PATH
+Known platform issues
+---------------------
-Check that you got the correct wx-config
+* Suse linux 9.1 is shipped with a patched GCC version 3.3.3, having the
+ rpm named `gcc-3.3.3-41`. That version has a serious optimization bug
+ that makes it unusable for building the Erlang emulator. Please
+ upgrade GCC to a newer version before building on Suse 9.1. Suse Linux
+ Enterprise edition 9 (SLES9) has `gcc-3.3.3-43` and is not affected.
- $ which wx-config
+* `gcc-4.3.0` has a serious optimizer bug. It produces an Erlang emulator
+ that will crash immediately. The bug is supposed to be fixed in
+ `gcc-4.3.1`.
-### Finish up ###
+* FreeBSD had a bug which caused `kqueue`/`poll`/`select` to fail to detect
+ that a `writev()` on a pipe has been made. This bug should have been fixed
+ in FreeBSD 6.3 and FreeBSD 7.0. NetBSD and DragonFlyBSD probably have or
+ have had the same bug. More information can be found at:
-Build Erlang
+ * <http://www.freebsd.org/cgi/cvsweb.cgi/src/sys/kern/sys_pipe.c>
+ * <http://lists.freebsd.org/pipermail/freebsd-arch/2007-September/006790.html>
- $ export PATH=/usr/local/bin:$PATH
- $ cd $ERL_TOP
- $ ./configure --enable-shared-zlib
- $ make
- $ sudo make install
+* `getcwd()` on Solaris 9 can cause an emulator crash. If you have
+ async-threads enabled you can increase the stack size of the
+ async-threads as a temporary workaround. See the `+a` command-line
+ argument in the documentation of `erl(1)`. Without async-threads the
+ emulator is not as vulnerable to this bug, but if you hit it without
+ async-threads the only workaround available is to enable async-threads
+ and increase the stack size of the async-threads. Oracle has however
+ released patches that fixes the issue:
-How to Build a Debug Enabled Erlang RunTime System
---------------------------------------------------
+ > Problem Description: 6448300 large mnttab can cause stack overrun
+ > during Solaris 9 getcwd
-After completing all the normal building steps described above a debug
-enabled runtime system can be built. To do this you have to change
-directory to `$ERL_TOP/erts/emulator`.
+ More information can be found at:
+ * <https://getupdates.oracle.com/readme/112874-40>
+ * <https://getupdates.oracle.com/readme/114432-29>
-In this directory execute:
+* `sed` on Solaris seem to have some problems. For example on
+ Solaris 8, the BSD `sed` and XPG4 `sed` should be avoided.
+ Make sure `/bin/sed` or `/usr/bin/sed` is used on the Solaris
+ platform.
- $ make debug FLAVOR=$FLAVOR
-where `$FLAVOR` is either `plain` or `smp`. The flavor options will
-produce a beam.debug and beam.smp.debug executable respectively. The
-files are installed along side with the normal (opt) versions `beam.smp`
-and `beam`.
+Daily Build and Test
+--------------------
+At Ericsson we have a "Daily Build and Test" that runs on:
-To start the debug enabled runtime system execute:
+* Solaris 8, 9
+ * Sparc32
+ * Sparc64
+* Solaris 10
+ * Sparc32
+ * Sparc64
+ * x86
+* SuSE Linux/GNU 9.4, 10.1
+ * x86
+* SuSE Linux/GNU 10.0, 10.1, 11.0
+ * x86
+ * x86\_64
+* openSuSE 11.4 (Celadon)
+ * x86\_64 (valgrind)
+* Fedora 7
+ * PowerPC
+* Fedora 16
+ * x86\_64
+* Gentoo Linux/GNU 1.12.11.1
+ * x86
+* Ubuntu Linux/GNU 7.04, 10.04, 10.10, 11.04, 12.04
+ * x86\_64
+* MontaVista Linux/GNU 4.0.1
+ * PowerPC
+* FreeBSD 10.0
+ * x86
+* OpenBSD 5.4
+ * x86\_64
+* OS X 10.5.8 (Leopard), 10.7.5 (Lion), 10.9.1 (Mavericks)
+ * x86
+* Windows XP SP3, 2003, Vista, 7
+ * x86
+* Windows 7
+ * x86\_64
- $ $ERL_TOP/bin/cerl -debug
+We also have the following "Daily Cross Builds":
-The debug enabled runtime system features lock violation checking,
-assert checking and various sanity checks to help a developer ensure
-correctness. Some of these features can be enabled on a normal beam
-using appropriate configure options.
+* SuSE Linux/GNU 10.1 x86 -> SuSE Linux/GNU 10.1 x86\_64
+* SuSE Linux/GNU 10.1 x86\_64 -> Linux/GNU TILEPro64
-There are other types of runtime systems that can be built as well
-using the similar steps just described.
+and the following "Daily Cross Build Tests":
- $ make $TYPE FLAVOR=$FLAVOR
+* SuSE Linux/GNU 10.1 x86\_64
-where `$TYPE` is `opt`, `gcov`, `gprof`, `debug`, `valgrind`, or `lcnt`.
-These different beam types are useful for debugging and profiling
-purposes.
Authors
-------
@@ -764,6 +819,7 @@ Authors are mostly listed in the application's `AUTHORS` files,
that is `$ERL_TOP/lib/*/AUTHORS` and `$ERL_TOP/erts/AUTHORS`,
not in the individual source files.
+
Copyright and License
---------------------
@@ -784,30 +840,25 @@ under the License.
%CopyrightEnd%
-More Information
-----------------
-
-More information can be found at <http://www.erlang.org>.
-Modifying This Document
------------------------
-
-Before modifying this document you need to have a look at the
-[$ERL_TOP/HOWTO/MARKDOWN.md][] document.
[$ERL_TOP/HOWTO/INSTALL-CROSS.md]: INSTALL-CROSS.md
[$ERL_TOP/HOWTO/INSTALL-WIN32.md]: INSTALL-WIN32.md
[DESTDIR]: http://www.gnu.org/prep/standards/html_node/DESTDIR.html
- [Building in Git]: #How-to-Build-and-Install-ErlangOTP_Building-in-Git
- [Pre-built Source Release]: #How-to-Build-and-Install-ErlangOTP_Prebuilt-Source-Release
- [make and $ERL_TOP]: #How-to-Build-and-Install-ErlangOTP_make-and-ERLTOP
+ [Building in Git]: #Advanced-configuration-and-build-of-ErlangOTP_Building_Within-Git
+ [Advanced Configure]: #Advanced-configuration-and-build-of-ErlangOTP_Configuring
+ [Pre-built Source Release]: #Advanced-configuration-and-build-of-ErlangOTP_Building_Prebuilt-Source-Release
+ [make and $ERL_TOP]: #Advanced-configuration-and-build-of-ErlangOTP_make-and-ERLTOP
[html documentation]: http://www.erlang.org/download/otp_doc_html_%OTP-VSN%.tar.gz
[man pages]: http://www.erlang.org/download/otp_doc_man_%OTP-VSN%.tar.gz
[the released source tar ball]: http://www.erlang.org/download/otp_src_%OTP-VSN%.tar.gz
+ [System Principles]: ../system_principles/system_principles
+ [Known platform issues]: #Known-platform-issues
[native build]: #How-to-Build-and-Install-ErlangOTP
[cross build]: INSTALL-CROSS.md
- [$ERL_TOP/HOWTO/MARKDOWN.md]: MARKDOWN.md
-
- [?TOC]: true
+ [Required Utilities]: #Required-Utilities
+ [Optional Utilities]: #Optional-Utilities
+ [Building on a Mac]: #Advanced-configuration-and-build-of-ErlangOTP_Building_OS-X-Darwin
+ [Building with wxErlang]: #Advanced-configuration-and-build-of-ErlangOTP_Building_Building-with-wxErlang
diff --git a/Makefile.in b/Makefile.in
index c667eb5f79..5c96c789dc 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -422,6 +422,10 @@ endif
cd $(ERL_TOP)/system/doc && \
PATH=$(BOOT_PREFIX)"$${PATH}" \
ERL_TOP=$(ERL_TOP) $(MAKE) TESTROOT="$(RELEASE_ROOT)" DOCGEN=$(BOOTSTRAP_ROOT)/bootstrap/lib/erl_docgen $@
+ifneq ($(OTP_SMALL_BUILD),true)
+ echo "OTP doc built" > $(ERL_TOP)/make/otp_doc_built
+endif
+
mod2app:
PATH=$(BOOT_PREFIX)"$${PATH}" escript $(BOOTSTRAP_ROOT)/bootstrap/lib/erl_docgen/priv/bin/xref_mod_app.escript -topdir $(ERL_TOP) -outfile $(ERL_TOP)/make/$(TARGET)/mod2app.xml
@@ -447,6 +451,7 @@ else
$(make_verbose)cd lib && \
ERL_TOP=$(ERL_TOP) PATH=$(BOOT_PREFIX)"$${PATH}" \
$(MAKE) opt BUILD_ALL=true
+ $(V_at)echo "OTP built" > $(ERL_TOP)/make/otp_built
endif
kernel:
$(make_verbose)cd lib/kernel && \
diff --git a/OTP_VERSION b/OTP_VERSION
index cfc4bcdf57..b7aba827ff 100644
--- a/OTP_VERSION
+++ b/OTP_VERSION
@@ -1 +1 @@
-17.0-rc2
+17.1-rc0
diff --git a/README.md b/README.md
index a6a4f11be8..bf80b6391b 100644
--- a/README.md
+++ b/README.md
@@ -12,6 +12,15 @@ middle-ware to develop these systems. It includes its own distributed
database, applications to interface towards other languages, debugging
and release handling tools.
+ERTS and BEAM
+-------------
+**BEAM** is the name of the virtual machine where all Erlang code is executed.
+Every compiled Erlang file has the suffix .beam. The virtual machine
+is sometimes referred to as the emulator.
+
+**ERTS** is the Erlang Runtime System where the BEAM, kernel and
+standard libraries amongst others are included.
+
More information can be found at [erlang.org] [1].
Building and Installing
@@ -57,7 +66,7 @@ Copyright and License
> %CopyrightBegin%
>
-> Copyright Ericsson AB 2010-2012. All Rights Reserved.
+> Copyright Ericsson AB 2010-2014. All Rights Reserved.
>
> The contents of this file are subject to the Erlang Public License,
> Version 1.1, (the "License"); you may not use this file except in
diff --git a/bootstrap/lib/compiler/ebin/beam_disasm.beam b/bootstrap/lib/compiler/ebin/beam_disasm.beam
index c129898523..f050f39ca0 100644
--- a/bootstrap/lib/compiler/ebin/beam_disasm.beam
+++ b/bootstrap/lib/compiler/ebin/beam_disasm.beam
Binary files differ
diff --git a/bootstrap/lib/compiler/ebin/compiler.appup b/bootstrap/lib/compiler/ebin/compiler.appup
index 13c2644004..e73b9aa60c 100644
--- a/bootstrap/lib/compiler/ebin/compiler.appup
+++ b/bootstrap/lib/compiler/ebin/compiler.appup
@@ -15,7 +15,7 @@
%% under the License.
%%
%% %CopyrightEnd%
-{"4.9.4",
+{"5.0",
[{<<".*">>,[{restart_application, compiler}]}],
[{<<".*">>,[{restart_application, compiler}]}]
}.
diff --git a/bootstrap/lib/compiler/ebin/core_lib.beam b/bootstrap/lib/compiler/ebin/core_lib.beam
index 4957fbabb7..bb38837049 100644
--- a/bootstrap/lib/compiler/ebin/core_lib.beam
+++ b/bootstrap/lib/compiler/ebin/core_lib.beam
Binary files differ
diff --git a/bootstrap/lib/compiler/ebin/core_pp.beam b/bootstrap/lib/compiler/ebin/core_pp.beam
index fbfd68a93b..e6e60fb658 100644
--- a/bootstrap/lib/compiler/ebin/core_pp.beam
+++ b/bootstrap/lib/compiler/ebin/core_pp.beam
Binary files differ
diff --git a/bootstrap/lib/compiler/ebin/sys_core_fold.beam b/bootstrap/lib/compiler/ebin/sys_core_fold.beam
index 39be60c555..923c4d98fd 100644
--- a/bootstrap/lib/compiler/ebin/sys_core_fold.beam
+++ b/bootstrap/lib/compiler/ebin/sys_core_fold.beam
Binary files differ
diff --git a/bootstrap/lib/compiler/ebin/sys_pre_expand.beam b/bootstrap/lib/compiler/ebin/sys_pre_expand.beam
index 5c14528eff..c0c537f623 100644
--- a/bootstrap/lib/compiler/ebin/sys_pre_expand.beam
+++ b/bootstrap/lib/compiler/ebin/sys_pre_expand.beam
Binary files differ
diff --git a/bootstrap/lib/compiler/ebin/v3_codegen.beam b/bootstrap/lib/compiler/ebin/v3_codegen.beam
index 6bf28f441e..3670fd206c 100644
--- a/bootstrap/lib/compiler/ebin/v3_codegen.beam
+++ b/bootstrap/lib/compiler/ebin/v3_codegen.beam
Binary files differ
diff --git a/bootstrap/lib/compiler/ebin/v3_core.beam b/bootstrap/lib/compiler/ebin/v3_core.beam
index 6b322b8da0..ac24c6a6cb 100644
--- a/bootstrap/lib/compiler/ebin/v3_core.beam
+++ b/bootstrap/lib/compiler/ebin/v3_core.beam
Binary files differ
diff --git a/bootstrap/lib/compiler/ebin/v3_kernel.beam b/bootstrap/lib/compiler/ebin/v3_kernel.beam
index f5dcecb807..1e549a41c7 100644
--- a/bootstrap/lib/compiler/ebin/v3_kernel.beam
+++ b/bootstrap/lib/compiler/ebin/v3_kernel.beam
Binary files differ
diff --git a/bootstrap/lib/compiler/ebin/v3_life.beam b/bootstrap/lib/compiler/ebin/v3_life.beam
index c2363fc62d..0eb0cb6caf 100644
--- a/bootstrap/lib/compiler/ebin/v3_life.beam
+++ b/bootstrap/lib/compiler/ebin/v3_life.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/application.beam b/bootstrap/lib/kernel/ebin/application.beam
index 2c8444fb95..6946d17545 100644
--- a/bootstrap/lib/kernel/ebin/application.beam
+++ b/bootstrap/lib/kernel/ebin/application.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/inet_config.beam b/bootstrap/lib/kernel/ebin/inet_config.beam
index 03b42209e6..e858ac20f1 100644
--- a/bootstrap/lib/kernel/ebin/inet_config.beam
+++ b/bootstrap/lib/kernel/ebin/inet_config.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/erl_expand_records.beam b/bootstrap/lib/stdlib/ebin/erl_expand_records.beam
index 0e72af0e35..9f7ad7265d 100644
--- a/bootstrap/lib/stdlib/ebin/erl_expand_records.beam
+++ b/bootstrap/lib/stdlib/ebin/erl_expand_records.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/erl_lint.beam b/bootstrap/lib/stdlib/ebin/erl_lint.beam
index 50b3e3c9d3..9481dc6ef5 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/erl_pp.beam b/bootstrap/lib/stdlib/ebin/erl_pp.beam
index 683a07fbd5..ff196f3a45 100644
--- a/bootstrap/lib/stdlib/ebin/erl_pp.beam
+++ b/bootstrap/lib/stdlib/ebin/erl_pp.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/otp_internal.beam b/bootstrap/lib/stdlib/ebin/otp_internal.beam
index defe4fa5a0..23b140aeb5 100644
--- a/bootstrap/lib/stdlib/ebin/otp_internal.beam
+++ b/bootstrap/lib/stdlib/ebin/otp_internal.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/pg.beam b/bootstrap/lib/stdlib/ebin/pg.beam
index 65195defbf..31f30461d8 100644
--- a/bootstrap/lib/stdlib/ebin/pg.beam
+++ b/bootstrap/lib/stdlib/ebin/pg.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/slave.beam b/bootstrap/lib/stdlib/ebin/slave.beam
index ba741284ac..532c46cd38 100644
--- a/bootstrap/lib/stdlib/ebin/slave.beam
+++ b/bootstrap/lib/stdlib/ebin/slave.beam
Binary files differ
diff --git a/erts/doc/src/erlang.xml b/erts/doc/src/erlang.xml
index 7aaded200c..e7e9b218f2 100644
--- a/erts/doc/src/erlang.xml
+++ b/erts/doc/src/erlang.xml
@@ -1784,6 +1784,15 @@ os_prompt% </pre>
</desc>
</func>
<func>
+ <name name="is_map" arity="1"/>
+ <fsummary>Check whether a term is a map</fsummary>
+ <desc>
+ <p>Returns <c>true</c> if <c><anno>Term</anno></c> is a map;
+ otherwise returns <c>false</c>.</p>
+ <p>Allowed in guard tests.</p>
+ </desc>
+ </func>
+ <func>
<name name="is_number" arity="1"/>
<fsummary>Check whether a term is a number</fsummary>
<desc>
@@ -2220,6 +2229,17 @@ os_prompt% </pre>
</desc>
</func>
<func>
+ <name name="map_size" arity="1"/>
+ <fsummary>Return the size of a map</fsummary>
+ <desc>
+ <p>Returns an integer which is the number of key-value pairs in <c><anno>Map</anno></c>.</p>
+ <pre>
+> <input>map_size(#{a=>1, b=>2, c=>3}).</input>
+3</pre>
+ <p>Allowed in guard tests.</p>
+ </desc>
+ </func>
+ <func>
<name name="max" arity="2"/>
<fsummary>Return the largest of two term</fsummary>
<desc>
diff --git a/erts/doc/src/notes.xml b/erts/doc/src/notes.xml
index b4ebef72f4..68feaa027a 100644
--- a/erts/doc/src/notes.xml
+++ b/erts/doc/src/notes.xml
@@ -30,6 +30,738 @@
</header>
<p>This document describes the changes made to the ERTS application.</p>
+<section><title>Erts 6.0.1</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Fix broken system monitoring of <c>large_heap</c> for
+ non-smp VM. No message for <c>large_heap</c> was ever
+ sent on non-smp VM. Bug exist since R16B.</p>
+ <p>
+ Own Id: OTP-11852</p>
+ </item>
+ <item>
+ <p>
+ Fixed type spec of <c>erlang:system_info/1</c>.</p>
+ <p>
+ Own Id: OTP-11859 Aux Id: OTP-11615 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Erts 6.0</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ The option dupnames did not work as intended in re. When
+ looking for names with {capture, [Name, ...]}, re:run
+ returned a random instance of the match for that name,
+ instead of the leftmost matching instance, which was what
+ the documentation stated. This is now corrected to adhere
+ to the documentation. The option {capture,all_names}
+ along with a re:inspect/2 function is also added to
+ further help in using named subpatterns.</p>
+ <p>
+ Own Id: OTP-11205</p>
+ </item>
+ <item>
+ <p>
+ Allow loading of NIF library with unicode path name</p>
+ <p>
+ Own Id: OTP-11408</p>
+ </item>
+ <item>
+ <p>
+ Allow loading of driver with unicode path name</p>
+ <p>
+ Own Id: OTP-11549</p>
+ </item>
+ <item>
+ <p>
+ Fixed a bug where starting Erlang without having an open
+ stdin on fd 0 would sometimes deadlock the emulator when
+ terminating.</p>
+ <p>
+ Own Id: OTP-11558</p>
+ </item>
+ <item>
+ <p>
+ The option '-names' in epmd now works on Windows (Thanks
+ to Johannes Weißl)</p>
+ <p>
+ Own Id: OTP-11565</p>
+ </item>
+ <item>
+ <p>
+ Correction of the examples in escript documentation.
+ (Thanks to Pierre Fenoll).</p>
+ <p>
+ Own Id: OTP-11577</p>
+ </item>
+ <item>
+ <p>
+ Fix bs_get_integer instruction</p>
+ <p>
+ The instruction bs_get_integer could unnecessarily
+ trigger a garbage collection in failure cases which is
+ unwanted or outright dangerous.</p>
+ <p>
+ Ex:</p>
+ <p>
+ &lt;&lt;X:Sz,_/bits&gt;&gt; = &lt;&lt;"some
+ binary"&gt;&gt;</p>
+ <p>
+ Previously, if Sz induced X to a bignum it would reserved
+ memory size this on the heap via a garbage collection
+ before checking if the size could actually match.</p>
+ <p>
+ It will now check the binary size before triggering a
+ collection.</p>
+ <p>
+ Own Id: OTP-11581</p>
+ </item>
+ <item>
+ <p>
+ Remove heap space overestimation in <c>binary_to_term</c>
+ (and remote message reception) for integers in the
+ intervals [-2147483648,-1] and [256,2147483647] on 64-bit
+ emulators.</p>
+ <p>
+ Own Id: OTP-11585</p>
+ </item>
+ <item>
+ <p>
+ Add support for detecting the separate tinfo library from
+ ncurses (Thanks to Dirkjan Ochtman)</p>
+ <p>
+ Own Id: OTP-11590</p>
+ </item>
+ <item>
+ <p>
+ Deprecation warning for system_flag(cpu_topology) has
+ been extended for removal in OTP 18 (Thanks to Steve
+ Vinoski for the update)</p>
+ <p>
+ Own Id: OTP-11602</p>
+ </item>
+ <item>
+ <p>
+ Documentation improvement regarding some awkward wording
+ around the +spp flag. (Thanks to Brian L. Troutwine )</p>
+ <p>
+ Own Id: OTP-11607</p>
+ </item>
+ <item>
+ <p>
+ Fixed bug where sendfile would return the wrong error
+ code for a remotely closed socket if the socket was in
+ passive mode. (Thanks to Vincent Siliakus for reporting
+ the bug.)</p>
+ <p>
+ Own Id: OTP-11614</p>
+ </item>
+ <item>
+ <p>
+ Increase garbage collection tenure rate</p>
+ <p>The garbage collector tries to maintain the previous
+ heap block size during a minor gc, i.e. 'need' is not
+ utilized in determining the size of the new heap, instead
+ it relies on tenure and garbage to be sufficiently
+ large.</p>
+ <p>In instances during intense growing with exclusively
+ live data on the heap coupled with delayed tenure,
+ fullsweeps would be triggered directly after a minor gc
+ to make room for 'need' since the new heap would be
+ full.</p>
+ <p>To remedy this, the tenure of terms on the minor heap
+ will always happen (if it is below the high watermark)
+ instead of every other minor gc.</p>
+ <p>Characteristics Impact: Reduced CPU-time spent in
+ garbage collection but may infer delays in collecting
+ garbage from the heap. Tweak 'fullsweep_after' options to
+ increase gc pressure if needed.</p>
+ <p>
+ Own Id: OTP-11617</p>
+ </item>
+ <item>
+ <p>
+ Fix bug when comparing integers with floats larger than
+ 2^992. The bug could potentially cause memory corruption
+ on 32-bit emulators.</p>
+ <p>
+ Own Id: OTP-11618</p>
+ </item>
+ <item>
+ <p>
+ Cross-compilation fixes for TileraMDE-3.0.1.125620</p>
+ <p>
+ Own Id: OTP-11635</p>
+ </item>
+ <item>
+ <p>
+ sendfile no longer uses async threads by default</p>
+ <p>
+ This has been done because a slow client attack is
+ possible if the async thread pool is used. The scenario
+ is:</p>
+ <p>
+ Client does a request for a file and then slowly receives
+ the file one byte at a time. This will eventually fill
+ the async thread pool with blocking sendfile operations
+ and thus starving the vm of all file operations.</p>
+ <p>
+ If you still want to use the async threads pool for
+ sendfile an option to enable it has been introduced.</p>
+ <p>
+ Thanks to Christopher Faulet for identifying this
+ vulnerability.</p>
+ <p>
+ *** POTENTIAL INCOMPATIBILITY ***</p>
+ <p>
+ Own Id: OTP-11639</p>
+ </item>
+ <item>
+ <p>
+ Do proper rollback of calls to
+ <c>enif_open_resource_type</c> when load/upgrade
+ callbacks of NIF library return failure.</p>
+ <p>
+ Own Id: OTP-11722</p>
+ </item>
+ <item>
+ <p>
+ Changed the default configuration when configuring with
+ <c>$ERL_TOP/configure</c> to be the same as when
+ configuring with <c>$ERL_TOP/otp_build configure</c>.</p>
+ <p>
+ Previously floating point exceptions got enabled by
+ default on Linux when HiPE was enabled when configuring
+ with <c>$ERL_TOP/configure</c>, but not when configuring
+ with <c>$ERL_TOP/otp_build configure</c>. The default is
+ now in both cases not to use floating point exceptions
+ since there still exist unresolved issues with floating
+ point exceptions on Linux.</p>
+ <p>
+ For more information see <seealso
+ marker="doc/installation_guide:INSTALL"><c>$ERL_TOP/HOWTO/INSTALL.md</c></seealso>.</p>
+ <p>
+ *** POTENTIAL INCOMPATIBILITY ***</p>
+ <p>
+ Own Id: OTP-11723</p>
+ </item>
+ <item>
+ <p>
+ A comment in erl_db_tree.c no longer differ from the
+ code. (Thanks to Cobus Carstens)</p>
+ <p>
+ Own Id: OTP-11793</p>
+ </item>
+ <item>
+ <p>
+ Fix epmd debug functionality for VxWorks (Thanks to Jay
+ True)</p>
+ <p>
+ Own Id: OTP-11808</p>
+ </item>
+ <item>
+ <p>
+ Use closefrom/2 when available in child_setup (Thanks to
+ Rick Reed and Anthony Ramine)</p>
+ <p>
+ Own Id: OTP-11809</p>
+ </item>
+ <item>
+ <p>
+ Fix dtrace/systemtap bug where the probe arguments would
+ be concatenated due to faulty length calculation. </p>
+ <p>
+ Thanks to Michal Ptaszek and Scott Lystig Fritchie</p>
+ <p>
+ Own Id: OTP-11816</p>
+ </item>
+ <item>
+ <p>
+ It is now better documented that the <c>+fn*</c> flags to
+ <c>erl</c> also affect how command line parameters and
+ environment variables are read. (Thanks to Vlad
+ Dumitrescu)</p>
+ <p>
+ Own Id: OTP-11818</p>
+ </item>
+ </list>
+ </section>
+
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p>
+ Options to set match_limit and match_limit_recursion are
+ added to re:run. The option report_errors is also added
+ to get more information when re:run fails due to limits
+ or compilation errors.</p>
+ <p>
+ Own Id: OTP-10285</p>
+ </item>
+ <item>
+ <p> Dialyzer's <c>unmatched_return</c> warnings have been
+ corrected. </p>
+ <p>
+ Own Id: OTP-10908</p>
+ </item>
+ <item>
+ <p>
+ A common case is to wrap an argument to
+ <c>list_to_binary/1</c> in a list to ensure conversion
+ can happen even though the argument may already be a
+ binary. Take special care of this case and do not copy
+ binary.</p>
+ <p>
+ Impact: May cause incompatibility since a single binary
+ is no longer copied. Use <c>binary:copy/1,2</c> instead.</p>
+ <p>
+ *** POTENTIAL INCOMPATIBILITY ***</p>
+ <p>
+ Own Id: OTP-11082</p>
+ </item>
+ <item>
+ <p>
+ Make erlang:open_port/2 spawn and spawn_executable handle
+ unicode.</p>
+ <p>
+ Own Id: OTP-11105</p>
+ </item>
+ <item>
+ <p>
+ Handle unicode (widestring) in erl, erlc, heart, etc on
+ windows.</p>
+ <p>
+ Own Id: OTP-11135</p>
+ </item>
+ <item>
+ <p>
+ The version of the PCRE library Used by Erlang's re
+ module is raised to 8.33 from 7.6. This means, among
+ other things, better Unicode and Unicode Character
+ Properties support. New options connected to PCRE 8.33
+ are also added to the re module (ucd, notempty_atstart,
+ no_start_optimize). PCRE has extended the regular
+ expression syntax between 7.6 and 8.33, why this imposes
+ a potential incompatibility. Only very complicated
+ regular expressions may be affected, but if you know you
+ are using obscure features, please test run your regular
+ expressions and verify that their behavior has not
+ changed.</p>
+ <p>
+ *** POTENTIAL INCOMPATIBILITY ***</p>
+ <p>
+ Own Id: OTP-11204</p>
+ </item>
+ <item>
+ <p>Filenames containing UTF-8 encoded characters can now
+ be handled by erlc.</p>
+ <p>If you have set the <c>ERLC_EMULATOR</c> environment
+ variable, note that <c>erlc</c> in OTP 17 will only work
+ with <c>erl</c> in OTP 17 since the protocol between the
+ <c>erlc</c> program and the <c>erl_compile</c> module has
+ changed.</p>
+ <p>
+ Own Id: OTP-11248</p>
+ </item>
+ <item>
+ <p>
+ By giving --enable-static-{nifs,drivers} to configure it
+ is now possible to statically linking of nifs and drivers
+ to the main Erlang VM binary. At the moment only the asn1
+ and crypto nifs of the Erlang/OTP nifs and drivers have
+ been prepared to be statically linked. For more details
+ see the Installation Guide in the System documentation.</p>
+ <p>
+ Own Id: OTP-11258</p>
+ </item>
+ <item>
+ <p>
+ Erlang/OTP has been ported to the realtime operating
+ system OSE. The port supports both smp and non-smp
+ emulator. For details around the port and how to started
+ see the User's Guide in the <seealso
+ marker="ose:ose_intro">ose</seealso> application. </p>
+ <p>
+ Note that not all parts of Erlang/OTP has been ported. </p>
+ <p>
+ Notable things that work are: non-smp and smp emulators,
+ OSE signal interaction, crypto, asn1, run_erl/to_erl,
+ tcp, epmd, distribution and most if not all non-os
+ specific functionality of Erlang.</p>
+ <p>
+ Notable things that does not work are: udp/sctp, os_mon,
+ erl_interface, binding of schedulers.</p>
+ <p>
+ Own Id: OTP-11334</p>
+ </item>
+ <item>
+ <p>
+ Add the {active,N} socket option for TCP, UDP, and SCTP,
+ where N is an integer in the range -32768..32767, to
+ allow a caller to specify the number of data messages to
+ be delivered to the controlling process. Once the
+ socket's delivered message count either reaches 0 or is
+ explicitly set to 0 with inet:setopts/2 or by including
+ {active,0} as an option when the socket is created, the
+ socket transitions to passive ({active, false}) mode and
+ the socket's controlling process receives a message to
+ inform it of the transition. TCP sockets receive
+ {tcp_passive,Socket}, UDP sockets receive
+ {udp_passive,Socket} and SCTP sockets receive
+ {sctp_passive,Socket}. </p>
+ <p>
+ The socket's delivered message counter defaults to 0, but
+ it can be set using {active,N} via any gen_tcp, gen_udp,
+ or gen_sctp function that takes socket options as
+ arguments, or via inet:setopts/2. New N values are added
+ to the socket's current counter value, and negative
+ numbers can be used to reduce the counter value.
+ Specifying a number that would cause the socket's counter
+ value to go above 32767 causes an einval error. If a
+ negative number is specified such that the counter value
+ would become negative, the socket's counter value is set
+ to 0 and the socket transitions to passive mode. If the
+ counter value is already 0 and inet:setopts(Socket,
+ [{active,0}]) is specified, the counter value remains at
+ 0 but the appropriate passive mode transition message is
+ generated for the socket.</p>
+ <p>
+ Thanks to Steve Vinoski</p>
+ <p>
+ Own Id: OTP-11368</p>
+ </item>
+ <item>
+ <p>
+ A new optional scheduler utilization balancing mechanism
+ has been introduced. For more information see the
+ <seealso marker="erl#+sub"><c>+sub</c></seealso> command
+ line argument.</p>
+ <p>
+ Characteristics impact: None, when not enabled. When
+ enabled, changed timing in the system, normally a small
+ overhead due to measuring of utilization and calculating
+ balancing information. On some systems, such as old
+ Windows systems, the overhead can be quite substantial.
+ This time measurement overhead highly depend on the
+ underlying primitives provided by the OS.</p>
+ <p>
+ Own Id: OTP-11385</p>
+ </item>
+ <item>
+ <p>
+ A call to either the <c>garbage_collect/1</c> BIF or the
+ <c>check_process_code/2</c> BIF may trigger garbage
+ collection of another processes than the process calling
+ the BIF. The previous implementations performed these
+ kinds of garbage collections without considering the
+ internal state of the process being garbage collected. In
+ order to be able to more easily and more efficiently
+ implement yielding native code, these types of garbage
+ collections have been rewritten. A garbage collection
+ like this is now triggered by an asynchronous request
+ signal, the actual garbage collection is performed by the
+ process being garbage collected itself, and finalized by
+ a reply signal to the process issuing the request. Using
+ this approach processes can disable garbage collection
+ and yield without having to set up the heap in a state
+ that can be garbage collected.</p>
+ <p>
+ The <seealso
+ marker="erts:erlang#garbage_collect/2"><c>garbage_collect/2</c></seealso>,
+ and <seealso
+ marker="erts:erlang#check_process_code/3"><c>check_process_code/3</c></seealso>
+ BIFs have been introduced. Both taking an option list as
+ last argument. Using these, one can issue asynchronous
+ requests.</p>
+ <p>
+ <c>code:purge/1</c> and <c>code:soft_purge/1</c> have
+ been rewritten to utilize asynchronous
+ <c>check_process_code</c> requests in order to
+ parallelize work.</p>
+ <p>
+ Characteristics impact: A call to the
+ <c>garbage_collect/1</c> BIF or the
+ <c>check_process_code/2</c> BIF will normally take longer
+ time to complete while the system as a whole wont be as
+ much negatively effected by the operation as before. A
+ call to <c>code:purge/1</c> and <c>code:soft_purge/1</c>
+ may complete faster or slower depending on the state of
+ the system while the system as a whole wont be as much
+ negatively effected by the operation as before.</p>
+ <p>
+ Own Id: OTP-11388 Aux Id: OTP-11535, OTP-11648 </p>
+ </item>
+ <item>
+ <p>
+ Cleanup 'Buckets' and 'Time left' fields in crashdump to
+ ease parsing.</p>
+ <p>
+ Own Id: OTP-11419</p>
+ </item>
+ <item>
+ <p>
+ Add sync option to file:open/2.</p>
+ <p>
+ The sync option adds the POSIX O_SYNC flag to the open
+ system call on platforms that support the flag or its
+ equivalent, e.g., FILE_FLAG_WRITE_THROUGH on Windows. For
+ platforms that don't support it, file:open/2 returns
+ {error, enotsup} if the sync option is passed in. Thank
+ to Steve Vinoski and Joseph Blomstedt</p>
+ <p>
+ Own Id: OTP-11498</p>
+ </item>
+ <item>
+ <p>
+ erlang:binary_to_term will now cost an appropriate amount
+ of reductions and will interrupt (yield) for reschedule
+ if the term is big. This avoids too long schedules when
+ binary_to_term is used. (Thanks to Svante Karlsson for
+ the original patch)</p>
+ <p>
+ Impact: Programs running binary_to_term on large binaries
+ will run more smoothly, but rescheduling will impact the
+ single process performance of the BIF. Single threaded
+ benchmarks might show degraded performance of the BIF,
+ while general system behaviour will be improved.</p>
+ <p>
+ Own Id: OTP-11535 Aux Id: OTP-11388 </p>
+ </item>
+ <item>
+ <p>
+ Added high resolution icon for windows. (Thanks to Daniel
+ Goertz for the inspiration.)</p>
+ <p>
+ Own Id: OTP-11560</p>
+ </item>
+ <item>
+ <p>
+ Migration of memory carriers has been enabled by default
+ on all ERTS internal memory allocators based on the
+ <seealso
+ marker="erts_alloc#alloc_util"><c>alloc_util</c></seealso>
+ framework except for <c>temp_alloc</c>. That is, <seealso
+ marker="erts_alloc#M_acul"><c>+M&lt;S&gt;acul
+ de</c></seealso> is default for these allocators. Note
+ that this also implies changed allocation strategies for
+ all of these allocators. They will all now use the
+ "address order first fit carrier best fit" strategy.</p>
+ <p>
+ By passing <c>+Muacul 0</c> on the command line, all
+ configuration changes made by this change will be
+ reverted.</p>
+ <p>
+ Characteristics impact: Improved memory characteristics
+ with a smaller memory footprint at the expense of a quite
+ small performance cost.</p>
+ <p>
+ Own Id: OTP-11604 Aux Id: OTP-10279 </p>
+ </item>
+ <item>
+ <p>A clarification has been added to the documentation of
+ <c>-on_load()</c> in the Reference Manual that it is only
+ recommended for loading NIF libraries.</p>
+ <p>
+ Own Id: OTP-11611</p>
+ </item>
+ <item>
+ <p><c>+fnaw</c> is now default when starting the
+ emulator; it used to be <c>+fnl</c>.</p>
+ <p>
+ *** POTENTIAL INCOMPATIBILITY ***</p>
+ <p>
+ Own Id: OTP-11612</p>
+ </item>
+ <item>
+ <p>
+ EEP43: New data type - Maps</p>
+ <p>
+ With Maps you may for instance: <taglist> <item><c>M0 =
+ #{ a =&gt; 1, b =&gt; 2}, % create
+ associations</c></item> <item><c>M1 = M0#{ a := 10 }, %
+ update values</c></item> <item><c>M2 = M1#{ "hi" =&gt;
+ "hello"}, % add new associations</c></item> <item><c>#{
+ "hi" := V1, a := V2, b := V3} = M2. % match keys with
+ values</c></item> </taglist></p>
+ <p>
+ For information on how to use Maps please see the
+ <seealso marker="doc/reference_manual:maps">Reference
+ Manual</seealso>.</p>
+ <p>
+ The current implementation is without the following
+ features: <taglist> <item>No variable keys</item>
+ <item>No single value access</item> <item>No map
+ comprehensions</item> </taglist></p>
+ <p>
+ Note that Maps is <em>experimental</em> during OTP 17.0.</p>
+ <p>
+ Own Id: OTP-11616</p>
+ </item>
+ <item>
+ <p>
+ The previously deprecated driver API function
+ <c>driver_async_cancel()</c> has been removed. Due to
+ this, the driver API version has been bumped to 3.0.</p>
+ <p>
+ Thanks to Steve Vinoski.</p>
+ <p>
+ *** POTENTIAL INCOMPATIBILITY ***</p>
+ <p>
+ Own Id: OTP-11628</p>
+ </item>
+ <item>
+ <p>
+ Experimental "dirty scheduler" functionality has been
+ introduced. In order to try the functionality out, you
+ need to pass the command line argument
+ <c>--enable-dirty-schedulers</c> to <c>configure</c> when
+ building the system.</p>
+ <p>
+ Dirty schedulers can currently only be used by NIFs on a
+ system with SMP support. More information can be found in
+ the <seealso
+ marker="erl_nif#dirty_nifs"><c>erl_nif(3)</c></seealso>
+ documentation, the <seealso
+ marker="erl"><c>erl(1)</c></seealso> documentation, and
+ in the git commit comment of commit
+ 'c1c03ae4ee50e58b7669ea88ec4d29c6b2b67c7b'.</p>
+ <p>
+ Note that the functionality is <em>experimental</em>, and
+ <em>not supported</em>. This functionality <em>will</em>
+ be subject to backward incompatible changes. You should
+ <em>not</em> enable the dirty scheduler functionality on
+ production systems. It is only provided for testing.</p>
+ <p>
+ Thanks to Steve Vinoski.</p>
+ <p>
+ Own Id: OTP-11629</p>
+ </item>
+ <item>
+ <p>
+ Improve reduction cost and yielding of
+ <c>term_to_binary</c>. The reduction cost is increased
+ and garbage collection is disabled during yield.</p>
+ <p>
+ Impact: Improves system responsiveness when
+ <c>term_to_binary</c> is called with large terms without
+ significant degradation of single threaded performance.</p>
+ <p>
+ Own Id: OTP-11648 Aux Id: OTP-11388 </p>
+ </item>
+ <item>
+ <p>
+ By default, the system's version of zlib will be used,
+ provided its version is 1.2.4 or higher; otherwise the
+ built-in zlib will be used. The built-in version of zlib
+ has been bumped to 1.2.8. (Use the
+ <c>--enable-builtin-zlib</c> option to <c>configure</c>
+ to force the use of the built-in zlib.)</p>
+ <p>
+ Own Id: OTP-11669</p>
+ </item>
+ <item>
+ <p>
+ The default float encoding in binary_to_term and
+ external_size has been changed to use minor_mode 1
+ instead of 0.</p>
+ <p>
+ *** POTENTIAL INCOMPATIBILITY ***</p>
+ <p>
+ Own Id: OTP-11738</p>
+ </item>
+ <item>
+ <p>
+ Introduced the <c>configure</c> option
+ <c>--with-assumed-cache-line-size=SIZE</c>. For more
+ information see <seealso
+ marker="doc/installation_guide:INSTALL"><c>$ERL_TOP/HOWTO/INSTALL.md</c></seealso>.</p>
+ <p>
+ Own Id: OTP-11742</p>
+ </item>
+ <item>
+ <p>
+ Halfword emulator is marked as deprecated. It still works
+ as before but is planned to be removed in a future major
+ release.</p>
+ <p>
+ Own Id: OTP-11777</p>
+ </item>
+ <item>
+ <p>
+ The external format for Maps has changed in a way that is
+ not compatible with the format used in OTP 17.0-rc1 and
+ OTP 17.0-rc2.</p>
+ <p>
+ *** POTENTIAL INCOMPATIBILITY ***</p>
+ <p>
+ Own Id: OTP-11782</p>
+ </item>
+ <item>
+ <p>
+ Fixed faulty make dependency that would make some make
+ versions fail while building gen_git_version.mk.</p>
+ <p>
+ Own Id: OTP-11784</p>
+ </item>
+ <item>
+ <p>
+ Introduced functionality for allowing old drivers and NIF
+ libraries to be loaded during a transition period. For
+ more information see <seealso
+ marker="erts:erl_driver#version_management">the version
+ management section in the <c>erl_driver(3)</c>
+ documentation</seealso> and <seealso
+ marker="erts:erl_nif#version_management">the version
+ management section in the <c>erl_nif(3)</c>
+ documentation</seealso>.</p>
+ <p>
+ Own Id: OTP-11799</p>
+ </item>
+ <item>
+ <p>
+ Support file paths longer than 259 characters on Windows.
+ Long absolute paths are automatically converted to UNC
+ format with a <c>\\?\</c> prefix which is the only way to
+ represent long paths. The 259 character limit still
+ applies for individual file names, relative paths and the
+ current working directory.</p>
+ <p>
+ Own Id: OTP-11813</p>
+ </item>
+ <item>
+ <p>
+ Document that escript:create/2 also accepts a 3-elements
+ tuple containing files and zip:create/3 options to build
+ a zip file.</p>
+ <p>
+ Thanks to Pierre Fenoll</p>
+ <p>
+ Own Id: OTP-11827</p>
+ </item>
+ <item>
+ <p>
+ Add systemd socket activation for epmd.</p>
+ <p>
+ Thanks to Matwey V. Kornilov</p>
+ <p>
+ Own Id: OTP-11829</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>Erts 5.10.4</title>
<section><title>Fixed Bugs and Malfunctions</title>
diff --git a/erts/emulator/Makefile.in b/erts/emulator/Makefile.in
index 58639c7190..7145824f91 100644
--- a/erts/emulator/Makefile.in
+++ b/erts/emulator/Makefile.in
@@ -1039,7 +1039,6 @@ $(BINDIR)/$(EMULATOR_EXECUTABLE): $(INIT_OBJS) $(OBJS) $(DEPLIBS) $(LCF)
else
$(BINDIR)/$(EMULATOR_EXECUTABLE): $(INIT_OBJS) $(OBJS) $(DEPLIBS)
- echo $(DEPLIBS)
$(ld_verbose)$(PURIFY) $(LD) -o $(BINDIR)/$(EMULATOR_EXECUTABLE) \
$(HIPEBEAMLDFLAGS) $(LDFLAGS) $(DEXPORT) $(INIT_OBJS) $(OBJS) \
$(STATIC_NIF_LIBS) $(STATIC_DRIVER_LIBS) $(LIBS)
diff --git a/erts/emulator/beam/beam_emu.c b/erts/emulator/beam/beam_emu.c
index 9634faff1d..1026e5f649 100644
--- a/erts/emulator/beam/beam_emu.c
+++ b/erts/emulator/beam/beam_emu.c
@@ -3525,7 +3525,7 @@ get_map_elements_fail:
erts_post_nif(&env);
#ifdef ERTS_DIRTY_SCHEDULERS
if (is_non_value(nif_bif_result) && c_p->freason == TRAP) {
- Export* ep = (Export*) c_p->psd->data[ERTS_PSD_DIRTY_SCHED_TRAP_EXPORT];
+ Export* ep = ERTS_PROC_GET_DIRTY_SCHED_TRAP_EXPORT(c_p);
ep->code[0] = I[-3];
ep->code[1] = I[-2];
}
diff --git a/erts/emulator/beam/erl_nif.c b/erts/emulator/beam/erl_nif.c
index 063dba056e..ff551ea3af 100644
--- a/erts/emulator/beam/erl_nif.c
+++ b/erts/emulator/beam/erl_nif.c
@@ -1515,26 +1515,35 @@ int enif_consume_timeslice(ErlNifEnv* env, int percent)
#ifdef ERTS_DIRTY_SCHEDULERS
+/* NIFs exports need one more item than the Export struct provides, the
+ * erl_module_nif*, so the DirtyNifExport below adds that. The Export
+ * member must be first in the struct.
+ */
+typedef struct {
+ Export exp;
+ struct erl_module_nif* m;
+} DirtyNifExport;
+
static void
-alloc_proc_psd(Process* proc, Export **ep)
+alloc_proc_psd(Process* proc, DirtyNifExport **ep)
{
int i;
if (!*ep) {
- *ep = erts_alloc(ERTS_ALC_T_PSD, sizeof(Export));
- sys_memset((void*) *ep, 0, sizeof(Export));
+ *ep = erts_alloc(ERTS_ALC_T_PSD, sizeof(DirtyNifExport));
+ sys_memset((void*) *ep, 0, sizeof(DirtyNifExport));
for (i=0; i<ERTS_NUM_CODE_IX; i++) {
- (*ep)->addressv[i] = &(*ep)->code[3];
+ (*ep)->exp.addressv[i] = &(*ep)->exp.code[3];
}
- (*ep)->code[3] = (BeamInstr) em_call_nif;
+ (*ep)->exp.code[3] = (BeamInstr) em_call_nif;
}
- (void) ERTS_PROC_SET_DIRTY_SCHED_TRAP_EXPORT(proc, ERTS_PROC_LOCK_MAIN, *ep);
+ (void) ERTS_PROC_SET_DIRTY_SCHED_TRAP_EXPORT(proc, ERTS_PROC_LOCK_MAIN, &(*ep)->exp);
}
static ERL_NIF_TERM
execute_dirty_nif_finalizer(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{
Eterm* reg = ERTS_PROC_GET_SCHDATA(env->proc)->x_reg_array;
- ERL_NIF_TERM result = (ERL_NIF_TERM) reg[0];
+ ERL_NIF_TERM result, dirty_result = (ERL_NIF_TERM) reg[0];
typedef ERL_NIF_TERM (*FinalizerFP)(ErlNifEnv*, ERL_NIF_TERM);
FinalizerFP fp;
#if HAVE_INT64 && SIZEOF_LONG != 8
@@ -1544,7 +1553,11 @@ execute_dirty_nif_finalizer(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
ASSERT(sizeof(fp) <= sizeof(unsigned long));
enif_get_ulong(env, reg[1], (unsigned long *) &fp);
#endif
- return (*fp)(env, result);
+ result = (*fp)(env, dirty_result);
+ if (erts_refc_dectest(&env->mod_nif->rt_dtor_cnt, 0) == 0
+ && env->mod_nif->mod == NULL)
+ close_lib(env->mod_nif);
+ return result;
}
#endif /* ERTS_DIRTY_SCHEDULERS */
@@ -1560,7 +1573,7 @@ enif_schedule_dirty_nif(ErlNifEnv* env, int flags,
erts_aint32_t state, n, a;
Process* proc = env->proc;
Eterm* reg = ERTS_PROC_GET_SCHDATA(proc)->x_reg_array;
- Export* ep = NULL;
+ DirtyNifExport* ep = NULL;
int i;
int chkflgs = (flags & (ERL_NIF_DIRTY_JOB_IO_BOUND|ERL_NIF_DIRTY_JOB_CPU_BOUND));
@@ -1585,17 +1598,20 @@ enif_schedule_dirty_nif(ErlNifEnv* env, int flags,
if (a == state)
break;
}
- if (!(ep = ERTS_PROC_GET_DIRTY_SCHED_TRAP_EXPORT(proc)))
+ if (!(ep = (DirtyNifExport*) ERTS_PROC_GET_DIRTY_SCHED_TRAP_EXPORT(proc)))
alloc_proc_psd(proc, &ep);
ERTS_VBUMP_ALL_REDS(proc);
- ep->code[2] = argc;
+ ep->exp.code[2] = argc;
for (i = 0; i < argc; i++) {
reg[i] = (Eterm) argv[i];
}
- proc->i = (BeamInstr*) ep->addressv[0];
- ep->code[4] = (BeamInstr) fp;
+ proc->i = (BeamInstr*) ep->exp.addressv[0];
+ ep->exp.code[4] = (BeamInstr) fp;
+ ep->m = env->mod_nif;
proc->freason = TRAP;
+ erts_refc_inc(&env->mod_nif->rt_dtor_cnt, 1);
+
return THE_NON_VALUE;
#else
return (*fp)(env, argc, argv);
@@ -1609,17 +1625,17 @@ enif_schedule_dirty_nif_finalizer(ErlNifEnv* env, ERL_NIF_TERM result,
#ifdef USE_THREADS
Process* proc = env->proc;
Eterm* reg = ERTS_PROC_GET_SCHDATA(proc)->x_reg_array;
- Export* ep;
+ DirtyNifExport* ep;
erts_smp_atomic32_read_band_mb(&proc->state,
~(ERTS_PSFLG_DIRTY_CPU_PROC
|ERTS_PSFLG_DIRTY_IO_PROC
|ERTS_PSFLG_DIRTY_CPU_PROC_IN_Q
|ERTS_PSFLG_DIRTY_IO_PROC_IN_Q));
- if (!(ep = ERTS_PROC_GET_DIRTY_SCHED_TRAP_EXPORT(proc)))
+ if (!(ep = (DirtyNifExport*) ERTS_PROC_GET_DIRTY_SCHED_TRAP_EXPORT(proc)))
alloc_proc_psd(proc, &ep);
ERTS_VBUMP_ALL_REDS(proc);
- ep->code[2] = 2;
+ ep->exp.code[2] = 2;
reg[0] = (Eterm) result;
#if HAVE_INT64 && SIZEOF_LONG != 8
ASSERT(sizeof(fp) <= sizeof(ErlNifUInt64));
@@ -1628,8 +1644,8 @@ enif_schedule_dirty_nif_finalizer(ErlNifEnv* env, ERL_NIF_TERM result,
ASSERT(sizeof(fp) <= sizeof(unsigned long));
reg[1] = (Eterm) enif_make_ulong(env, (unsigned long) fp);
#endif
- proc->i = (BeamInstr*) ep->addressv[0];
- ep->code[4] = (BeamInstr) execute_dirty_nif_finalizer;
+ proc->i = (BeamInstr*) ep->exp.addressv[0];
+ ep->exp.code[4] = (BeamInstr) execute_dirty_nif_finalizer;
proc->freason = TRAP;
return THE_NON_VALUE;
diff --git a/erts/emulator/beam/erl_process.c b/erts/emulator/beam/erl_process.c
index baca73f7f6..3130b207e1 100644
--- a/erts/emulator/beam/erl_process.c
+++ b/erts/emulator/beam/erl_process.c
@@ -9214,7 +9214,6 @@ Process *schedule(Process *p, int calls)
*/
pick_next_process: {
erts_aint32_t psflg_band_mask;
- erts_aint32_t running_flag;
int prio_q;
int qmask;
@@ -9276,12 +9275,6 @@ Process *schedule(Process *p, int calls)
state = erts_smp_atomic32_read_nob(&p->state);
}
-
- if (state & ERTS_PSFLG_ACTIVE_SYS)
- running_flag = ERTS_PSFLG_RUNNING_SYS;
- else
- running_flag = ERTS_PSFLG_RUNNING;
-
while (1) {
erts_aint32_t exp, new, tmp;
tmp = new = exp = state;
@@ -9291,8 +9284,12 @@ Process *schedule(Process *p, int calls)
tmp = state & (ERTS_PSFLG_SUSPENDED
| ERTS_PSFLG_PENDING_EXIT
| ERTS_PSFLG_ACTIVE_SYS);
- if (tmp != ERTS_PSFLG_SUSPENDED)
- new |= running_flag;
+ if (tmp != ERTS_PSFLG_SUSPENDED) {
+ if (state & ERTS_PSFLG_ACTIVE_SYS)
+ new |= ERTS_PSFLG_RUNNING_SYS;
+ else
+ new |= ERTS_PSFLG_RUNNING;
+ }
}
state = erts_smp_atomic32_cmpxchg_relb(&p->state, new, exp);
if (state == exp) {
diff --git a/erts/emulator/beam/erl_term.h b/erts/emulator/beam/erl_term.h
index f10a3a9d38..37014ccf94 100644
--- a/erts/emulator/beam/erl_term.h
+++ b/erts/emulator/beam/erl_term.h
@@ -112,11 +112,11 @@ struct erl_node_; /* Declared in erl_node_tables.h */
* 1000 REFC_BINARY | |
* 1001 HEAP_BINARY | BINARIES |
* 1010 SUB_BINARY | |
- * 1011 Not used
+ * 1011 Not used; see comment below
* 1100 EXTERNAL_PID | |
* 1101 EXTERNAL_PORT | EXTERNAL THINGS |
* 1110 EXTERNAL_REF | |
- * 1111 Not used
+ * 1111 MAP
*
* COMMENTS:
*
@@ -140,10 +140,11 @@ struct erl_node_; /* Declared in erl_node_tables.h */
#define REFC_BINARY_SUBTAG (0x8 << _TAG_PRIMARY_SIZE) /* BINARY */
#define HEAP_BINARY_SUBTAG (0x9 << _TAG_PRIMARY_SIZE) /* BINARY */
#define SUB_BINARY_SUBTAG (0xA << _TAG_PRIMARY_SIZE) /* BINARY */
-#define MAP_SUBTAG (0xB << _TAG_PRIMARY_SIZE) /* MAP */
+/* _BINARY_XXX_MASK depends on 0xB being unused */
#define EXTERNAL_PID_SUBTAG (0xC << _TAG_PRIMARY_SIZE) /* EXTERNAL_PID */
#define EXTERNAL_PORT_SUBTAG (0xD << _TAG_PRIMARY_SIZE) /* EXTERNAL_PORT */
#define EXTERNAL_REF_SUBTAG (0xE << _TAG_PRIMARY_SIZE) /* EXTERNAL_REF */
+#define MAP_SUBTAG (0xF << _TAG_PRIMARY_SIZE) /* MAP */
#define _TAG_HEADER_ARITYVAL (TAG_PRIMARY_HEADER|ARITYVAL_SUBTAG)
@@ -156,11 +157,11 @@ struct erl_node_; /* Declared in erl_node_tables.h */
#define _TAG_HEADER_REFC_BIN (TAG_PRIMARY_HEADER|REFC_BINARY_SUBTAG)
#define _TAG_HEADER_HEAP_BIN (TAG_PRIMARY_HEADER|HEAP_BINARY_SUBTAG)
#define _TAG_HEADER_SUB_BIN (TAG_PRIMARY_HEADER|SUB_BINARY_SUBTAG)
-#define _TAG_HEADER_MAP (TAG_PRIMARY_HEADER|MAP_SUBTAG)
#define _TAG_HEADER_EXTERNAL_PID (TAG_PRIMARY_HEADER|EXTERNAL_PID_SUBTAG)
#define _TAG_HEADER_EXTERNAL_PORT (TAG_PRIMARY_HEADER|EXTERNAL_PORT_SUBTAG)
#define _TAG_HEADER_EXTERNAL_REF (TAG_PRIMARY_HEADER|EXTERNAL_REF_SUBTAG)
#define _TAG_HEADER_BIN_MATCHSTATE (TAG_PRIMARY_HEADER|BIN_MATCHSTATE_SUBTAG)
+#define _TAG_HEADER_MAP (TAG_PRIMARY_HEADER|MAP_SUBTAG)
#define _TAG_HEADER_MASK 0x3F
@@ -892,7 +893,8 @@ typedef struct external_thing_ {
(((x) & _TAG_HEADER_MASK) == _TAG_HEADER_EXTERNAL_REF)
#define is_external_header(x) \
- (((x) & (_TAG_HEADER_MASK-_BINARY_XXX_MASK)) == _TAG_HEADER_EXTERNAL_PID)
+ (((x) & (_TAG_HEADER_MASK-_BINARY_XXX_MASK)) == _TAG_HEADER_EXTERNAL_PID \
+ && ((x) & _TAG_HEADER_MASK) != _TAG_HEADER_MAP)
#define is_external(x) (is_boxed((x)) && is_external_header(*boxed_val((x))))
diff --git a/erts/emulator/beam/erl_trace.c b/erts/emulator/beam/erl_trace.c
index 305058ceff..ea5c850a30 100644
--- a/erts/emulator/beam/erl_trace.c
+++ b/erts/emulator/beam/erl_trace.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 1999-2013. All Rights Reserved.
+ * Copyright Ericsson AB 1999-2014. All Rights Reserved.
*
* The contents of this file are subject to the Erlang Public License,
* Version 1.1, (the "License"); you may not use this file except in
@@ -2524,7 +2524,7 @@ monitor_large_heap(Process *p) {
#ifndef ERTS_SMP
ASSERT(is_internal_pid(system_monitor));
monitor_p = erts_proc_lookup(system_monitor);
- if (monitor_p || p == monitor_p) {
+ if (!monitor_p || p == monitor_p) {
return;
}
#endif
diff --git a/erts/emulator/test/binary_SUITE.erl b/erts/emulator/test/binary_SUITE.erl
index 938aac6a0e..7aba367e33 100644
--- a/erts/emulator/test/binary_SUITE.erl
+++ b/erts/emulator/test/binary_SUITE.erl
@@ -64,7 +64,7 @@
-export([sleeper/0,trapping_loop/4]).
suite() -> [{ct_hooks,[ts_install_cth]},
- {timetrap,{minutes,2}}].
+ {timetrap,{minutes,4}}].
all() ->
[copy_terms, conversions, deep_lists, deep_bitstr_lists,
@@ -1266,7 +1266,7 @@ deep(Config) when is_list(Config) ->
deep_roundtrip(T) ->
B = term_to_binary(T),
- T = binary_to_term_stress(B).
+ T = binary_to_term(B).
obsolete_funs(Config) when is_list(Config) ->
erts_debug:set_internal_state(available_internal_state, true),
diff --git a/erts/emulator/test/match_spec_SUITE.erl b/erts/emulator/test/match_spec_SUITE.erl
index 330bef7104..fdce157abc 100644
--- a/erts/emulator/test/match_spec_SUITE.erl
+++ b/erts/emulator/test/match_spec_SUITE.erl
@@ -42,7 +42,7 @@
-export([init_per_testcase/2, end_per_testcase/2]).
init_per_testcase(Func, Config) when is_atom(Func), is_list(Config) ->
- Dog=?t:timetrap(?t:seconds(10)),
+ Dog=?t:timetrap(?t:seconds(30)),
[{watchdog, Dog}|Config].
end_per_testcase(_Func, Config) ->
@@ -1009,12 +1009,14 @@ loop_runner(Collector, Fun, Laps) ->
end,
loop_runner_cont(Collector, Fun, 0, Laps).
-loop_runner_cont(_Collector, _Fun, Laps, Laps) ->
+loop_runner_cont(Collector, _Fun, Laps, Laps) ->
receive
- {done, Collector} ->
- io:format("loop_runner ~p exit after ~p laps\n", [self(), Laps]),
- Collector ! {gone, self()}
- end;
+ {done, Collector} -> ok;
+ {abort, Collector} -> ok
+ end,
+ io:format("loop_runner ~p exit after ~p laps\n", [self(), Laps]),
+ Collector ! {gone, self()};
+
loop_runner_cont(Collector, Fun, N, Laps) ->
Fun(),
receive
diff --git a/erts/emulator/test/port_SUITE.erl b/erts/emulator/test/port_SUITE.erl
index 202a8b7537..e01b2f253b 100644
--- a/erts/emulator/test/port_SUITE.erl
+++ b/erts/emulator/test/port_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2013. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2014. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -1698,12 +1698,13 @@ otp_5119(Config) when is_list(Config) ->
Path = ?config(data_dir, Config),
ok = load_driver(Path, "exit_drv"),
PI1 = port_ix(otp_5119_fill_empty_port_tab([])),
- PI2 = port_ix(erlang:open_port({spawn, "exit_drv"}, [])),
+ Port2 = erlang:open_port({spawn, "exit_drv"}, []),
+ PI2 = port_ix(Port2),
{PortIx1, PortIx2} = case PI2 > PI1 of
true ->
{PI1, PI2};
false ->
- {port_ix(otp_5119_fill_empty_port_tab([PI2])),
+ {port_ix(otp_5119_fill_empty_port_tab([Port2])),
port_ix(erlang:open_port({spawn, "exit_drv"}, []))}
end,
MaxPorts = max_ports(),
@@ -2318,7 +2319,7 @@ close_deaf_port(Config) when is_list(Config) ->
test_server:timetrap_cancel(Dog),
Res.
-close_deaf_port_1(1000, _) ->
+close_deaf_port_1(200, _) ->
ok;
close_deaf_port_1(N, Cmd) ->
Timeout = integer_to_list(random:uniform(5*1000)),
diff --git a/erts/preloaded/ebin/erl_prim_loader.beam b/erts/preloaded/ebin/erl_prim_loader.beam
index 26f851fd7a..f1e588320b 100644
--- a/erts/preloaded/ebin/erl_prim_loader.beam
+++ b/erts/preloaded/ebin/erl_prim_loader.beam
Binary files differ
diff --git a/erts/preloaded/ebin/erlang.beam b/erts/preloaded/ebin/erlang.beam
index 344176b71b..e19bb370bc 100644
--- a/erts/preloaded/ebin/erlang.beam
+++ b/erts/preloaded/ebin/erlang.beam
Binary files differ
diff --git a/erts/preloaded/ebin/erts_internal.beam b/erts/preloaded/ebin/erts_internal.beam
index bd402f9a98..d41c833e05 100644
--- a/erts/preloaded/ebin/erts_internal.beam
+++ b/erts/preloaded/ebin/erts_internal.beam
Binary files differ
diff --git a/erts/preloaded/ebin/init.beam b/erts/preloaded/ebin/init.beam
index 5d49eed469..7f2d2740e1 100644
--- a/erts/preloaded/ebin/init.beam
+++ b/erts/preloaded/ebin/init.beam
Binary files differ
diff --git a/erts/preloaded/ebin/otp_ring0.beam b/erts/preloaded/ebin/otp_ring0.beam
index 2607739d12..4d22d8bace 100644
--- a/erts/preloaded/ebin/otp_ring0.beam
+++ b/erts/preloaded/ebin/otp_ring0.beam
Binary files differ
diff --git a/erts/preloaded/ebin/prim_eval.beam b/erts/preloaded/ebin/prim_eval.beam
index d665d35ab1..efc8347b6e 100644
--- a/erts/preloaded/ebin/prim_eval.beam
+++ b/erts/preloaded/ebin/prim_eval.beam
Binary files differ
diff --git a/erts/preloaded/ebin/prim_file.beam b/erts/preloaded/ebin/prim_file.beam
index 201252de34..6c49b5185e 100644
--- a/erts/preloaded/ebin/prim_file.beam
+++ b/erts/preloaded/ebin/prim_file.beam
Binary files differ
diff --git a/erts/preloaded/ebin/prim_inet.beam b/erts/preloaded/ebin/prim_inet.beam
index ff8265414e..fe5431c5ff 100644
--- a/erts/preloaded/ebin/prim_inet.beam
+++ b/erts/preloaded/ebin/prim_inet.beam
Binary files differ
diff --git a/erts/preloaded/ebin/prim_zip.beam b/erts/preloaded/ebin/prim_zip.beam
index f80d4a96e5..73be297bbb 100644
--- a/erts/preloaded/ebin/prim_zip.beam
+++ b/erts/preloaded/ebin/prim_zip.beam
Binary files differ
diff --git a/erts/preloaded/ebin/zlib.beam b/erts/preloaded/ebin/zlib.beam
index dba3ec9546..193cebdc31 100644
--- a/erts/preloaded/ebin/zlib.beam
+++ b/erts/preloaded/ebin/zlib.beam
Binary files differ
diff --git a/erts/preloaded/src/erlang.erl b/erts/preloaded/src/erlang.erl
index fbc37bd955..1508eed9ee 100644
--- a/erts/preloaded/src/erlang.erl
+++ b/erts/preloaded/src/erlang.erl
@@ -1745,9 +1745,9 @@ is_pid(_Term) ->
erlang:nif_error(undefined).
%% Shadowed by erl_bif_types: erlang:is_map/1
--spec is_map(Map) -> boolean() when
- Map :: map().
-is_map(_Map) ->
+-spec is_map(Term) -> boolean() when
+ Term :: term().
+is_map(_Term) ->
erlang:nif_error(undefined).
%% Shadowed by erl_bif_types: erlang:is_port/1
@@ -2264,7 +2264,6 @@ tuple_to_list(_Tuple) ->
(modified_timing_level) -> integer() | undefined;
(multi_scheduling) -> disabled | blocked | enabled;
(multi_scheduling_blockers) -> [PID :: pid()];
- (otp_correction_package) -> string();
(otp_release) -> string();
(port_count) -> non_neg_integer();
(port_limit) -> pos_integer();
diff --git a/erts/test/otp_SUITE.erl b/erts/test/otp_SUITE.erl
index cd5cfcbab4..229d10ccee 100644
--- a/erts/test/otp_SUITE.erl
+++ b/erts/test/otp_SUITE.erl
@@ -392,12 +392,18 @@ is_bad_encoding(File) ->
end.
runtime_dependencies(Config) ->
+ %% Ignore applications intentionally not declaring dependencies
+ %% found by xref.
+ IgnoreApps = [diameter],
+
+
%% Verify that (at least) OTP application runtime dependencies found
%% by xref are listed in the runtime_dependencies field of the .app file
%% of each application.
Server = ?config(xref_server, Config),
{ok, AE} = xref:q(Server, "AE"),
SAE = lists:keysort(1, AE),
+ put(ignored_failures, []),
{AppDep, AppDeps} = lists:foldl(fun ({App, App}, Acc) ->
Acc;
({App, Dep}, {undefined, []}) ->
@@ -409,8 +415,45 @@ runtime_dependencies(Config) ->
end,
{undefined, []},
SAE),
- [] = check_apps_deps([AppDep|AppDeps]),
- ok.
+ [] = lists:filter(fun ({missing_runtime_dependency,
+ AppFile,
+ common_test}) ->
+ %% The test_server app is contaminated by
+ %% common_test when run in a source tree. It
+ %% should however *not* be contaminated
+ %% when run in an installation.
+ case {filename:basename(AppFile),
+ is_run_in_src_tree()} of
+ {"test_server.app", true} ->
+ false;
+ _ ->
+ true
+ end;
+ (_) ->
+ true
+ end,
+ check_apps_deps([AppDep|AppDeps], IgnoreApps)),
+ case IgnoreApps of
+ [] ->
+ ok;
+ _ ->
+ Comment = lists:flatten(io_lib:format("Ignored applications: ~p "
+ "Ignored failures: ~p",
+ [IgnoreApps,
+ get(ignored_failures)])),
+ {comment, Comment}
+ end.
+
+is_run_in_src_tree() ->
+ %% At least currently run_erl is not present in <code-root>/bin
+ %% in the source tree, but present in <code-root>/bin of an
+ %% ordinary installation.
+ case file:read_file_info(filename:join([code:root_dir(),
+ "bin",
+ "run_erl"])) of
+ {ok, _} -> false;
+ {error, _} -> true
+ end.
have_rdep(_App, [], _Dep) ->
false;
@@ -424,28 +467,43 @@ have_rdep(App, [RDep | RDeps], Dep) ->
have_rdep(App, RDeps, Dep)
end.
-check_app_deps(_App, _AppFile, _AFDeps, []) ->
+check_app_deps(_App, _AppFile, _AFDeps, [], _IgnoreApps) ->
[];
-check_app_deps(App, AppFile, AFDeps, [XRDep | XRDeps]) ->
- ResOtherDeps = check_app_deps(App, AppFile, AFDeps, XRDeps),
+check_app_deps(App, AppFile, AFDeps, [XRDep | XRDeps], IgnoreApps) ->
+ ResOtherDeps = check_app_deps(App, AppFile, AFDeps, XRDeps, IgnoreApps),
case have_rdep(App, AFDeps, XRDep) of
true ->
ResOtherDeps;
false ->
- [{missing_runtime_dependency, AppFile, XRDep} | ResOtherDeps]
+ Failure = {missing_runtime_dependency, AppFile, XRDep},
+ case lists:member(App, IgnoreApps) of
+ true ->
+ put(ignored_failures, [Failure | get(ignored_failures)]),
+ ResOtherDeps;
+ false ->
+ [Failure | ResOtherDeps]
+ end
end.
-check_apps_deps([]) ->
+check_apps_deps([], _IgnoreApps) ->
[];
-check_apps_deps([{App, Deps}|AppDeps]) ->
- ResOtherApps = check_apps_deps(AppDeps),
+check_apps_deps([{App, Deps}|AppDeps], IgnoreApps) ->
+ ResOtherApps = check_apps_deps(AppDeps, IgnoreApps),
AppFile = code:where_is_file(atom_to_list(App) ++ ".app"),
{ok,[{application, App, Info}]} = file:consult(AppFile),
case lists:keyfind(runtime_dependencies, 1, Info) of
{runtime_dependencies, RDeps} ->
- check_app_deps(App, AppFile, RDeps, Deps) ++ ResOtherApps;
+ check_app_deps(App, AppFile, RDeps, Deps, IgnoreApps)
+ ++ ResOtherApps;
false ->
- [{missing_runtime_dependencies_key, AppFile} | ResOtherApps]
+ Failure = {missing_runtime_dependencies_key, AppFile},
+ case lists:member(App, IgnoreApps) of
+ true ->
+ put(ignored_failures, [Failure | get(ignored_failures)]),
+ ResOtherApps;
+ false ->
+ [Failure | ResOtherApps]
+ end
end.
%%%
diff --git a/erts/vsn.mk b/erts/vsn.mk
index 081fb66398..2e773079f3 100644
--- a/erts/vsn.mk
+++ b/erts/vsn.mk
@@ -17,7 +17,7 @@
# %CopyrightEnd%
#
-VSN = 6.0
+VSN = 6.1
# Port number 4365 in 4.2
# Port number 4366 in 4.3
diff --git a/lib/asn1/doc/src/asn1_ug.xml b/lib/asn1/doc/src/asn1_ug.xml
index ee54fdffd7..020e58c615 100644
--- a/lib/asn1/doc/src/asn1_ug.xml
+++ b/lib/asn1/doc/src/asn1_ug.xml
@@ -34,23 +34,25 @@
<section>
<title>Features</title>
- <p>The Asn1 application provides:
- </p>
+ <p>The Asn1 application provides:</p>
<list type="bulleted">
<item>An ASN.1 compiler for Erlang, which generates encode and
decode functions to be used by Erlang programs sending and
receiving ASN.1 specified data.</item>
<item>Run-time functions used by the generated code.</item>
- <item>The supported encoding rules are:
+ <item>Support for the following encoding rules:
<list>
<item>
Basic Encoding Rules (<em>BER</em>)
</item>
<item>
- Distinguished Encoding Rules (<em>DER</em>), a specialized form of BER that is used in security-conscious applications.
+ Distinguished Encoding Rules (<em>DER</em>), a specialized
+ form of BER that is used in security-conscious
+ applications.
</item>
<item>
- Packed Encoding Rules (<em>PER</em>) both the aligned and unaligned variant.
+ Packed Encoding Rules (<em>PER</em>); both the aligned and
+ unaligned variant.
</item>
</list>
</item>
@@ -59,71 +61,41 @@
<section>
<title>Overview</title>
- <p>ASN.1 (Abstract Syntax Notation 1) is a formal language for describing data structures to be exchanged between distributed computer systems.
- The purpose of ASN.1 is to have
- a platform and programming language independent notation to express
- types using a
- standardized set of rules for the transformation of values of
- a defined type, into a stream of bytes. This stream of bytes
- can then be sent on a communication channel set up by the
- lower layers in the stack of communication protocols e.g.
- TCP/IP or encapsulated within UDP packets. This way, two
- different applications written in two completely different
- programming languages running on different computers with
- different internal representation of data can exchange
- instances of structured data types (instead of exchanging
- bytes or bits). This makes programming faster and easier since no code
- has to be written to process the transport format of the
- data.
- </p>
- <p>To write a network application which processes ASN.1 encoded
- messages, it is prudent and sometimes essential to have a set
- of off-line development tools such as an ASN.1 compiler which
- can generate the encode and decode logic for the specific ASN.1
- data types. It is also necessary to combine this with some
- general language-specific runtime support for ASN.1 encoding and
- decoding.
- </p>
- <p>The ASN.1 compiler must be directed towards a target language
- or a set of closely related languages. This manual describes a
- compiler which is directed towards the functional language
- Erlang. In order to use this compiler, familiarity with the
- language Erlang is essential. Therefore, the runtime support for ASN.1 is
- also closely related to the language Erlang and
- consist of a number of functions, which the
- compiler uses. The types in ASN.1 and how to represent
- values of those types in Erlang are described in this manual.
- </p>
- <p>The following document is structured so that the first part describes
- how to use ASN.1 compiler, and then there are descriptions of all
- the primitive and constructed ASN.1 types and their representation
- in Erlang,
- </p>
+ <p>ASN.1 (Abstract Syntax Notation One) is a formal language for
+ describing data structures to be exchanged between distributed
+ computer systems. The purpose of ASN.1 is to have a platform
+ and programming language independent notation to express types
+ using a standardized set of rules for the transformation of
+ values of a defined type into a stream of bytes. This stream of
+ bytes can then be sent on any type of communication
+ channel. This way, two applications written in different
+ programming languages running on different computers with
+ different internal representation of data can exchange instances
+ of structured data types.</p>
</section>
<section>
<title>Prerequisites</title>
- <p>It is assumed that the reader is familiar with the ASN.1 notation
- as documented in the standard definition [<cite id="X.680"></cite>] which is
- the primary text. It may also be helpful, but not necessary,
- to read the standard definitions
- [<cite id="X.681"></cite>] [<cite id="X.682"></cite>] [<cite id="X.683"></cite>]
- [<cite id="X.690"></cite>] [<cite id="X.691"></cite>]. </p>
- <p>A very good book explaining those reference texts is
- [<cite id="DUBUISSON"></cite>], free to download at
- <url href="http://www.oss.com/asn1/dubuisson.html">http://www.oss.com/asn1/dubuisson.html </url>.
+ <p>It is assumed that the reader is familiar with the ASN.1
+ notation as documented in the standard definition [<cite
+ id="X.680"></cite>] which is the primary text. It may also be
+ helpful, but not necessary, to read the standard definitions
+ [<cite id="X.681"></cite>] [<cite id="X.682"></cite>] [<cite
+ id="X.683"></cite>] [<cite id="X.690"></cite>] [<cite
+ id="X.691"></cite>]. </p>
+ <p>A good book explaining those reference texts is
+ [<cite id="DUBUISSON"></cite>], which is free to download at
+ <url href="http://www.oss.com/asn1/dubuisson.html">http://www.oss.com/asn1/dubuisson.html</url>.
</p>
</section>
<section>
- <title>Capability</title>
+ <title>Capabilities</title>
<p>This application covers all features of ASN.1 up to the 1997
- edition of the specification. In the 2002 edition of ASN.1 a number of
- new features where introduced of which some are supported while
- others are not. For example the
- ECN (Encoding Control Notation) and XML notation are still
- unsupported. Though, the other features of the 2002 edition are
- fully or partly supported as shown below:</p>
+ edition of the specification. In the 2002 edition of ASN.1 a
+ number of new features were introduced. The following features
+ of the 2002 edition are fully or partly supported as shown
+ below:</p>
<list type="bulleted">
<item>
<p>Decimal notation (e.g., "1.5e3") for REAL values. The
@@ -131,7 +103,7 @@
supported.</p>
</item>
<item>
- <p>The RELATIVE-OID type for relative object identifiers are
+ <p>The RELATIVE-OID type for relative object identifiers is
fully supported.</p>
</item>
<item>
@@ -141,16 +113,16 @@
constraint is not a PER-visible constraint.</p>
</item>
<item>
- <p>The subtype constraint by regular expressions (PATTERN) for character string types is parsed when compiling, but no further action is taken. This constraint is not a PER-visible constraint.</p>
+ <p>The subtype constraint by regular expressions (PATTERN)
+ for character string types is parsed when compiling, but no
+ further action is taken. This constraint is not a
+ PER-visible constraint.</p>
</item>
<item>
<p>Multiple-line comments as in C, <c>/* ... */</c>, are
supported.</p>
</item>
</list>
- <p>It should also be added here that the encoding formats
- supported are <em>BER</em>, <em>DER</em>, <em>PER aligned
- basic</em> variant and <em>PER unaligned basic</em> variant.</p>
</section>
</section>
@@ -162,19 +134,17 @@
<title>A First Example</title>
<p>The following example demonstrates the basic functionality used to run
the Erlang ASN.1 compiler.</p>
- <p>First, create a file called <c>People.asn</c> containing the following:</p>
+ <p>Create a file called <c>People.asn</c> containing the following:</p>
<pre>
-People DEFINITIONS IMPLICIT TAGS ::=
-
+People DEFINITIONS AUTOMATIC TAGS ::=
BEGIN
-EXPORTS Person;
-
-Person ::= [PRIVATE 19] SEQUENCE {
- name PrintableString,
- location INTEGER {home(0),field(1),roving(2)},
- age INTEGER OPTIONAL }
+ Person ::= SEQUENCE {
+ name PrintableString,
+ location INTEGER {home(0),field(1),roving(2)},
+ age INTEGER OPTIONAL
+ }
END </pre>
- <p>This file (<c>people.asn</c>) must be compiled before it can be
+ <p>This file (<c>People.asn</c>) must be compiled before it can be
used.
The ASN.1 compiler checks that the syntax is correct and that the
text represents proper ASN.1 code before generating an abstract
@@ -186,14 +156,14 @@ END </pre>
The following shows how the compiler
can be called from the Erlang shell:</p>
<pre>
-1><input>asn1ct:compile("People", [ber]).</input>
+1><input> asn1ct:compile("People", [ber]).</input>
ok
2> </pre>
<p>The <c>verbose</c> option can be given to have information
about the generated files printed:</p>
<pre>
-2><input>asn1ct:compile("People", [ber,verbose]).</input>
+2><input> asn1ct:compile("People", [ber,verbose]).</input>
Erlang ASN.1 compiling "People.asn"
--{generated,"People.asn1db"}--
--{generated,"People.hrl"}--
@@ -201,17 +171,17 @@ Erlang ASN.1 compiling "People.asn"
ok
3> </pre>
- <p>The ASN.1 module People is now accepted and the abstract syntax tree
- is saved in the <c>People.asn1db</c> file, the
- generated Erlang code is compiled using the Erlang compiler and
- loaded into the Erlang runtime system. Now there is a user interface
- for <c>encode/2</c> and <c>decode/2</c> in the module People,
- which is invoked by:
- <br></br>
-<c><![CDATA['People':encode(<Type name>,<Value>),]]></c> <br></br>
-
+ <p>The ASN.1 module <c>People</c> is now accepted and the
+ abstract syntax tree is saved in the <c>People.asn1db</c> file;
+ the generated Erlang code is compiled using the Erlang compiler
+ and loaded into the Erlang run-time system. Now there is an API
+ for <c>encode/2</c> and <c>decode/2</c> in the module
+ <c>People</c>, which is invoked by: <br></br>
+ <c><![CDATA['People':encode(<Type name>, <Value>)]]></c>
+ <br></br>
or <br></br>
-<c><![CDATA['People':decode(<Type name>,<Value>),]]></c></p>
+<c><![CDATA['People':decode(<Type name>, <Value>)]]></c></p>
+
<p>Assume there is a network
application which receives instances of the ASN.1 defined
type Person, modifies and sends them back again:</p>
@@ -234,8 +204,7 @@ receive
constructed and encoded using
<c>'People':encode('Person',Answer)</c> which takes an
instance of a defined ASN.1 type and transforms it to a
- binary according to the BER or PER
- encoding-rules.
+ binary according to the BER or PER encoding rules.
<br></br>
The encoder and the decoder can also be run from
the shell.</p>
@@ -252,13 +221,13 @@ The encoder and the decoder can also be run from
<section>
<title>Module dependencies</title>
- <p>It is common that asn1 modules import defined types, values and
- other entities from another asn1 module.</p>
- <p>Earlier versions of the asn1 compiler required that modules that
+ <p>It is common that ASN.1 modules import defined types, values and
+ other entities from another ASN.1 module.</p>
+ <p>Earlier versions of the ASN.1 compiler required that modules that
were imported from had to be compiled before the module that
- imported. This caused problems when asn1 modules had circular
+ imported. This caused problems when ASN.1 modules had circular
dependencies.</p>
- <p>Now are referenced modules parsed when the compiler finds an
+ <p>Referenced modules are now parsed when the compiler finds an
entity that is imported. There will not be any code generated for
the referenced module. However, the compiled module rely on
that the referenced modules also will be compiled.</p>
@@ -310,7 +279,7 @@ erlc -o ../asnfiles -I ../asnfiles -I /usr/local/standards/asn1 Person.asn
</item>
<tag><c>-I IncludeDir</c></tag>
<item>
- <p>Where to search for <c>.asn1db</c> files and asn1
+ <p>Where to search for <c>.asn1db</c> files and ASN.1
source specs in order to resolve references to other
modules. This option can be repeated many times if there
are several places to search in. The compiler will always
@@ -322,26 +291,26 @@ erlc -o ../asnfiles -I ../asnfiles -I /usr/local/standards/asn1 Person.asn
</item>
<tag><c>+asn1config</c></tag>
<item>
- <p>This functionality works together with the flags
- <c>ber</c>. It enables the
+ <p>This functionality works together with the
+ <c>ber</c> option. It enables the
specialized decodes, see the <seealso marker="asn1_spec">Specialized Decode</seealso> chapter.
</p>
</item>
<tag><c>+undec_rest</c></tag>
<item>
- <p>A buffer that holds a message, being decoded may
- also have some following bytes. Now it is possible to get
- those following bytes returned together with the decoded
- value. If an asn1 spec is compiled with this option a tuple
- <c>{ok,Value,Rest}</c> is returned. <c>Rest</c> may be a
- list or a binary. Earlier versions of the compiler ignored
- those following bytes.</p>
+ <p>A buffer that holds a message being decoded may also have
+ trailing bytes. If those trailing bytes are important they
+ can be returned along with the decoded value by compiling
+ the ASN.1 specification with the <c>+undec_rest</c> option.
+ The return value from the decoder will be
+ <c>{ok,Value,Rest}</c> where <c>Rest</c> is a binary
+ containing the trailing bytes.</p>
</item>
<tag><c>+'Any Erlc Option'</c></tag>
<item>
<p>You may add any option to the Erlang compiler when
compiling the generated Erlang files. Any option
- unrecognised by the asn1 compiler will be passed to the
+ unrecognized by the ASN.1 compiler will be passed to the
Erlang compiler.</p>
</item>
</taglist>
@@ -366,10 +335,6 @@ asn1ct:compile("H323-MESSAGES.asn1",[ber]). </pre>
asn1ct:compile("H323-MESSAGES.asn1",[per]). </pre>
<p>The generic encode and decode functions can be invoked like this:</p>
<pre>
-asn1ct:encode('H323-MESSAGES','SomeChoiceType',{call,"octetstring"}).
-asn1ct:decode('H323-MESSAGES','SomeChoiceType',Bytes). </pre>
- <p>Or, preferable like:</p>
- <pre>
'H323-MESSAGES':encode('SomeChoiceType',{call,"octetstring"}).
'H323-MESSAGES':decode('SomeChoiceType',Bytes). </pre>
</section>
@@ -389,7 +354,7 @@ asn1ct:decode('H323-MESSAGES','SomeChoiceType',Bytes). </pre>
compile time appear on the screen together with
a line number indicating where in the source file the error
was detected. If no errors are found, an Erlang ASN.1 module will
- be created as default.</p>
+ be created.</p>
<p>The run-time encoders and decoders execute within a catch and
returns <c>{ok, Data}</c> or
<c>{error, {asn1, Description}}</c> where
@@ -400,18 +365,18 @@ asn1ct:decode('H323-MESSAGES','SomeChoiceType',Bytes). </pre>
<section>
<marker id="inlineExamples"></marker>
- <title>Multi File Compilation</title>
- <p>There are various reasons for using a multi file compilation:</p>
+ <title>Multi-file Compilation</title>
+ <p>There are various reasons for using multi-file compilation:</p>
<list type="bulleted">
- <item>You want to choose name for the generated module by
- any reason. Maybe you need to compile the same specs for
- different encoding/decoding standards.</item>
+ <item>You want to choose the name for the generated module,
+ perhaps because you need to compile the same specs for
+ different encoding rules.</item>
<item>You want only one resulting module.</item>
</list>
- <p>You need to specify which asn1 specs you will
+ <p>You need to specify which ASN.1 specs you will
compile in a module that must have the extension
<c>.set.asn</c>. You chose name of the module and provide the
- names of the asn1 specs. For instance, if you have the specs
+ names of the ASN.1 specs. For instance, if you have the specs
<c>File1.asn</c>, <c>File2.asn</c> and <c>File3.asn</c> your
module <c>MyModule.set.asn</c> will look like:</p>
<pre>
@@ -422,11 +387,45 @@ File3.asn </pre>
<code type="none">
~> erlc MyModule.set.asn </code>
<p>the result will be one merged module <c>MyModule.erl</c> with
- the generated code from the three asn1 specs.
+ the generated code from the three ASN.1 specs.
</p>
</section>
<section>
+ <title>A quick note about tags</title>
+
+ <p>Tags used to be important for all users of ASN.1, because it
+ was necessary to manually add tags to certain constructs in order
+ for the ASN.1 specification to be valid. Here is an example of
+ an old-style specification:</p>
+
+ <pre>
+Tags DEFINITIONS ::=
+BEGIN
+ Afters ::= CHOICE { cheese [0] IA5String,
+ dessert [1] IA5String }
+END </pre>
+
+ <p>Without the tags (the numbers in square brackets) the ASN.1
+ compiler would refuse to compile the file.</p>
+
+ <p>In 1994 the global tagging mode AUTOMATIC TAGS was introduced.
+ By putting AUTOMATIC TAGS in the module header, the ASN.1 compiler
+ will automatically add tags when needed. Here is the same
+ specification in AUTOMATIC TAGS mode:</p>
+
+ <pre>
+Tags DEFINITIONS AUTOMATIC TAGS ::=
+BEGIN
+ Afters ::= CHOICE { cheese IA5String,
+ dessert IA5String }
+END
+</pre>
+
+ <p>Tags will not be mentioned any more in this manual.</p>
+ </section>
+
+ <section>
<marker id="ASN1Types"></marker>
<title>The ASN.1 Types</title>
<p>This section describes the ASN.1 types including their
@@ -497,7 +496,7 @@ Operational ::= BOOLEAN --ASN.1 definition </pre>
<p>In Erlang code it may look like:</p>
<pre>
Val = true,
-{ok,Bytes}=asn1rt:encode(MyModule,'Operational',Val), </pre>
+{ok,Bytes} = MyModule:encode('Operational', Val), </pre>
<p>Below follows a description of how
values of each type can be represented in Erlang.
</p>
@@ -563,20 +562,18 @@ T6value3 = white
<section>
<marker id="REAL"></marker>
<title>REAL</title>
- <p>In this version reals are not implemented. When they are,
- the following
- ASN.1 type is used:</p>
+ <p>The following ASN.1 type is used for real numbers:</p>
<pre>
R1 ::= REAL
</pre>
- <p>Can be assigned a value in Erlang as:</p>
+ <p>It can be assigned a value in Erlang as:</p>
<pre>
-R1value1 = 2.14,
+R1value1 = "2.14",
R1value2 = {256,10,-2},
</pre>
<p>In the last line note that the tuple {256,10,-2} is the real number
2.56 in a special notation, which will encode faster than simply
- stating the number as 2.56. The arity three tuple is
+ stating the number as <c>"2.56"</c>. The arity three tuple is
<c>{Mantissa,Base,Exponent}</c> i.e. Mantissa * Base^Exponent.</p>
</section>
@@ -736,13 +733,11 @@ O2Val = &lt;&lt;"must be exactly 28 chars...."&gt;&gt;,</pre>
specified for a type are especially important for PER, where
they affect the encoding.
</p>
- <p>Please note that <em>all</em> the Character strings are
- supported and it is possible to use the following ASN.1 type
- definitions:</p>
+ <p>Here are some examples:</p>
<pre>
Digs ::= NumericString (SIZE(1..3))
TextFile ::= IA5String (SIZE(0..64000)) </pre>
- <p>and the following Erlang assignments:</p>
+ <p>with corresponding Erlang assignments:</p>
<pre>
DigsVal1 = "456",
DigsVal2 = "123",
@@ -755,70 +750,86 @@ TextFileVal2 = [88,76,55,44,99,121 .......... a lot of characters here ....]
characters are all represented by quadruples beginning with
three zeros like {0,0,0,65} for the 'A' character. When
decoding a value for these strings the result is a list of
- quadruples, or integers when the value is an ASCII character.
- The following example shows how it works:</p>
- <p>In a file <c>PrimStrings.asn1</c> the type <c>BMP</c> is defined as
- <br></br>
-<c>BMP ::= BMPString</c> then using BER encoding (<c>ber</c>
- option)the input/output format will be:</p>
+ quadruples, or integers when the value is an ASCII character.</p>
+
+ <p>The following example shows how it works. We have the following
+ specification in the file <c>PrimStrings.asn1</c>.</p>
+ <pre>
+PrimStrings DEFINITIONS AUTOMATIC TAGS ::=
+BEGIN
+ BMP ::= BMPString
+END
+ </pre>
+
+ <p>Encoding and decoding some strings:</p>
+
<pre>
-1> <input>{ok,Bytes1} = asn1rt:encode('PrimStrings','BMP',[{0,0,53,53},{0,0,45,56}]).</input>
-{ok,[30,4,"55-8"]}
-2> <input>asn1rt:decode('PrimStrings','BMP',list_to_binary(Bytes1)).</input>
+1> <input>asn1ct:compile('PrimStrings', [ber]).</input>
+ok
+2> <input>{ok,Bytes1} = 'PrimStrings':encode('BMP', [{0,0,53,53},{0,0,45,56}]).</input>
+{ok,&lt;&lt;30,4,53,54,45,56>>}
+3> <input>'PrimStrings':decode('BMP', Bytes1).</input>
{ok,[{0,0,53,53},{0,0,45,56}]}
-3> <input>{ok,Bytes2} = asn1rt:encode('PrimStrings','BMP',[{0,0,53,53},{0,0,0,65}]).</input>
-{ok,[30,4,[53,53,0,65]]}
-4> <input>asn1rt:decode('PrimStrings','BMP',list_to_binary(Bytes2)).</input>
+4> <input>{ok,Bytes2} = 'PrimStrings':encode('BMP', [{0,0,53,53},{0,0,0,65}]).</input>
+{ok,&lt;&lt;30,4,53,53,0,65>>}
+5> <input>'PrimStrings':decode('BMP', Bytes2).</input>
{ok,[{0,0,53,53},65]}
-5> <input>{ok,Bytes3} = asn1rt:encode('PrimStrings','BMP',"BMP string").</input>
-{ok,[30,20,[0,66,0,77,0,80,0,32,0,115,0,116,0,114,0,105,0,110,0,103]]}
-6> <input>asn1rt:decode('PrimStrings','BMP',list_to_binary(Bytes3)).</input>
+6> <input>{ok,Bytes3} = 'PrimStrings':encode('BMP', "BMP string").</input>
+{ok,&lt;&lt;30,20,0,66,0,77,0,80,0,32,0,115,0,116,0,114,0,105,0,110,0,103>>}
+7> <input>'PrimStrings':decode('BMP', Bytes3).</input>
{ok,"BMP string"} </pre>
- <p>The UTF8String is represented in Erlang as a list of integers,
- where each integer represents the unicode value of one
- character. When a value shall be encoded one first has to
- transform it to a UTF8 encoded binary, then it can be encoded by
- asn1. When decoding the result is a UTF8 encoded binary, which
- may be transformed to an integer list. The transformation
- functions, <c>utf8_binary_to_list</c> and
- <c>utf8_list_to_binary</c>, are in the <c>asn1rt</c> module. In
- the example below we assume an asn1 definition <c>UTF ::= UTF8String</c> in a module <c>UTF.asn</c>:</p>
+
+ <p>The UTF8String type is represented as a UTF-8 encoded binary in
+ Erlang. Such binaries can be created directly using the binary syntax
+ or by converting from a list of Unicode code points using the
+ <c>unicode:characters_to_binary/1</c> function.</p>
+
+ <p>Here are some examples showing how UTF-8 encoded binaries can
+ be created and manipulated:</p>
+
+ <pre>
+1> <input>Gs = "Мой маленький Гном".</input>
+[1052,1086,1081,32,1084,1072,1083,1077,1085,1100,1082,1080,
+ 1081,32,1043,1085,1086,1084]
+2> <input>Gbin = unicode:characters_to_binary(Gs).</input>
+&lt;&lt;208,156,208,190,208,185,32,208,188,208,176,208,187,208,
+ 181,208,189,209,140,208,186,208,184,208,185,32,208,147,
+ 208,...>>
+3> <input>Gbin = &lt;&lt;"Мой маленький Гном"/utf8>>.</input>
+&lt;&lt;208,156,208,190,208,185,32,208,188,208,176,208,187,208,
+ 181,208,189,209,140,208,186,208,184,208,185,32,208,147,
+ 208,...>>
+4> <input>Gs = unicode:characters_to_list(Gbin).</input>
+[1052,1086,1081,32,1084,1072,1083,1077,1085,1100,1082,1080,
+ 1081,32,1043,1085,1086,1084]
+ </pre>
+
+ <p>See the <seealso marker="stdlib:unicode">unicode</seealso> module
+ for more details.</p>
+
+ <p>In the following example we will use this ASN.1 specification:</p>
<pre>
-1> <input>asn1ct:compile('UTF',[ber]).</input>
-Erlang ASN.1 version "1.4.3.3" compiling "UTF.asn"
-Compiler Options: [ber]
---{generated,"UTF.asn1db"}--
---{generated,"UTF.erl"}--
+UTF DEFINITIONS AUTOMATIC TAGS ::=
+BEGIN
+ UTF ::= UTF8String
+END
+ </pre>
+
+ <p>Encoding and decoding a string with Unicode characters:</p>
+
+ <pre>
+5> <input>asn1ct:compile('UTF', [ber]).</input>
+ok
+6> <input>{ok,Bytes1} = 'UTF':encode('UTF', &lt;&lt;"Гном"/utf8>>).</input>
+{ok,&lt;&lt;12,8,208,147,208,189,208,190,208,188>>}
+7> <input>{ok,Bin1} = 'UTF':decode('UTF', Bytes1).</input>
+{ok,&lt;&lt;208,147,208,189,208,190,208,188>>}
+8> <input>io:format("~ts\n", [Bin1]).</input>
+Гном
ok
-2> <input>UTF8Val1 = "hello".</input>
-"hello"
-3> <input>{ok,UTF8bin1} = asn1rt:utf8_list_to_binary(UTF8Val1).</input>
-{ok,&lt;&lt;104,101,108,108,111&gt;&gt;}
-4> <input>{ok,B}='UTF':encode('UTF',UTF8bin1).</input>
-{ok,[12,
- 5,
- &lt;&lt;104,101,108,108,111&gt;&gt;]}
-5> <input>Bin = list_to_binary(B).</input>
-&lt;&lt;12,5,104,101,108,108,111&gt;&gt;
-6> <input>{ok,UTF8bin1}='UTF':decode('UTF',Bin).</input>
-{ok,&lt;&lt;104,101,108,108,111&gt;&gt;}
-7> <input>asn1rt:utf8_binary_to_list(UTF8bin1).</input>
-{ok,"hello"}
-8> <input>UTF8Val2 = [16#00,16#100,16#ffff,16#ffffff].</input>
-[0,256,65535,16777215]
-9> <input>{ok,UTF8bin2} = asn1rt:utf8_list_to_binary(UTF8Val2).</input>
-{ok,&lt;&lt;0,196,128,239,191,191,248,191,191,191,191&gt;&gt;}
-10> <input>{ok,B2} = 'UTF':encode('UTF',UTF8bin2).</input>
-{ok,[12,
- 11,
- &lt;&lt;0,196,128,239,191,191,248,191,191,191,191&gt;&gt;]}
-11> <input>Bin2 = list_to_binary(B2).</input>
-&lt;&lt;12,11,0,196,128,239,191,191,248,191,191,191,191&gt;&gt;
-12> <input>{ok,UTF8bin2} = 'UTF':decode('UTF',Bin2).</input>
-{ok,&lt;&lt;0,196,128,239,191,191,248,191,191,191,191&gt;&gt;}
-13> <input>asn1rt:utf8_binary_to_list(UTF8bin2).</input>
-{ok,[0,256,65535,16777215]}
-14> </pre>
+9> <input>unicode:characters_to_list(Bin1).</input>
+[1043,1085,1086,1084]
+ </pre>
</section>
<section>
@@ -853,9 +864,11 @@ OidVal1 = {1,2,55},
<section>
<marker id="Object Descriptor"></marker>
<title>Object Descriptor</title>
- <p>Values of this type can be assigned a value as an ordinary string i.e. <br></br>
+ <p>Values of this type can be assigned a value as an ordinary string
+ like this:</p>
- "This is the value of an Object descriptor"</p>
+ <pre>
+ "This is the value of an Object descriptor"</pre>
</section>
<section>
@@ -898,19 +911,31 @@ Pdu ::= SEQUENCE {
<pre>
MyPdu = #'Pdu'{a=22,b=77.99,c={0,1,2,3,4},d='NULL'}. </pre>
<p>The decode functions will return a record as result when decoding
- a <c>SEQUENCE</c> or a <c>SET</c>.
- <marker id="DEFAULT"></marker>
-</p>
- <p>A <c>SEQUENCE</c> and a <c>SET</c> may contain a component with a
- <c>DEFAULT</c> key word followed by the actual value that is the
- default value. In case of BER encoding it is optional to encode the
- value if it equals the default value. If the application uses the
- atom asn1_DEFAULT as value or if the value is a primitive value
- that equals the default value the encoding omits the bytes for
- this value, which is more efficient and it results in fever
- bytes to send to the receiving application.</p>
- <p>For instance, if the following types exists in a file "File.asn":</p>
+ a <c>SEQUENCE</c> or a <c>SET</c>.</p>
+
+ <p>A <c>SEQUENCE</c> and a <c>SET</c> may contain a component
+ with a <c>DEFAULT</c> key word followed by the actual value that
+ is the default value. The <c>DEFAULT</c> keyword means that the
+ application doing the encoding can omit encoding of the value,
+ thus resulting in fewer bytes to send to the receiving
+ application.</p>
+
+ <p>An application can use the atom <c>asn1_DEFAULT</c> to indicate
+ that the encoding should be omitted for that position in
+ the SEQUENCE.</p>
+
+ <p>Depending on the encoding rules, the encoder may also compare
+ the given value to the default value and automatically omit the
+ encoding if they are equal. How much effort the encoder makes to
+ to compare the values depends on the encoding rules. The DER
+ encoding rules forbids encoding a value equal to the default value,
+ so it has a more thorough and time-consuming comparison than the
+ encoders for the other encoding rules.</p>
+
+ <p>In the following example we will use this ASN.1 specification:</p>
<pre>
+File DEFINITIONS AUTOMATIC TAGS ::=
+BEGIN
Seq1 ::= SEQUENCE {
a INTEGER DEFAULT 1,
b Seq2 DEFAULT {aa TRUE, bb 15}
@@ -920,131 +945,50 @@ Seq2 ::= SEQUENCE {
aa BOOLEAN,
bb INTEGER
}
- </pre>
- <p>Some values and the corresponding encoding in an Erlang terminal
- is shown below:</p>
+
+Seq3 ::= SEQUENCE {
+ bs BIT STRING {a(0), b(1), c(2)} DEFAULT {a, c}
+}
+END </pre>
+ <p>Here is an example where the BER encoder is able to omit encoding
+ of the default values:</p>
<pre>
-1> <input>asn1ct:compile('File').</input>
-Erlang ASN.1 version "1.3.2" compiling "File.asn1"
-Compiler Options: []
---{generated,"File.asn1db"}--
---{generated,"File.hrl"}--
---{generated,"File.erl"}--
+1> <input>asn1ct:compile('File', [ber]).</input>
ok
-2> <input>'File':encode('Seq1',{'Seq1',asn1_DEFAULT,asn1_DEFAULT}).</input>
-{ok,["0",[0],[[],[]]]}
-3> <input>lists:flatten(["0",[0],[[],[]]]).</input>
-[48,0]
-4> <input>'File':encode('Seq1',{'Seq1',1,{'Seq2',true,15}}).</input>
-{ok,["0","\\b",[[],["\\241",[6],[[[128],[1],"\\377"],[[129],[1],[15]]]]]]}
-5> <input>lists:flatten(["0","\\b",[[],["\\241",[6],[[[128],[1],"\\377"],[[129],[1],[15]]]]]]).</input>
-[48,8,161,6,128,1,255,129,1,15]
-6> </pre>
- <p>The result after command line 3, in the example above,shows that the
- encoder omits the encoding of default values when they are specific
- by asn1_DEFAULT. Line 5 shows that even primitive values that equals
- the default value are detected and not encoded. But the constructed
- value of component <c>b</c> in <c>Seq1</c> is not recognized as the
- default value. Checking of default values in <c>BER</c> is not done
- in case of complex values, because it would be to expensive.
- <marker id="DEFAULT DER"></marker>
-</p>
- <p>But, the DER encoding format has stronger requirements regarding
- default values both for SET and SEQUENCE. A more elaborate and time
- expensive check of default values will take place. The following is
- an example with the same types and values as above but with der
- encoding format.</p>
- <pre>
-1> <input>asn1ct:compile('File',[der]).</input>
-Erlang ASN.1 version "1.3.2" compiling "File.asn1"
-Compiler Options: [der]
---{generated,"File.asn1db"}--
---{generated,"File.hrl"}--
---{generated,"File.erl"}--
+2> <input>'File':encode('Seq1', {'Seq1',asn1_DEFAULT,asn1_DEFAULT}).</input>
+{ok,&lt;&lt;48,0>>}
+3> <input>'File':encode('Seq1', {'Seq1',1,{'Seq2',true,15}}).</input>
+{ok,&lt;&lt;48,0>>} </pre>
+
+ <p>And here is an example with a named BIT STRING where the BER
+ encoder will not omit the encoding:</p>
+ <pre>
+4> <input>'File':encode('Seq3', {'Seq3',asn1_DEFAULT).</input>
+{ok,&lt;&lt;48,0>>}
+5> <input>'File':encode('Seq3', {'Seq3',&lt;&lt;16#101:3>>).</input>
+{ok,&lt;&lt;48,4,128,2,5,160>>} </pre>
+
+ <p>The DER encoder will omit the encoding for the same BIT STRING:</p>
+ <pre>
+6> <input>asn1ct:compile('File', [ber,der]).</input>
ok
-2> <input>'File':encode('Seq1',{'Seq1',asn1_DEFAULT,asn1_DEFAULT}).</input>
-{ok,["0",[0],[[],[]]]}
-3> <input>lists:flatten(["0",[0],[[],[]]]).</input>
-[48,0]
-4> <input>'File':encode('Seq1',{'Seq1',1,{'Seq2',true,15}}).</input>
-{ok,["0",[0],[[],[]]]}
-5> <input>lists:flatten(["0",[0],[[],[]]]).</input>
-[48,0]
-6>
- </pre>
- <p>Line 5 shows that even values of constructed types is checked and if
- it equals the default value it will not be encoded.</p>
+7> <input>'File':encode('Seq3', {'Seq3',asn1_DEFAULT).</input>
+{ok,&lt;&lt;48,0>>}
+8> <input>'File':encode('Seq3', {'Seq3',&lt;&lt;16#101:3>>).</input>
+{ok,&lt;&lt;48,0>>} </pre>
</section>
<section>
<marker id="SET"></marker>
<title>SET</title>
- <p>The SET type is an unusual construct and normally the SEQUENCE
- type is more appropriate to use. Set is also inefficient compared with SEQUENCE, as the components can be in any order. Hence, it must be possible
- to distinguish every component in 'SET', both when
- encoding and decoding a value of a type defined to be a SET.
- The tags of all components must be different from each other
- in order to be easily recognizable.</p>
- <p>A SET may be defined as:</p>
- <pre>
-Pdu2 ::= SET {
- a INTEGER,
- b BOOLEAN,
- c ENUMERATED {on(0),off(1)} } </pre>
- <p>A SET is represented as an Erlang record.
- For each SEQUENCE and <c>SET</c> in
- an ASN.1 module an Erlang record declaration is generated. For
- <c>Pdu2</c> above a record is defined like this:</p>
- <pre>
--record('Pdu2',{a, b, c}). </pre>
- <p>The record declarations for a module <c>M</c> are placed in a
- separate <c>M.hrl</c> file.</p>
- <p>Values can be assigned in Erlang as demonstrated below:</p>
- <pre>
-V = #'Pdu2'{a=44,b=false,c=off}. </pre>
- <p>The decode functions will return a record as result when decoding
- a SET.
- </p>
- <p>The difference between SET and SEQUENCE is that the order of
- the components (in the BER encoded format) is undefined for SET
- and defined as the lexical order from the ASN.1 definition for
- SEQUENCE. The ASN.1 compiler for Erlang will always encode a
- SET in the lexical order. The decode routines can handle SET
- components encoded in any order but will always return the
- result as a record. Since all components of the SET must be
- distinguishable both in the encoding phase as well as the
- decoding phase the following type is not allowed in a module
- with EXPLICIT or IMPLICIT as tag-default :</p>
- <p></p>
- <pre>
-Bad ::= SET {i INTEGER,
- j INTEGER } </pre>
- <p>The ASN.1 to Erlang compiler rejects the above type. We
- shall not explain the concept of tag further here, we refer to
- [<cite id="X.680"></cite>].
- </p>
- <p>Encoding of a SET with components with DEFAULT values behaves
- similar as a SEQUENCE, <seealso marker="#DEFAULT">see above</seealso>. The DER encoding format restrictions on DEFAULT
- values is the same for SET as for SEQUENCE, and is supported by
- the compiler, <seealso marker="#DEFAULT DER">see above</seealso>.</p>
- <p>Moreover, in DER the elements of a SET will be sorted. If a
- component is an un-tagged choice the sorting have to take place
- in run-time. This fact emphasizes the following recommendation
- if DER encoding format is used.</p>
- <p>The concept of SET is an unusual
- construct and one cannot think of one single application
- where the set type is essential. (Imagine if someone
- "invented'' the shuffled array in 'C') People tend to think
- that 'SET' sounds nicer and more mathematical than 'SEQUENCE'
- and hence use it when 'SEQUENCE' would have been more
- appropriate. It is also most inefficient, since every correct
- implementation of SET must always be prepared to accept the
- components in any order. So, if possible use SEQUENCE instead
- of SET.</p>
+ <p>In Erlang, the SET type is used exactly as SEQUENCE. Note
+ that if the BER or DER encoding rules are used, decoding a
+ SET is slower than decoding a SEQUENCE because the components
+ must be sorted.</p>
</section>
<section>
- <title>Notes about Extend-ability for SEQUENCE and SET</title>
+ <title>Notes about extensibility for SEQUENCE and SET</title>
<p>When a SEQUENCE or SET contains an extension marker and
extension components like this:</p>
<pre>
@@ -1071,51 +1015,28 @@ SExt ::= SEQUENCE {
<marker id="CHOICE"></marker>
<title>CHOICE</title>
<p>The CHOICE type is a space saver and is similar to the concept of a
- 'union' in the C-language. As with the previous SET-type, the
- tags of all components of a CHOICE need to be distinct. If
- AUTOMATIC TAGS are defined for the module (which is
- preferable) the tags can be omitted completely in the ASN.1
- specification of a CHOICE.
- </p>
+ 'union' in the C language.</p>
<p>Assume:</p>
<pre>
+SomeModuleName DEFINITIONS AUTOMATIC TAGS ::=
+BEGIN
T ::= CHOICE {
- x [0] REAL,
- y [1] INTEGER,
- z [2] OBJECT IDENTIFIER }
- </pre>
+ x REAL,
+ y INTEGER,
+ z OBJECT IDENTIFIER }
+END </pre>
<p>It is then possible to assign values:</p>
<pre>
TVal1 = {y,17},
TVal2 = {z,{0,1,2}},
</pre>
- <p>A CHOICE value is always represented as the tuple
+ <p>A CHOICE value is always represented as the tuple
<c>{ChoiceAlternative, Val}</c> where <c>ChoiceAlternative</c>
- is an atom denoting the selected choice
- alternative.
- </p>
- <p>It is also allowed to have a CHOICE type tagged as follow:</p>
- <p></p>
- <pre>
-C ::= [PRIVATE 111] CHOICE {
- C1,
- C2 }
-
-C1 ::= CHOICE {
- a [0] INTEGER,
- b [1] BOOLEAN }
-
-C2 ::= CHOICE {
- c [2] INTEGER,
- d [3] OCTET STRING } </pre>
- <p>In this case, the top type C appears to have no tags at all in
- its components, however, both C1 and C2 are also defined as
- CHOICE types and they have distinct tags among themselves.
- Hence, the above type C is both legal and allowed.
+ is an atom denoting the selected choice alternative.
</p>
<section>
- <title>Extendable CHOICE</title>
+ <title>Extensible CHOICE</title>
<p>When a CHOICE contains an extension marker and the decoder detects
an unknown alternative of the CHOICE the value is represented as:</p>
<pre>
@@ -1192,26 +1113,29 @@ Arr2Val = ["abc",[14,34,54],"Octets"], </pre>
Where <c>Value</c> may be a value of yet another type T2.</p>
<p>For example:</p>
<pre>
+EmbeddedExample DEFINITIONS AUTOMATIC TAGS ::=
+BEGIN
B ::= SEQUENCE {
a Arr1,
- b [0] T }
+ b T }
Arr1 ::= SET SIZE (5) OF INTEGER (4..9)
T ::= CHOICE {
- x [0] REAL,
- y [1] INTEGER,
- z [2] OBJECT IDENTIFIER } </pre>
- <p>The above example can be assigned like this in Erlang:</p>
+ x REAL,
+ y INTEGER,
+ z OBJECT IDENTIFIER }
+ END </pre>
+ <p>The SEQUENCE b can be encoded like this in Erlang:</p>
<pre>
-V2 = #'B'{a=[4,5,6,7,8], b={x,7.77}}.
- </pre>
+1> 'EmbeddedExample':encode('B', {'B',[4,5,6,7,8],{x,"7.77"}}).
+{ok,&lt;&lt;5,56,0,8,3,55,55,55,46,69,45,50>>} </pre>
</section>
</section>
<section>
<title>Naming of Records in .hrl Files</title>
- <p>When an asn1 specification is compiled all defined types of
+ <p>When an ASN.1 specification is compiled all defined types of
type SET or SEQUENCE will result in a corresponding record in the
generated hrl file. This is because the values for SET/SEQUENCE
as mentioned in sections above are represented as records.</p>
@@ -1227,8 +1151,8 @@ V2 = #'B'{a=[4,5,6,7,8], b={x,7.77}}.
Emb ::= SEQUENCE {
a SEQUENCE OF OCTET STRING,
b SET {
- a [0] INTEGER,
- b [1] INTEGER DEFAULT 66},
+ a INTEGER,
+ b INTEGER DEFAULT 66},
c CHOICE {
a INTEGER,
b FooType } }
@@ -1299,7 +1223,7 @@ PType{T} ::= SEQUENCE{
<p>Types may refer to themselves. Suppose:</p>
<pre>
Rec ::= CHOICE {
- nothing [0] NULL,
+ nothing NULL,
something SEQUENCE {
a INTEGER,
b OCTET STRING,
@@ -1331,7 +1255,7 @@ tt TT ::= {a 77,b {"kalle","kula"}} </pre>
Firstly, it could be used as the value in some DEFAULT component:</p>
<pre>
SS ::= SET {
- s [0] OBJECT IDENTIFIER,
+ s OBJECT IDENTIFIER,
val TT DEFAULT tt } </pre>
<p>It could also be used from inside an Erlang program. If the above ASN.1
code was defined in ASN.1 module <c>Values</c>, then the ASN.1 value
@@ -1365,8 +1289,8 @@ SS ::= SET {
<marker id="Information Object"></marker>
<title>ASN.1 Information Objects (X.681)</title>
<p>Information Object Classes, Information Objects and Information
- Object Sets, (in the following called classes, objects and
- object sets respectively), are defined in the standard
+ Object Sets (in the following called classes, objects and
+ object sets respectively) are defined in the standard
definition [<cite id="X.681"></cite>]. In the following only a brief
explanation is given. </p>
<p>These constructs makes it possible to define open types,
@@ -1435,9 +1359,26 @@ StartMessage ::= SEQUENCE {
<p><c>StartMessage</c> can in the <c>content</c> field be
encoded with a value of any type that an object in the
<c>GENERAL-PROCEDURES</c> object set has in its <c>NEW MESSAGE</c> field. This field refers to a type field
- <c><![CDATA[&amp;Message]]></c> in the class. The <c>msgId</c> field is always
+ <c>&amp;Message</c> in the class. The <c>msgId</c> field is always
encoded as a PrintableString, since the field refers to a fixed type
in the class.</p>
+ <p>In practice, object sets are usually declared to be extensible so
+ so that more objects can be added to the set later. Extensibility is
+ indicated like this:</p>
+ <pre>
+GENERAL-PROCEDURES GENERAL-PROCEDURE ::= {
+ object1 | object2, ...} </pre>
+ <p>When decoding a type that uses an extensible set constraint,
+ there is always the possibility that the value in the UNIQUE
+ field is unknown (i.e. the type has been encoded with a later
+ version of the ASN.1 specification). When that happens, the
+ unencoded data will be returned wrapped in a tuple like this:</p>
+
+ <pre>
+{asn1_OPENTYPE,Binary}</pre>
+ <p>where <c>Binary</c> is an Erlang binary that contains the encoded
+ data. (If the option <c>legacy_erlang_types</c> has been given,
+ just the binary will be returned.)</p>
</section>
<section>
@@ -1466,132 +1407,11 @@ T1 ::= General{PrintableString}
T2 ::= General{BIT STRING}
</pre>
<p>An example of a value that can be encoded as type T1 is {12,"hello"}.</p>
- <p>Observe that the compiler not generates encode/decode functions for
- parameterized types, only for the instances of the parameterized
- types. So, if a file contains the types General{}, T1 and T2 above,
+ <p>Note that the compiler does not generate encode/decode functions for
+ parameterized types, but only for the instances of the parameterized
+ types. Therefore, if a file contains the types General{}, T1 and T2 above,
encode/decode functions will only be generated for T1 and T2.
</p>
</section>
-
- <section>
- <title>Tags</title>
- <p>Every built-in ASN.1 type, except CHOICE and ANY have a universal tag.
- This is a unique number that clearly identifies the type. <br></br>
-
- It is essential for all users of ASN.1 to
- understand all the details about tags.</p>
- <p>Tags are implicitly encoded in the BER encoding as shown below, but
- are hardly not accounted for in the PER encoding. In PER tags are
- used for instance to sort the components of a SET.</p>
- <p>There are four different types of tags.</p>
- <taglist>
- <tag><em>universal</em></tag>
- <item>
- <p>For types whose meaning is the same in all
- applications. Such as integers, sequences and so on; that is, all the built in
- types.</p>
- </item>
- <tag><em>application</em></tag>
- <item>
- <p>For application specific types for example, the types in
- X.400 Message handling service have this sort of tag.</p>
- </item>
- <tag><em>private</em></tag>
- <item>
- <p>For your own private types.</p>
- </item>
- <tag><em>context</em></tag>
- <item>
- <p>This is used to distinguish otherwise indistinguishable
- types in a specific context. For example, if we have two
- components of a
- CHOICE type that are both <c>INTEGER</c> values, there is no
- way for the decoder to
- decipher which component was actually chosen, since both
- components will be
- tagged as <c>INTEGER</c>. When this or similar situations occur,
- one or both of the components should be given a context specific
- to resolve the ambiguity.</p>
- </item>
- </taglist>
- <p>The tag in the case of the 'Apdu' type [PRIVATE 1] is encoded to a
- sequence of bytes making it possible for a
- decoder to look at the (initial) bytes that arrive and determine
- whether the rest of the bytes must be of the type associated
- with that particular sequence of bytes. This means that each
- tag must be uniquely associated with <em>only</em> one ASN.1
- type.
- </p>
- <p>Immediately following the tag is a sequence of bytes
- informing the decoder of the length of the instance. This is
- sometimes referred to as TLV (Tag length value) encoding.
- Hence, the structure of a BER encoded series of bytes is as shown in the table below.</p>
- <p></p>
- <table>
- <row>
- <cell align="left" valign="middle">Tag</cell>
- <cell align="left" valign="middle">Len</cell>
- <cell align="left" valign="middle">Value</cell>
- </row>
- <tcaption>Structure of a BER encoded series of bytes</tcaption>
- </table>
- </section>
-
- <section>
- <title>Encoding Rules</title>
- <p>When the first recommendation on ASN.1 was released 1988 it was
- accompanied with the Basic Encoding Rules, BER, as the only
- alternative for encoding.
- BER is a somewhat verbose protocol. It adopts a so-called TLV (type,
- length, value) approach to encoding in which every element of the
- encoding carries some type information, some length information and
- then the value of that element. Where the element is itself
- structured, then the Value part of the element is itself a series of
- embedded TLV components, to whatever depth is necessary. In summary,
- BER is not a compact encoding but is relatively fast and easy to
- produce.</p>
- <p>The DER (Distinguished Encoding Rule) encoding format was included in
- the standard in 1994. It is a specialized form of BER, which gives
- the encoder the option to encode some entities differently. For
- instance, is the value for TRUE any octet with any bit set to one. But,
- DER does not leave any such choices. The value for TRUE in the DER
- case is encoded as the octet <c>11111111</c>. So, the same value
- encoded by two different DER encoders must result in the same bit
- stream.</p>
- <p>A more compact encoding is achieved with the Packed Encoding
- Rules PER which was introduced together with the revised
- recommendation in 1994. PER takes a rather different approach from
- that taken by BER. The first difference is that the tag part in
- the TLV is omitted from the encodings, and any tags in the
- notation are not encoded. The potential ambiguities are resolved
- as follows:</p>
- <list type="bulleted">
- <item>
- <p>A CHOICE is encoded by first encoding a choice index which
- identifies the chosen
- alternative by its position in the notation.</p>
- </item>
- <item>
- <p>The elements of a SEQUENCE are transmitted in textual
- order. OPTIONAL or DEFAULT elements are preceded by a bit map
- to identify which elements are present. After sorting the
- elements of a SET in the "canonical tag order" as defined in
- X.680 8.6 they are treated as a SEQUENCE regarding OPTIONAL
- and DEFAULT elements. A SET is transferred in the sorted
- order.</p>
- </item>
- </list>
- <p>A second difference is that PER takes full account of the sub-typing
- information in that the encoded bytes are affected by the constraints.
- The BER encoded bytes are unaffected by the constraints.
- PER uses the sub-typing information to for example omit length fields
- whenever possible. </p>
- <p>The run-time functions, sometimes take the constraints into account
- both for BER and PER. For instance are SIZE constrained strings checked.</p>
- <p>There are two variants of PER, <em>aligned</em> and <em>unaligned</em>.
- In summary, PER results in compact encodings which require much more
- computation to produce than BER.
- </p>
- </section>
</chapter>
diff --git a/lib/asn1/doc/src/asn1ct.xml b/lib/asn1/doc/src/asn1ct.xml
index 4d5a1a402a..32ff2d52cf 100644
--- a/lib/asn1/doc/src/asn1ct.xml
+++ b/lib/asn1/doc/src/asn1ct.xml
@@ -45,10 +45,11 @@
<p>By default in OTP 17, the representation of the BIT STRING
and OCTET STRING types as Erlang terms have changed. BIT
STRING values are now Erlang bitstrings and OCTET STRING values
- are binaries. For details see <seealso
- marker="asn1_ug#BIT STRING">BIT STRING</seealso> and <seealso
- marker="asn1_ug#OCTET STRING">OCTET STRING</seealso> in User's
- Guide.</p>
+ are binaries. Also, an undecoded open type will now be wrapped in
+ a <c>asn1_OPENTYPE</c> tuple. For details see <seealso
+ marker="asn1_ug#BIT STRING">BIT STRING</seealso>, <seealso
+ marker="asn1_ug#OCTET STRING">OCTET STRING</seealso>, and
+ <seealso marker="asn1_ug#Information%20Object">ASN.1 Information Objects</seealso> in User's Guide.</p>
<p>To revert to the old representation of the types, use the
<c>legacy_erlang_types</c> option.</p>
</note>
diff --git a/lib/asn1/doc/src/notes.xml b/lib/asn1/doc/src/notes.xml
index ff7962edd9..cb89bb298b 100644
--- a/lib/asn1/doc/src/notes.xml
+++ b/lib/asn1/doc/src/notes.xml
@@ -31,6 +31,112 @@
<p>This document describes the changes made to the asn1 application.</p>
+<section><title>Asn1 3.0</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Subtyping an extensible ENUMERATED would cause an
+ compilation error. (Thanks to Morten Nygaard Ã…snes for
+ reporting this bug.)</p>
+ <p>
+ Own Id: OTP-11700</p>
+ </item>
+ <item>
+ <p>When specifying the value for an OCTET STRING in a
+ specification, the ASN.1 standard clearly states that the
+ value must be either a bstring or an hstring, but NOT a
+ cstring. The ASN.1 compiler will now generate a
+ compilation error if the value of an OCTET STRING is
+ given as a character string.</p>
+ <p>That is, the following example is now illegal:</p>
+ <p><c>string OCTET STRING ::= "Now illegal"</c></p>
+ <p>
+ *** POTENTIAL INCOMPATIBILITY ***</p>
+ <p>
+ Own Id: OTP-11727</p>
+ </item>
+ <item>
+ <p>
+ Application upgrade (appup) files are corrected for the
+ following applications: </p>
+ <p>
+ <c>asn1, common_test, compiler, crypto, debugger,
+ dialyzer, edoc, eldap, erl_docgen, et, eunit, gs, hipe,
+ inets, observer, odbc, os_mon, otp_mibs, parsetools,
+ percept, public_key, reltool, runtime_tools, ssh,
+ syntax_tools, test_server, tools, typer, webtool, wx,
+ xmerl</c></p>
+ <p>
+ A new test utility for testing appup files is added to
+ test_server. This is now used by most applications in
+ OTP.</p>
+ <p>
+ (Thanks to Tobias Schlager)</p>
+ <p>
+ Own Id: OTP-11744</p>
+ </item>
+ </list>
+ </section>
+
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p>
+ By giving --enable-static-{nifs,drivers} to configure it
+ is now possible to statically linking of nifs and drivers
+ to the main Erlang VM binary. At the moment only the asn1
+ and crypto nifs of the Erlang/OTP nifs and drivers have
+ been prepared to be statically linked. For more details
+ see the Installation Guide in the System documentation.</p>
+ <p>
+ Own Id: OTP-11258</p>
+ </item>
+ <item>
+ <p>Code generation for the <c>per</c> and <c>uper</c>
+ backends has been somewhat improved.</p>
+ <p>
+ Own Id: OTP-11573</p>
+ </item>
+ <item>
+ <p>The OCTET STRING and BIT STRING types now have a more
+ natural mapping to Erlang types (binary and bitstring,
+ respectively), which is more efficient and will avoid
+ useless conversions between lists and
+ binaries/bitstrings.</p>
+ <p>This is an incompatible change. To revert to the old
+ mapping to support existing applications, use the
+ <c>legacy_erlang_types</c> option.</p>
+ <p>Impact: There is a potential for better performance,
+ as it is now possible to avoid conversions between lists
+ and binaries both in the generated ASN.1 encode/decode
+ code and in the application itself.</p>
+ <p>
+ *** POTENTIAL INCOMPATIBILITY ***</p>
+ <p>
+ Own Id: OTP-11594</p>
+ </item>
+ <item>
+ <p>All functions in the <c>asn1rt</c> module, as well as
+ <c>asn1ct:decode/3</c> and <c>asn1ct:encode/3</c>, are
+ now deprecated.</p>
+ <p>
+ Own Id: OTP-11731</p>
+ </item>
+ <item>
+ <p>
+ Generated .hrl files are now protected from being
+ included more than once.</p>
+ <p>
+ Own Id: OTP-11804</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>Asn1 2.0.4</title>
<section><title>Fixed Bugs and Malfunctions</title>
diff --git a/lib/common_test/doc/src/ct_hooks.xml b/lib/common_test/doc/src/ct_hooks.xml
index 859ff9df14..cab6dfea51 100644
--- a/lib/common_test/doc/src/ct_hooks.xml
+++ b/lib/common_test/doc/src/ct_hooks.xml
@@ -450,12 +450,15 @@
</func>
<func>
- <name>Module:on_tc_fail(TestcaseName, Reason, CTHState) -&gt;
+ <name>Module:on_tc_fail(TestName, Reason, CTHState) -&gt;
NewCTHState</name>
<fsummary>Called after the CTH scope ends</fsummary>
<type>
- <v>TestcaseName = init_per_suite | end_per_suite |
- init_per_group | end_per_group | atom()</v>
+ <v>TestName = init_per_suite | end_per_suite |
+ {init_per_group,GroupName} | {end_per_group,GroupName} |
+ {FuncName,GroupName} | FuncName</v>
+ <v>FuncName = atom()</v>
+ <v>GroupName = atom()</v>
<v>Reason = term()</v>
<v>CTHState = NewCTHState = term()</v>
</type>
@@ -463,14 +466,16 @@
<desc>
<p> OPTIONAL </p>
- <p>This function is called whenever a testcase fails.
- It is called after the post function has been called for
- the testcase which failed. i.e.
- if init_per_suite fails this function is called after
+ <p>This function is called whenever a test case (or config function)
+ fails. It is called after the post function has been called for
+ the failed test case. I.e. if init_per_suite fails, this function
+ is called after
<seealso marker="#Module:post_init_per_suite-4">
- post_init_per_suite</seealso>, and if a testcase fails it is called
+ post_init_per_suite</seealso>, and if a test case fails, it is called
after <seealso marker="#Module:post_end_per_testcase-4">
- post_end_per_testcase</seealso>.</p>
+ post_end_per_testcase</seealso>. If the failed test case belongs
+ to a test case group, the first argument is a tuple
+ <c>{FuncName,GroupName}</c>, otherwise simply the function name.</p>
<p>The data which comes with the Reason follows the same format as the
<seealso marker="event_handler_chapter#failreason">FailReason
@@ -481,12 +486,14 @@
</func>
<func>
- <name>Module:on_tc_skip(TestcaseName, Reason, CTHState) -&gt;
+ <name>Module:on_tc_skip(TestName, Reason, CTHState) -&gt;
NewCTHState</name>
<fsummary>Called after the CTH scope ends</fsummary>
<type>
- <v>TestcaseName = end_per_suite | {init_per_group,GroupName} |
- {end_per_group,GroupName} | atom()</v>
+ <v>TestName = init_per_suite | end_per_suite |
+ {init_per_group,GroupName} | {end_per_group,GroupName} |
+ {FuncName,GroupName} | FuncName</v>
+ <v>FuncName = atom()</v>
<v>GroupName = atom()</v>
<v>Reason = {tc_auto_skip | tc_user_skip, term()}</v>
<v>CTHState = NewCTHState = term()</v>
@@ -495,14 +502,17 @@
<desc>
<p> OPTIONAL </p>
- <p>This function is called whenever a testcase is skipped.
- It is called after the post function has been called for the
- testcase which was skipped.
- i.e. if init_per_group is skipped this function is called after
- <seealso marker="#Module:post_init_per_suite-4">post_init_per_group
- </seealso>, and if a testcase is skipped it is called after
- <seealso marker="#Module:post_end_per_testcase-4">post_end_per_testcase
- </seealso>.</p>
+ <p>This function is called whenever a test case (or config function)
+ is skipped. It is called after the post function has been called
+ for the skipped test case. I.e. if init_per_group is skipped, this
+ function is called after
+ <seealso marker="#Module:post_init_per_group-4">
+ post_init_per_group</seealso>, and if a test case is skipped,
+ it is called after
+ <seealso marker="#Module:post_end_per_testcase-4">
+ post_end_per_testcase</seealso>. If the skipped test case belongs to a
+ test case group, the first argument is a tuple <c>{FuncName,GroupName}</c>,
+ otherwise simply the function name.</p>
<p>The data which comes with the Reason follows the same format as
<seealso marker="event_handler_chapter#tc_auto_skip">tc_auto_skip
diff --git a/lib/common_test/doc/src/ct_run.xml b/lib/common_test/doc/src/ct_run.xml
index 39259b092a..d8e79ca80e 100644
--- a/lib/common_test/doc/src/ct_run.xml
+++ b/lib/common_test/doc/src/ct_run.xml
@@ -108,6 +108,7 @@
EvHandler2 InitArg2 and .. EvHandlerN InitArgN]
[-include InclDir1 InclDir2 .. InclDirN]
[-no_auto_compile]
+ [-abort_if_missing_suites]
[-muliply_timetraps Multiplier]
[-scale_timetraps]
[-create_priv_dir auto_per_run | auto_per_tc | manual_per_tc]
@@ -144,6 +145,7 @@
EvHandler2 InitArg2 and .. EvHandlerN InitArgN]
[-include InclDir1 InclDir2 .. InclDirN]
[-no_auto_compile]
+ [-abort_if_missing_suites]
[-muliply_timetraps Multiplier]
[-scale_timetraps]
[-create_priv_dir auto_per_run | auto_per_tc | manual_per_tc]
@@ -171,6 +173,7 @@
[-decrypt_key Key] | [-decrypt_file KeyFile]
[-include InclDir1 InclDir2 .. InclDirN]
[-no_auto_compile]
+ [-abort_if_missing_suites]
[-muliply_timetraps Multiplier]
[-scale_timetraps]
[-create_priv_dir auto_per_run | auto_per_tc | manual_per_tc]
diff --git a/lib/common_test/doc/src/event_handler_chapter.xml b/lib/common_test/doc/src/event_handler_chapter.xml
index 47d0ba59fb..45f01c12ec 100644
--- a/lib/common_test/doc/src/event_handler_chapter.xml
+++ b/lib/common_test/doc/src/event_handler_chapter.xml
@@ -227,11 +227,13 @@
<item>
<marker id="tc_auto_skip"></marker>
- <c>#event{name = tc_auto_skip, data = {Suite,Func,Reason}}</c>
+ <c>#event{name = tc_auto_skip, data = {Suite,TestName,Reason}}</c>
<p><c>Suite = atom()</c>, the name of the suite.</p>
- <p><c>Func = atom() | {end_per_group,GroupName}</c>, the name of the test case
- or configuration function.</p>
- <p><c>GroupName = atom()</c>, name of the group.</p>
+ <p><c>TestName = init_per_suite | end_per_suite |
+ {init_per_group,GroupName} | {end_per_group,GroupName} |
+ {FuncName,GroupName} | FuncName</c></p>
+ <p><c>FuncName = atom()</c>, the name of the test case or configuration function.</p>
+ <p><c>GroupName = atom()</c>, the name of the test case group.</p>
<p><c>Reason = {failed,FailReason} |
{require_failed_in_suite0,RequireInfo}</c>,
reason for auto skipping <c>Func</c>.</p>
@@ -252,21 +254,26 @@
<c>init_per_group</c>, a failed <c>require</c> in <c>suite/0</c>, or a failed test case
in a sequence. Note that this event is never received as a result of a test case getting
skipped because of <c>init_per_testcase</c> failing, since that information is carried with
- the <c>tc_done</c> event.
+ the <c>tc_done</c> event. If a failed test case belongs to a test case group, the second
+ data element is a tuple <c>{FuncName,GroupName}</c>, otherwise simply the function name.
</p></item>
-
+
<item>
<marker id="tc_user_skip"></marker>
- <c>#event{name = tc_user_skip, data = {Suite,Func,Comment}}</c>
+ <c>#event{name = tc_user_skip, data = {Suite,TestName,Comment}}</c>
<p><c>Suite = atom()</c>, the name of the suite.</p>
- <p><c>Func = atom() | {end_per_group,GroupName}</c>, the name of the test case
- or configuration function.</p>
- <p><c>GroupName = atom()</c>, name of the group.</p>
+ <p><c>TestName = init_per_suite | end_per_suite |
+ {init_per_group,GroupName} | {end_per_group,GroupName} |
+ {FuncName,GroupName} | FuncName</c></p>
+ <p><c>FuncName = atom()</c>, the name of the test case or configuration function.</p>
+ <p><c>GroupName = atom()</c>, the name of the test case group.</p>
<p><c>Comment = string()</c>, reason for skipping the test case.</p>
<p>This event specifies that a test case has been skipped by the user.
It is only ever received if the skip was declared in a test specification.
Otherwise, user skip information is received as a <c>{skipped,SkipReason}</c>
- result in the <c>tc_done</c> event for the test case.
+ result in the <c>tc_done</c> event for the test case. If a skipped test case belongs
+ to a test case group, the second data element is a tuple <c>{FuncName,GroupName}</c>,
+ otherwise simply the function name.
</p></item>
<item><c>#event{name = test_stats, data = {Ok,Failed,Skipped}}</c>
diff --git a/lib/common_test/doc/src/notes.xml b/lib/common_test/doc/src/notes.xml
index f10d5f85bf..ddfeb0964b 100644
--- a/lib/common_test/doc/src/notes.xml
+++ b/lib/common_test/doc/src/notes.xml
@@ -32,6 +32,184 @@
<file>notes.xml</file>
</header>
+<section><title>Common_Test 1.8</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ The error generated if a test case process received an
+ exit from a linked process while executing
+ init_per_testcase/2, was handled incorrectly by Common
+ Test. The problem has been solved, and Common Test now
+ reports this type of error correctly, with proper error
+ reason and exit location as well.</p>
+ <p>
+ Own Id: OTP-11643</p>
+ </item>
+ <item>
+ <p>
+ Running a parallel test case group with two or more
+ instances of the same test case would result in identical
+ log file names, and one test case instance would
+ overwrite the log file of another. This problem has been
+ solved.</p>
+ <p>
+ Own Id: OTP-11644</p>
+ </item>
+ <item>
+ <p>
+ Application upgrade (appup) files are corrected for the
+ following applications: </p>
+ <p>
+ <c>asn1, common_test, compiler, crypto, debugger,
+ dialyzer, edoc, eldap, erl_docgen, et, eunit, gs, hipe,
+ inets, observer, odbc, os_mon, otp_mibs, parsetools,
+ percept, public_key, reltool, runtime_tools, ssh,
+ syntax_tools, test_server, tools, typer, webtool, wx,
+ xmerl</c></p>
+ <p>
+ A new test utility for testing appup files is added to
+ test_server. This is now used by most applications in
+ OTP.</p>
+ <p>
+ (Thanks to Tobias Schlager)</p>
+ <p>
+ Own Id: OTP-11744</p>
+ </item>
+ <item>
+ <p>
+ The <c>cth_surefire</c> hook would crash in
+ <c>pre_init_per_suite/3</c> if a previous hook returned
+ <c>{skip,Reason}</c> or <c>{fail,Reason}</c> instead of a
+ <c>Config</c> list. This error has been corrected, and
+ <c>cth_surefire</c> will now simply propagate the
+ received <c>InitData</c> value instead.</p>
+ <p>
+ Own Id: OTP-11811</p>
+ </item>
+ <item>
+ <p>
+ Specs of return values are corrected for
+ <c>ct_netconfc:get/2,3</c>,
+ <c>ct_netconfc:get_config/3,4</c>,
+ <c>ct_netconfc:action/2,3</c>,
+ <c>ct_netconfc:send_rpc/2,3</c> and
+ <c>ct_netconfc:send/2,3</c>.</p>
+ <p>
+ Own Id: OTP-11834 Aux Id: seq12574 </p>
+ </item>
+ </list>
+ </section>
+
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p>
+ ct_telnet can now log all communication taking place
+ during a telnet session. Previously, only information
+ about ct_telnet operations and commands, as well as
+ explicitly requested data from the server, was logged.</p>
+ <p>
+ Furthermore, a logging mechanism based on an Error Logger
+ event handler and a dedicated Common Test hook,
+ <c>cth_conn_log</c>, now makes it possible to print data
+ for individual connections to separate log files. Please
+ see the <c>ct_telnet</c> reference manual for more
+ information and examples.</p>
+ <p>
+ Important note: A new argument, <c>ConnName</c> has been
+ added to the <c>unix_telnet:connect/5</c> callback
+ function. This forces users that use private ct_telnet
+ callback modules to update their code according to
+ <c>unix_telnet:connect/6</c>. Please see the
+ <c>unix_telnet</c> reference manual and source code
+ module for details.</p>
+ <p>
+ Own Id: OTP-11440 Aux Id: seq12457 </p>
+ </item>
+ <item>
+ <p>
+ A new timeout option has been introduced for the
+ <c>ct_telnet:expect/3</c> function. With
+ <c>{total_timeout,Time}</c> it's possible to set a time
+ limit for the complete expect operation. After
+ <c>Time</c> milliseconds, <c>expect/3</c> returns
+ <c>{error,timeout}</c>. The default value used if
+ <c>total_timeout</c> is not specified, is infinity (i.e.
+ no time limit). Please see the <c>ct_telnet</c> reference
+ manual for more information.</p>
+ <p>
+ Own Id: OTP-11689</p>
+ </item>
+ <item>
+ <p>
+ Some function specs are corrected or moved and some edoc
+ comments are corrected in order to allow use of edoc.
+ (Thanks to Pierre Fenoll)</p>
+ <p>
+ Own Id: OTP-11702</p>
+ </item>
+ <item>
+ <p>
+ Test case group name information has been added to the
+ data sent with <c>tc_user_skip</c> and
+ <c>tc_auto_skip</c> event messages, as well as the data
+ passed in calls to the CT Hook functions
+ <c>on_tc_skip/3</c> and <c>on_tc_fail/3</c>. The
+ modification only affects the function name
+ element/argument. This value remains an atom if the test
+ case in question does not belong to a test case group.
+ Otherwise a tuple <c>{FuncName,GroupName}</c>
+ (<c>{atom(),atom()}</c>) is passed instead.</p>
+ <p>
+ Note that this change may (depending on the patterns used
+ for matching) require modifications of user event
+ handlers and hook modules. Please see the Event Handling
+ chapter in the Common Test User's Guide, and the
+ reference manual for <c>ct_hooks</c>, for details.</p>
+ <p>
+ Note also that the Test Server framework callback
+ function <c>report/2</c> has been modified. This change
+ only affects users with test frameworks interfacing Test
+ Server rather than Common Test. See the
+ <c>test_server_ctrl</c> reference manual for details.</p>
+ <p>
+ *** POTENTIAL INCOMPATIBILITY ***</p>
+ <p>
+ Own Id: OTP-11732 Aux Id: seq12541 </p>
+ </item>
+ <item>
+ <p>
+ If Common Test can't prompt the user to abort or continue
+ the test run when one or more test suites fail to
+ compile, a new option,
+ <c>{abort_if_missing_suites,Bool}</c>, can be used to
+ specify whether it should proceed with the test run, or
+ stop execution. The default value of <c>Bool</c> is
+ <c>false</c> (i.e. to proceed even if suites are
+ missing).</p>
+ <p>
+ Own Id: OTP-11769</p>
+ </item>
+ </list>
+ </section>
+
+
+ <section><title>Known Bugs and Problems</title>
+ <list>
+ <item>
+ <p>
+ common_test: Fix problems reported by Dialyzer.</p>
+ <p>
+ Own Id: OTP-11525</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>Common_Test 1.7.4</title>
<section><title>Fixed Bugs and Malfunctions</title>
diff --git a/lib/common_test/doc/src/run_test_chapter.xml b/lib/common_test/doc/src/run_test_chapter.xml
index a4a77ee400..864f82cb63 100644
--- a/lib/common_test/doc/src/run_test_chapter.xml
+++ b/lib/common_test/doc/src/run_test_chapter.xml
@@ -59,7 +59,15 @@
<p>If compilation should fail for one or more suites, the compilation errors
are printed to tty and the operator is asked if the test run should proceed
without the missing suites, or be aborted. If the operator chooses to proceed,
- it is noted in the HTML log which tests have missing suites.</p>
+ it is noted in the HTML log which tests have missing suites. If Common Test is
+ unable to prompt the user after compilation failure (if Common Test doesn't
+ control stdin), the test run will proceed automatically without the missing
+ suites. This behaviour can however be modified with the
+ <c><![CDATA[ct_run]]></c> flag <c><![CDATA[-abort_if_missing_suites]]></c>,
+ or the <c><![CDATA[ct:run_test/1]]></c> option
+ <c><![CDATA[{abort_if_missing_suites,TrueOrFalse}]]></c>. If
+ <c><![CDATA[abort_if_missing_suites]]></c> is set (to true), the test run
+ will stop immediately if some suites fail to compile.</p>
<p>Any help module (i.e. regular Erlang module with name not ending with
"_SUITE") that resides in the same test object directory as a suite
@@ -167,6 +175,7 @@
<seealso marker="ct_hooks_chapter#builtin_cths">Built-in Common Test Hooks</seealso>. Default is <c>true</c>.</item>
<item><c><![CDATA[-include]]></c>, specifies include directories (see above).</item>
<item><c><![CDATA[-no_auto_compile]]></c>, disables the automatic test suite compilation feature (see above).</item>
+ <item><c><![CDATA[-abort_if_missing_suites]]></c>, aborts the test run if one or more suites fail to compile (see above).</item>
<item><c><![CDATA[-multiply_timetraps <n>]]></c>, extends <seealso marker="write_test_chapter#timetraps">timetrap
timeout</seealso> values.</item>
<item><c><![CDATA[-scale_timetraps <bool>]]></c>, enables automatic <seealso marker="write_test_chapter#timetraps">timetrap
@@ -589,8 +598,8 @@
Common Test will either execute one test run per specification file, or
join the files and perform all tests within one single test run. The first
behaviour is the default one. The latter requires that the start
- flag/option <c>join_suites</c> is provided, e.g.
- <c>run_test -spec ./my_tests1.ts ./my_tests2.ts -join_suites</c>.</p>
+ flag/option <c>join_specs</c> is provided, e.g.
+ <c>run_test -spec ./my_tests1.ts ./my_tests2.ts -join_specs</c>.</p>
<p>Joining a number of specifications, or running them separately, can
also be accomplished with (and may be combined with) test specification
@@ -744,6 +753,9 @@
{auto_compile, Bool},
{auto_compile, NodeRefs, Bool},
+ {abort_if_missing_suites, Bool},
+ {abort_if_missing_suites, NodeRefs, Bool},
+
{config, ConfigFiles}.
{config, ConfigDir, ConfigBaseNames}.
{config, NodeRefs, ConfigFiles}.
diff --git a/lib/common_test/src/ct.erl b/lib/common_test/src/ct.erl
index e6732f7fc7..85afdc7834 100644
--- a/lib/common_test/src/ct.erl
+++ b/lib/common_test/src/ct.erl
@@ -150,7 +150,8 @@ run(TestDirs) ->
%%% {silent_connections,Conns} | {stylesheet,CSSFile} |
%%% {cover,CoverSpecFile} | {cover_stop,Bool} | {step,StepOpts} |
%%% {event_handler,EventHandlers} | {include,InclDirs} |
-%%% {auto_compile,Bool} | {create_priv_dir,CreatePrivDir} |
+%%% {auto_compile,Bool} | {abort_if_missing_suites,Bool} |
+%%% {create_priv_dir,CreatePrivDir} |
%%% {multiply_timetraps,M} | {scale_timetraps,Bool} |
%%% {repeat,N} | {duration,DurTime} | {until,StopTime} |
%%% {force_stop,ForceStop} | {decrypt,DecryptKeyOrFile} |
@@ -772,7 +773,7 @@ comment(Format, Args) when is_list(Format), is_list(Args) ->
send_html_comment(Comment) ->
Html = "<font color=\"green\">" ++ Comment ++ "</font>",
- ct_util:set_testdata({comment,Html}),
+ ct_util:set_testdata({{comment,group_leader()},Html}),
test_server:comment(Html).
%%%-----------------------------------------------------------------
diff --git a/lib/common_test/src/ct_framework.erl b/lib/common_test/src/ct_framework.erl
index 7d577462b0..20903607dc 100644
--- a/lib/common_test/src/ct_framework.erl
+++ b/lib/common_test/src/ct_framework.erl
@@ -657,7 +657,18 @@ end_tc(Mod,Func,TCPid,Result,Args,Return) ->
_ ->
ok
end,
- ct_util:delete_testdata(comment),
+ if Func == end_per_group; Func == end_per_suite ->
+ %% clean up any saved comments
+ ct_util:match_delete_testdata({comment,'_'});
+ true ->
+ %% attemp to delete any saved comment for this TC
+ case process_info(TCPid, group_leader) of
+ {group_leader,TCGL} ->
+ ct_util:delete_testdata({comment,TCGL});
+ _ ->
+ ok
+ end
+ end,
ct_util:delete_suite_data(last_saved_config),
FuncSpec = group_or_func(Func,Args),
@@ -850,7 +861,7 @@ error_notification(Mod,Func,_Args,{Error,Loc}) ->
_ ->
%% this notification comes from the test case process, so
%% we can add error info to comment with test_server:comment/1
- case ct_util:get_testdata(comment) of
+ case ct_util:get_testdata({comment,group_leader()}) of
undefined ->
test_server:comment(ErrorHtml);
Comment ->
@@ -1274,7 +1285,7 @@ report(What,Data) ->
ct_util:set_testdata({What,Data}),
ok;
tc_start ->
- %% Data = {Suite,{Func,GroupName}},LogFileName}
+ %% Data = {{Suite,{Func,GroupName}},LogFileName}
Data1 = case Data of
{{Suite,{Func,undefined}},LFN} -> {{Suite,Func},LFN};
_ -> Data
diff --git a/lib/common_test/src/ct_netconfc.erl b/lib/common_test/src/ct_netconfc.erl
index 6fc840745d..a3861dc745 100644
--- a/lib/common_test/src/ct_netconfc.erl
+++ b/lib/common_test/src/ct_netconfc.erl
@@ -536,7 +536,7 @@ send(Client, SimpleXml) ->
Client :: client(),
SimpleXml :: simple_xml(),
Timeout :: timeout(),
- Result :: ok | {error,error_reason()}.
+ Result :: simple_xml() | {error,error_reason()}.
%% @doc Send an XML document to the server.
%%
%% The given XML document is sent as is to the server. This function
@@ -556,7 +556,7 @@ send_rpc(Client, SimpleXml) ->
Client :: client(),
SimpleXml :: simple_xml(),
Timeout :: timeout(),
- Result :: ok | {error,error_reason()}.
+ Result :: [simple_xml()] | {error,error_reason()}.
%% @doc Send a Netconf <code>rpc</code> request to the server.
%%
%% The given XML document is wrapped in a valid Netconf
@@ -635,7 +635,7 @@ get(Client, Filter) ->
Client :: client(),
Filter :: simple_xml() | xpath(),
Timeout :: timeout(),
- Result :: {ok,simple_xml()} | {error,error_reason()}.
+ Result :: {ok,[simple_xml()]} | {error,error_reason()}.
%% @doc Get data.
%%
%% This operation returns both configuration and state data from the
@@ -661,7 +661,7 @@ get_config(Client, Source, Filter) ->
Source :: netconf_db(),
Filter :: simple_xml() | xpath(),
Timeout :: timeout(),
- Result :: {ok,simple_xml()} | {error,error_reason()}.
+ Result :: {ok,[simple_xml()]} | {error,error_reason()}.
%% @doc Get configuration data.
%%
%% To be able to access another source than `running', the server
@@ -759,7 +759,7 @@ action(Client,Action) ->
Client :: client(),
Action :: simple_xml(),
Timeout :: timeout(),
- Result :: {ok,simple_xml()} | {error,error_reason()}.
+ Result :: {ok,[simple_xml()]} | {error,error_reason()}.
%% @doc Execute an action.
%%
%% @end
diff --git a/lib/common_test/src/ct_telnet.erl b/lib/common_test/src/ct_telnet.erl
index 0a067b3a08..3b2652d06c 100644
--- a/lib/common_test/src/ct_telnet.erl
+++ b/lib/common_test/src/ct_telnet.erl
@@ -46,100 +46,80 @@
%%
%% == Logging ==
%%
-%% `ct_telnet' can be configured to uses the `error_logger' for logging telnet
-%% traffic. A special purpose error handler is implemented in
-%% `ct_conn_log_h'. To use this error handler, add the `cth_conn_log'
-%% hook in your test suite, e.g:
-%%
+%% The default logging behaviour of `ct_telnet' is to print information
+%% to the test case HTML log about performed operations and commands
+%% and their corresponding results. What won't be printed to the HTML log
+%% are text strings sent from the telnet server that are not explicitly
+%% received by means of a `ct_telnet' function such as `expect/3'.
+%% `ct_telnet' may however be configured to use a special purpose event handler,
+%% implemented in `ct_conn_log_h', for logging <b>all</b> telnet traffic.
+%% To use this handler, you need to install a Common Test hook named
+%% `cth_conn_log'. Example (using the test suite info function):
%%
%% ```
%% suite() ->
-%% [{ct_hooks, [{cth_conn_log, [{conn_mod(),hook_options()}]}]}].
-%%'''
+%% [{ct_hooks, [{cth_conn_log, [{conn_mod(),hook_options()}]}]}].
+%% '''
%%
%% `conn_mod()' is the name of the common_test module implementing
%% the connection protocol, i.e. `ct_telnet'.
%%
-%% The hook option `log_type' specifies the type of logging:
-%%
-%% <dl>
-%% <dt>`raw'</dt>
-%% <dd>The sent and received telnet data is logged to a separate
-%% text file as is, without any formatting. A link to the file is
-%% added to the test case HTML log.</dd>
+%% The `cth_conn_log' hook performs unformatted logging of telnet data to
+%% a separate text file. All telnet communication is captured and printed,
+%% including arbitrary data sent from the server. The link to this text file
+%% can be found on the top of the test case HTML log.
%%
-%% <dt>`html (default)'</dt>
-%% <dd>The sent and received telnet traffic is pretty printed
-%% directly in the test case HTML log.</dd>
-%%
-%% <dt>`silent'</dt>
-%% <dd>Telnet traffic is not logged.</dd>
-%% </dl>
-%%
-%% By default, all telnet traffic is logged in one single log
-%% file. However, it is possible to have different connections logged
-%% in separate files. To do this, use the hook option `hosts' and
-%% list the names of the servers/connections that will be used in the
-%% suite. Note that the connections must be named for this to work
+%% By default, data for all telnet connections is logged in one common
+%% file (named `default'), which might get messy e.g. if multiple telnet
+%% sessions are running in parallel. It is therefore possible to create a
+%% separate log file for each connection. To configure this, use the hook
+%% option `hosts' and list the names of the servers/connections that will be
+%% used in the suite. Note that the connections must be named for this to work
%% (see the `open' function below).
%%
-%% The `hosts' option has no effect if `log_type' is set to `html' or
-%% `silent'.
-%%
-%% The hook options can also be specified in a configuration file with
-%% the configuration variable `ct_conn_log':
+%% The hook option named `log_type' may be used to change the `cth_conn_log'
+%% behaviour. The default value of this option is `raw', which results in the
+%% behaviour described above. If the value is set to `html', all telnet
+%% communication is printed to the test case HTML log instead.
%%
-%% ```
-%% {ct_conn_log,[{conn_mod(),hook_options()}]}.
-%% '''
-%%
-%% For example:
+%% All `cth_conn_log' hook options described above can also be specified in
+%% a configuration file with the configuration variable `ct_conn_log'. Example:
%%
%% ```
-%% {ct_conn_log,[{ct_telnet,[{log_type,raw},
-%% {hosts,[key_or_name()]}]}]}
+%% {ct_conn_log, [{ct_telnet,[{log_type,raw},
+%% {hosts,[key_or_name()]}]}]}
%% '''
%%
%% <b>Note</b> that hook options specified in a configuration file
-%% will overwrite any hardcoded hook options in the test suite.
+%% will overwrite any hardcoded hook options in the test suite!
%%
-%% === Logging example 1 ===
+%% === Logging example ===
%%
-%% The following `ct_hooks' statement will cause raw printing of
-%% telnet traffic to separate logs for the connections named
-%% `server1' and `server2'. Any other connections will be logged
-%% to default telnet log.
+%% The following `ct_hooks' statement will cause printing of telnet traffic
+%% to separate logs for the connections named `server1' and `server2'.
+%% Traffic for any other connections will be logged in the default telnet log.
%%
%% ```
%% suite() ->
-%% [{ct_hooks, [{cth_conn_log, [{ct_telnet,[{log_type,raw}},
-%% {hosts,[server1,server2]}]}
-%% ]}]}].
+%% [{ct_hooks,
+%% [{cth_conn_log, [{ct_telnet,[{hosts,[server1,server2]}]}]}]}].
%%'''
%%
-%% === Logging example 2 ===
-%%
-%% The following configuration file will cause raw logging of all
-%% telnet traffic into one single text file.
+%% As previously explained, the above specification could also be provided
+%% by means of an entry like this in a configuration file:
%%
%% ```
-%% {ct_conn_log,[{ct_telnet,[{log_type,raw}]}]}.
+%% {ct_conn_log, [{ct_telnet,[{hosts,[server1,server2]}]}]}.
%% '''
%%
-%% The `ct_hooks' statement must look like this:
+%% in which case the `ct_hooks' statement in the test suite may simply look
+%% like this:
%%
%% ```
%% suite() ->
-%% [{ct_hooks, [{cth_conn_log, []}]}].
+%% [{ct_hooks, [{cth_conn_log, []}]}].
%% '''
%%
-%% The same `ct_hooks' statement without the configuration file would
-%% cause HTML logging of all telnet connections into the test case
-%% HTML log.
-%%
-%% <b>Note</b> that if the `cth_conn_log' hook is not added, telnet
-%% traffic is still logged in the test case HTML log file (on the legacy
-%% `ct_telnet' format).
%% @end
%% @type connection_type() = telnet | ts1 | ts2
@@ -205,6 +185,7 @@ open(Name) ->
%%% Name = target_name()
%%% ConnType = ct_telnet:connection_type()
%%% Handle = ct_telnet:handle()
+%%% Reason = term()
%%%
%%% @doc Open a telnet connection to the specified target host.
open(Name,ConnType) ->
@@ -234,6 +215,7 @@ open(KeyOrName,ConnType,TargetMod) ->
%%% TargetMod = atom()
%%% Extra = term()
%%% Handle = handle()
+%%% Reason = term()
%%%
%%% @doc Open a telnet connection to the specified target host.
%%%
@@ -295,7 +277,8 @@ open(KeyOrName,ConnType,TargetMod,Extra) ->
%%%-----------------------------------------------------------------
%%% @spec close(Connection) -> ok | {error,Reason}
-%%% Connection = ct_telnet:connection()
+%%% Connection = ct_telnet:connection()
+%%% Reason = term()
%%%
%%% @doc Close the telnet connection and stop the process managing it.
%%%
@@ -308,7 +291,7 @@ close(Connection) ->
{ok,Pid} ->
log(undefined,close,"Connection closed, handle: ~w",[Pid]),
case ct_gen_conn:stop(Pid) of
- {error,{process_down,Pid,noproc}} ->
+ {error,{process_down,Pid,_}} ->
{error,already_closed};
Result ->
Result
@@ -330,6 +313,7 @@ cmd(Connection,Cmd) ->
%%% Cmd = string()
%%% Timeout = integer()
%%% Data = [string()]
+%%% Reason = term()
%%% @doc Send a command via telnet and wait for prompt.
cmd(Connection,Cmd,Timeout) ->
case get_handle(Connection) of
@@ -350,6 +334,7 @@ cmdf(Connection,CmdFormat,Args) ->
%%% Args = list()
%%% Timeout = integer()
%%% Data = [string()]
+%%% Reason = term()
%%% @doc Send a telnet command and wait for prompt
%%% (uses a format string and list of arguments to build the command).
cmdf(Connection,CmdFormat,Args,Timeout) when is_list(Args) ->
@@ -360,6 +345,7 @@ cmdf(Connection,CmdFormat,Args,Timeout) when is_list(Args) ->
%%% @spec get_data(Connection) -> {ok,Data} | {error,Reason}
%%% Connection = ct_telnet:connection()
%%% Data = [string()]
+%%% Reason = term()
%%% @doc Get all data which has been received by the telnet client
%%% since last command was sent.
get_data(Connection) ->
@@ -374,6 +360,7 @@ get_data(Connection) ->
%%% @spec send(Connection,Cmd) -> ok | {error,Reason}
%%% Connection = ct_telnet:connection()
%%% Cmd = string()
+%%% Reason = term()
%%% @doc Send a telnet command and return immediately.
%%%
%%% <p>The resulting output from the command can be read with
@@ -391,6 +378,7 @@ send(Connection,Cmd) ->
%%% Connection = ct_telnet:connection()
%%% CmdFormat = string()
%%% Args = list()
+%%% Reason = term()
%%% @doc Send a telnet command and return immediately (uses a format
%%% string and a list of arguments to build the command).
sendf(Connection,CmdFormat,Args) when is_list(Args) ->
@@ -616,9 +604,12 @@ handle_msg({cmd,Cmd,Timeout},State) ->
end_gen_log(),
{Return,State#state{buffer=NewBuffer,prompt=Prompt}};
handle_msg({send,Cmd},State) ->
+ start_gen_log(heading(send,State#state.name)),
log(State,send,"Sending: ~p",[Cmd]),
+
debug_cont_gen_log("Throwing Buffer:",[]),
debug_log_lines(State#state.buffer),
+
case {State#state.type,State#state.prompt} of
{ts,_} ->
silent_teln_expect(State#state.name,
@@ -638,6 +629,7 @@ handle_msg({send,Cmd},State) ->
ok
end,
ct_telnet_client:send_data(State#state.teln_pid,Cmd),
+ end_gen_log(),
{ok,State#state{buffer=[],prompt=false}};
handle_msg(get_data,State) ->
start_gen_log(heading(get_data,State#state.name)),
@@ -765,8 +757,8 @@ check_if_prompt_was_reached(Data,_) when is_list(Data) ->
check_if_prompt_was_reached(_,_) ->
false.
-%%% @hidden
-%% Functions for logging ct_telnet reports and telnet data
+%%%-----------------------------------------------------------------
+%%% Functions for logging ct_telnet reports and telnet data
heading(Action,undefined) ->
io_lib:format("~w ~w",[?MODULE,Action]);
@@ -776,6 +768,8 @@ heading(Action,Name) ->
force_log(State,Action,String,Args) ->
log(State,Action,String,Args,true).
+%%%-----------------------------------------------------------------
+%%% @hidden
log(State,Action,String,Args) when is_record(State, state) ->
log(State,Action,String,Args,false);
log(Name,Action,String,Args) when is_atom(Name) ->
@@ -783,6 +777,8 @@ log(Name,Action,String,Args) when is_atom(Name) ->
log(TelnPid,Action,String,Args) when is_pid(TelnPid) ->
log(#state{teln_pid=TelnPid},Action,String,Args,false).
+%%%-----------------------------------------------------------------
+%%% @hidden
log(undefined,String,Args) ->
log(#state{},undefined,String,Args,false);
log(Name,String,Args) when is_atom(Name) ->
@@ -790,6 +786,8 @@ log(Name,String,Args) when is_atom(Name) ->
log(TelnPid,String,Args) when is_pid(TelnPid) ->
log(#state{teln_pid=TelnPid},undefined,String,Args).
+%%%-----------------------------------------------------------------
+%%% @hidden
log(#state{name=Name,teln_pid=TelnPid,host=Host,port=Port},
Action,String,Args,ForcePrint) ->
Name1 = if Name == undefined -> get({ct_telnet_pid2name,TelnPid});
@@ -839,6 +837,8 @@ log(#state{name=Name,teln_pid=TelnPid,host=Host,port=Port},
end
end.
+%%%-----------------------------------------------------------------
+%%% @hidden
start_gen_log(Heading) ->
%% check if output is suppressed
case ct_util:is_silenced(telnet) of
@@ -846,6 +846,8 @@ start_gen_log(Heading) ->
false -> ct_gen_conn:start_log(Heading)
end.
+%%%-----------------------------------------------------------------
+%%% @hidden
end_gen_log() ->
%% check if output is suppressed
case ct_util:is_silenced(telnet) of
@@ -871,14 +873,13 @@ teln_cmd(Pid,Cmd,Prx,Timeout) ->
teln_receive_until_prompt(Pid,Prx,Timeout).
teln_get_all_data(Pid,Prx,Data,Acc,LastLine) ->
- case check_for_prompt(Prx,lists:reverse(LastLine) ++ Data) of
+ case check_for_prompt(Prx,LastLine++Data) of
{prompt,Lines,_PromptType,Rest} ->
teln_get_all_data(Pid,Prx,Rest,[Lines|Acc],[]);
{noprompt,Lines,LastLine1} ->
case ct_telnet_client:get_data(Pid) of
{ok,[]} ->
- {ok,lists:reverse(lists:append([Lines|Acc])),
- lists:reverse(LastLine1)};
+ {ok,lists:reverse(lists:append([Lines|Acc])),LastLine1};
{ok,Data1} ->
teln_get_all_data(Pid,Prx,Data1,[Lines|Acc],LastLine1)
end
@@ -1336,7 +1337,7 @@ teln_receive_until_prompt(Pid,Prx,Timeout) ->
teln_receive_until_prompt(Pid,Prx,Acc,LastLine) ->
{ok,Data} = ct_telnet_client:get_data(Pid),
- case check_for_prompt(Prx,LastLine ++ Data) of
+ case check_for_prompt(Prx,LastLine++Data) of
{prompt,Lines,PromptType,Rest} ->
Return = lists:reverse(lists:append([Lines|Acc])),
{ok,Return,PromptType,Rest};
diff --git a/lib/common_test/src/ct_util.erl b/lib/common_test/src/ct_util.erl
index f5eb3a72f0..56027586d1 100644
--- a/lib/common_test/src/ct_util.erl
+++ b/lib/common_test/src/ct_util.erl
@@ -37,7 +37,7 @@
save_suite_data_async/3, save_suite_data_async/2,
read_suite_data/1,
delete_suite_data/0, delete_suite_data/1, match_delete_suite_data/1,
- delete_testdata/0, delete_testdata/1,
+ delete_testdata/0, delete_testdata/1, match_delete_testdata/1,
set_testdata/1, get_testdata/1, get_testdata/2,
set_testdata_async/1, update_testdata/2, update_testdata/3,
set_verbosity/1, get_verbosity/1]).
@@ -270,6 +270,9 @@ delete_testdata() ->
delete_testdata(Key) ->
call({delete_testdata, Key}).
+match_delete_testdata(KeyPat) ->
+ call({match_delete_testdata, KeyPat}).
+
update_testdata(Key, Fun) ->
update_testdata(Key, Fun, []).
@@ -361,7 +364,25 @@ loop(Mode,TestData,StartDir) ->
{{delete_testdata,Key},From} ->
TestData1 = lists:keydelete(Key,1,TestData),
return(From,ok),
- loop(From,TestData1,StartDir);
+ loop(From,TestData1,StartDir);
+ {{match_delete_testdata,{Key1,Key2}},From} ->
+ %% handles keys with 2 elements
+ TestData1 =
+ lists:filter(fun({Key,_}) when not is_tuple(Key) ->
+ true;
+ ({Key,_}) when tuple_size(Key) =/= 2 ->
+ true;
+ ({{_,KeyB},_}) when Key1 == '_' ->
+ KeyB =/= Key2;
+ ({{KeyA,_},_}) when Key2 == '_' ->
+ KeyA =/= Key1;
+ (_) when Key1 == '_' ; Key2 == '_' ->
+ false;
+ (_) ->
+ true
+ end, TestData),
+ return(From,ok),
+ loop(From,TestData1,StartDir);
{{set_testdata,New = {Key,_Val}},From} ->
TestData1 = lists:keydelete(Key,1,TestData),
return(From,ok),
diff --git a/lib/common_test/src/cth_conn_log.erl b/lib/common_test/src/cth_conn_log.erl
index 0e6c877c5d..1e60f2751e 100644
--- a/lib/common_test/src/cth_conn_log.erl
+++ b/lib/common_test/src/cth_conn_log.erl
@@ -91,12 +91,15 @@ merge_log_info([{Mod,ConfOpts}|ConfList],HookList) ->
{value,{_,HookOpts},HL1} ->
{ConfOpts ++ HookOpts, HL1} % ConfOpts overwrites HookOpts!
end,
- [{Mod,get_log_opts(Opts)} | merge_log_info(ConfList,HookList1)];
+ [{Mod,get_log_opts(Mod,Opts)} | merge_log_info(ConfList,HookList1)];
merge_log_info([],HookList) ->
- [{Mod,get_log_opts(Opts)} || {Mod,Opts} <- HookList].
+ [{Mod,get_log_opts(Mod,Opts)} || {Mod,Opts} <- HookList].
-get_log_opts(Opts) ->
- LogType = proplists:get_value(log_type,Opts,html),
+get_log_opts(Mod,Opts) ->
+ DefaultLogType = if Mod == ct_telnet -> raw;
+ true -> html
+ end,
+ LogType = proplists:get_value(log_type,Opts,DefaultLogType),
Hosts = proplists:get_value(hosts,Opts,[]),
{LogType,Hosts}.
diff --git a/lib/common_test/src/unix_telnet.erl b/lib/common_test/src/unix_telnet.erl
index b05386a5ab..10666b979d 100644
--- a/lib/common_test/src/unix_telnet.erl
+++ b/lib/common_test/src/unix_telnet.erl
@@ -17,8 +17,8 @@
%% %CopyrightEnd%
%%
-%%% @doc Callback module for ct_telnet for talking telnet
-%%% to a unix host.
+%%% @doc Callback module for ct_telnet, for connecting to a telnet
+%%% server on a unix host.
%%%
%%% <p>It requires the following entry in the config file:</p>
%%% <pre>
@@ -28,15 +28,15 @@
%%% {password,Password},
%%% {keep_alive,Bool}]}. % optional</pre>
%%%
-%%% <p>To talk telnet to the host specified by
+%%% <p>To communicate via telnet to the host specified by
%%% <code>HostNameOrIpAddress</code>, use the interface functions in
-%%% <code>ct</code>, e.g. <code>open(Name), cmd(Name,Cmd), ...</code>.</p>
+%%% <code>ct_telnet</code>, e.g. <code>open(Name), cmd(Name,Cmd), ...</code>.</p>
%%%
%%% <p><code>Name</code> is the name you allocated to the unix host in
%%% your <code>require</code> statement. E.g.</p>
-%%% <pre> suite() -> [{require,Name,{unix,[telnet,username,password]}}].</pre>
+%%% <pre> suite() -> [{require,Name,{unix,[telnet]}}].</pre>
%%% <p>or</p>
-%%% <pre> ct:require(Name,{unix,[telnet,username,password]}).</pre>
+%%% <pre> ct:require(Name,{unix,[telnet]}).</pre>
%%%
%%% <p>The "keep alive" activity (i.e. that Common Test sends NOP to the server
%%% every 10 seconds if the connection is idle) may be enabled or disabled for one
@@ -62,20 +62,18 @@
-define(prx,"login: |Password: |\\\$ |> ").
%%%-----------------------------------------------------------------
-%%% @hidden
%%% @spec get_prompt_regexp() -> PromptRegexp
%%% PromptRegexp = ct_telnet:prompt_regexp()
%%%
%%% @doc Callback for ct_telnet.erl.
%%%
-%%% <p>Return the prompt regexp for telnet connections to the
-%%% interwatch instrument.</p>
+%%% <p>Return a suitable regexp string that will match common
+%%% prompts for users on unix hosts.</p>
get_prompt_regexp() ->
?prx.
%%%-----------------------------------------------------------------
-%%% @hidden
%%% @spec connect(ConnName,Ip,Port,Timeout,KeepAlive,Extra) ->
%%% {ok,Handle} | {error,Reason}
%%% ConnName = ct:target_name()
@@ -83,14 +81,15 @@ get_prompt_regexp() ->
%%% Port = integer()
%%% Timeout = integer()
%%% KeepAlive = bool()
-%%% Extra = {Username,Password}
+%%% Extra = ct:target_name() | {Username,Password}
%%% Username = string()
%%% Password = string()
%%% Handle = ct_telnet:handle()
+%%% Reason = term()
%%%
%%% @doc Callback for ct_telnet.erl.
%%%
-%%% <p>Setup telnet connection to a UNIX host.</p>
+%%% <p>Setup telnet connection to a unix host.</p>
connect(ConnName,Ip,Port,Timeout,KeepAlive,Extra) ->
case Extra of
{Username,Password} ->
diff --git a/lib/common_test/test/ct_telnet_SUITE.erl b/lib/common_test/test/ct_telnet_SUITE.erl
index f5cff76fd1..84e69c2b54 100644
--- a/lib/common_test/test/ct_telnet_SUITE.erl
+++ b/lib/common_test/test/ct_telnet_SUITE.erl
@@ -180,14 +180,20 @@ telnet_config(unix_telnet, legacy) ->
{ct_conn_log,[]}];
%% LogType same as GroupName
telnet_config(unix_telnet, LogType) ->
+ LogTypeTerm = if LogType == raw -> [];
+ true -> [{log_type,LogType}]
+ end,
[{unix, ct:get_config(unix)},
{ct_conn_log,
- [{ct_telnet,[{log_type,LogType},
- {hosts,[telnet_server_conn1,
- telnet_server_conn2,
- telnet_server_conn3,
- telnet_server_conn4]}]}]}];
+ [{ct_telnet, LogTypeTerm ++
+ [{hosts,[telnet_server_conn1,
+ telnet_server_conn2,
+ telnet_server_conn3,
+ telnet_server_conn4]}]}]}];
telnet_config(_, LogType) ->
+ LogTypeTerm = if LogType == raw -> [];
+ true -> [{log_type,LogType}]
+ end,
[{unix,[{telnet,"localhost"},
{port, ?erl_telnet_server_port},
{username,?erl_telnet_server_user},
@@ -202,11 +208,11 @@ telnet_config(_, LogType) ->
[{ct_conn_log,[]}];
true ->
[{ct_conn_log,
- [{ct_telnet,[{log_type,LogType},
- {hosts,[telnet_server_conn1,
- telnet_server_conn2,
- telnet_server_conn3,
- telnet_server_conn4]}]}]}]
+ [{ct_telnet, LogTypeTerm ++
+ [{hosts,[telnet_server_conn1,
+ telnet_server_conn2,
+ telnet_server_conn3,
+ telnet_server_conn4]}]}]}]
end].
%%%-----------------------------------------------------------------
diff --git a/lib/common_test/test/ct_telnet_SUITE_data/ct_telnet_own_server_SUITE.erl b/lib/common_test/test/ct_telnet_SUITE_data/ct_telnet_own_server_SUITE.erl
index 0ee0525216..c0f79d0f10 100644
--- a/lib/common_test/test/ct_telnet_SUITE_data/ct_telnet_own_server_SUITE.erl
+++ b/lib/common_test/test/ct_telnet_SUITE_data/ct_telnet_own_server_SUITE.erl
@@ -16,7 +16,8 @@ suite() ->
].
all() ->
- [expect,
+ [
+ expect,
expect_repeat,
expect_sequence,
expect_error_prompt,
@@ -31,8 +32,10 @@ all() ->
ignore_prompt_repeat,
ignore_prompt_sequence,
ignore_prompt_timeout,
+ large_string,
server_speaks,
- server_disconnects].
+ server_disconnects
+ ].
groups() ->
[].
@@ -214,6 +217,41 @@ no_prompt_check_timeout(_) ->
ok = ct_telnet:close(Handle),
ok.
+%% Check that it's possible to receive multiple chunks of data sent from
+%% the server with one get_data call
+large_string(_) ->
+ {ok, Handle} = ct_telnet:open(telnet_server_conn1),
+ String = "abcd efgh ijkl mnop qrst uvwx yz ",
+ BigString = lists:flatmap(fun(S) -> S end,
+ [String || _ <- lists:seq(1,10)]),
+ VerifyStr = [C || C <- BigString, C/=$ ],
+
+ {ok,Data} = ct_telnet:cmd(Handle, "echo_sep "++BigString),
+ ct:log("[CMD] Received ~w chars: ~s", [length(lists:flatten(Data)),Data]),
+ VerifyStr = [C || C <- lists:flatten(Data), C/=$ , C/=$\r, C/=$\n, C/=$>],
+
+ %% Test #1: With a long sleep value, all data gets gets buffered and
+ %% ct_telnet can receive it with one single request to ct_telnet_client.
+ %% Test #2: With a short sleep value, ct_telnet needs multiple calls to
+ %% ct_telnet_client to collect the data. This iterative operation should
+ %% yield the same result as the single request case.
+
+ ok = ct_telnet:send(Handle, "echo_sep "++BigString),
+ timer:sleep(1000),
+ {ok,Data1} = ct_telnet:get_data(Handle),
+ ct:log("[GET DATA #1] Received ~w chars: ~s",
+ [length(lists:flatten(Data1)),Data1]),
+ VerifyStr = [C || C <- lists:flatten(Data1), C/=$ , C/=$\r, C/=$\n, C/=$>],
+
+ ok = ct_telnet:send(Handle, "echo_sep "++BigString),
+ timer:sleep(50),
+ {ok,Data2} = ct_telnet:get_data(Handle),
+ ct:log("[GET DATA #2] Received ~w chars: ~s", [length(lists:flatten(Data2)),Data2]),
+ VerifyStr = [C || C <- lists:flatten(Data2), C/=$ , C/=$\r, C/=$\n, C/=$>],
+
+ ok = ct_telnet:close(Handle),
+ ok.
+
%% The server says things. Manually check that it gets printed correctly
%% in the general IO log.
server_speaks(_) ->
diff --git a/lib/common_test/test/telnet_server.erl b/lib/common_test/test/telnet_server.erl
index ae56787819..1d341d6106 100644
--- a/lib/common_test/test/telnet_server.erl
+++ b/lib/common_test/test/telnet_server.erl
@@ -198,6 +198,14 @@ do_handle_data(Data,#state{authorized={user,_}}=State) ->
do_handle_data("echo " ++ Data,State) ->
send(Data++"\r\n> ",State),
{ok,State};
+do_handle_data("echo_sep " ++ Data,State) ->
+ Msgs = string:tokens(Data," "),
+ lists:foreach(fun(Msg) ->
+ send(Msg,State),
+ timer:sleep(10)
+ end, Msgs),
+ send("\r\n> ",State),
+ {ok,State};
do_handle_data("echo_no_prompt " ++ Data,State) ->
send(Data,State),
{ok,State};
diff --git a/lib/compiler/doc/src/notes.xml b/lib/compiler/doc/src/notes.xml
index cb39b28d3d..a0f2e617cb 100644
--- a/lib/compiler/doc/src/notes.xml
+++ b/lib/compiler/doc/src/notes.xml
@@ -31,6 +31,233 @@
<p>This document describes the changes made to the Compiler
application.</p>
+<section><title>Compiler 5.0</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Line numbers would not be correct when a binary
+ construction such as
+ '<c>&lt;&lt;Bin/binary,...&gt;&gt;</c>' fails. (Thanks to
+ Stanislav Seletskiy for reporting this bug.)</p>
+ <p>
+ Own Id: OTP-11572</p>
+ </item>
+ <item>
+ <p>
+ The compiler now properly annotates the code in value in
+ the '<c>after</c>' clause for a '<c>try</c>' so that
+ Dialyzer no longer generates a false warning for an
+ unmatched return.</p>
+ <p>
+ Own Id: OTP-11580</p>
+ </item>
+ <item>
+ <p>
+ Some case statements where no clause would match could
+ cause an internal error in the compiler. (Thanks to Erik
+ Soe Sorensen for reporting this bug.)</p>
+ <p>
+ Own Id: OTP-11610</p>
+ </item>
+ <item>
+ <p>
+ With <c>--Wunmatched_returns</c>, dialyzer will no longer
+ warn when the value of a list comprehension is ignored,
+ provided that the each value in the list would be an
+ atomic value (such as integer or atoms, as opposed to
+ tuples and lists). Example: ignoring '<c>[io:format(...)
+ || ...]</c>' will not cause a warning, while ignoring
+ '<c>[file:close(Fd) || ...]</c>' will.</p>
+ <p>
+ Own Id: OTP-11626</p>
+ </item>
+ <item>
+ <p>
+ Matching out a binary and applying the binary as if it
+ were a fun would crash the run-time system. (Thanks to
+ Loïc Hoguin.)</p>
+ <p>
+ Own Id: OTP-11672</p>
+ </item>
+ <item>
+ <p>
+ Some local implementations of removing the last element
+ from a list are replaced by <c>lists:droplast/1</c>. Note
+ that this requires at least <c>stdlib-2.0</c>, which is
+ the stdlib version delivered in OTP 17.0. (Thanks to Hans
+ Svensson)</p>
+ <p>
+ Own Id: OTP-11678</p>
+ </item>
+ <item>
+ <p>
+ Allow all auto imports to be suppressed at once.
+ Introducing the no_auto_import attribute:
+ -compile(no_auto_import). Useful for code generation
+ tools that always use the qualified function names and
+ want to avoid the auto imported functions clashing with
+ local ones. (Thanks to José Valim.)</p>
+ <p>
+ Own Id: OTP-11682</p>
+ </item>
+ <item>
+ <p>
+ Application upgrade (appup) files are corrected for the
+ following applications: </p>
+ <p>
+ <c>asn1, common_test, compiler, crypto, debugger,
+ dialyzer, edoc, eldap, erl_docgen, et, eunit, gs, hipe,
+ inets, observer, odbc, os_mon, otp_mibs, parsetools,
+ percept, public_key, reltool, runtime_tools, ssh,
+ syntax_tools, test_server, tools, typer, webtool, wx,
+ xmerl</c></p>
+ <p>
+ A new test utility for testing appup files is added to
+ test_server. This is now used by most applications in
+ OTP.</p>
+ <p>
+ (Thanks to Tobias Schlager)</p>
+ <p>
+ Own Id: OTP-11744</p>
+ </item>
+ <item>
+ <p>
+ Adapt 'asm' deprecation message to new version scheme.
+ (Thanks to Tuncer Ayaz)</p>
+ <p>
+ Own Id: OTP-11751</p>
+ </item>
+ <item>
+ <p>
+ A number of compiler errors where unusual or nonsensical
+ code would crash the compiler have been reported by Ulf
+ Norell and corrected by Anthony Ramine.</p>
+ <p>
+ Own Id: OTP-11770</p>
+ </item>
+ </list>
+ </section>
+
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p>
+ Compilation times for modules with a huge number for
+ record accesses using the dot operator has been improved.</p>
+ <p>
+ Own Id: OTP-10652</p>
+ </item>
+ <item>
+ <p>
+ The compiler can generate somewhat better code by moving
+ let expressions into sequences. (Thanks to Anthony
+ Ramine.)</p>
+ <p>
+ Own Id: OTP-11056</p>
+ </item>
+ <item>
+ <p>
+ Forbid unsized fields in patterns of binary generators
+ and simplified v3_core's translation of bit string
+ generators. (Thanks to Anthony Ramine.)</p>
+ <p>
+ Own Id: OTP-11186</p>
+ </item>
+ <item>
+ <p>
+ Funs can now be a given a name. Thanks to to Richard
+ O'Keefe for the idea (EEP37) and to Anthony Ramine for
+ the implementation.</p>
+ <p>
+ Own Id: OTP-11537</p>
+ </item>
+ <item>
+ <p>
+ Using the <c>from_asm</c> option to produce a BEAM file
+ starting from BEAM assembly code would often fail because
+ early optimization passes would not understand
+ instructions that later optimization passes would
+ introduce. (Thanks to Anthony Ramine.)</p>
+ <p>
+ Own Id: OTP-11544</p>
+ </item>
+ <item>
+ <p>
+ The <c>.core</c> and <c>.S</c> extensions are now
+ documented in the <c>erlc</c> documentation, and the
+ '<c>from_core</c>' and '<c>from_asm</c>' options are now
+ documented in the compiler documentation. (Thanks to
+ Tuncer Ayaz.)</p>
+ <p>
+ Own Id: OTP-11547</p>
+ </item>
+ <item>
+ <p>Optimization of case expressions that build tuples or
+ lists have been improved.</p>
+ <p>
+ Own Id: OTP-11584</p>
+ </item>
+ <item>
+ <p>
+ EEP43: New data type - Maps</p>
+ <p>
+ With Maps you may for instance: <taglist> <item><c>M0 =
+ #{ a =&gt; 1, b =&gt; 2}, % create
+ associations</c></item> <item><c>M1 = M0#{ a := 10 }, %
+ update values</c></item> <item><c>M2 = M1#{ "hi" =&gt;
+ "hello"}, % add new associations</c></item> <item><c>#{
+ "hi" := V1, a := V2, b := V3} = M2. % match keys with
+ values</c></item> </taglist></p>
+ <p>
+ For information on how to use Maps please see the
+ <seealso marker="doc/reference_manual:maps">Reference
+ Manual</seealso>.</p>
+ <p>
+ The current implementation is without the following
+ features: <taglist> <item>No variable keys</item>
+ <item>No single value access</item> <item>No map
+ comprehensions</item> </taglist></p>
+ <p>
+ Note that Maps is <em>experimental</em> during OTP 17.0.</p>
+ <p>
+ Own Id: OTP-11616</p>
+ </item>
+ <item>
+ <p>
+ Some function specs are corrected or moved and some edoc
+ comments are corrected in order to allow use of edoc.
+ (Thanks to Pierre Fenoll)</p>
+ <p>
+ Own Id: OTP-11702</p>
+ </item>
+ <item>
+ <p>
+ Thanks to Anthony Ramine for several improvements to the
+ optimizations in the BEAM compiler and for cleaning up
+ the code the code that transforms list and binary
+ comprehensions to Core Erlang.</p>
+ <p>
+ Own Id: OTP-11720</p>
+ </item>
+ <item>
+ <p>
+ The default encoding for Erlang source files is now
+ UTF-8. As a temporary measure to ease the transition from
+ the old default of latin-1, if the compiler encounters
+ byte sequences that are not valid UTF-8 sequences, the
+ compiler will re-try the compilation in latin-1 mode.
+ This workaround will be removed in a future release.</p>
+ <p>
+ Own Id: OTP-11791</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>Compiler 4.9.4</title>
<section><title>Fixed Bugs and Malfunctions</title>
diff --git a/lib/compiler/src/beam_disasm.erl b/lib/compiler/src/beam_disasm.erl
index 4bdfe4e0c2..c45596f236 100644
--- a/lib/compiler/src/beam_disasm.erl
+++ b/lib/compiler/src/beam_disasm.erl
@@ -1030,6 +1030,7 @@ resolve_inst({gc_bif2,Args},Imports,_,_) ->
[F,Live,Bif,A1,A2,Reg] = resolve_args(Args),
{extfunc,_Mod,BifName,_Arity} = lookup(Bif+1,Imports),
{gc_bif,BifName,F,Live,[A1,A2],Reg};
+
%%
%% New instruction in R14, gc_bif with 3 arguments
%%
@@ -1146,21 +1147,17 @@ resolve_inst({put_map_assoc,Args},_,_,_) ->
[FLbl,Src,Dst,{u,N},{{z,1},{u,_Len},List0}] = Args,
List = resolve_args(List0),
{put_map_assoc,FLbl,Src,Dst,N,{list,List}};
-
resolve_inst({put_map_exact,Args},_,_,_) ->
[FLbl,Src,Dst,{u,N},{{z,1},{u,_Len},List0}] = Args,
List = resolve_args(List0),
{put_map_exact,FLbl,Src,Dst,N,{list,List}};
-
-resolve_inst({is_map,Args0},_,_,_) ->
+resolve_inst({is_map=I,Args0},_,_,_) ->
[FLbl|Args] = resolve_args(Args0),
- {test, is_map, FLbl, Args};
-
+ {test,I,FLbl,Args};
resolve_inst({has_map_fields,Args0},_,_,_) ->
[FLbl,Src,{{z,1},{u,_Len},List0}] = Args0,
List = resolve_args(List0),
{test,has_map_fields,FLbl,Src,{list,List}};
-
resolve_inst({get_map_elements,Args0},_,_,_) ->
[FLbl,Src,{{z,1},{u,_Len},List0}] = Args0,
List = resolve_args(List0),
diff --git a/lib/compiler/src/cerl.erl b/lib/compiler/src/cerl.erl
index e400e4f185..54eac20ac4 100644
--- a/lib/compiler/src/cerl.erl
+++ b/lib/compiler/src/cerl.erl
@@ -133,13 +133,9 @@
]).
-export_type([c_binary/0, c_bitstr/0, c_call/0, c_clause/0, c_cons/0, c_fun/0,
- c_literal/0, c_map_pair/0, c_module/0, c_tuple/0,
+ c_literal/0, c_map/0, c_map_pair/0, c_module/0, c_tuple/0,
c_values/0, c_var/0, cerl/0, var_name/0]).
-%% HiPE does not understand Maps
-%% (guard functions is_map/1 and map_size/1 in ann_c_map/3)
--compile(no_native).
-
-include("core_parse.hrl").
-type c_alias() :: #c_alias{}.
diff --git a/lib/compiler/src/core_lib.erl b/lib/compiler/src/core_lib.erl
index 93ec3bbad5..2792fd8fa5 100644
--- a/lib/compiler/src/core_lib.erl
+++ b/lib/compiler/src/core_lib.erl
@@ -59,7 +59,7 @@ is_lit_bin(Es) ->
%% Return the value of LitExpr.
-spec literal_value(cerl:c_literal() | cerl:c_binary() |
- cerl:c_cons() | cerl:c_tuple()) -> term().
+ cerl:c_map() | cerl:c_cons() | cerl:c_tuple()) -> term().
literal_value(#c_literal{val=V}) -> V;
literal_value(#c_binary{segments=Es}) ->
@@ -67,7 +67,14 @@ literal_value(#c_binary{segments=Es}) ->
literal_value(#c_cons{hd=H,tl=T}) ->
[literal_value(H)|literal_value(T)];
literal_value(#c_tuple{es=Es}) ->
- list_to_tuple(literal_value_list(Es)).
+ list_to_tuple(literal_value_list(Es));
+literal_value(#c_map{arg=Cm,es=Cmps}) ->
+ M = literal_value(Cm),
+ lists:foldl(fun(#c_map_pair{ key=Ck, val=Cv },Mi) ->
+ K = literal_value(Ck),
+ V = literal_value(Cv),
+ maps:put(K,V,Mi)
+ end, M, Cmps).
literal_value_list(Vals) -> [literal_value(V) || V <- Vals].
diff --git a/lib/compiler/src/core_pp.erl b/lib/compiler/src/core_pp.erl
index a76327457d..83412ecdd7 100644
--- a/lib/compiler/src/core_pp.erl
+++ b/lib/compiler/src/core_pp.erl
@@ -120,7 +120,11 @@ format_1(#c_literal{anno=A,val=Bitstring}, Ctxt) when is_bitstring(Bitstring) ->
format_1(#c_binary{anno=A,segments=Segs}, Ctxt);
format_1(#c_literal{anno=A,val=M},Ctxt) when is_map(M) ->
Pairs = maps:to_list(M),
- Cpairs = [#c_map_pair{op=#c_literal{val=assoc},
+ Op = case Ctxt of
+ #ctxt{ class = clause } -> exact;
+ _ -> assoc
+ end,
+ Cpairs = [#c_map_pair{op=#c_literal{val=Op},
key=#c_literal{val=V},
val=#c_literal{val=K}} || {K,V} <- Pairs],
format_1(#c_map{anno=A,arg=#c_literal{val=#{}},es=Cpairs},Ctxt);
diff --git a/lib/compiler/src/sys_core_fold.erl b/lib/compiler/src/sys_core_fold.erl
index b7422318b2..ce40213bad 100644
--- a/lib/compiler/src/sys_core_fold.erl
+++ b/lib/compiler/src/sys_core_fold.erl
@@ -1556,16 +1556,8 @@ map_pair_pattern_list(Ps0, Isub, Osub0) ->
{Ps,Osub}.
map_pair_pattern(#c_map_pair{op=#c_literal{val=exact},key=K0,val=V0}=Pair,{Isub,Osub0}) ->
- {K,Osub1} = case cerl:type(K0) of
- binary ->
- K1 = eval_binary(K0),
- case cerl:type(K1) of
- literal -> {K1,Osub0};
- _ -> pattern(K0,Isub,Osub0)
- end;
- _ -> pattern(K0,Isub,Osub0)
- end,
- {V,Osub} = pattern(V0,Isub,Osub1),
+ K = expr(K0, Isub),
+ {V,Osub} = pattern(V0,Isub,Osub0),
{Pair#c_map_pair{key=K,val=V},{Isub,Osub}}.
bin_pattern_list(Ps0, Isub, Osub0) ->
diff --git a/lib/compiler/src/sys_pre_expand.erl b/lib/compiler/src/sys_pre_expand.erl
index 91a46a20fe..761ae8409c 100644
--- a/lib/compiler/src/sys_pre_expand.erl
+++ b/lib/compiler/src/sys_pre_expand.erl
@@ -232,7 +232,7 @@ pattern({map,Line,Ps}, St0) ->
{TPs,St1} = pattern_list(Ps, St0),
{{map,Line,TPs},St1};
pattern({map_field_exact,Line,K0,V0}, St0) ->
- {K,St1} = pattern(K0, St0),
+ {K,St1} = expr(K0, St0),
{V,St2} = pattern(V0, St1),
{{map_field_exact,Line,K,V},St2};
%%pattern({struct,Line,Tag,Ps}, St0) ->
diff --git a/lib/compiler/src/v3_core.erl b/lib/compiler/src/v3_core.erl
index a548ba2f7c..8c18f6a9f7 100644
--- a/lib/compiler/src/v3_core.erl
+++ b/lib/compiler/src/v3_core.erl
@@ -1605,26 +1605,17 @@ pattern_alias_map_pair_patterns([Cv1,Cv2|Cvs]) ->
pattern_alias_map_pair_patterns([pat_alias(Cv1,Cv2)|Cvs]).
pattern_map_pair({map_field_exact,L,K,V}, St) ->
- %% FIXME: Better way to construct literals? or missing case
- %% {Key,_,_} = expr(K, St),
- Key = case K of
- {bin,L,Es0} ->
- case constant_bin(Es0) of
- error ->
- %% this will throw a cryptic error message
- %% but it is better than nothing
- throw(nomatch);
- Bin ->
- #c_literal{anno=lineno_anno(L,St),val=Bin}
- end;
+ case expr(K,St) of
+ {#c_literal{}=Key,_,_} ->
+ #c_map_pair{anno=lineno_anno(L, St),
+ op=#c_literal{val=exact},
+ key=Key,
+ val=pattern(V, St)};
_ ->
- pattern(K,St)
- end,
- #c_map_pair{anno=lineno_anno(L, St),
- op=#c_literal{val=exact},
- key=Key,
- val=pattern(V, St)}.
-
+ %% this will throw a cryptic error message
+ %% but it is better than nothing
+ throw(nomatch)
+ end.
%% pat_bin([BinElement], State) -> [BinSeg].
diff --git a/lib/compiler/test/map_SUITE.erl b/lib/compiler/test/map_SUITE.erl
index cc018e4305..403b7e8405 100644
--- a/lib/compiler/test/map_SUITE.erl
+++ b/lib/compiler/test/map_SUITE.erl
@@ -113,6 +113,10 @@ t_build_and_match_literals(Config) when is_list(Config) ->
M = #{ map_1:=#{ map_2:=#{value_3 := third}, value_2:= second}, value_1:=first} =
id(#{ map_1=>#{ map_2=>#{value_3 => third}, value_2=> second}, value_1=>first}),
+ %% map key
+ #{ #{} := 42 } = id(#{ #{} => 42 }),
+ #{ #{ "a" => 3 } := 42 } = id(#{ #{ "a" => 3} => 42 }),
+
%% nil key
#{[]:=ok,1:=2} = id(#{[]=>ok,1=>2}),
@@ -123,6 +127,7 @@ t_build_and_match_literals(Config) when is_list(Config) ->
{'EXIT',{{badmatch,_},_}} = (catch (#{x:=3} = id(#{y=>3}))),
{'EXIT',{{badmatch,_},_}} = (catch (#{x:=3} = id(#{x=>"three"}))),
{'EXIT',{badarg,_}} = (catch id(#{<<0:258>> =>"three"})),
+ {'EXIT',{{badmatch,_},_}} = (catch (#{#{"a"=>42} := 3}=id(#{#{"a"=>3}=>42}))),
ok.
t_build_and_match_aliasing(Config) when is_list(Config) ->
diff --git a/lib/cosEvent/doc/src/notes.xml b/lib/cosEvent/doc/src/notes.xml
index df05f5634e..8f519447fc 100644
--- a/lib/cosEvent/doc/src/notes.xml
+++ b/lib/cosEvent/doc/src/notes.xml
@@ -32,7 +32,23 @@
<file>notes.xml</file>
</header>
- <section><title>cosEvent 2.1.14</title>
+ <section><title>cosEvent 2.1.15</title>
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p> The default encoding of Erlang files has been changed
+ from ISO-8859-1 to UTF-8. </p> <p> The encoding of XML
+ files has also been changed to UTF-8. </p>
+ <p>
+ Own Id: OTP-10907</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>cosEvent 2.1.14</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 f88d101a69..2c3bf16411 100644
--- a/lib/cosEventDomain/doc/src/notes.xml
+++ b/lib/cosEventDomain/doc/src/notes.xml
@@ -31,7 +31,23 @@
<file>notes.xml</file>
</header>
- <section><title>cosEventDomain 1.1.13</title>
+ <section><title>cosEventDomain 1.1.14</title>
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p> The default encoding of Erlang files has been changed
+ from ISO-8859-1 to UTF-8. </p> <p> The encoding of XML
+ files has also been changed to UTF-8. </p>
+ <p>
+ Own Id: OTP-10907</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>cosEventDomain 1.1.13</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 5cca5e307b..1d0c826d40 100644
--- a/lib/cosFileTransfer/doc/src/notes.xml
+++ b/lib/cosFileTransfer/doc/src/notes.xml
@@ -30,7 +30,23 @@
<file>notes.xml</file>
</header>
- <section><title>cosFileTransfer 1.1.15</title>
+ <section><title>cosFileTransfer 1.1.16</title>
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p> The default encoding of Erlang files has been changed
+ from ISO-8859-1 to UTF-8. </p> <p> The encoding of XML
+ files has also been changed to UTF-8. </p>
+ <p>
+ Own Id: OTP-10907</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>cosFileTransfer 1.1.15</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 b700e0984c..2e4f922142 100644
--- a/lib/cosNotification/doc/src/notes.xml
+++ b/lib/cosNotification/doc/src/notes.xml
@@ -31,7 +31,23 @@
<file>notes.xml</file>
</header>
- <section><title>cosNotification 1.1.20</title>
+ <section><title>cosNotification 1.1.21</title>
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p> The default encoding of Erlang files has been changed
+ from ISO-8859-1 to UTF-8. </p> <p> The encoding of XML
+ files has also been changed to UTF-8. </p>
+ <p>
+ Own Id: OTP-10907</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>cosNotification 1.1.20</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 22b1a73d29..739f41617f 100644
--- a/lib/cosProperty/doc/src/notes.xml
+++ b/lib/cosProperty/doc/src/notes.xml
@@ -31,7 +31,23 @@
<file>notes.xml</file>
</header>
- <section><title>cosProperty 1.1.16</title>
+ <section><title>cosProperty 1.1.17</title>
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p> The default encoding of Erlang files has been changed
+ from ISO-8859-1 to UTF-8. </p> <p> The encoding of XML
+ files has also been changed to UTF-8. </p>
+ <p>
+ Own Id: OTP-10907</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>cosProperty 1.1.16</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 c1d000a5ff..f218f19a6b 100644
--- a/lib/cosTime/doc/src/notes.xml
+++ b/lib/cosTime/doc/src/notes.xml
@@ -32,7 +32,23 @@
<file>notes.xml</file>
</header>
- <section><title>cosTime 1.1.13</title>
+ <section><title>cosTime 1.1.14</title>
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p> The default encoding of Erlang files has been changed
+ from ISO-8859-1 to UTF-8. </p> <p> The encoding of XML
+ files has also been changed to UTF-8. </p>
+ <p>
+ Own Id: OTP-10907</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>cosTime 1.1.13</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 eab402aee8..4b20f23efb 100644
--- a/lib/cosTransactions/doc/src/notes.xml
+++ b/lib/cosTransactions/doc/src/notes.xml
@@ -32,7 +32,23 @@
<file>notes.xml</file>
</header>
- <section><title>cosTransactions 1.2.13</title>
+ <section><title>cosTransactions 1.2.14</title>
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p> The default encoding of Erlang files has been changed
+ from ISO-8859-1 to UTF-8. </p> <p> The encoding of XML
+ files has also been changed to UTF-8. </p>
+ <p>
+ Own Id: OTP-10907</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>cosTransactions 1.2.13</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 53249479f1..34f2e3c469 100644
--- a/lib/crypto/doc/src/notes.xml
+++ b/lib/crypto/doc/src/notes.xml
@@ -30,6 +30,110 @@
</header>
<p>This document describes the changes made to the Crypto application.</p>
+<section><title>Crypto 3.3</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Fix memory leaks and invalid deallocations in
+ <c>mod_pow</c>, <c>mod_exp</c> and
+ <c>generate_key(srp,...)</c> when bad arguments are
+ passed. (Thanks to Florian Zumbiehi)</p>
+ <p>
+ Own Id: OTP-11550</p>
+ </item>
+ <item>
+ <p>
+ Correction of the word 'ChipherText' throughout the
+ documentation (Thanks to Andrew Tunnell-Jones)</p>
+ <p>
+ Own Id: OTP-11609</p>
+ </item>
+ <item>
+ <p>
+ Fix fatal bug when using a hmac context variable in more
+ than one call to <c>hmac_update</c> or <c>hmac_final</c>.
+ The reuse of hmac contexts has never worked as the
+ underlying OpenSSL implementation does not support it. It
+ is now documented as having undefined behaviour, but it
+ does not crash or corrupt the VM anymore.</p>
+ <p>
+ Own Id: OTP-11724</p>
+ </item>
+ <item>
+ <p>
+ Crypto handles out-of-memory with a controlled abort
+ instead of crash/corruption. (Thanks to Florian Zumbiehi)</p>
+ <p>
+ Own Id: OTP-11725</p>
+ </item>
+ <item>
+ <p>
+ Application upgrade (appup) files are corrected for the
+ following applications: </p>
+ <p>
+ <c>asn1, common_test, compiler, crypto, debugger,
+ dialyzer, edoc, eldap, erl_docgen, et, eunit, gs, hipe,
+ inets, observer, odbc, os_mon, otp_mibs, parsetools,
+ percept, public_key, reltool, runtime_tools, ssh,
+ syntax_tools, test_server, tools, typer, webtool, wx,
+ xmerl</c></p>
+ <p>
+ A new test utility for testing appup files is added to
+ test_server. This is now used by most applications in
+ OTP.</p>
+ <p>
+ (Thanks to Tobias Schlager)</p>
+ <p>
+ Own Id: OTP-11744</p>
+ </item>
+ </list>
+ </section>
+
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p>
+ By giving --enable-static-{nifs,drivers} to configure it
+ is now possible to statically linking of nifs and drivers
+ to the main Erlang VM binary. At the moment only the asn1
+ and crypto nifs of the Erlang/OTP nifs and drivers have
+ been prepared to be statically linked. For more details
+ see the Installation Guide in the System documentation.</p>
+ <p>
+ Own Id: OTP-11258</p>
+ </item>
+ <item>
+ <p>
+ Add IGE mode for AES cipher in crypto (Thanks to Yura
+ Beznos).</p>
+ <p>
+ Own Id: OTP-11522</p>
+ </item>
+ <item>
+ <p>
+ Moved elliptic curve definition from the crypto
+ NIF/OpenSSL into Erlang code, adds the RFC-5639 brainpool
+ curves and makes TLS use them (RFC-7027).</p>
+ <p>
+ Thanks to Andreas Schultz</p>
+ <p>
+ Own Id: OTP-11578</p>
+ </item>
+ <item>
+ <p>
+ Remove all obsolete application processes from crypto and
+ make it into a pure library application.</p>
+ <p>
+ Own Id: OTP-11619</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>Crypto 3.2</title>
<section><title>Fixed Bugs and Malfunctions</title>
diff --git a/lib/debugger/doc/src/notes.xml b/lib/debugger/doc/src/notes.xml
index a3543a1e11..8832f99fc3 100644
--- a/lib/debugger/doc/src/notes.xml
+++ b/lib/debugger/doc/src/notes.xml
@@ -32,6 +32,72 @@
<p>This document describes the changes made to the Debugger
application.</p>
+<section><title>Debugger 4.0</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ The debugger now correctly evaluates code such as '<c>X =
+ true andalso X</c>'. (Thanks to Anthony Ramine.)</p>
+ <p>
+ Own Id: OTP-11553</p>
+ </item>
+ <item>
+ <p>
+ A few subtle bugs in the evaluation of code in the
+ debugger has been corrected. (Thanks to Anthony Ramine.)</p>
+ <p>
+ Own Id: OTP-11676</p>
+ </item>
+ <item>
+ <p>
+ Application upgrade (appup) files are corrected for the
+ following applications: </p>
+ <p>
+ <c>asn1, common_test, compiler, crypto, debugger,
+ dialyzer, edoc, eldap, erl_docgen, et, eunit, gs, hipe,
+ inets, observer, odbc, os_mon, otp_mibs, parsetools,
+ percept, public_key, reltool, runtime_tools, ssh,
+ syntax_tools, test_server, tools, typer, webtool, wx,
+ xmerl</c></p>
+ <p>
+ A new test utility for testing appup files is added to
+ test_server. This is now used by most applications in
+ OTP.</p>
+ <p>
+ (Thanks to Tobias Schlager)</p>
+ <p>
+ Own Id: OTP-11744</p>
+ </item>
+ </list>
+ </section>
+
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p>
+ Removed gs based applications and gs based backends. The
+ <c>observer</c> application replaces the removed
+ applications.</p>
+ <p>
+ *** POTENTIAL INCOMPATIBILITY ***</p>
+ <p>
+ Own Id: OTP-10915</p>
+ </item>
+ <item>
+ <p>
+ Support Maps syntax in debugger (Thanks to Anthony
+ Ramine).</p>
+ <p>
+ Own Id: OTP-11673</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>Debugger 3.2.12</title>
<section><title>Improvements and New Features</title>
diff --git a/lib/dialyzer/doc/src/notes.xml b/lib/dialyzer/doc/src/notes.xml
index b61b1af1b0..05baa93557 100644
--- a/lib/dialyzer/doc/src/notes.xml
+++ b/lib/dialyzer/doc/src/notes.xml
@@ -31,6 +31,173 @@
<p>This document describes the changes made to the Dialyzer
application.</p>
+<section><title>Dialyzer 2.7</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p> Dialyzer will no longer emit warnings when inspecting
+ or modifying opaque types within the scope of a module.
+ </p> <p> Hitherto the shape of terms (tuple, list, etc.)
+ has been used to determine the opaque terms, but now the
+ contracts are used for decorating types with opaqueness.
+ </p>
+ <p>
+ Own Id: OTP-10397</p>
+ </item>
+ <item>
+ <p>
+ With <c>--Wunmatched_returns</c>, dialyzer will no longer
+ warn when the value of a list comprehension is ignored,
+ provided that the each value in the list would be an
+ atomic value (such as integer or atoms, as opposed to
+ tuples and lists). Example: ignoring '<c>[io:format(...)
+ || ...]</c>' will not cause a warning, while ignoring
+ '<c>[file:close(Fd) || ...]</c>' will.</p>
+ <p>
+ Own Id: OTP-11626</p>
+ </item>
+ <item>
+ <p>
+ The man page for dialyzer now contains correct
+ information regarding -Wno_behaviours. (Thanks to Steve
+ Vinosky.)</p>
+ <p>
+ Own Id: OTP-11706</p>
+ </item>
+ <item>
+ <p> Fix handling of 'on_load' attribute. (Thanks to
+ Kostis Sagonas.) </p>
+ <p>
+ Own Id: OTP-11743</p>
+ </item>
+ <item>
+ <p>
+ Application upgrade (appup) files are corrected for the
+ following applications: </p>
+ <p>
+ <c>asn1, common_test, compiler, crypto, debugger,
+ dialyzer, edoc, eldap, erl_docgen, et, eunit, gs, hipe,
+ inets, observer, odbc, os_mon, otp_mibs, parsetools,
+ percept, public_key, reltool, runtime_tools, ssh,
+ syntax_tools, test_server, tools, typer, webtool, wx,
+ xmerl</c></p>
+ <p>
+ A new test utility for testing appup files is added to
+ test_server. This is now used by most applications in
+ OTP.</p>
+ <p>
+ (Thanks to Tobias Schlager)</p>
+ <p>
+ Own Id: OTP-11744</p>
+ </item>
+ <item>
+ <p> The generalization of guard constraints has been
+ modified. </p>
+ <p>
+ Own Id: OTP-11798 Aux Id: seq12547 </p>
+ </item>
+ <item>
+ <p> Dialyzer now plays nicely with funs that come as
+ "external" arguments. (Thanks to Stavros Aronis for
+ fixing the bug.) </p>
+ <p>
+ Own Id: OTP-11826</p>
+ </item>
+ </list>
+ </section>
+
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p> The pre-defined types <c>array/0</c>, <c>dict/0</c>,
+ <c>digraph/0</c>, <c>gb_set/0</c>, <c>gb_tree/0</c>,
+ <c>queue/0</c>, <c>set/0</c>, and <c>tid/0</c> have been
+ deprecated. They will be removed in Erlang/OTP 18.0. </p>
+ <p> Instead the types <c>array:array/0</c>,
+ <c>dict:dict/0</c>, <c>digraph:graph/0</c>,
+ <c>gb_set:set/0</c>, <c>gb_tree:tree/0</c>,
+ <c>queue:queue/0</c>, <c>sets:set/0</c>, and
+ <c>ets:tid/0</c> can be used. (Note: it has always been
+ necessary to use <c>ets:tid/0</c>.) </p> <p> It is
+ allowed in Erlang/OTP 17.0 to locally re-define the types
+ <c>array/0</c>, <c>dict/0</c>, and so on. </p> <p> New
+ types <c>array:array/1</c>, <c>dict:dict/2</c>,
+ <c>gb_sets:set/1</c>, <c>gb_trees:tree/2</c>,
+ <c>queue:queue/1</c>, and <c>sets:set/1</c> have been
+ added. </p> <p> A compiler option,
+ <c>nowarn_deprecated_type</c>, has been introduced. By
+ including the attribute </p> <c>
+ -compile(nowarn_deprecated_type).</c> <p> in an Erlang
+ source file, warnings about deprecated types can be
+ avoided in Erlang/OTP 17.0. </p> <p> The option can also
+ be given as a compiler flag: </p> <c> erlc
+ +nowarn_deprecated_type file.erl</c>
+ <p>
+ Own Id: OTP-10342</p>
+ </item>
+ <item>
+ <p>
+ Removed gs based applications and gs based backends. The
+ <c>observer</c> application replaces the removed
+ applications.</p>
+ <p>
+ *** POTENTIAL INCOMPATIBILITY ***</p>
+ <p>
+ Own Id: OTP-10915</p>
+ </item>
+ <item>
+ <p>
+ Forbid unsized fields in patterns of binary generators
+ and simplified v3_core's translation of bit string
+ generators. (Thanks to Anthony Ramine.)</p>
+ <p>
+ Own Id: OTP-11186</p>
+ </item>
+ <item>
+ <p>
+ EEP43: New data type - Maps</p>
+ <p>
+ With Maps you may for instance: <taglist> <item><c>M0 =
+ #{ a =&gt; 1, b =&gt; 2}, % create
+ associations</c></item> <item><c>M1 = M0#{ a := 10 }, %
+ update values</c></item> <item><c>M2 = M1#{ "hi" =&gt;
+ "hello"}, % add new associations</c></item> <item><c>#{
+ "hi" := V1, a := V2, b := V3} = M2. % match keys with
+ values</c></item> </taglist></p>
+ <p>
+ For information on how to use Maps please see the
+ <seealso marker="doc/reference_manual:maps">Reference
+ Manual</seealso>.</p>
+ <p>
+ The current implementation is without the following
+ features: <taglist> <item>No variable keys</item>
+ <item>No single value access</item> <item>No map
+ comprehensions</item> </taglist></p>
+ <p>
+ Note that Maps is <em>experimental</em> during OTP 17.0.</p>
+ <p>
+ Own Id: OTP-11616</p>
+ </item>
+ <item>
+ <p> Parameterized opaque types have been introduced. </p>
+ <p>
+ Own Id: OTP-11625</p>
+ </item>
+ <item>
+ <p>
+ Some function specs are corrected or moved and some edoc
+ comments are corrected in order to allow use of edoc.
+ (Thanks to Pierre Fenoll)</p>
+ <p>
+ Own Id: OTP-11702</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>Dialyzer 2.6.1</title>
<section><title>Fixed Bugs and Malfunctions</title>
diff --git a/lib/dialyzer/src/Makefile b/lib/dialyzer/src/Makefile
index d7265ba31a..91fbdca5bd 100644
--- a/lib/dialyzer/src/Makefile
+++ b/lib/dialyzer/src/Makefile
@@ -88,7 +88,7 @@ APPUP_TARGET= $(EBIN)/$(APPUP_FILE)
ifeq ($(NATIVE_LIBS_ENABLED),yes)
ERL_COMPILE_FLAGS += +native
endif
-ERL_COMPILE_FLAGS += +warn_exported_vars +warn_unused_import +warn_untyped_record +warn_missing_spec +warnings_as_errors
+ERL_COMPILE_FLAGS += +warn_export_vars +warn_unused_import +warn_untyped_record +warn_missing_spec +warnings_as_errors
# ----------------------------------------------------
# Targets
diff --git a/lib/dialyzer/src/dialyzer_analysis_callgraph.erl b/lib/dialyzer/src/dialyzer_analysis_callgraph.erl
index 2a633c5e37..6a33a2acb3 100644
--- a/lib/dialyzer/src/dialyzer_analysis_callgraph.erl
+++ b/lib/dialyzer/src/dialyzer_analysis_callgraph.erl
@@ -249,7 +249,7 @@ compile_and_store(Files, #analysis_state{codeserver = CServer,
timing_server = Timing,
parent = Parent} = State) ->
send_log(Parent, "Reading files and computing callgraph... "),
- {T1, _} = statistics(runtime),
+ {T1, _} = statistics(wall_clock),
Callgraph = dialyzer_callgraph:new(),
CompileInit = make_compile_init(State, Callgraph),
{{Failed, NoWarn, Modules}, NextLabel} =
@@ -272,13 +272,13 @@ compile_and_store(Files, #analysis_state{codeserver = CServer,
[[Reason || {_Filename, Reason} <- Failed]]),
exit({error, Msg})
end,
- {T2, _} = statistics(runtime),
+ {T2, _} = statistics(wall_clock),
Msg1 = io_lib:format("done in ~.2f secs\nRemoving edges... ", [(T2-T1)/1000]),
send_log(Parent, Msg1),
Callgraph =
?timing(Timing, "clean", _C2,
cleanup_callgraph(State, CServer2, Callgraph, Modules)),
- {T3, _} = statistics(runtime),
+ {T3, _} = statistics(wall_clock),
Msg2 = io_lib:format("done in ~.2f secs\n", [(T3-T2)/1000]),
send_log(Parent, Msg2),
{Callgraph, sets:from_list(NoWarn), CServer2}.
@@ -620,9 +620,9 @@ dump_callgraph(CallGraph, State, #analysis{callgraph_file = File} = Analysis) ->
Extension = filename:extension(File),
Start_Msg = io_lib:format("Dumping the callgraph... ", []),
send_log(State#analysis_state.parent, Start_Msg),
- {T1, _} = statistics(runtime),
+ {T1, _} = statistics(wall_clock),
dump_callgraph(CallGraph, State, Analysis, Extension),
- {T2, _} = statistics(runtime),
+ {T2, _} = statistics(wall_clock),
Finish_Msg = io_lib:format("done in ~2f secs\n", [(T2-T1)/1000]),
send_log(State#analysis_state.parent, Finish_Msg),
ok.
diff --git a/lib/dialyzer/src/dialyzer_cl.erl b/lib/dialyzer/src/dialyzer_cl.erl
index e013d39a0e..3e7d9dfa99 100644
--- a/lib/dialyzer/src/dialyzer_cl.erl
+++ b/lib/dialyzer/src/dialyzer_cl.erl
@@ -504,9 +504,7 @@ hipe_compile(Files, #options{erlang_mode = ErlangMode} = Options) ->
_ ->
Mods = [lists, dict, digraph, digraph_utils, ets,
gb_sets, gb_trees, ordsets, sets, sofs,
- %cerl, % uses maps instructions
- %erl_types, % uses maps instructions
- cerl_trees, erl_bif_types,
+ cerl, erl_types, cerl_trees, erl_bif_types,
dialyzer_analysis_callgraph, dialyzer, dialyzer_behaviours,
dialyzer_codeserver, dialyzer_contracts,
dialyzer_coordinator, dialyzer_dataflow, dialyzer_dep,
diff --git a/lib/dialyzer/src/dialyzer_dataflow.erl b/lib/dialyzer/src/dialyzer_dataflow.erl
index 692684cd99..e0873b17f8 100644
--- a/lib/dialyzer/src/dialyzer_dataflow.erl
+++ b/lib/dialyzer/src/dialyzer_dataflow.erl
@@ -363,20 +363,24 @@ traverse_list([], Map, State, Acc) ->
handle_apply(Tree, Map, State) ->
Args = cerl:apply_args(Tree),
Op = cerl:apply_op(Tree),
- {State1, Map1, ArgTypes} = traverse_list(Args, Map, State),
- {State2, Map2, OpType} = traverse(Op, Map1, State1),
+ {State0, Map1, ArgTypes} = traverse_list(Args, Map, State),
+ {State1, Map2, OpType} = traverse(Op, Map1, State0),
case any_none(ArgTypes) of
true ->
- {State2, Map2, t_none()};
+ {State1, Map2, t_none()};
false ->
- {CallSitesKnown, FunList} =
- case state__lookup_call_site(Tree, State2) of
- error -> {false, []};
- {ok, [external]} -> {false, []};
- {ok, List} -> {true, List}
+ FunList =
+ case state__lookup_call_site(Tree, State) of
+ error -> [external]; %% so that we go directly in the fallback
+ {ok, List} -> List
end,
- case CallSitesKnown of
- false ->
+ FunInfoList = [{local, state__fun_info(Fun, State)} || Fun <- FunList],
+ case
+ handle_apply_or_call(FunInfoList, Args, ArgTypes, Map2, Tree, State1)
+ of
+ {had_external, State2} ->
+ %% Fallback: use whatever info we collected from traversing the op
+ %% instead of the result that has been generalized to t_any().
Arity = length(Args),
OpType1 = t_inf(OpType, t_fun(Arity, t_any())),
case t_is_none(OpType1) of
@@ -408,25 +412,23 @@ handle_apply(Tree, Map, State) ->
{State2, enter_type(Op, OpType1, Map3), Range}
end
end;
- true ->
- FunInfoList = [{local, state__fun_info(Fun, State)}
- || Fun <- FunList],
- handle_apply_or_call(FunInfoList, Args, ArgTypes, Map2, Tree, State1)
+ Normal -> Normal
end
end.
handle_apply_or_call(FunInfoList, Args, ArgTypes, Map, Tree, State) ->
None = t_none(),
handle_apply_or_call(FunInfoList, Args, ArgTypes, Map, Tree, State,
- [None || _ <- ArgTypes], None).
+ [None || _ <- ArgTypes], None, false).
handle_apply_or_call([{local, external}|Left], Args, ArgTypes, Map, Tree, State,
- _AccArgTypes, _AccRet) ->
+ _AccArgTypes, _AccRet, _HadExternal) ->
handle_apply_or_call(Left, Args, ArgTypes, Map, Tree, State,
- ArgTypes, t_any());
+ ArgTypes, t_any(), true);
handle_apply_or_call([{TypeOfApply, {Fun, Sig, Contr, LocalRet}}|Left],
Args, ArgTypes, Map, Tree,
- #state{opaques = Opaques} = State, AccArgTypes, AccRet) ->
+ #state{opaques = Opaques} = State,
+ AccArgTypes, AccRet, HadExternal) ->
Any = t_any(),
AnyArgs = [Any || _ <- Args],
GenSig = {AnyArgs, fun(_) -> t_any() end},
@@ -573,11 +575,16 @@ handle_apply_or_call([{TypeOfApply, {Fun, Sig, Contr, LocalRet}}|Left],
NewAccRet = t_sup(AccRet, TotalRet),
?debug("NewAccRet: ~s\n", [t_to_string(NewAccRet)]),
handle_apply_or_call(Left, Args, ArgTypes, Map, Tree,
- State3, NewAccArgTypes, NewAccRet);
+ State3, NewAccArgTypes, NewAccRet, HadExternal);
handle_apply_or_call([], Args, _ArgTypes, Map, _Tree, State,
- AccArgTypes, AccRet) ->
- NewMap = enter_type_lists(Args, AccArgTypes, Map),
- {State, NewMap, AccRet}.
+ AccArgTypes, AccRet, HadExternal) ->
+ case HadExternal of
+ false ->
+ NewMap = enter_type_lists(Args, AccArgTypes, Map),
+ {State, NewMap, AccRet};
+ true ->
+ {had_external, State}
+ end.
apply_fail_reason(FailedSig, FailedBif, FailedContract) ->
if
diff --git a/lib/dialyzer/src/dialyzer_dep.erl b/lib/dialyzer/src/dialyzer_dep.erl
index e3ece144c9..572e60278d 100644
--- a/lib/dialyzer/src/dialyzer_dep.erl
+++ b/lib/dialyzer/src/dialyzer_dep.erl
@@ -124,8 +124,10 @@ traverse(Tree, Out, State, CurrentFun) ->
TmpState = state__add_deps(Label, O1, State),
state__add_deps(CurrentFun, O2,TmpState)
end,
- {BodyFuns, State2} = traverse(Body, Out, State1,
- cerl_trees:get_label(Tree)),
+ Vars = cerl:fun_vars(Tree),
+ Out1 = bind_single(Vars, output(set__singleton(external)), Out),
+ {BodyFuns, State2} =
+ traverse(Body, Out1, State1, cerl_trees:get_label(Tree)),
{output(set__singleton(Label)), state__add_esc(BodyFuns, State2)};
'let' ->
Vars = cerl:let_vars(Tree),
diff --git a/lib/dialyzer/src/dialyzer_gui_wx.erl b/lib/dialyzer/src/dialyzer_gui_wx.erl
index 7070fa240d..868857d675 100644
--- a/lib/dialyzer/src/dialyzer_gui_wx.erl
+++ b/lib/dialyzer/src/dialyzer_gui_wx.erl
@@ -699,8 +699,7 @@ handle_add_files(#gui_state{chosen_box = ChosenBox, file_box = FileBox,
end.
handle_add_dir(#gui_state{chosen_box = ChosenBox, dir_entry = DirBox,
- files_to_analyze = FileList,
- mode = Mode} = State) ->
+ files_to_analyze = FileList, mode = Mode} = State) ->
case wxDirPickerCtrl:getPath(DirBox) of
"" ->
State;
@@ -714,8 +713,8 @@ handle_add_dir(#gui_state{chosen_box = ChosenBox, dir_entry = DirBox,
State#gui_state{files_to_analyze = add_files(filter_mods(NewDir1,Ext), FileList, ChosenBox, Ext)}
end.
-handle_add_rec(#gui_state{chosen_box = ChosenBox, dir_entry = DirBox, files_to_analyze = FileList,
- mode = Mode} = State) ->
+handle_add_rec(#gui_state{chosen_box = ChosenBox, dir_entry = DirBox,
+ files_to_analyze = FileList, mode = Mode} = State) ->
case wxDirPickerCtrl:getPath(DirBox) of
"" ->
State;
@@ -723,11 +722,11 @@ handle_add_rec(#gui_state{chosen_box = ChosenBox, dir_entry = DirBox, files_to_a
NewDir = ordsets:new(),
NewDir1 = ordsets:add_element(Dir,NewDir),
TargetDirs = ordsets:union(NewDir1, all_subdirs(NewDir1)),
- case wxRadioBox:getSelection(Mode) of
- 0 -> Ext = ".beam";
- 1-> Ext = ".erl"
- end,
- State#gui_state{files_to_analyze = add_files(filter_mods(TargetDirs,Ext), FileList, ChosenBox, Ext)}
+ Ext = case wxRadioBox:getSelection(Mode) of
+ 0 -> ".beam";
+ 1 -> ".erl"
+ end,
+ State#gui_state{files_to_analyze = add_files(filter_mods(TargetDirs, Ext), FileList, ChosenBox, Ext)}
end.
handle_file_delete(#gui_state{chosen_box = ChosenBox,
@@ -886,13 +885,10 @@ config_gui_start(State) ->
wxRadioBox:disable(State#gui_state.mode).
save_file(#gui_state{frame = Frame, warnings_box = WBox, log = Log} = State, Type) ->
- case Type of
- warnings ->
- Message = "Save Warnings",
- Box = WBox;
- log -> Message = "Save Log",
- Box = Log
- end,
+ {Message, Box} = case Type of
+ warnings -> {"Save Warnings", WBox};
+ log -> {"Save Log", Log}
+ end,
case wxTextCtrl:getValue(Box) of
"" -> error_sms(State,"There is nothing to save...\n");
_ ->
@@ -936,8 +932,7 @@ include_dialog(#gui_state{gui = Wx, frame = Frame, options = Options}) ->
wxButton:connect(DeleteAllButton, command_button_clicked),
wxButton:connect(Ok, command_button_clicked),
wxButton:connect(Cancel, command_button_clicked),
- Dirs = [io_lib:format("~s", [X])
- || X <- Options#options.include_dirs],
+ Dirs = [io_lib:format("~s", [X]) || X <- Options#options.include_dirs],
wxListBox:set(Box, Dirs),
Layout = wxBoxSizer:new(?wxVERTICAL),
Buttons = wxBoxSizer:new(?wxHORIZONTAL),
diff --git a/lib/dialyzer/src/dialyzer_races.erl b/lib/dialyzer/src/dialyzer_races.erl
index b1f849b16f..28c2ad2c0b 100644
--- a/lib/dialyzer/src/dialyzer_races.erl
+++ b/lib/dialyzer/src/dialyzer_races.erl
@@ -990,8 +990,7 @@ fixup_race_forward_helper(CurrFun, CurrFunLabel, Fun, FunLabel,
NewRaceVarMap, Args, NewFunArgs, NewFunTypes, NestingLevel};
{CurrFun, Fun} ->
NewCallsToAnalyze = lists:delete(Head, CallsToAnalyze),
- NewRaceVarMap =
- race_var_map(Args, NewFunArgs, RaceVarMap, bind),
+ NewRaceVarMap = race_var_map(Args, NewFunArgs, RaceVarMap, bind),
RetC =
case Fun of
InitFun ->
@@ -1018,8 +1017,7 @@ fixup_race_forward_helper(CurrFun, CurrFunLabel, Fun, FunLabel,
label = FunLabel, var_map = NewRaceVarMap,
def_vars = Args, call_vars = NewFunArgs,
arg_types = NewFunTypes}|
- lists:reverse(StateRaceList)] ++
- RetC;
+ lists:reverse(StateRaceList)] ++ RetC;
_ ->
[#curr_fun{status = in, mfa = Fun,
label = FunLabel, var_map = NewRaceVarMap,
@@ -1054,13 +1052,9 @@ fixup_race_backward(CurrFun, Calls, CallsToAnalyze, Parents, Height) ->
false -> [CurrFun|Parents]
end;
[Head|Tail] ->
- MorePaths =
- case Head of
- {Parent, CurrFun} -> true;
- {Parent, _TupleB} -> false
- end,
- case MorePaths of
- true ->
+ {Parent, TupleB} = Head,
+ case TupleB =:= CurrFun of
+ true -> % more paths are needed
NewCallsToAnalyze = lists:delete(Head, CallsToAnalyze),
NewParents =
fixup_race_backward(Parent, NewCallsToAnalyze,
diff --git a/lib/dialyzer/test/small_SUITE_data/results/funs_from_outside b/lib/dialyzer/test/small_SUITE_data/results/funs_from_outside
new file mode 100644
index 0000000000..3e597ef1bc
--- /dev/null
+++ b/lib/dialyzer/test/small_SUITE_data/results/funs_from_outside
@@ -0,0 +1,7 @@
+
+funs_from_outside.erl:18: The pattern 'error' can never match the type {'ok','nothing' | 'something'}
+funs_from_outside.erl:32: Function run2/2 has no local return
+funs_from_outside.erl:35: Function testb/3 has no local return
+funs_from_outside.erl:41: The pattern 'error' can never match the type {'ok','nothing' | 'something'}
+funs_from_outside.erl:78: Function test2/1 has no local return
+funs_from_outside.erl:83: The pattern 'error' can never match the type 'ok'
diff --git a/lib/dialyzer/test/small_SUITE_data/src/ddfs_master/common_types.hrl b/lib/dialyzer/test/small_SUITE_data/src/ddfs_master/common_types.hrl
new file mode 100644
index 0000000000..f362a06bca
--- /dev/null
+++ b/lib/dialyzer/test/small_SUITE_data/src/ddfs_master/common_types.hrl
@@ -0,0 +1,6 @@
+-type host() :: nonempty_string().
+-type path() :: nonempty_string().
+-type url() :: binary().
+
+% The host portion of a url, if available.
+-type url_host() :: host() | none.
diff --git a/lib/dialyzer/test/small_SUITE_data/src/ddfs_master/config.hrl b/lib/dialyzer/test/small_SUITE_data/src/ddfs_master/config.hrl
new file mode 100644
index 0000000000..8cab65fc9c
--- /dev/null
+++ b/lib/dialyzer/test/small_SUITE_data/src/ddfs_master/config.hrl
@@ -0,0 +1,148 @@
+
+-define(SECOND, 1000).
+-define(MINUTE, (60 * ?SECOND)).
+-define(HOUR, (60 * ?MINUTE)).
+-define(DAY, (24 * ?HOUR)).
+-define(MB, (1024 * 1024)).
+
+% Maximum length of tag/blob prefix
+-define(NAME_MAX, 511).
+
+% How long ddfs node startup can take. The most time-consuming part
+% is the scanning of the tag objects in the node's DDFS volumes.
+-define(NODE_STARTUP, (1 * ?MINUTE)).
+
+% How long to wait on the master for replies from nodes.
+-define(NODE_TIMEOUT, (10 * ?SECOND)).
+
+% How long to wait for a reply from an operation coordinated by the
+% master that accesses nodes. This value should be larger than
+% NODE_TIMEOUT.
+-define(NODEOP_TIMEOUT, (1 * ?MINUTE)).
+
+% The minimum amount of free space a node must have, to be considered
+% a primary candidate host for a new blob.
+-define(MIN_FREE_SPACE, (1024 * ?MB)).
+
+% The maximum number of active HTTP connections on a system (this
+% applies separately for GET and PUT operations).
+-define(HTTP_MAX_ACTIVE, 3).
+
+% The maximum number of waiting HTTP connections to queue up on a busy system.
+-define(HTTP_QUEUE_LENGTH, 100).
+
+% The maximum number of simultaneous HTTP connections. Note that
+% HTTP_MAX_CONNS * 2 * 2 + 32 < Maximum number of file descriptors, where
+% 2 = Get and put, 2 = two FDs required for each connection (connection
+% itself + a file it accesses), 32 = a guess how many extra fds is needed.
+-define(HTTP_MAX_CONNS, 128).
+
+% How long to keep a PUT request in queue if the system is busy.
+-define(PUT_WAIT_TIMEOUT, (1 * ?MINUTE)).
+
+% How long to keep a GET request in queue if the system is busy.
+-define(GET_WAIT_TIMEOUT, (1 * ?MINUTE)).
+
+% An unused loaded tag expires in TAG_EXPIRES milliseconds. Note that
+% if TAG_EXPIRES is not smaller than GC_INTERVAL, tags will never
+% expire from the memory cache and will always take up memory.
+-define(TAG_EXPIRES, (10 * ?HOUR)).
+
+% How often the master's cache of all known tag names is refreshed.
+% This refresh is only needed to purge deleted tags eventually from
+% the tag cache. It doesn't harm to have a long interval.
+-define(TAG_CACHE_INTERVAL, (10 * ?MINUTE)).
+
+% How soon a tag object initialized in memory expires if it's content
+% cannot be fetched from the cluster.
+-define(TAG_EXPIRES_ONERROR, (1 * ?SECOND)).
+
+% How often a DDFS node should refresh its tag cache from disk.
+-define(FIND_TAGS_INTERVAL, ?DAY).
+
+% How often buffered (delayed) updates to a tag need to be
+% flushed. Tradeoff: The longer the interval, the more updates are
+% bundled in a single commit. On the other hand, in the worst case
+% the requester has to wait for the full interval before getting a
+% reply. A long interval also increases the likelihood that the server
+% crashes before the commit has finished successfully, making requests
+% more unreliable.
+-define(DELAYED_FLUSH_INTERVAL, (1 * ?SECOND)).
+
+% How long to wait between garbage collection runs.
+-define(GC_INTERVAL, ?DAY).
+
+% Max duration for a GC run. This should be smaller than
+% min(ORPHANED_{BLOB,TAG}_EXPIRES).
+-define(GC_MAX_DURATION, (3 * ?DAY)).
+
+% How long to wait after startup for cluster to stabilize before
+% starting the first GC run.
+-define(GC_DEFAULT_INITIAL_WAIT, (5 * ?MINUTE)).
+
+% The longest potential interval between messages in the GC protocol;
+% used to ensure GC makes forward progress. This can be set to the
+% estimated time to traverse all the volumes on a DDFS node.
+-define(GC_PROGRESS_INTERVAL, (30 * ?MINUTE)).
+
+% Number of extra replicas (i.e. lost replicas recovered during GC) to
+% allow before deleting extra replicas.
+-define(NUM_EXTRA_REPLICAS, 1).
+
+% Permissions for files backing blobs and tags.
+-define(FILE_MODE, 8#00400).
+
+% How often to check available disk space in ddfs_node.
+-define(DISKSPACE_INTERVAL, (10 * ?SECOND)).
+
+% The maximum size of payloads of HTTP requests to the /ddfs/tag/
+% prefix.
+-define(MAX_TAG_BODY_SIZE, (512 * ?MB)).
+
+% Tag attribute names and values have a limited size, and there
+% can be only a limited number of them.
+-define(MAX_TAG_ATTRIB_NAME_SIZE, 1024).
+-define(MAX_TAG_ATTRIB_VALUE_SIZE, 1024).
+-define(MAX_NUM_TAG_ATTRIBS, 1000).
+
+% How long HTTP requests that perform tag updates should wait to
+% finish (a long time).
+-define(TAG_UPDATE_TIMEOUT, ?DAY).
+
+% Timeout for re-replicating a single blob over HTTP PUT. This
+% depends on the largest blobs hosted by DDFS, and the speed of the
+% cluster network.
+-define(GC_PUT_TIMEOUT, (180 * ?MINUTE)).
+
+% Delete !partial files after this many milliseconds.
+-define(PARTIAL_EXPIRES, ?DAY).
+
+% When orphaned blob can be deleted. This should be large enough that
+% you can upload all the new blobs of a tag and perform the tag update
+% within this time.
+-define(ORPHANED_BLOB_EXPIRES, (5 * ?DAY)).
+
+% When orphaned tag can be deleted.
+-define(ORPHANED_TAG_EXPIRES, (5 * ?DAY)).
+
+% How long a tag has to stay on the deleted list before
+% we can permanently forget it, after all known instances
+% of the tag object have been removed. This quarantine period
+% ensures that a node that was temporarily unavailable
+% and reactivates can't resurrect deleted tags. You
+% must ensure that all temporarily inactive nodes
+% are reactivated (or cleaned) within the ?DELETED_TAG_EXPIRES
+% time frame.
+%
+% This value _must_ be larger than the other time-related DDFS
+% parameters listed in this file. In particular, it must be larger
+% than ORPHANED_TAG_EXPIRES.
+-define(DELETED_TAG_EXPIRES, (30 * ?DAY)).
+
+% How many times a tag operation should be retried before aborting.
+-define(MAX_TAG_OP_RETRIES, 3).
+
+% How long to wait before timing out a tag retrieval. This should be
+% large enough to read a large tag object off the disk and send it
+% over the network.
+-define(GET_TAG_TIMEOUT, (5 * ?MINUTE)).
diff --git a/lib/dialyzer/test/small_SUITE_data/src/ddfs_master/ddfs.hrl b/lib/dialyzer/test/small_SUITE_data/src/ddfs_master/ddfs.hrl
new file mode 100644
index 0000000000..e43ec23fe1
--- /dev/null
+++ b/lib/dialyzer/test/small_SUITE_data/src/ddfs_master/ddfs.hrl
@@ -0,0 +1,9 @@
+-type volume_name() :: nonempty_string().
+
+% Diskinfo is {FreeSpace, UsedSpace}.
+-type diskinfo() :: {non_neg_integer(), non_neg_integer()}.
+-type volume() :: {diskinfo(), volume_name()}.
+
+-type object_type() :: 'blob' | 'tag'.
+-type object_name() :: binary().
+-type taginfo() :: {erlang:timestamp(), volume_name()}.
diff --git a/lib/dialyzer/test/small_SUITE_data/src/ddfs_master/ddfs_gc.hrl b/lib/dialyzer/test/small_SUITE_data/src/ddfs_master/ddfs_gc.hrl
new file mode 100644
index 0000000000..dc43f7586b
--- /dev/null
+++ b/lib/dialyzer/test/small_SUITE_data/src/ddfs_master/ddfs_gc.hrl
@@ -0,0 +1,17 @@
+-type local_object() :: {object_name(), node()}.
+-type phase() :: 'start' | 'build_map' | 'map_wait' | 'gc'
+ | 'rr_blobs' | 'rr_blobs_wait' | 'rr_tags'.
+-type protocol_msg() :: {'check_blob', object_name()} | 'start_gc' | 'end_rr'.
+
+-type blob_update() :: {object_name(), 'filter' | [url()]}.
+
+-type check_blob_result() :: 'false' | {'true', volume_name()}.
+
+% GC statistics
+
+% {Files, Bytes}
+-type gc_stat() :: {non_neg_integer(), non_neg_integer()}.
+% {Kept, Deleted}
+-type obj_stats() :: {gc_stat(), gc_stat()}.
+% {Tags, Blobs}.
+-type gc_run_stats() :: {obj_stats(), obj_stats()}.
diff --git a/lib/dialyzer/test/small_SUITE_data/src/ddfs_master/ddfs_master.erl b/lib/dialyzer/test/small_SUITE_data/src/ddfs_master/ddfs_master.erl
new file mode 100644
index 0000000000..2be2773dc5
--- /dev/null
+++ b/lib/dialyzer/test/small_SUITE_data/src/ddfs_master/ddfs_master.erl
@@ -0,0 +1,531 @@
+-module(ddfs_master).
+-behaviour(gen_server).
+
+-export([start_link/0]).
+-export([get_tags/1, get_tags/3,
+ get_nodeinfo/1,
+ get_read_nodes/0,
+ get_hosted_tags/1,
+ gc_blacklist/0, gc_blacklist/1,
+ gc_stats/0,
+ choose_write_nodes/3,
+ new_blob/4, new_blob/5,
+ safe_gc_blacklist/0, safe_gc_blacklist/1,
+ refresh_tag_cache/0,
+ tag_notify/2,
+ tag_operation/2, tag_operation/3,
+ update_gc_stats/1,
+ update_nodes/1
+ ]).
+-export([init/1,
+ handle_call/3,
+ handle_cast/2,
+ handle_info/2,
+ terminate/2,
+ code_change/3]).
+
+-define(WEB_PORT, 8011).
+
+-compile(nowarn_deprecated_type).
+
+-include("common_types.hrl").
+-include("gs_util.hrl").
+-include("config.hrl").
+-include("ddfs.hrl").
+-include("ddfs_tag.hrl").
+-include("ddfs_gc.hrl").
+
+-type node_info() :: {node(), {non_neg_integer(), non_neg_integer()}}.
+-type gc_stats() :: none | gc_run_stats().
+
+-record(state, {tags = gb_trees:empty() :: gb_trees:tree(),
+ tag_cache = false :: false | gb_sets:set(),
+ cache_refresher :: pid(),
+
+ nodes = [] :: [node_info()],
+ write_blacklist = [] :: [node()],
+ read_blacklist = [] :: [node()],
+ gc_blacklist = [] :: [node()],
+ safe_gc_blacklist = gb_sets:empty() :: gb_sets:set(),
+ gc_stats = none :: none | {gc_stats(), erlang:timestamp()}}).
+-type state() :: #state{}.
+-type replyto() :: {pid(), reference()}.
+
+-export_type([gc_stats/0, node_info/0]).
+
+%% ===================================================================
+%% API functions
+
+-spec start_link() -> {ok, pid()}.
+start_link() ->
+ lager:info("DDFS master starts"),
+ case gen_server:start_link({local, ?MODULE}, ?MODULE, [], []) of
+ {ok, Server} -> {ok, Server};
+ {error, {already_started, Server}} -> {ok, Server}
+ end.
+
+-spec tag_operation(term(), tagname()) -> term().
+tag_operation(Op, Tag) ->
+ gen_server:call(?MODULE, {tag, Op, Tag}).
+-spec tag_operation(term(), tagname(), non_neg_integer() | infinity) ->
+ term().
+tag_operation(Op, Tag, Timeout) ->
+ gen_server:call(?MODULE, {tag, Op, Tag}, Timeout).
+
+-spec tag_notify(term(), tagname()) -> ok.
+tag_notify(Op, Tag) ->
+ gen_server:cast(?MODULE, {tag_notify, Op, Tag}).
+
+-spec get_nodeinfo(all) -> {ok, [node_info()]}.
+get_nodeinfo(all) ->
+ gen_server:call(?MODULE, {get_nodeinfo, all}).
+
+-spec get_read_nodes() -> {ok, [node()], non_neg_integer()} | {error, term()}.
+get_read_nodes() ->
+ gen_server:call(?MODULE, get_read_nodes, infinity).
+
+-spec gc_blacklist() -> {ok, [node()]}.
+gc_blacklist() ->
+ gen_server:call(?MODULE, gc_blacklist).
+
+-spec gc_blacklist([node()]) -> ok.
+gc_blacklist(Nodes) ->
+ gen_server:cast(?MODULE, {gc_blacklist, Nodes}).
+
+-spec gc_stats() -> {ok, none | {gc_stats(), erlang:timestamp()}} | {error, term()}.
+gc_stats() ->
+ gen_server:call(?MODULE, gc_stats).
+
+-spec get_hosted_tags(host()) -> {ok, [tagname()]} | {error, term()}.
+get_hosted_tags(Host) ->
+ gen_server:call(?MODULE, {get_hosted_tags, Host}).
+
+-spec choose_write_nodes(non_neg_integer(), [node()], [node()]) -> {ok, [node()]}.
+choose_write_nodes(K, Include, Exclude) ->
+ gen_server:call(?MODULE, {choose_write_nodes, K, Include, Exclude}).
+
+-spec get_tags(gc) -> {ok, [tagname()], [node()]} | too_many_failed_nodes;
+ (safe) -> {ok, [binary()]} | too_many_failed_nodes.
+get_tags(Mode) ->
+ get_tags(?MODULE, Mode, ?GET_TAG_TIMEOUT).
+
+-spec get_tags(server(), gc, non_neg_integer()) ->
+ {ok, [tagname()], [node()]} | too_many_failed_nodes;
+ (server(), safe, non_neg_integer()) ->
+ {ok, [binary()]} | too_many_failed_nodes.
+get_tags(Server, Mode, Timeout) ->
+ disco_profile:timed_run(
+ fun() -> gen_server:call(Server, {get_tags, Mode}, Timeout) end,
+ get_tags).
+
+-spec new_blob(string()|object_name(), non_neg_integer(), [node()], [node()]) ->
+ too_many_replicas | {ok, [nonempty_string()]}.
+new_blob(Obj, K, Include, Exclude) ->
+ gen_server:call(?MODULE, {new_blob, Obj, K, Include, Exclude}, infinity).
+
+-spec new_blob(server(), string()|object_name(), non_neg_integer(), [node()], [node()]) ->
+ too_many_replicas | {ok, [nonempty_string()]}.
+new_blob(Master, Obj, K, Include, Exclude) ->
+ gen_server:call(Master, {new_blob, Obj, K, Include, Exclude}, infinity).
+
+-spec safe_gc_blacklist() -> {ok, [node()]} | {error, term()}.
+safe_gc_blacklist() ->
+ gen_server:call(?MODULE, safe_gc_blacklist).
+
+-spec safe_gc_blacklist(gb_sets:set()) -> ok.
+safe_gc_blacklist(SafeGCBlacklist) ->
+ gen_server:cast(?MODULE, {safe_gc_blacklist, SafeGCBlacklist}).
+
+-spec update_gc_stats(gc_run_stats()) -> ok.
+update_gc_stats(Stats) ->
+ gen_server:cast(?MODULE, {update_gc_stats, Stats}).
+
+-type nodes_update() :: [{node(), boolean(), boolean()}].
+-spec update_nodes(nodes_update()) -> ok.
+update_nodes(DDFSNodes) ->
+ gen_server:cast(?MODULE, {update_nodes, DDFSNodes}).
+
+-spec update_nodestats(gb_trees:tree()) -> ok.
+update_nodestats(NewNodes) ->
+ gen_server:cast(?MODULE, {update_nodestats, NewNodes}).
+
+-spec update_tag_cache(gb_sets:set()) -> ok.
+update_tag_cache(TagCache) ->
+ gen_server:cast(?MODULE, {update_tag_cache, TagCache}).
+
+-spec refresh_tag_cache() -> ok.
+refresh_tag_cache() ->
+ gen_server:cast(?MODULE, refresh_tag_cache).
+
+%% ===================================================================
+%% gen_server callbacks
+
+-spec init(_) -> gs_init().
+init(_Args) ->
+ _ = [disco_profile:new_histogram(Name)
+ || Name <- [get_tags, do_get_tags_all, do_get_tags_filter,
+ do_get_tags_safe, do_get_tags_gc]],
+ spawn_link(fun() -> monitor_diskspace() end),
+ spawn_link(fun() -> ddfs_gc:start_gc(disco:get_setting("DDFS_DATA")) end),
+ Refresher = spawn_link(fun() -> refresh_tag_cache_proc() end),
+ put(put_port, disco:get_setting("DDFS_PUT_PORT")),
+ {ok, #state{cache_refresher = Refresher}}.
+
+-type choose_write_nodes_msg() :: {choose_write_nodes, non_neg_integer(), [node()], [node()]}.
+-type new_blob_msg() :: {new_blob, string() | object_name(), non_neg_integer(), [node()]}.
+-type tag_msg() :: {tag, ddfs_tag:call_msg(), tagname()}.
+-spec handle_call(dbg_state_msg(), from(), state()) ->
+ gs_reply(state());
+ ({get_nodeinfo, all}, from(), state()) ->
+ gs_reply({ok, [node_info()]});
+ (get_read_nodes, from(), state()) ->
+ gs_reply({ok, [node()], non_neg_integer});
+ (gc_blacklist, from(), state()) ->
+ gs_reply({ok, [node()]});
+ (gc_stats, from(), state()) ->
+ gs_reply({ok, gc_stats(), erlang:timestamp()});
+ (choose_write_nodes_msg(), from(), state()) ->
+ gs_reply({ok, [node()]});
+ (new_blob_msg(), from(), state()) ->
+ gs_reply(new_blob_result());
+ (tag_msg(), from(), state()) ->
+ gs_reply({error, nonodes}) | gs_noreply();
+ ({get_tags, gc | safe}, from(), state()) ->
+ gs_noreply();
+ ({get_hosted_tags, host()}, from(), state()) ->
+ gs_noreply();
+ (safe_gc_blacklist, from(), state()) ->
+ gs_reply({ok, [node()]}).
+handle_call(dbg_get_state, _, S) ->
+ {reply, S, S};
+
+handle_call({get_nodeinfo, all}, _From, #state{nodes = Nodes} = S) ->
+ {reply, {ok, Nodes}, S};
+
+handle_call(get_read_nodes, _F, #state{nodes = Nodes, read_blacklist = RB} = S) ->
+ {reply, do_get_readable_nodes(Nodes, RB), S};
+
+handle_call(gc_blacklist, _F, #state{gc_blacklist = Nodes} = S) ->
+ {reply, {ok, Nodes}, S};
+
+handle_call(gc_stats, _F, #state{gc_stats = Stats} = S) ->
+ {reply, {ok, Stats}, S};
+
+handle_call({choose_write_nodes, K, Include, Exclude}, _,
+ #state{nodes = N, write_blacklist = WBL, gc_blacklist = GBL} = S) ->
+ BL = lists:umerge(WBL, GBL),
+ {reply, do_choose_write_nodes(N, K, Include, Exclude, BL), S};
+
+handle_call({new_blob, Obj, K, Include, Exclude}, _,
+ #state{nodes = N, gc_blacklist = GBL, write_blacklist = WBL} = S) ->
+ BL = lists:umerge(WBL, GBL),
+ {reply, do_new_blob(Obj, K, Include, Exclude, BL, N), S};
+
+handle_call({tag, _M, _Tag}, _From, #state{nodes = []} = S) ->
+ {reply, {error, no_nodes}, S};
+
+handle_call({tag, M, Tag}, From, S) ->
+ {noreply, do_tag_request(M, Tag, From, S)};
+
+handle_call({get_tags, Mode}, From, #state{nodes = Nodes} = S) ->
+ spawn(fun() ->
+ gen_server:reply(From, do_get_tags(Mode, [N || {N, _} <- Nodes]))
+ end),
+ {noreply, S};
+
+handle_call({get_hosted_tags, Host}, From, S) ->
+ spawn(fun() -> gen_server:reply(From, ddfs_gc:hosted_tags(Host)) end),
+ {noreply, S};
+
+handle_call(safe_gc_blacklist, _From, #state{safe_gc_blacklist = SBL} = S) ->
+ {reply, {ok, gb_sets:to_list(SBL)}, S}.
+
+-spec handle_cast({tag_notify, ddfs_tag:cast_msg(), tagname()}
+ | {gc_blacklist, [node()]}
+ | {safe_gc_blacklist, gb_sets:set()}
+ | {update_gc_stats, gc_stats()}
+ | {update_tag_cache, gb_sets:set()}
+ | refresh_tag_cache
+ | {update_nodes, nodes_update()}
+ | {update_nodestats, gb_trees:tree()},
+ state()) -> gs_noreply().
+handle_cast({tag_notify, M, Tag}, S) ->
+ {noreply, do_tag_notify(M, Tag, S)};
+
+handle_cast({gc_blacklist, Nodes}, #state{safe_gc_blacklist = SBL} = S) ->
+ BLSet = gb_sets:from_list(Nodes),
+ NewSBL = gb_sets:intersection(BLSet, SBL),
+ {noreply, S#state{gc_blacklist = gb_sets:to_list(BLSet),
+ safe_gc_blacklist = NewSBL}};
+
+handle_cast({safe_gc_blacklist, SafeBlacklist}, #state{gc_blacklist = BL} = S) ->
+ SBL = gb_sets:intersection(SafeBlacklist, gb_sets:from_list(BL)),
+ {noreply, S#state{safe_gc_blacklist = SBL}};
+
+handle_cast({update_gc_stats, Stats}, S) ->
+ {noreply, S#state{gc_stats = {Stats, now()}}};
+
+handle_cast({update_tag_cache, TagCache}, S) ->
+ {noreply, S#state{tag_cache = TagCache}};
+
+handle_cast(refresh_tag_cache, #state{cache_refresher = Refresher} = S) ->
+ Refresher ! refresh,
+ {noreply, S};
+
+handle_cast({update_nodes, NewNodes}, S) ->
+ {noreply, do_update_nodes(NewNodes, S)};
+
+handle_cast({update_nodestats, NewNodes}, S) ->
+ {noreply, do_update_nodestats(NewNodes, S)}.
+
+-spec handle_info({'DOWN', _, _, pid(), _}, state()) -> gs_noreply().
+handle_info({'DOWN', _, _, Pid, _}, S) ->
+ {noreply, do_tag_exit(Pid, S)}.
+
+%% ===================================================================
+%% gen_server callback stubs
+
+-spec terminate(term(), state()) -> ok.
+terminate(Reason, _State) ->
+ lager:warning("DDFS master died: ~p", [Reason]).
+
+-spec code_change(term(), state(), term()) -> {ok, state()}.
+code_change(_OldVsn, State, _Extra) -> {ok, State}.
+
+%% ===================================================================
+%% internal functions
+
+-spec do_get_readable_nodes([node_info()], [node()]) ->
+ {ok, [node()], non_neg_integer()}.
+do_get_readable_nodes(Nodes, ReadBlacklist) ->
+ NodeSet = gb_sets:from_ordset(lists:sort([Node || {Node, _} <- Nodes])),
+ BlackSet = gb_sets:from_ordset(ReadBlacklist),
+ ReadableNodeSet = gb_sets:subtract(NodeSet, BlackSet),
+ {ok, gb_sets:to_list(ReadableNodeSet), gb_sets:size(BlackSet)}.
+
+-spec do_choose_write_nodes([node_info()], non_neg_integer(), [node()], [node()], [node()]) ->
+ {ok, [node()]}.
+do_choose_write_nodes(Nodes, K, Include, Exclude, BlackList) ->
+ % Include is the list of nodes that must be included
+ %
+ % Node selection algorithm:
+ % 1. try to choose K nodes randomly from all the nodes which have
+ % more than ?MIN_FREE_SPACE bytes free space available and which
+ % are not excluded or blacklisted.
+ % 2. if K nodes cannot be found this way, choose the K emptiest
+ % nodes which are not excluded or blacklisted.
+ Primary = ([N || {N, {Free, _Total}} <- Nodes, Free > ?MIN_FREE_SPACE / 1024]
+ -- (Exclude ++ BlackList)),
+ if length(Primary) >= K ->
+ {ok, Include ++ disco_util:choose_random(Primary -- Include , K - length(Include))};
+ true ->
+ Preferred = [N || {N, _} <- lists:reverse(lists:keysort(2, Nodes))],
+ Secondary = Include ++ lists:sublist(Preferred -- (Include ++ Exclude ++ BlackList),
+ K - length(Include)),
+ {ok, Secondary}
+ end.
+
+-type new_blob_result() :: too_many_replicas | {ok, [nonempty_string()]}.
+-spec do_new_blob(string()|object_name(), non_neg_integer(), [node()], [node()], [node()], [node_info()]) ->
+ new_blob_result().
+do_new_blob(_Obj, K, _Include, _Exclude, _BlackList, Nodes) when K > length(Nodes) ->
+ too_many_replicas;
+do_new_blob(Obj, K, Include, Exclude, BlackList, Nodes) ->
+ {ok, WriteNodes} = do_choose_write_nodes(Nodes, K, Include, Exclude, BlackList),
+ Urls = [["http://", disco:host(N), ":", get(put_port), "/ddfs/", Obj]
+ || N <- WriteNodes],
+ {ok, Urls}.
+
+% Tag request: Start a new tag server if one doesn't exist already. Forward
+% the request to the tag server.
+
+-spec get_tag_pid(tagname(), gb_trees:tree(), false | gb_sets:set()) ->
+ {pid(), gb_trees:tree()}.
+get_tag_pid(Tag, Tags, Cache) ->
+ case gb_trees:lookup(Tag, Tags) of
+ none ->
+ NotFound = (Cache =/= false
+ andalso not gb_sets:is_element(Tag, Cache)),
+ {ok, Server} = ddfs_tag:start(Tag, NotFound),
+ erlang:monitor(process, Server),
+ {Server, gb_trees:insert(Tag, Server, Tags)};
+ {value, P} ->
+ {P, Tags}
+ end.
+
+-spec do_tag_request(term(), tagname(), replyto(), state()) ->
+ state().
+do_tag_request(M, Tag, From, #state{tags = Tags, tag_cache = Cache} = S) ->
+ {Pid, TagsN} = get_tag_pid(Tag, Tags, Cache),
+ gen_server:cast(Pid, {M, From}),
+ S#state{tags = TagsN,
+ tag_cache = Cache =/= false andalso gb_sets:add(Tag, Cache)}.
+
+-spec do_tag_notify(term(), tagname(), state()) -> state().
+do_tag_notify(M, Tag, #state{tags = Tags, tag_cache = Cache} = S) ->
+ {Pid, TagsN} = get_tag_pid(Tag, Tags, Cache),
+ gen_server:cast(Pid, {notify, M}),
+ S#state{tags = TagsN,
+ tag_cache = Cache =/= false andalso gb_sets:add(Tag, Cache)}.
+
+-spec do_update_nodes(nodes_update(), state()) -> state().
+do_update_nodes(NewNodes, #state{nodes = Nodes, tags = Tags} = S) ->
+ WriteBlacklist = lists:sort([Node || {Node, false, _} <- NewNodes]),
+ ReadBlacklist = lists:sort([Node || {Node, _, false} <- NewNodes]),
+ OldNodes = gb_trees:from_orddict(Nodes),
+ UpdatedNodes = lists:keysort(1, [case gb_trees:lookup(Node, OldNodes) of
+ none ->
+ {Node, {0, 0}};
+ {value, OldStats} ->
+ {Node, OldStats}
+ end || {Node, _WB, _RB} <- NewNodes]),
+ if
+ UpdatedNodes =/= Nodes ->
+ _ = [gen_server:cast(Pid, {die, none}) || Pid <- gb_trees:values(Tags)],
+ spawn(fun() ->
+ {ok, ReadableNodes, RBSize} =
+ do_get_readable_nodes(UpdatedNodes, ReadBlacklist),
+ refresh_tag_cache(ReadableNodes, RBSize)
+ end),
+ S#state{nodes = UpdatedNodes,
+ write_blacklist = WriteBlacklist,
+ read_blacklist = ReadBlacklist,
+ tag_cache = false,
+ tags = gb_trees:empty()};
+ true ->
+ S#state{write_blacklist = WriteBlacklist,
+ read_blacklist = ReadBlacklist}
+ end.
+
+-spec do_update_nodestats(gb_trees:tree(), state()) -> state().
+do_update_nodestats(NewNodes, #state{nodes = Nodes} = S) ->
+ UpdatedNodes = [case gb_trees:lookup(Node, NewNodes) of
+ none ->
+ {Node, Stats};
+ {value, NewStats} ->
+ {Node, NewStats}
+ end || {Node, Stats} <- Nodes],
+ S#state{nodes = UpdatedNodes}.
+
+-spec do_tag_exit(pid(), state()) -> state().
+do_tag_exit(Pid, S) ->
+ NewTags = [X || {_, V} = X <- gb_trees:to_list(S#state.tags), V =/= Pid],
+ S#state{tags = gb_trees:from_orddict(NewTags)}.
+
+-spec do_get_tags(all | filter, [node()]) -> {[node()], [node()], [binary()]};
+ (safe, [node()]) -> {ok, [binary()]} | too_many_failed_nodes;
+ (gc, [node()]) -> {ok, [binary()], [node()]} | too_many_failed_nodes.
+do_get_tags(all, Nodes) ->
+ disco_profile:timed_run(
+ fun() ->
+ {Replies, Failed} =
+ gen_server:multi_call(Nodes, ddfs_node, get_tags, ?NODE_TIMEOUT),
+ {OkNodes, Tags} = lists:unzip(Replies),
+ {OkNodes, Failed, lists:usort(lists:flatten(Tags))}
+ end, do_get_tags_all);
+
+do_get_tags(filter, Nodes) ->
+ disco_profile:timed_run(
+ fun() ->
+ {OkNodes, Failed, Tags} = do_get_tags(all, Nodes),
+ case tag_operation(get_tagnames, <<"+deleted">>, ?NODEOP_TIMEOUT) of
+ {ok, Deleted} ->
+ TagSet = gb_sets:from_ordset(Tags),
+ DelSet = gb_sets:insert(<<"+deleted">>, Deleted),
+ NotDeleted = gb_sets:to_list(gb_sets:subtract(TagSet, DelSet)),
+ {OkNodes, Failed, NotDeleted};
+ E ->
+ E
+ end
+ end, do_get_tags_filter);
+
+do_get_tags(safe, Nodes) ->
+ disco_profile:timed_run(
+ fun() ->
+ TagMinK = list_to_integer(disco:get_setting("DDFS_TAG_MIN_REPLICAS")),
+ case do_get_tags(filter, Nodes) of
+ {_OkNodes, Failed, Tags} when length(Failed) < TagMinK ->
+ {ok, Tags};
+ _ ->
+ too_many_failed_nodes
+ end
+ end, do_get_tags_safe);
+
+% The returned tag list may include +deleted.
+do_get_tags(gc, Nodes) ->
+ disco_profile:timed_run(
+ fun() ->
+ {OkNodes, Failed, Tags} = do_get_tags(all, Nodes),
+ TagMinK = list_to_integer(disco:get_setting("DDFS_TAG_MIN_REPLICAS")),
+ case length(Failed) < TagMinK of
+ false ->
+ too_many_failed_nodes;
+ true ->
+ case tag_operation(get_tagnames, <<"+deleted">>, ?NODEOP_TIMEOUT) of
+ {ok, Deleted} ->
+ TagSet = gb_sets:from_ordset(Tags),
+ NotDeleted = gb_sets:subtract(TagSet, Deleted),
+ {ok, gb_sets:to_list(NotDeleted), OkNodes};
+ E ->
+ E
+ end
+ end
+ end, do_get_tags_gc).
+
+% Timeouts in this call by the below processes can cause ddfs_master
+% itself to crash, since the processes are linked to it.
+-spec safe_get_read_nodes() -> {ok, [node()], non_neg_integer()} | error.
+safe_get_read_nodes() ->
+ try get_read_nodes() of
+ {ok, _ReadableNodes, _RBSize} = RN ->
+ RN;
+ E ->
+ lager:error("unexpected response retrieving readable nodes: ~p", [E]),
+ error
+ catch
+ K:E ->
+ lager:error("error retrieving readable nodes: ~p:~p", [K, E]),
+ error
+ end.
+
+-spec monitor_diskspace() -> no_return().
+monitor_diskspace() ->
+ case safe_get_read_nodes() of
+ {ok, ReadableNodes, _RBSize} ->
+ {Space, _F} = gen_server:multi_call(ReadableNodes,
+ ddfs_node,
+ get_diskspace,
+ ?NODE_TIMEOUT),
+ update_nodestats(gb_trees:from_orddict(lists:keysort(1, Space)));
+ error ->
+ ok
+ end,
+ timer:sleep(?DISKSPACE_INTERVAL),
+ monitor_diskspace().
+
+-spec refresh_tag_cache_proc() -> no_return().
+refresh_tag_cache_proc() ->
+ case safe_get_read_nodes() of
+ {ok, ReadableNodes, RBSize} ->
+ refresh_tag_cache(ReadableNodes, RBSize);
+ error ->
+ ok
+ end,
+ receive
+ refresh ->
+ ok
+ after ?TAG_CACHE_INTERVAL ->
+ ok
+ end,
+ refresh_tag_cache_proc().
+
+-spec refresh_tag_cache([node()], non_neg_integer()) -> ok.
+refresh_tag_cache(Nodes, BLSize) ->
+ TagMinK = list_to_integer(disco:get_setting("DDFS_TAG_MIN_REPLICAS")),
+ {Replies, Failed} =
+ gen_server:multi_call(Nodes, ddfs_node, get_tags, ?NODE_TIMEOUT),
+ if Nodes =/= [], length(Failed) + BLSize < TagMinK ->
+ {_OkNodes, Tags} = lists:unzip(Replies),
+ update_tag_cache(gb_sets:from_list(lists:flatten(Tags)));
+ true -> ok
+ end.
diff --git a/lib/dialyzer/test/small_SUITE_data/src/ddfs_master/ddfs_tag.hrl b/lib/dialyzer/test/small_SUITE_data/src/ddfs_master/ddfs_tag.hrl
new file mode 100644
index 0000000000..2920b67fc5
--- /dev/null
+++ b/lib/dialyzer/test/small_SUITE_data/src/ddfs_master/ddfs_tag.hrl
@@ -0,0 +1,19 @@
+
+-type tokentype() :: 'read' | 'write'.
+-type user_attr() :: [{binary(), binary()}].
+% An 'internal' token is also used by internal consumers, but never stored.
+-type token() :: 'null' | binary().
+
+-type tagname() :: binary().
+-type tagid() :: binary().
+
+-type attrib() :: 'urls' | 'read_token' | 'write_token' | {'user', binary()}.
+
+-record(tagcontent, {id :: tagid(),
+ last_modified :: binary(),
+ read_token = null :: token(),
+ write_token = null :: token(),
+ urls = [] :: [[binary()]],
+ user = [] :: user_attr()}).
+
+-type tagcontent() :: #tagcontent{}.
diff --git a/lib/dialyzer/test/small_SUITE_data/src/ddfs_master/gs_util.hrl b/lib/dialyzer/test/small_SUITE_data/src/ddfs_master/gs_util.hrl
new file mode 100644
index 0000000000..d579e9a7d7
--- /dev/null
+++ b/lib/dialyzer/test/small_SUITE_data/src/ddfs_master/gs_util.hrl
@@ -0,0 +1,16 @@
+% This is a set of type utilities to be used when spec-cing the
+% callbacks of a gen_server implementation. It should be included in
+% the impl module, which needs to define the state() type.
+
+-type gs_init() :: {ok, state()}.
+-type gs_reply(T) :: {reply, (T), state()}.
+-type gs_noreply() :: {noreply, state()}.
+-type gs_noreply_t() :: {noreply, state(), non_neg_integer()}.
+-type gs_stop(T) :: {stop, (T), state()}.
+
+% Generic utilities.
+
+-type server() :: pid() | atom() | {atom(), node()}.
+-type from() :: {pid(), term()}.
+
+-type dbg_state_msg() :: dbg_get_state.
diff --git a/lib/dialyzer/test/small_SUITE_data/src/funs_from_outside.erl b/lib/dialyzer/test/small_SUITE_data/src/funs_from_outside.erl
new file mode 100644
index 0000000000..f4cbf31160
--- /dev/null
+++ b/lib/dialyzer/test/small_SUITE_data/src/funs_from_outside.erl
@@ -0,0 +1,83 @@
+-module(funs_from_outside).
+
+-export([run1/2, run2/2, run3/2]).
+-export([test1/1, test2/1]).
+
+%%------------------------------------------------------------------------------
+
+run1(X, Y) ->
+ testa(fun do_something/1, X, Y).
+
+testa(Fun, X, Y) ->
+ F = case even(X) of
+ true -> Fun;
+ false -> fun do_nothing/1
+ end,
+ case F(Y) of
+ {ok, _} -> ok;
+ error -> error
+ end.
+
+do_nothing(_) -> {ok, nothing}.
+
+do_something(_) -> {ok, something}.
+
+even(X) ->
+ X rem 2 =:= 0.
+
+%%------------------------------------------------------------------------------
+
+%% Duplicating code since we are monovariant...
+
+run2(X, Y) ->
+ testb(fun do_something/1, X, Y).
+
+testb(Fun, X, Y) ->
+ F = case even(X) of
+ true -> Fun;
+ false -> fun do_nothing/1
+ end,
+ case F(Y) of
+ error -> error
+ end.
+
+%%------------------------------------------------------------------------------
+
+%% Duplicating code since we are monovariant...
+
+run3(X, Y) ->
+ testc(fun do_something_2/1, X, Y).
+
+testc(Fun, X, Y) ->
+ F = case even(X) of
+ true -> Fun;
+ false -> fun do_nothing/1
+ end,
+ case F(Y) of
+ {ok, _} -> ok;
+ %% This pattern can match.
+ error -> error
+ end.
+
+do_something_2(foo) -> {ok, something};
+do_something_2(_) -> error.
+
+%%------------------------------------------------------------------------------
+
+test1(Fun) ->
+ F = case get(test1) of
+ test1_t -> Fun;
+ test1_f -> fun fok/0
+ end,
+ error = F().
+
+fok() -> ok.
+
+%%------------------------------------------------------------------------------
+
+test2(Fun) ->
+ F = case get(test1) of
+ test1_t -> fun fok/0;
+ test1_f -> fun fok/0
+ end,
+ error = F().
diff --git a/lib/diameter/doc/src/diameter_make.xml b/lib/diameter/doc/src/diameter_make.xml
index 13ec5bbfc1..0c7e6b794d 100644
--- a/lib/diameter/doc/src/diameter_make.xml
+++ b/lib/diameter/doc/src/diameter_make.xml
@@ -52,7 +52,7 @@ under the License.
<p>
The function &codec; is used to compile a diameter
&dictionary; into Erlang source.
-The resulting source implements the interface diameter required
+The resulting source implements the interface diameter requires
to encode and decode the dictionary's messages and AVPs.</p>
<p>
diff --git a/lib/diameter/doc/src/notes.xml b/lib/diameter/doc/src/notes.xml
index cd14195e78..675ffcfd18 100644
--- a/lib/diameter/doc/src/notes.xml
+++ b/lib/diameter/doc/src/notes.xml
@@ -11,7 +11,7 @@
<header>
<copyright>
<year>2011</year>
-<year>2013</year>
+<year>2014</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -42,6 +42,164 @@ first.</p>
<!-- ===================================================================== -->
+<section><title>diameter 1.6</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Add missing check at dictionary compilation.</p>
+ <p>
+ In particular, that an AVP defined as having type Grouped
+ in an @avp_types section has a corresponding definition
+ in a @grouped section.</p>
+ <p>
+ Own Id: OTP-11561</p>
+ </item>
+ <item>
+ <p>
+ Correct documentation on the setting of Origin-State-Id</p>
+ <p>
+ It was incorrectly stated that the AVP would be set in an
+ outgoing DPR/DPA.</p>
+ <p>
+ Own Id: OTP-11583</p>
+ </item>
+ <item>
+ <p>
+ Change interface for communicating outbound stream id to
+ diameter_sctp</p>
+ <p>
+ The module uses the transport_data field of record
+ diameter_packet to communicate the stream on which the an
+ incoming message is received and on which an outgoing
+ message should be sent, the previous interface being that
+ both are communicated as a tuple of the form {stream,
+ Id}. However, since diameter retains the value of an
+ incoming request's transport_data unless the
+ corresponding answer message specifies otherwise, the
+ behaviour in this case is to send an answer on the
+ outbound stream with the same identifier as the that of
+ the inbound stream on which the request was received. If
+ the inbound stream id is greater than or equal to the
+ number of outbound streams then this is guaranteed to
+ fail, causing the transport process in question to
+ terminate. There is no relationship between inbound and
+ outbound stream identifiers so diameter_sctp's imposition
+ of one is simply wrong.</p>
+ <p>
+ Outbound stream ids are now communicated with a different
+ tuple: {outstream, Id}, interpreted modulo the number of
+ outbound streams. Thus, retention of an inbound request's
+ transport_data has no effect on the selection of an
+ outbound stream.</p>
+ <p>
+ The change in interface is not strictly backwards
+ compatible because of the new atom for the outbound
+ stream. However, as there is currently no documented way
+ of obtaining the available number of outbound streams for
+ a peer connection, there is no way for a client to have
+ known the range of ids from which it could reliably have
+ chosen with the previous interface, so any setting of the
+ outbound stream has probably been unintentional. Not
+ explicitly specifying an outbound stream now results in a
+ round-robin selection.</p>
+ <p>
+ Thanks to Sharmila Pillai for reporting the problem.</p>
+ <p>
+ *** POTENTIAL INCOMPATIBILITY ***</p>
+ <p>
+ Own Id: OTP-11593</p>
+ </item>
+ <item>
+ <p>
+ Fix unicode path failure in diameter_make:codec/2.</p>
+ <p>
+ A dictionary path containing a unicode codepoint > 255
+ caused the function to fail.</p>
+ <p>
+ Own Id: OTP-11655</p>
+ </item>
+ <item>
+ <p>
+ Fix 'accept' config to diameter_sctp.</p>
+ <p>
+ OTP-10893 added support for {accept, Match} tuples to
+ specify addresses or regexps that should be matched
+ against peer addresses to decide whether or not a newly
+ established association should be retained, but this
+ hasn't been functional in the SCTP case because of
+ missing support in inet(3).</p>
+ <p>
+ The display of both local and peer addresses in
+ diameter:service_info/2 output has also been corrected.</p>
+ <p>
+ Own Id: OTP-11661 Aux Id: OTP-10229 </p>
+ </item>
+ <item>
+ <p>
+ Be lenient with the M-bit in Grouped AVPs.</p>
+ <p>
+ RFC 6733 says this, in 4.4:</p>
+ <p>
+ <taglist><item><p><c>Receivers of a Grouped AVP that does
+ not have the 'M' (mandatory) bit set and one or more of
+ the encapsulated AVPs within the group has the 'M'
+ (mandatory) bit set MAY simply be ignored if the Grouped
+ AVP itself is unrecognized. The rule applies even if the
+ encapsulated AVP with its 'M' (mandatory) bit set is
+ further encapsulated within other sub-groups, i.e., other
+ Grouped AVPs embedded within the Grouped
+ AVP.</c></p></item></taglist></p>
+ <p>
+ The first sentence is mangled but take it to mean this:</p>
+ <p>
+ <taglist><item><p><c>An unrecognized AVP of type Grouped
+ that does not set the 'M' bit MAY be ignored even if one
+ of its encapsulated AVPs sets the 'M'
+ bit.</c></p></item></taglist></p>
+ <p>
+ This is a bit of a non-statement since if the AVP is
+ unrecognized then its type is unknown. We therefore don't
+ know that its data bytes contain encapsulated AVPs, so
+ can't but ignore any of those that set the M-bit. Doing
+ anything else when the type *is* known would be
+ inconsistent.</p>
+ <p>
+ OTP-11087 (R16B03) caused the M-bit on any unrecognized
+ AVP to be regarded as an error, unrecognized being taken
+ to mean "not explicitly defined as a member of its
+ container". (That is, an AVP that can't be packed into a
+ dedicated record field, which is slightly stronger than
+ "not defined".) This fixed the original intention for
+ top-level AVPs but broke the required leniency for
+ Grouped AVPs whose type is known. This leniency is now
+ restored.</p>
+ <p>
+ Note that dictionary files need to be recompiled for the
+ change to have effect.</p>
+ <p>
+ Thanks to Rory McKeown for reporting the problem.</p>
+ <p>
+ Own Id: OTP-11675 Aux Id: OTP-11087 </p>
+ </item>
+ <item>
+ <p>
+ Fix pick_peer case clause failure.</p>
+ <p>
+ In the case of {call_mutates_state, true} configuration
+ on the service in question, any peer selection that
+ failed to select a peer resulted in a case clause
+ failure. This was noticed in the case of a peer failover
+ in which an alternate peer wasn't available.</p>
+ <p>
+ Own Id: OTP-11789</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>diameter 1.5</title>
<section><title>Improvements and New Features</title>
@@ -73,12 +231,6 @@ first.</p>
<p>
Own Id: OTP-11361</p>
</item>
- <item>
- <p>
- Fix silent make rules (Thanks to Anthony Ramine)</p>
- <p>
- Own Id: OTP-11514</p>
- </item>
</list>
</section>
diff --git a/lib/diameter/include/diameter.hrl b/lib/diameter/include/diameter.hrl
index 79c4dce541..5a40e42300 100644
--- a/lib/diameter/include/diameter.hrl
+++ b/lib/diameter/include/diameter.hrl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2010-2013. All Rights Reserved.
+%% Copyright Ericsson AB 2010-2014. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -58,8 +58,8 @@
-record(diameter_header,
{version, %% 8-bit unsigned
length, %% 24-bit unsigned
- cmd_code, %% 8-bit unsigned
- application_id, %% 24-bit unsigned
+ cmd_code, %% 24-bit unsigned
+ application_id, %% 32-bit unsigned
hop_by_hop_id, %% 32-bit unsigned
end_to_end_id, %% 32-bit unsigned
is_request, %% boolean() R flag
diff --git a/lib/diameter/src/Makefile b/lib/diameter/src/Makefile
index 578bbaee2e..9afccf298c 100644
--- a/lib/diameter/src/Makefile
+++ b/lib/diameter/src/Makefile
@@ -1,7 +1,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 2010-2013. All Rights Reserved.
+# Copyright Ericsson AB 2010-2014. All Rights Reserved.
#
# The contents of this file are subject to the Erlang Public License,
# Version 1.1, (the "License"); you may not use this file except in
@@ -41,7 +41,7 @@ INCDIR = ../include
ABS_EBIN := $(shell cd $(EBIN) && pwd)
# Where make should look for dependencies.
-VPATH = .:base:compiler:transport:gen
+VPATH = .:base:compiler:transport:gen:info
# ----------------------------------------------------
# Target specs
@@ -55,13 +55,13 @@ DICT_ERLS = $(DICT_MODULES:%=%.erl)
DICT_HRLS = $(DICT_MODULES:%=%.hrl)
# Modules to build before compiling dictionaries.
-COMPILER_MODULES = $(notdir $(filter compiler/%, $(CT_MODULES))) \
- $(DICT_YRL)
+COMPILER_MODULES = $(notdir $(CT_MODULES)) $(DICT_YRL)
# All handwritten modules from which a depend.mk is generated.
MODULES = \
$(RT_MODULES) \
- $(CT_MODULES)
+ $(CT_MODULES) \
+ $(INFO_MODULES)
# Modules whose names are inserted into the app file.
APP_MODULES = \
@@ -72,6 +72,7 @@ APP_MODULES = \
TARGET_MODULES = \
$(APP_MODULES) \
$(CT_MODULES) \
+ $(INFO_MODULES) \
$(DICT_YRL:%=gen/%)
# What to build for the 'opt' target.
@@ -147,14 +148,19 @@ gen/$(DICT_YRL).erl: compiler/$(DICT_YRL).yrl
$(ERLC) -Werror -o $(@D) $<
# Generate the app file.
-$(APP_TARGET): $(APP_SRC) ../vsn.mk modules.mk
+$(APP_TARGET): $(APP_SRC) ../vsn.mk modules.mk app.sed
$(gen_verbose) \
M=`echo $(notdir $(APP_MODULES)) | tr ' ' ,`; \
+ C=`echo $(COMPILER_MODULES) | tr ' ' ,`; \
+ I=`echo $(notdir $(INFO_MODULES)) | tr ' ' ,`; \
R=`echo $(REGISTERED) | tr ' ' ,`; \
sed -e 's;%VSN%;$(VSN);' \
-e "s;%MODULES%;$$M;" \
+ -e "s;%COMPILER%;$$C;" \
+ -e "s;%INFO%;$$I;" \
-e "s;%REGISTERED%;$$R;" \
- $< > $@
+ $< \
+ | sed -f app.sed > $@
$(APPUP_TARGET): $(APPUP_SRC) ../vsn.mk
$(vsn_verbose) \
@@ -177,6 +183,8 @@ info:
@echo
@$(call list,CT_MODULES)
@echo
+ @$(call list,INFO_MODULES)
+ @echo
@$(call list,TARGET_MODULES)
@echo
@$(call list,TARGET_DIRS)
@@ -216,7 +224,7 @@ dialyze: opt $(PLT)
-Wno_improper_lists \
$(EBIN)/diameter_gen_base_rfc3588.$(EMULATOR) \
$(patsubst %, $(EBIN)/%.$(EMULATOR), \
- $(notdir $(RT_MODULES) $(CT_MODULES)))
+ $(notdir $(RT_MODULES) $(CT_MODULES) $(INFO_MODULES)))
# Omit all but the common dictionary module since these
# (diameter_gen_relay in particular) generate warning depending on how
# much of the included diameter_gen.hrl they use.
diff --git a/lib/diameter/src/app.sed b/lib/diameter/src/app.sed
new file mode 100644
index 0000000000..7916f65002
--- /dev/null
+++ b/lib/diameter/src/app.sed
@@ -0,0 +1,40 @@
+#
+# %CopyrightBegin%
+#
+# Copyright Ericsson AB 2014. All Rights Reserved.
+#
+# The contents of this file are subject to the Erlang Public License,
+# Version 1.1, (the "License"); you may not use this file except in
+# compliance with the License. You should have received a copy of the
+# Erlang Public License along with this software. If not, it can be
+# retrieved online at http://www.erlang.org/.
+#
+# Software distributed under the License is distributed on an "AS IS"
+# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+# the License for the specific language governing rights and limitations
+# under the License.
+#
+# %CopyrightEnd%
+
+#
+# Generate runtime_dependencies from applications to avoid having to
+# specify the same application more than once.
+#
+
+/{runtime_dependencies,/b v
+/{[-a-z]*, "[0-9.]*"}/!b
+/{vsn,/b
+
+/%%/!H
+s/{\([^,]*\)[^}]*}/\1/g
+s/%%/%,/
+b
+
+:v
+
+p
+x
+s/\n//
+s/%//g
+s/\n */ /g
+s/{\([^,]*\), "\([^"]*"\)}/"\1-\2/g
diff --git a/lib/diameter/src/base/diameter_service.erl b/lib/diameter/src/base/diameter_service.erl
index 1274e0fc48..8914992f17 100644
--- a/lib/diameter/src/base/diameter_service.erl
+++ b/lib/diameter/src/base/diameter_service.erl
@@ -1389,6 +1389,8 @@ pick_peer(Local, Remote, Pid, _SvcName, #diameter_app{mutable = true} = App)
case call_service(Pid, {pick_peer, Local, Remote, App}) of
{TPid, _} = T when is_pid(TPid) ->
T;
+ false = No ->
+ No;
{error, _} ->
false
end;
diff --git a/lib/diameter/src/compiler/diameter_codegen.erl b/lib/diameter/src/compiler/diameter_codegen.erl
index 22422f2ef2..5a068c1a25 100644
--- a/lib/diameter/src/compiler/diameter_codegen.erl
+++ b/lib/diameter/src/compiler/diameter_codegen.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2010-2013. All Rights Reserved.
+%% Copyright Ericsson AB 2010-2014. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -31,7 +31,8 @@
%% on the beam file of another dictionary.
%%
--export([from_dict/4]).
+-export([from_dict/4,
+ is_printable_ascii/1]). %% used by ?TERM/1 in diameter_forms.hrl
-include("diameter_forms.hrl").
-include("diameter_vsn.hrl").
@@ -121,6 +122,9 @@ eraser(Key) ->
%% ===========================================================================
%% ===========================================================================
+is_printable_ascii(C) ->
+ 16#20 =< C andalso C =< 16#7F.
+
get_value(Key, Plist) ->
proplists:get_value(Key, Plist, []).
diff --git a/lib/diameter/src/compiler/diameter_forms.hrl b/lib/diameter/src/compiler/diameter_forms.hrl
index 9b14c1715a..dd03401b9e 100644
--- a/lib/diameter/src/compiler/diameter_forms.hrl
+++ b/lib/diameter/src/compiler/diameter_forms.hrl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2010-2013. All Rights Reserved.
+%% Copyright Ericsson AB 2010-2014. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -57,4 +57,6 @@
-define(FIELDS(Fs), [{?record_field, ?ATOM(F), V} || {F,V} <- Fs]).
%% Literal term.
--define(TERM(T), erl_parse:abstract(T, ?LINE)).
+-define(TERM(T), erl_parse:abstract(T, [
+ {line, ?LINE},
+ {encoding, fun diameter_codegen:is_printable_ascii/1}])).
diff --git a/lib/diameter/src/compiler/diameter_make.erl b/lib/diameter/src/compiler/diameter_make.erl
index adc7808e49..72f5d36da4 100644
--- a/lib/diameter/src/compiler/diameter_make.erl
+++ b/lib/diameter/src/compiler/diameter_make.erl
@@ -232,21 +232,29 @@ identify([Vsn | [T|_] = ParseD])
identify({path, File} = T) ->
{T, File};
identify(File) ->
- Bin = iolist_to_binary([File]),
- case is_path(Bin) of
+ case is_path([File]) of
true -> {{path, File}, File};
- false -> {Bin, ?DEFAULT_DICT_FILE}
+ false -> {File, ?DEFAULT_DICT_FILE}
end.
-%% Interpret anything containing \n or \r as a literal dictionary,
-%% otherwise a path. (Which might be the wrong guess in the worst case.)
-is_path(Bin) ->
- try
- [throw(C) || <<C>> <= Bin, $\n == C orelse $\r == C],
- true
- catch
- throw:_ -> false
- end.
+%% Interpret anything containing \n or \r as a literal dictionary.
+
+is_path([<<C,B/binary>> | T]) ->
+ is_path([C, B | T]);
+
+is_path([[C|L] | T]) ->
+ is_path([C, L | T]);
+
+is_path([C|_])
+ when $\n == C;
+ $\r == C ->
+ false;
+
+is_path([_|T]) ->
+ is_path(T);
+
+is_path([]) ->
+ true.
make(File, Opts, Dict) ->
ok(lists:foldl(fun(M,A) -> [make(File, Opts, Dict, M) | A] end,
diff --git a/lib/diameter/src/diameter.app.src b/lib/diameter/src/diameter.app.src
index 509de9e595..ac1d847753 100644
--- a/lib/diameter/src/diameter.app.src
+++ b/lib/diameter/src/diameter.app.src
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2010-2013. All Rights Reserved.
+%% Copyright Ericsson AB 2010-2014. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -20,11 +20,27 @@
{application, diameter,
[{description, "Diameter protocol"},
{vsn, "%VSN%"},
- {modules, [%MODULES%]},
+ {modules, [
+ %MODULES%
+ %,%COMPILER%
+ %,%INFO%
+ ]},
{registered, [%REGISTERED%]},
- {applications, [stdlib, kernel]},
+ {applications, [
+ {stdlib, "2.0"}, {kernel, "3.0"}%, {erts, "6.0"}
+ %% {syntax-tools, "1.6.14"}
+ %% {runtime-tools, "1.8.14"}
+ %, {ssl, "5.3.4"}
+ ]},
{env, []},
{mod, {diameter_app, []}},
- {runtime_dependencies, ["syntax_tools-1.6.14","stdlib-2.0","ssl-5.3.4",
- "runtime_tools-1.8.14","kernel-3.0","erts-6.0"]}
+ {runtime_dependencies, [
+ ]}
+ %%
+ %% Note that ssl is only required if configured on TCP transports,
+ %% and syntax-tools and runtime-tools are only required if the
+ %% dictionary compiler and debug modules (respectively) are
+ %% needed/wanted at runtime, which they typically aren't. These
+ %% modules are the two commented lines in the 'modules' tuple.
+ %%
]}.
diff --git a/lib/diameter/src/base/diameter_dbg.erl b/lib/diameter/src/info/diameter_dbg.erl
index 5b0ac3a3b6..b5b3983afa 100644
--- a/lib/diameter/src/base/diameter_dbg.erl
+++ b/lib/diameter/src/info/diameter_dbg.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2010-2011. All Rights Reserved.
+%% Copyright Ericsson AB 2010-2014. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -17,20 +17,22 @@
%% %CopyrightEnd%
%%
+%%
+%% Information and debug functions.
+%%
+
-module(diameter_dbg).
-export([table/1,
tables/0,
fields/1,
- help/0,
modules/0,
versions/0,
version_info/0,
compiled/0,
procs/0,
latest/0,
- nl/0,
- log/4]).
+ nl/0]).
-export([diameter_config/0,
diameter_peer/0,
@@ -52,11 +54,9 @@
tp/1]).
-include_lib("diameter/include/diameter.hrl").
--include("diameter_internal.hrl").
-
--define(INFO, diameter_info).
--define(SEP(), ?INFO:sep()).
+-define(APP, diameter).
+-define(I, diameter_info).
-define(LOCAL, [diameter_config,
diameter_peer,
@@ -68,27 +68,16 @@
-define(VALUES(Rec), tl(tuple_to_list(Rec))).
-log(_Slogan, _Mod, _Line, _Details) ->
- ok.
-
-%%% ----------------------------------------------------------
-%%% # help()
-%%% ----------------------------------------------------------
-
-help() ->
- not_yet_implemented.
-
-%%% ----------------------------------------------------------
-%%% # table(TableName)
-%%%
-%%% Input: TableName = diameter table containing record entries.
-%%%
-%%% Output: Count | undefined
-%%% ----------------------------------------------------------
+%% ----------------------------------------------------------
+%% # table(TableName)
+%%
+%% Pretty-print a diameter table. Returns the number of records
+%% printed, or undefined.
+%% ----------------------------------------------------------
table(T)
when (T == diameter_peer) orelse (T == diameter_reg) ->
- ?INFO:format(collect(T), fields(T), fun ?INFO:split/2);
+ ?I:format(collect(T), fields(T), fun ?I:split/2);
table(Table)
when is_atom(Table) ->
@@ -96,7 +85,7 @@ table(Table)
undefined = No ->
No;
Fields ->
- ?INFO:format(Table, Fields, fun split/2)
+ ?I:format(Table, Fields, fun split/2)
end.
split([started, name | Fs], [S, N | Vs]) ->
@@ -107,9 +96,9 @@ split([[F|FT]|Fs], [Rec|Vs]) ->
split([F|Fs], [V|Vs]) ->
{F, Fs, V, Vs}.
-%%% ----------------------------------------------------------
-%%% # TableName()
-%%% ----------------------------------------------------------
+%% ----------------------------------------------------------
+%% # TableName()
+%% ----------------------------------------------------------
-define(TABLE(Name), Name() -> table(Name)).
@@ -121,16 +110,15 @@ split([F|Fs], [V|Vs]) ->
?TABLE(diameter_service).
?TABLE(diameter_stats).
-%%% ----------------------------------------------------------
-%%% # tables()
-%%%
-%%% Output: Number of records output.
-%%%
-%%% Description: Pretty-print records in diameter tables from all nodes.
-%%% ----------------------------------------------------------
+%% ----------------------------------------------------------
+%% # tables()
+%%
+%% Pretty-print diameter tables from all nodes. Returns the number of
+%% records printed.
+%% ----------------------------------------------------------
tables() ->
- ?INFO:format(field(?LOCAL), fun split/3, fun collect/1).
+ ?I:format(field(?LOCAL), fun split/3, fun collect/1).
field(Tables) ->
lists:map(fun(T) -> {T, fields(T)} end, lists:sort(Tables)).
@@ -138,66 +126,66 @@ field(Tables) ->
split(_, Fs, Vs) ->
split(Fs, Vs).
-%%% ----------------------------------------------------------
-%%% # modules()
-%%% ----------------------------------------------------------
+%% ----------------------------------------------------------
+%% # modules()
+%% ----------------------------------------------------------
modules() ->
- Path = filename:join([appdir(), atom_to_list(?APPLICATION) ++ ".app"]),
- {ok, [{application, ?APPLICATION, Attrs}]} = file:consult(Path),
+ Path = filename:join([appdir(), atom_to_list(?APP) ++ ".app"]),
+ {ok, [{application, ?APP, Attrs}]} = file:consult(Path),
{modules, Mods} = lists:keyfind(modules, 1, Attrs),
Mods.
appdir() ->
- [_|_] = code:lib_dir(?APPLICATION, ebin).
+ [_|_] = code:lib_dir(?APP, ebin).
-%%% ----------------------------------------------------------
-%%% # versions()
-%%% ----------------------------------------------------------
+%% ----------------------------------------------------------
+%% # versions()
+%% ----------------------------------------------------------
versions() ->
- ?INFO:versions(modules()).
+ ?I:versions(modules()).
-%%% ----------------------------------------------------------
-%%% # versions()
-%%% ----------------------------------------------------------
+%% ----------------------------------------------------------
+%% # versions()
+%% ----------------------------------------------------------
version_info() ->
- ?INFO:version_info(modules()).
+ ?I:version_info(modules()).
-%%% ----------------------------------------------------------
-%%% # compiled()
-%%% ----------------------------------------------------------
+%% ----------------------------------------------------------
+%% # compiled()
+%% ----------------------------------------------------------
compiled() ->
- ?INFO:compiled(modules()).
+ ?I:compiled(modules()).
-%%% ----------------------------------------------------------
-%%% procs()
-%%% ----------------------------------------------------------
+%% ----------------------------------------------------------
+%% procs()
+%% ----------------------------------------------------------
procs() ->
- ?INFO:procs(?APPLICATION).
+ ?I:procs(?APP).
-%%% ----------------------------------------------------------
-%%% # latest()
-%%% ----------------------------------------------------------
+%% ----------------------------------------------------------
+%% # latest()
+%% ----------------------------------------------------------
latest() ->
- ?INFO:latest(modules()).
+ ?I:latest(modules()).
-%%% ----------------------------------------------------------
-%%% # nl()
-%%% ----------------------------------------------------------
+%% ----------------------------------------------------------
+%% # nl()
+%% ----------------------------------------------------------
nl() ->
lists:foreach(fun(M) -> abcast = c:nl(M) end, modules()).
-%%% ----------------------------------------------------------
-%%% # pp(Bin)
-%%%
-%%% Description: Pretty-print a message binary.
-%%% ----------------------------------------------------------
+%% ----------------------------------------------------------
+%% # pp(Bin)
+%%
+%% Description: Pretty-print a message binary.
+%% ----------------------------------------------------------
%% Network byte order = big endian.
@@ -207,7 +195,7 @@ pp(<<Version:8, MsgLength:24,
HbHid:32,
E2Eid:32,
AVPs/binary>>) ->
- ?SEP(),
+ ?I:sep(),
ppp(["Version",
"Message length",
"[Actual length]",
@@ -227,7 +215,7 @@ pp(<<Version:8, MsgLength:24,
HbHid,
E2Eid]),
N = avp_loop({AVPs, MsgLength - 20}, 0),
- ?SEP(),
+ ?I:sep(),
N;
pp(<<_Version:8, MsgLength:24, _/binary>> = Bin) ->
@@ -328,23 +316,23 @@ ppp(Fields, Values) ->
ppp({Field, Value}) ->
io:format(": ~-22s : ~p~n", [Field, Value]).
-%%% ----------------------------------------------------------
-%%% # subscriptions()
-%%%
-%%% Output: list of {SvcName, Pid}
-%%% ----------------------------------------------------------
+%% ----------------------------------------------------------
+%% # subscriptions()
+%%
+%% Returns a list of {SvcName, Pid}.
+%% ----------------------------------------------------------
subscriptions() ->
diameter_service:subscriptions().
-%%% ----------------------------------------------------------
-%%% # children()
-%%% ----------------------------------------------------------
+%% ----------------------------------------------------------
+%% # children()
+%% ----------------------------------------------------------
children() ->
diameter_sup:tree().
-%%% ----------------------------------------------------------
+%% ----------------------------------------------------------
%% tracer/[12]
@@ -430,7 +418,7 @@ peers(Name, Ts) ->
mk_peers(Name, [_, {type, connect} | _] = Ts) ->
[[Name | mk_peer(Ts)]];
-mk_peers(Name, [R, {type, listen}, O, {accept = A, As}]) ->
+mk_peers(Name, [R, {type, listen}, O, {accept = A, As} | _]) ->
[[Name | mk_peer([R, {type, A}, O | Ts])] || Ts <- As].
%% This is a bit lame: service_info works to build this list and out
%% of something like what we want here and then we take it apart.
@@ -485,13 +473,12 @@ fields(diameter_service) ->
[started,
name,
record_info(fields, diameter_service),
+ watchdogT,
peerT,
- connT,
- share_peers,
- use_shared_peers,
shared_peers,
local_peers,
- monitor];
+ monitor,
+ options];
?FIELDS(diameter_event);
?FIELDS(diameter_uri);
diff --git a/lib/diameter/src/base/diameter_info.erl b/lib/diameter/src/info/diameter_info.erl
index 39d32d07cd..10972f3231 100644
--- a/lib/diameter/src/base/diameter_info.erl
+++ b/lib/diameter/src/info/diameter_info.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2010-2011. All Rights Reserved.
+%% Copyright Ericsson AB 2010-2014. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -17,6 +17,11 @@
%% %CopyrightEnd%
%%
+%%
+%% Generic functions for formatting table listings and more. Used by
+%% diameter_dbg.
+%%
+
-module(diameter_info).
-export([usage/1,
@@ -573,12 +578,7 @@ sys_info() ->
{A,V}.
os_info() ->
- {os:version(), case os:type() of
- {_Fam, _Name} = T ->
- T;
- Fam ->
- {Fam, ""}
- end}.
+ {os:version(), os:type()}.
chomp(S) ->
string:strip(S, right, $\n).
diff --git a/lib/diameter/src/modules.mk b/lib/diameter/src/modules.mk
index f8d3cf1d6f..a2a7a51892 100644
--- a/lib/diameter/src/modules.mk
+++ b/lib/diameter/src/modules.mk
@@ -1,8 +1,7 @@
-#-*-makefile-*- ; force emacs to enter makefile-mode
# %CopyrightBegin%
#
-# Copyright Ericsson AB 2010-2013. All Rights Reserved.
+# Copyright Ericsson AB 2010-2014. All Rights Reserved.
#
# The contents of this file are subject to the Erlang Public License,
# Version 1.1, (the "License"); you may not use this file except in
@@ -64,16 +63,19 @@ RT_MODULES = \
transport/diameter_transport \
transport/diameter_transport_sup
-# Handwritten (compile time) modules not included in the app file.
+# Handwritten compiler modules not included in the app file.
CT_MODULES = \
- base/diameter_dbg \
- base/diameter_info \
compiler/diameter_codegen \
compiler/diameter_exprecs \
compiler/diameter_dict_scanner \
compiler/diameter_dict_util \
compiler/diameter_make
+# Info/debug modules, also not included in the app file.
+INFO_MODULES = \
+ info/diameter_dbg \
+ info/diameter_info
+
# Released hrl files in ../include intended for public consumption.
EXTERNAL_HRLS = \
diameter.hrl \
diff --git a/lib/diameter/test/diameter_app_SUITE.erl b/lib/diameter/test/diameter_app_SUITE.erl
index 1e262895a6..f68a18b5c2 100644
--- a/lib/diameter/test/diameter_app_SUITE.erl
+++ b/lib/diameter/test/diameter_app_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2010-2013. All Rights Reserved.
+%% Copyright Ericsson AB 2010-2014. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -50,7 +50,7 @@
diameter_exprecs,
diameter_make]).
--define(HELP_MODULES, [diameter_dbg,
+-define(INFO_MODULES, [diameter_dbg,
diameter_info]).
%% ===========================================================================
@@ -99,13 +99,13 @@ vsn(Config) ->
%% # modules/1
%%
%% Ensure that the app file modules and installed modules differ by
-%% compiler/help modules.
+%% compiler/info modules.
%% ===========================================================================
modules(Config) ->
Mods = fetch(modules, fetch(app, Config)),
Installed = code_mods(),
- Help = lists:sort(?HELP_MODULES ++ ?COMPILER_MODULES),
+ Help = lists:sort(?INFO_MODULES ++ ?COMPILER_MODULES),
{[], Help} = {Mods -- Installed, lists:sort(Installed -- Mods)}.
@@ -158,12 +158,15 @@ appvsn(Name) ->
%% # xref/1
%%
%% Ensure that no function in our application calls an undefined function
-%% or one in an application we haven't specified as a dependency. (Almost.)
+%% or one in an application we haven't declared as a dependency. (Almost.)
%% ===========================================================================
xref(Config) ->
App = fetch(app, Config),
- Mods = fetch(modules, App),
+ Mods = fetch(modules, App), %% modules listed in the app file
+
+ %% List of application names extracted from runtime_dependencies.
+ Deps = lists:map(fun unversion/1, fetch(runtime_dependencies, App)),
{ok, XRef} = xref:start(make_name(xref_test_name)),
ok = xref:set_default(XRef, [{verbose, false}, {warnings, false}]),
@@ -178,7 +181,9 @@ xref(Config) ->
[?APP, erts | fetch(applications, App)]),
{ok, Undefs} = xref:analyze(XRef, undefined_function_calls),
- {ok, Called} = xref:analyze(XRef, {module_call, ?COMPILER_MODULES}),
+ {ok, RTmods} = xref:analyze(XRef, {module_use, Mods}),
+ {ok, CTmods} = xref:analyze(XRef, {module_use, ?COMPILER_MODULES}),
+ {ok, RTdeps} = xref:analyze(XRef, {module_call, Mods}),
xref:stop(XRef),
@@ -190,18 +195,41 @@ xref(Config) ->
Undefs),
%% diameter_tcp does call ssl despite the latter not being listed
%% as a dependency in the app file since ssl is only required for
- %% TLS security: it's up to a client who wants TLS it to start
- %% ssl.
-
- [] = lists:filter(fun is_bad_dependency/1, Called).
-
-%% It's not strictly necessary that diameter compiler modules not
-%% depend on other diameter modules but it's a simple source of build
-%% errors if not encoded in the makefile (hence the test) so guard
-%% against it.
-is_bad_dependency(Mod) ->
- lists:prefix("diameter", atom_to_list(Mod))
- andalso not lists:member(Mod, ?COMPILER_MODULES).
+ %% TLS security: it's up to a client who wants TLS to start ssl.
+
+ %% Ensure that only runtime or info modules call runtime modules.
+ %% It's not strictly necessary that diameter compiler modules not
+ %% depend on other diameter modules but it's a simple source of
+ %% build errors if not properly encoded in the makefile so guard
+ %% against it.
+ [] = (RTmods -- Mods) -- ?INFO_MODULES,
+
+ %% Ensure that runtime modules don't call compiler modules.
+ CTmods = CTmods -- Mods,
+
+ %% Ensure that runtime modules only call other runtime modules, or
+ %% applications declared as in runtime_dependencies in the app
+ %% file. Note that the declared application versions are ignored
+ %% since we only know what we can see now.
+ [] = lists:filter(fun(M) -> not lists:member(app(M), Deps) end,
+ RTdeps -- Mods).
+
+unversion(App) ->
+ T = lists:dropwhile(fun is_vsn_ch/1, lists:reverse(App)),
+ lists:reverse(case T of [$-|TT] -> TT; _ -> T end).
+
+is_vsn_ch(C) ->
+ $0 =< C andalso C =< $9 orelse $. == C.
+
+app('$M_EXPR') -> %% could be anything but assume it's ok
+ "erts";
+app(Mod) ->
+ case code:which(Mod) of
+ preloaded ->
+ "erts";
+ Path ->
+ unversion(lists:nth(3, lists:reverse(filename:split(Path))))
+ end.
add_application(XRef, App) ->
add_application(XRef, App, code:lib_dir(App)).
diff --git a/lib/diameter/test/diameter_compiler_SUITE.erl b/lib/diameter/test/diameter_compiler_SUITE.erl
index df4dde6240..08ffe5981d 100644
--- a/lib/diameter/test/diameter_compiler_SUITE.erl
+++ b/lib/diameter/test/diameter_compiler_SUITE.erl
@@ -120,6 +120,16 @@
{avp_has_duplicate_flag,
" -",
" MM"},
+ {ok,
+ "@vendor 0",
+ "@vendor 10415"},
+ {ok,
+ [{"@vendor 0", "@vendor 10415"},
+ {"Proxy-Info .*M$", "&V"},
+ {"Proxy-Info ::= [^>]*", "& 10415 "}]},
+ {grouped_vendor_id_without_flag,
+ [{"@vendor 0", "@vendor 10415"},
+ {"Proxy-Info ::= [^>]*", "& 10415 "}]},
{avp_has_vendor_id,
"@avp_types",
"@avp_vendor_id 667 Class\n&"},
diff --git a/lib/edoc/doc/src/notes.xml b/lib/edoc/doc/src/notes.xml
index 394e7af09c..d7cbfa1fdc 100644
--- a/lib/edoc/doc/src/notes.xml
+++ b/lib/edoc/doc/src/notes.xml
@@ -31,6 +31,35 @@
<p>This document describes the changes made to the EDoc
application.</p>
+<section><title>Edoc 0.7.13</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Application upgrade (appup) files are corrected for the
+ following applications: </p>
+ <p>
+ <c>asn1, common_test, compiler, crypto, debugger,
+ dialyzer, edoc, eldap, erl_docgen, et, eunit, gs, hipe,
+ inets, observer, odbc, os_mon, otp_mibs, parsetools,
+ percept, public_key, reltool, runtime_tools, ssh,
+ syntax_tools, test_server, tools, typer, webtool, wx,
+ xmerl</c></p>
+ <p>
+ A new test utility for testing appup files is added to
+ test_server. This is now used by most applications in
+ OTP.</p>
+ <p>
+ (Thanks to Tobias Schlager)</p>
+ <p>
+ Own Id: OTP-11744</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>Edoc 0.7.12.1</title>
<section><title>Improvements and New Features</title>
diff --git a/lib/edoc/src/edoc_types.erl b/lib/edoc/src/edoc_types.erl
index af8f1230fb..d4e00d3ecd 100644
--- a/lib/edoc/src/edoc_types.erl
+++ b/lib/edoc/src/edoc_types.erl
@@ -66,6 +66,7 @@ is_new_predefined(boolean, 0) -> true;
is_new_predefined(byte, 0) -> true;
is_new_predefined(iodata, 0) -> true;
is_new_predefined(iolist, 0) -> true;
+is_new_predefined(map, 0) -> true;
is_new_predefined(maybe_improper_list, 0) -> true;
is_new_predefined(maybe_improper_list, 2) -> true;
is_new_predefined(mfa, 0) -> true;
diff --git a/lib/eldap/doc/src/notes.xml b/lib/eldap/doc/src/notes.xml
index e7a3e20202..089bb731d4 100644
--- a/lib/eldap/doc/src/notes.xml
+++ b/lib/eldap/doc/src/notes.xml
@@ -30,7 +30,51 @@
</header>
<p>This document describes the changes made to the Eldap application.</p>
- <section><title>Eldap 1.0.2</title>
+ <section><title>Eldap 1.0.3</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Application upgrade (appup) files are corrected for the
+ following applications: </p>
+ <p>
+ <c>asn1, common_test, compiler, crypto, debugger,
+ dialyzer, edoc, eldap, erl_docgen, et, eunit, gs, hipe,
+ inets, observer, odbc, os_mon, otp_mibs, parsetools,
+ percept, public_key, reltool, runtime_tools, ssh,
+ syntax_tools, test_server, tools, typer, webtool, wx,
+ xmerl</c></p>
+ <p>
+ A new test utility for testing appup files is added to
+ test_server. This is now used by most applications in
+ OTP.</p>
+ <p>
+ (Thanks to Tobias Schlager)</p>
+ <p>
+ Own Id: OTP-11744</p>
+ </item>
+ <item>
+ <p>
+ Add support for IPv6 connections, By including the
+ [inet6] option in eldap:open/2. Default value is still
+ [inet] (Thanks to Edwin Fine)</p>
+ <p>
+ Own Id: OTP-11753</p>
+ </item>
+ <item>
+ <p>
+ Fixed bug where eldap:search returned binaries instead of
+ strings. (Thanks Simon MacMullen for the report)</p>
+ <p>
+ Own Id: OTP-11768</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Eldap 1.0.2</title>
<section><title>Fixed Bugs and Malfunctions</title>
<list>
diff --git a/lib/erl_docgen/doc/src/notes.xml b/lib/erl_docgen/doc/src/notes.xml
index 24d12b2bb7..e546eb97fc 100644
--- a/lib/erl_docgen/doc/src/notes.xml
+++ b/lib/erl_docgen/doc/src/notes.xml
@@ -30,7 +30,48 @@
</header>
<p>This document describes the changes made to the <em>erl_docgen</em> application.</p>
- <section><title>Erl_Docgen 0.3.4.1</title>
+ <section><title>Erl_Docgen 0.3.5</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Application upgrade (appup) files are corrected for the
+ following applications: </p>
+ <p>
+ <c>asn1, common_test, compiler, crypto, debugger,
+ dialyzer, edoc, eldap, erl_docgen, et, eunit, gs, hipe,
+ inets, observer, odbc, os_mon, otp_mibs, parsetools,
+ percept, public_key, reltool, runtime_tools, ssh,
+ syntax_tools, test_server, tools, typer, webtool, wx,
+ xmerl</c></p>
+ <p>
+ A new test utility for testing appup files is added to
+ test_server. This is now used by most applications in
+ OTP.</p>
+ <p>
+ (Thanks to Tobias Schlager)</p>
+ <p>
+ Own Id: OTP-11744</p>
+ </item>
+ </list>
+ </section>
+
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p>
+ Handle map types in docgen_edoc_xml_cb</p>
+ <p>
+ Own Id: OTP-11776</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Erl_Docgen 0.3.4.1</title>
<section><title>Improvements and New Features</title>
<list>
diff --git a/lib/erl_interface/doc/src/notes.xml b/lib/erl_interface/doc/src/notes.xml
index 4eb61015cc..ab6f4179d6 100644
--- a/lib/erl_interface/doc/src/notes.xml
+++ b/lib/erl_interface/doc/src/notes.xml
@@ -30,6 +30,22 @@
</header>
<p>This document describes the changes made to the Erl_interface application.</p>
+<section><title>Erl_Interface 3.7.16</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Fix memcheck warning in gen_challange (Thanks to Olivier
+ Girondel)</p>
+ <p>
+ Own Id: OTP-11608</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>Erl_Interface 3.7.15</title>
<section><title>Fixed Bugs and Malfunctions</title>
diff --git a/lib/et/doc/src/notes.xml b/lib/et/doc/src/notes.xml
index 815dfada5e..e122187cf3 100644
--- a/lib/et/doc/src/notes.xml
+++ b/lib/et/doc/src/notes.xml
@@ -36,6 +36,51 @@
one section in this document. The title of each section is the
version number of <c>Event Tracer (ET)</c>.</p>
+<section><title>ET 1.5</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Application upgrade (appup) files are corrected for the
+ following applications: </p>
+ <p>
+ <c>asn1, common_test, compiler, crypto, debugger,
+ dialyzer, edoc, eldap, erl_docgen, et, eunit, gs, hipe,
+ inets, observer, odbc, os_mon, otp_mibs, parsetools,
+ percept, public_key, reltool, runtime_tools, ssh,
+ syntax_tools, test_server, tools, typer, webtool, wx,
+ xmerl</c></p>
+ <p>
+ A new test utility for testing appup files is added to
+ test_server. This is now used by most applications in
+ OTP.</p>
+ <p>
+ (Thanks to Tobias Schlager)</p>
+ <p>
+ Own Id: OTP-11744</p>
+ </item>
+ </list>
+ </section>
+
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p>
+ Removed gs based applications and gs based backends. The
+ <c>observer</c> application replaces the removed
+ applications.</p>
+ <p>
+ *** POTENTIAL INCOMPATIBILITY ***</p>
+ <p>
+ Own Id: OTP-10915</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>ET 1.4.4.5</title>
<section><title>Improvements and New Features</title>
diff --git a/lib/eunit/doc/src/notes.xml b/lib/eunit/doc/src/notes.xml
index c52f12dcc8..72ffda3cd5 100644
--- a/lib/eunit/doc/src/notes.xml
+++ b/lib/eunit/doc/src/notes.xml
@@ -32,6 +32,35 @@
</header>
<p>This document describes the changes made to the EUnit application.</p>
+<section><title>Eunit 2.2.7</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Application upgrade (appup) files are corrected for the
+ following applications: </p>
+ <p>
+ <c>asn1, common_test, compiler, crypto, debugger,
+ dialyzer, edoc, eldap, erl_docgen, et, eunit, gs, hipe,
+ inets, observer, odbc, os_mon, otp_mibs, parsetools,
+ percept, public_key, reltool, runtime_tools, ssh,
+ syntax_tools, test_server, tools, typer, webtool, wx,
+ xmerl</c></p>
+ <p>
+ A new test utility for testing appup files is added to
+ test_server. This is now used by most applications in
+ OTP.</p>
+ <p>
+ (Thanks to Tobias Schlager)</p>
+ <p>
+ Own Id: OTP-11744</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>Eunit 2.2.6</title>
<section><title>Fixed Bugs and Malfunctions</title>
diff --git a/lib/gs/doc/src/notes.xml b/lib/gs/doc/src/notes.xml
index f5117cb9ba..e40310d36e 100644
--- a/lib/gs/doc/src/notes.xml
+++ b/lib/gs/doc/src/notes.xml
@@ -30,7 +30,36 @@
</header>
<p>This document describes the changes made to the GS application.</p>
- <section><title>GS 1.5.15.2</title>
+ <section><title>GS 1.5.16</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Application upgrade (appup) files are corrected for the
+ following applications: </p>
+ <p>
+ <c>asn1, common_test, compiler, crypto, debugger,
+ dialyzer, edoc, eldap, erl_docgen, et, eunit, gs, hipe,
+ inets, observer, odbc, os_mon, otp_mibs, parsetools,
+ percept, public_key, reltool, runtime_tools, ssh,
+ syntax_tools, test_server, tools, typer, webtool, wx,
+ xmerl</c></p>
+ <p>
+ A new test utility for testing appup files is added to
+ test_server. This is now used by most applications in
+ OTP.</p>
+ <p>
+ (Thanks to Tobias Schlager)</p>
+ <p>
+ Own Id: OTP-11744</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>GS 1.5.15.2</title>
<section><title>Improvements and New Features</title>
<list>
diff --git a/lib/hipe/cerl/erl_types.erl b/lib/hipe/cerl/erl_types.erl
index 28281a2fac..6065b79664 100644
--- a/lib/hipe/cerl/erl_types.erl
+++ b/lib/hipe/cerl/erl_types.erl
@@ -126,6 +126,8 @@
t_is_instance/2,
t_is_integer/1, t_is_integer/2,
t_is_list/1,
+ t_is_map/1,
+ t_is_map/2,
t_is_matchstate/1,
t_is_nil/1, t_is_nil/2,
t_is_non_neg_integer/1,
@@ -148,6 +150,8 @@
t_list/1,
t_list_elements/1, t_list_elements/2,
t_list_termination/1,
+ t_map/0,
+ t_map/1,
t_matchstate/0,
t_matchstate/2,
t_matchstate_present/1,
@@ -208,20 +212,12 @@
lift_list_to_pos_empty/1,
is_opaque_type/2,
is_erl_type/1,
- atom_to_string/1,
-
- t_is_map/2,
- t_map/1,
- t_map/0
+ atom_to_string/1
]).
%%-define(DO_ERL_TYPES_TEST, true).
-compile({no_auto_import,[min/2,max/2]}).
-%% HiPE does not understand Maps
-%% (guard function is_map/1 in t_from_term/1)
--compile(no_native).
-
-ifdef(DO_ERL_TYPES_TEST).
-export([test/0]).
-else.
@@ -1733,11 +1729,16 @@ lift_list_to_pos_empty(?list(Content, Termination, _)) ->
t_map() ->
?map([]).
--spec t_map([{erl_type(),erl_type()}]) -> erl_type().
+-spec t_map([{erl_type(), erl_type()}]) -> erl_type().
t_map(_) ->
?map([]).
+-spec t_is_map(erl_type()) -> boolean().
+
+t_is_map(Type) ->
+ t_is_map(Type, 'universe').
+
-spec t_is_map(erl_type(), opaques()) -> boolean().
t_is_map(Type, Opaques) ->
@@ -1746,7 +1747,6 @@ t_is_map(Type, Opaques) ->
is_map1(?map(_)) -> true;
is_map1(_) -> false.
-
%%-----------------------------------------------------------------------------
%% Tuples
%%
@@ -2167,10 +2167,10 @@ t_from_term(T) when is_function(T) ->
{arity, Arity} = erlang:fun_info(T, arity),
t_fun(Arity, t_any());
t_from_term(T) when is_integer(T) -> t_integer(T);
+t_from_term(T) when is_map(T) -> t_map();
t_from_term(T) when is_pid(T) -> t_pid();
t_from_term(T) when is_port(T) -> t_port();
t_from_term(T) when is_reference(T) -> t_reference();
-t_from_term(T) when is_map(T) -> t_map();
t_from_term(T) when is_tuple(T) ->
t_tuple([t_from_term(E) || E <- tuple_to_list(T)]).
@@ -2570,7 +2570,7 @@ force_union(T = ?function(_, _)) -> ?function_union(T);
force_union(T = ?identifier(_)) -> ?identifier_union(T);
force_union(T = ?list(_, _, _)) -> ?list_union(T);
force_union(T = ?nil) -> ?list_union(T);
-force_union(T = ?number(_,_)) -> ?number_union(T);
+force_union(T = ?number(_, _)) -> ?number_union(T);
force_union(T = ?opaque(_)) -> ?opaque_union(T);
force_union(T = ?remote(_)) -> ?remote_union(T);
force_union(T = ?map(_)) -> ?map_union(T);
@@ -2985,16 +2985,19 @@ inf_union(U1, U2, Opaques) ->
List = [A,B,F,I,L,N,T,M,Map],
inf_union_collect(List, Opaque, InfFun, [], [])
end,
- O1 = OpaqueFun(U1, U2, fun(E, Opaque) -> t_inf(Opaque, E, Opaques) end),
- O2 = OpaqueFun(U2, U1, fun(E, Opaque) -> t_inf(E, Opaque, Opaques) end),
- Union = inf_union(U1, U2, 0, [], Opaques),
- t_sup([O1, O2, Union]).
+ {O1, ThrowList1} =
+ OpaqueFun(U1, U2, fun(E, Opaque) -> t_inf(Opaque, E, Opaques) end),
+ {O2, ThrowList2}
+ = OpaqueFun(U2, U1, fun(E, Opaque) -> t_inf(E, Opaque, Opaques) end),
+ {Union, ThrowList3} = inf_union(U1, U2, 0, [], [], Opaques),
+ ThrowList = lists:merge3(ThrowList1, ThrowList2, ThrowList3),
+ case t_sup([O1, O2, Union]) of
+ ?none when ThrowList =/= [] -> throw(hd(ThrowList));
+ Sup -> Sup
+ end.
inf_union_collect([], _Opaque, _InfFun, InfList, ThrowList) ->
- case t_sup(InfList) of
- ?none when ThrowList =/= [] -> throw(hd(lists:flatten(ThrowList)));
- Sup -> Sup
- end;
+ {t_sup(InfList), lists:usort(ThrowList)};
inf_union_collect([?none|L], Opaque, InfFun, InfList, ThrowList) ->
inf_union_collect(L, Opaque, InfFun, [?none|InfList], ThrowList);
inf_union_collect([E|L], Opaque, InfFun, InfList, ThrowList) ->
@@ -3005,19 +3008,21 @@ inf_union_collect([E|L], Opaque, InfFun, InfList, ThrowList) ->
inf_union_collect(L, Opaque, InfFun, InfList, [N|ThrowList])
end.
-inf_union([?none|Left1], [?none|Left2], N, Acc, Opaques) ->
- inf_union(Left1, Left2, N, [?none|Acc], Opaques);
-inf_union([T1|Left1], [T2|Left2], N, Acc, Opaques) ->
- case t_inf(T1, T2, Opaques) of
- ?none -> inf_union(Left1, Left2, N, [?none|Acc], Opaques);
- T -> inf_union(Left1, Left2, N+1, [T|Acc], Opaques)
+inf_union([?none|Left1], [?none|Left2], N, Acc, ThrowList, Opaques) ->
+ inf_union(Left1, Left2, N, [?none|Acc], ThrowList, Opaques);
+inf_union([T1|Left1], [T2|Left2], N, Acc, ThrowList, Opaques) ->
+ try t_inf(T1, T2, Opaques) of
+ ?none -> inf_union(Left1, Left2, N, [?none|Acc], ThrowList, Opaques);
+ T -> inf_union(Left1, Left2, N+1, [T|Acc], ThrowList, Opaques)
+ catch throw:N when is_integer(N) ->
+ inf_union(Left1, Left2, N, [?none|Acc], [N|ThrowList], Opaques)
end;
-inf_union([], [], N, Acc, _Opaques) ->
- if N =:= 0 -> ?none;
+inf_union([], [], N, Acc, ThrowList, _Opaques) ->
+ if N =:= 0 -> {?none, ThrowList};
N =:= 1 ->
[Type] = [T || T <- Acc, T =/= ?none],
- Type;
- N >= 2 -> ?union(lists:reverse(Acc))
+ {Type, ThrowList};
+ N >= 2 -> {?union(lists:reverse(Acc)), ThrowList}
end.
inf_bitstr(U1, B1, U2, B2) ->
@@ -3581,6 +3586,8 @@ t_subtract(?product(Elements1) = T1, ?product(Elements2)) ->
_ -> T1
end
end;
+t_subtract(?map(_) = T, _) -> % XXX: very crude; will probably need refinement
+ T;
t_subtract(?product(P1), _) ->
?product(P1);
t_subtract(T, ?product(_)) ->
diff --git a/lib/hipe/doc/src/notes.xml b/lib/hipe/doc/src/notes.xml
index e0b1622d19..c7faf733c7 100644
--- a/lib/hipe/doc/src/notes.xml
+++ b/lib/hipe/doc/src/notes.xml
@@ -30,6 +30,124 @@
</header>
<p>This document describes the changes made to HiPE.</p>
+<section><title>Hipe 3.10.3</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Fix compilation with 'no_remove_comments' (Thanks to
+ Johannes Weißl)</p>
+ <p>
+ Own Id: OTP-11564</p>
+ </item>
+ <item>
+ <p>
+ Application upgrade (appup) files are corrected for the
+ following applications: </p>
+ <p>
+ <c>asn1, common_test, compiler, crypto, debugger,
+ dialyzer, edoc, eldap, erl_docgen, et, eunit, gs, hipe,
+ inets, observer, odbc, os_mon, otp_mibs, parsetools,
+ percept, public_key, reltool, runtime_tools, ssh,
+ syntax_tools, test_server, tools, typer, webtool, wx,
+ xmerl</c></p>
+ <p>
+ A new test utility for testing appup files is added to
+ test_server. This is now used by most applications in
+ OTP.</p>
+ <p>
+ (Thanks to Tobias Schlager)</p>
+ <p>
+ Own Id: OTP-11744</p>
+ </item>
+ <item>
+ <p>
+ There is now a test suite for the Hipe application</p>
+ <p>
+ Own Id: OTP-11748</p>
+ </item>
+ <item>
+ <p>
+ Support for a LLVM backend has been added in HiPE</p>
+ <p>
+ Own Id: OTP-11801</p>
+ </item>
+ </list>
+ </section>
+
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p> The pre-defined types <c>array/0</c>, <c>dict/0</c>,
+ <c>digraph/0</c>, <c>gb_set/0</c>, <c>gb_tree/0</c>,
+ <c>queue/0</c>, <c>set/0</c>, and <c>tid/0</c> have been
+ deprecated. They will be removed in Erlang/OTP 18.0. </p>
+ <p> Instead the types <c>array:array/0</c>,
+ <c>dict:dict/0</c>, <c>digraph:graph/0</c>,
+ <c>gb_set:set/0</c>, <c>gb_tree:tree/0</c>,
+ <c>queue:queue/0</c>, <c>sets:set/0</c>, and
+ <c>ets:tid/0</c> can be used. (Note: it has always been
+ necessary to use <c>ets:tid/0</c>.) </p> <p> It is
+ allowed in Erlang/OTP 17.0 to locally re-define the types
+ <c>array/0</c>, <c>dict/0</c>, and so on. </p> <p> New
+ types <c>array:array/1</c>, <c>dict:dict/2</c>,
+ <c>gb_sets:set/1</c>, <c>gb_trees:tree/2</c>,
+ <c>queue:queue/1</c>, and <c>sets:set/1</c> have been
+ added. </p> <p> A compiler option,
+ <c>nowarn_deprecated_type</c>, has been introduced. By
+ including the attribute </p> <c>
+ -compile(nowarn_deprecated_type).</c> <p> in an Erlang
+ source file, warnings about deprecated types can be
+ avoided in Erlang/OTP 17.0. </p> <p> The option can also
+ be given as a compiler flag: </p> <c> erlc
+ +nowarn_deprecated_type file.erl</c>
+ <p>
+ Own Id: OTP-10342</p>
+ </item>
+ <item>
+ <p>
+ EEP43: New data type - Maps</p>
+ <p>
+ With Maps you may for instance: <taglist> <item><c>M0 =
+ #{ a =&gt; 1, b =&gt; 2}, % create
+ associations</c></item> <item><c>M1 = M0#{ a := 10 }, %
+ update values</c></item> <item><c>M2 = M1#{ "hi" =&gt;
+ "hello"}, % add new associations</c></item> <item><c>#{
+ "hi" := V1, a := V2, b := V3} = M2. % match keys with
+ values</c></item> </taglist></p>
+ <p>
+ For information on how to use Maps please see the
+ <seealso marker="doc/reference_manual:maps">Reference
+ Manual</seealso>.</p>
+ <p>
+ The current implementation is without the following
+ features: <taglist> <item>No variable keys</item>
+ <item>No single value access</item> <item>No map
+ comprehensions</item> </taglist></p>
+ <p>
+ Note that Maps is <em>experimental</em> during OTP 17.0.</p>
+ <p>
+ Own Id: OTP-11616</p>
+ </item>
+ <item>
+ <p> Parameterized opaque types have been introduced. </p>
+ <p>
+ Own Id: OTP-11625</p>
+ </item>
+ <item>
+ <p>
+ Add support for the compilation of the is_map/1 and
+ map_size/1 guards to native code.</p>
+ <p>
+ Own Id: OTP-11831</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>Hipe 3.10.2.2</title>
<section><title>Fixed Bugs and Malfunctions</title>
diff --git a/lib/hipe/icode/hipe_beam_to_icode.erl b/lib/hipe/icode/hipe_beam_to_icode.erl
index 81249c958e..dcd547fd5f 100644
--- a/lib/hipe/icode/hipe_beam_to_icode.erl
+++ b/lib/hipe/icode/hipe_beam_to_icode.erl
@@ -509,6 +509,10 @@ trans_fun([{test,test_arity,{f,Lbl},[Reg,N]}|Instructions], Env) ->
I = hipe_icode:mk_type([trans_arg(Reg)],{tuple,N},
hipe_icode:label_name(True),map_label(Lbl)),
[I,True | trans_fun(Instructions,Env)];
+%%--- is_map ---
+trans_fun([{test,is_map,{f,Lbl},[Arg]}|Instructions], Env) ->
+ {Code,Env1} = trans_type_test(map,Lbl,Arg,Env),
+ [Code | trans_fun(Instructions,Env1)];
%%--------------------------------------------------------------------
%%--- select_val ---
trans_fun([{select_val,Reg,{f,Lbl},{list,Cases}}|Instructions], Env) ->
diff --git a/lib/hipe/icode/hipe_icode.hrl b/lib/hipe/icode/hipe_icode.hrl
index 25deac5152..46c04beb40 100644
--- a/lib/hipe/icode/hipe_icode.hrl
+++ b/lib/hipe/icode/hipe_icode.hrl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2004-2013. All Rights Reserved.
+%% Copyright Ericsson AB 2004-2014. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -61,8 +61,8 @@
| 'op_exact_eqeq_2' | 'suspend_msg_timeout'.
-type icode_type_test() :: 'atom' | 'bignum' | 'binary' | 'bitstr' | 'boolean'
- | 'cons' | 'fixnum' | 'float'
- | 'function' | 'function2' | 'integer' | 'list' | 'nil'
+ | 'cons' | 'fixnum' | 'float' | 'function'
+ | 'function2' | 'integer' | 'list' | 'map' | 'nil'
| 'number' | 'pid' | 'port' | 'reference' | 'tuple'
| {'atom', atom()} | {'integer', integer()}
| {'record', atom(), non_neg_integer()}
@@ -108,7 +108,6 @@
length :: non_neg_integer(),
cases :: [icode_switch_case()]}).
-
-record(icode_type, {test :: icode_type_test(),
args :: [icode_term_arg()],
true_label :: icode_lbl(),
diff --git a/lib/hipe/icode/hipe_icode_type.erl b/lib/hipe/icode/hipe_icode_type.erl
index 65876b83ea..ebeb5e2c10 100644
--- a/lib/hipe/icode/hipe_icode_type.erl
+++ b/lib/hipe/icode/hipe_icode_type.erl
@@ -84,15 +84,15 @@
t_fun/0, t_fun/1, t_fun/2, t_fun_args/1, t_fun_arity/1,
t_inf/2, t_inf_lists/2, t_integer/0,
t_integer/1, t_is_atom/1, t_is_any/1,
- t_is_binary/1, t_is_bitstr/1, t_is_bitwidth/1, t_is_boolean/1,
- t_is_fixnum/1, t_is_cons/1,
+ t_is_binary/1, t_is_bitstr/1, t_is_bitwidth/1,
+ t_is_boolean/1, t_is_fixnum/1, t_is_cons/1, t_is_map/1,
t_is_maybe_improper_list/1, t_is_equal/2, t_is_float/1,
t_is_fun/1, t_is_integer/1, t_is_non_neg_integer/1,
t_is_number/1, t_is_matchstate/1,
- t_is_nil/1, t_is_none/1, t_is_port/1, t_is_pid/1,
+ t_is_none/1, t_is_port/1, t_is_pid/1,
t_is_reference/1, t_is_subtype/2, t_is_tuple/1,
t_limit/2, t_matchstate_present/1, t_matchstate/0,
- t_matchstate_slots/1, t_maybe_improper_list/0,
+ t_matchstate_slots/1, t_maybe_improper_list/0, t_map/0,
t_nil/0, t_none/0, t_number/0, t_number/1, t_number_vals/1,
t_pid/0, t_port/0, t_reference/0, t_subtract/2, t_sup/2,
t_to_tlist/1, t_tuple/0, t_tuple/1, t_tuple_sizes/1]).
@@ -213,7 +213,7 @@ analyse_blocks(Work, State, MFA) ->
{NewState, NewLabels} =
try analyse_block(Label, Info, State)
catch throw:none_type ->
- %% io:format("received none type at label: ~p~n",[Label]),
+ %% io:format("received none type at label: ~p~n", [Label]),
{State,[]}
end,
NewWork2 = add_work(NewWork, NewLabels),
@@ -265,7 +265,7 @@ analyse_insn(I, Info, LookupFun) ->
do_move(I, Info);
#icode_call{} ->
NewInfo = do_call(I, Info, LookupFun),
- %%io:format("Analysing Call: ~w~n~w~n", [I,NewInfo]),
+ %% io:format("Analysing Call: ~w~n~w~n", [I, NewInfo]),
update_call_arguments(I, NewInfo);
#icode_phi{} ->
Type = t_limit(join_list(hipe_icode:args(I), Info), ?TYPE_DEPTH),
@@ -788,16 +788,16 @@ test_record(Atom, Size, Var, VarInfo, TrueLab, FalseLab, Info) ->
end.
test_type(Test, Type) ->
- %%io:format("Test is: ~w\n", [Test]),
- %%io:format("Type is: ~s\n", [format_type(Type)]),
+ %% io:format("Test is: ~w\n", [Test]),
+ %% io:format("Type is: ~s\n", [format_type(Type)]),
Ans =
case t_is_any(Type) of
true -> maybe;
false ->
TrueTest = true_branch_info(Test),
Inf = t_inf(TrueTest, Type),
- %%io:format("TrueTest is: ~s\n", [format_type(TrueTest)]),
- %%io:format("Inf is: ~s\n", [format_type(Inf)]),
+ %% io:format("TrueTest is: ~s\n", [format_type(TrueTest)]),
+ %% io:format("Inf is: ~s\n", [format_type(Inf)]),
case t_is_equal(Type, Inf) of
true ->
not t_is_none(Type);
@@ -895,11 +895,12 @@ test_type0(boolean, T) ->
t_is_boolean(T);
test_type0(list, T) ->
t_is_maybe_improper_list(T);
-test_type0(cons, T) ->
- t_is_cons(T);
-test_type0(nil, T) ->
- t_is_nil(T).
-
+%% test_type0(cons, T) ->
+%% t_is_cons(T);
+%% test_type0(nil, T) ->
+%% t_is_nil(T).
+test_type0(map, T) ->
+ t_is_map(T).
true_branch_info(integer) ->
t_integer();
@@ -931,22 +932,24 @@ true_branch_info(reference) ->
t_reference();
true_branch_info(function) ->
t_fun();
-true_branch_info(cons) ->
- t_cons();
-true_branch_info(nil) ->
- t_nil();
+%% true_branch_info(cons) ->
+%% t_cons();
+%% true_branch_info(nil) ->
+%% t_nil();
true_branch_info(boolean) ->
t_boolean();
+true_branch_info(map) ->
+ t_map();
true_branch_info(T) ->
- exit({?MODULE,unknown_typetest,T}).
+ exit({?MODULE, unknown_typetest, T}).
%% _________________________________________________________________
%%
%% Remove the redundant type tests. If a test is removed, the trace
-%% that isn't taken is explicitly removed from the CFG to simpilify
+%% that isn't taken is explicitly removed from the CFG to simplify
%% the handling of Phi nodes. If a Phi node is left and at least one
-%% branch into it has disappeared, the SSA propagation pass can't
+%% branch into it has disappeared, the SSA propagation pass cannot
%% handle it.
%%
%% If the CFG has changed at the end of this pass, the analysis is
diff --git a/lib/hipe/llvm/hipe_llvm_main.erl b/lib/hipe/llvm/hipe_llvm_main.erl
index e911fb89c9..0e50c9539b 100644
--- a/lib/hipe/llvm/hipe_llvm_main.erl
+++ b/lib/hipe/llvm/hipe_llvm_main.erl
@@ -342,8 +342,8 @@ create_sdesc_list([{ExnLbl, SPOff} | MoreExnAndSPOffs],
%% (thus, some of their arguments are passed to the stack). Because of the
%% Reserved Call Frame feature that the LLVM uses, the stack descriptors
%% are not correct since at the point of call the frame size is reduced
-%% proportionally to the number of arguments that are passed on the stack.
-%% Also the offsets of the roots need to be re-adjusted.
+%% by the number of arguments that are passed on the stack. Also, the
+%% offsets of the roots need to be re-adjusted.
fix_stack_descriptors(_, _, [], _) ->
[];
fix_stack_descriptors(RelocsDict, Relocs, SDescs, ExposedClosures) ->
@@ -427,30 +427,22 @@ find_offsets([{Off,Arity}|Rest], Offsets, Acc) ->
[I | RestOffsets] = lists:dropwhile(fun (Y) -> Y<Off end, Offsets),
find_offsets(Rest, RestOffsets, [{I, Arity}|Acc]).
-%% The functions below correct the arity of calls, that are identified
-%% by offset, in the stack descriptors.
+%% The function below corrects the stack descriptors of calls with arguments
+%% that are passed on the stack (more than NR_ARG_REGS) by subtracting the
+%% number of stacked arguments from the frame size and from the offset of the
+%% roots.
fix_sdescs([], SDescs) -> SDescs;
fix_sdescs([{Offset, Arity} | Rest], SDescs) ->
case lists:keyfind(Offset, 2, SDescs) of
false ->
fix_sdescs(Rest, SDescs);
- {?SDESC, Offset, SDesc} ->
- {ExnHandler, FrameSize, StkArity, Roots} = SDesc,
- DecRoot = fun(X) -> X-Arity end,
- NewRootsList = lists:map(DecRoot, tuple_to_list(Roots)),
- NewSDesc =
- case length(NewRootsList) > 0 andalso hd(NewRootsList) >= 0 of
- true ->
- {?SDESC, Offset, {ExnHandler, FrameSize-Arity, StkArity,
- list_to_tuple(NewRootsList)}};
- false ->
- {?SDESC, Offset, {ExnHandler, FrameSize, StkArity, Roots}}
- end,
- RestSDescs = lists:keydelete(Offset, 2, SDescs),
- fix_sdescs(Rest, [NewSDesc | RestSDescs])
+ {?SDESC, Offset, {ExnHandler, FrameSize, StkArity, Roots}} ->
+ FixedRoots = list_to_tuple([Ri - Arity || Ri <- tuple_to_list(Roots)]),
+ FixedSDesc =
+ {?SDESC, Offset, {ExnHandler, FrameSize - Arity, StkArity, FixedRoots}},
+ fix_sdescs(Rest, [FixedSDesc | lists:keydelete(Offset, 2, SDescs)])
end.
-
%%------------------------------------------------------------------------------
%% Miscellaneous functions
%%------------------------------------------------------------------------------
diff --git a/lib/hipe/llvm/hipe_rtl_to_llvm.erl b/lib/hipe/llvm/hipe_rtl_to_llvm.erl
index ba76e1d815..d7d8d1b049 100644
--- a/lib/hipe/llvm/hipe_rtl_to_llvm.erl
+++ b/lib/hipe/llvm/hipe_rtl_to_llvm.erl
@@ -430,12 +430,13 @@ trans_call_name(RtlCallName, Relocs, CallArgs, FinalArgs) ->
case RtlCallName of
PrimOp when is_atom(PrimOp) ->
LlvmName = trans_prim_op(PrimOp),
- Relocs1 = relocs_store(LlvmName, {call, {bif, PrimOp, length(CallArgs)}},
- Relocs),
+ Relocs1 =
+ relocs_store(LlvmName, {call, {bif, PrimOp, length(CallArgs)}}, Relocs),
{"@" ++ LlvmName, [], Relocs1};
{M, F, A} when is_atom(M), is_atom(F), is_integer(A) ->
- LlvmName = trans_mfa_name({M,F,A}),
- Relocs1 = relocs_store(LlvmName, {call, {M,F,A}}, Relocs),
+ LlvmName = trans_mfa_name({M, F, A}),
+ Relocs1 =
+ relocs_store(LlvmName, {call, {M, F, length(CallArgs)}}, Relocs),
{"@" ++ LlvmName, [], Relocs1};
Reg ->
case hipe_rtl:is_reg(Reg) of
diff --git a/lib/hipe/main/hipe.erl b/lib/hipe/main/hipe.erl
index d47eced6d8..539ce883c0 100644
--- a/lib/hipe/main/hipe.erl
+++ b/lib/hipe/main/hipe.erl
@@ -200,6 +200,7 @@
compile_core/4,
file/1,
file/2,
+ llvm_support_available/0,
load/1,
help/0,
help_hiper/0,
@@ -648,7 +649,18 @@ run_compiler_1(DisasmFun, IcodeFun, Options) ->
%% The full option expansion is not done
%% until the DisasmFun returns.
{Code, CompOpts} = DisasmFun(Options),
- Opts = expand_options(Options ++ CompOpts),
+ Opts0 = expand_options(Options ++ CompOpts),
+ Opts =
+ case proplists:get_bool(to_llvm, Opts0) andalso
+ not llvm_support_available() of
+ true ->
+ ?error_msg("No LLVM version 3.4 or greater "
+ "found in $PATH; aborting "
+ "native code compilation.\n", []),
+ ?EXIT(cant_find_required_llvm_version);
+ false ->
+ Opts0
+ end,
check_options(Opts),
?when_option(verbose, Options,
?debug_msg("Options: ~p.\n",[Opts])),
@@ -1537,4 +1549,22 @@ check_options(Opts) ->
ok
end.
+-spec llvm_support_available() -> boolean().
+
+llvm_support_available() ->
+ get_llvm_version() >= 3.4.
+
+get_llvm_version() ->
+ OptStr = os:cmd("opt -version"),
+ SubStr = "LLVM version ", N = length(SubStr),
+ case string:str(OptStr, SubStr) of
+ 0 -> % No opt available
+ 0.0;
+ S ->
+ case string:to_float(string:sub_string(OptStr, S + N)) of
+ {error, _} -> 0.0; %XXX: Assumes no revision numbers in versioning
+ {Float, _} -> Float
+ end
+ end.
+
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
diff --git a/lib/hipe/rtl/hipe_icode2rtl.erl b/lib/hipe/rtl/hipe_icode2rtl.erl
index 6ab40adcc8..483d0b37f7 100644
--- a/lib/hipe/rtl/hipe_icode2rtl.erl
+++ b/lib/hipe/rtl/hipe_icode2rtl.erl
@@ -437,6 +437,8 @@ gen_type_test([X], Type, TrueLbl, FalseLbl, Pred, ConstTab) ->
{hipe_tagscheme:test_integer(X, TrueLbl, FalseLbl, Pred), ConstTab};
list ->
{hipe_tagscheme:test_list(X, TrueLbl, FalseLbl, Pred), ConstTab};
+ map ->
+ {hipe_tagscheme:test_map(X, TrueLbl, FalseLbl, Pred), ConstTab};
nil ->
{hipe_tagscheme:test_nil(X, TrueLbl, FalseLbl, Pred), ConstTab};
number ->
diff --git a/lib/hipe/rtl/hipe_tagscheme.erl b/lib/hipe/rtl/hipe_tagscheme.erl
index 4725889d8d..c27c682915 100644
--- a/lib/hipe/rtl/hipe_tagscheme.erl
+++ b/lib/hipe/rtl/hipe_tagscheme.erl
@@ -39,7 +39,7 @@
test_tuple/4, test_atom/4, test_bignum/4, test_pos_bignum/4,
test_any_pid/4, test_any_port/4,
test_ref/4, test_fun/4, test_fun2/5, test_matchstate/4,
- test_binary/4, test_bitstr/4, test_list/4,
+ test_binary/4, test_bitstr/4, test_list/4, test_map/4,
test_integer/4, test_number/4, test_tuple_N/5]).
-export([realtag_fixnum/2, tag_fixnum/2, realuntag_fixnum/2, untag_fixnum/2]).
-export([test_two_fixnums/3, test_fixnums/4, unsafe_fixnum_add/3,
@@ -112,13 +112,15 @@
-define(TAG_HEADER_EXTERNAL_PID, ((16#C bsl ?TAG_PRIMARY_SIZE) bor ?TAG_PRIMARY_HEADER)).
-define(TAG_HEADER_EXTERNAL_PORT,((16#D bsl ?TAG_PRIMARY_SIZE) bor ?TAG_PRIMARY_HEADER)).
-define(TAG_HEADER_EXTERNAL_REF, ((16#E bsl ?TAG_PRIMARY_SIZE) bor ?TAG_PRIMARY_HEADER)).
+-define(TAG_HEADER_MAP, ((16#F bsl ?TAG_PRIMARY_SIZE) bor ?TAG_PRIMARY_HEADER)).
-define(TAG_HEADER_MASK, 16#3F).
-define(HEADER_ARITY_OFFS, 6).
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-mk_header(SZ,TAG) -> (SZ bsl ?HEADER_ARITY_OFFS) + TAG.
+mk_header(SZ, TAG) -> (SZ bsl ?HEADER_ARITY_OFFS) + TAG.
+
mk_arityval(SZ) -> mk_header(SZ, ?TAG_HEADER_ARITYVAL).
size_from_header(Sz, Header) ->
@@ -132,9 +134,9 @@ mk_var_header(Header, Size, Tag) ->
mk_fixnum(X) -> (X bsl ?TAG_IMMED1_SIZE) + ?TAG_IMMED1_SMALL.
-define(NIL, ((-1 bsl ?TAG_IMMED2_SIZE) bor ?TAG_IMMED2_NIL)).
-mk_nil() -> ?NIL.
-%% mk_atom(X) -> (X bsl ?TAG_IMMED2_SIZE) + ?TAG_IMMED2_ATOM.
-mk_non_value() -> ?THE_NON_VALUE.
+mk_nil() -> ?NIL.
+%% mk_atom(X) -> (X bsl ?TAG_IMMED2_SIZE) + ?TAG_IMMED2_ATOM.
+mk_non_value() -> ?THE_NON_VALUE.
-spec is_fixnum(integer()) -> boolean().
is_fixnum(N) when is_integer(N) ->
@@ -252,6 +254,15 @@ test_tuple_N(X, N, TrueLab, FalseLab, Pred) ->
hipe_rtl:mk_branch(Tmp, 'eq', hipe_rtl:mk_imm(mk_arityval(N)),
TrueLab, FalseLab, Pred)].
+test_map(X, TrueLab, FalseLab, Pred) ->
+ Tmp = hipe_rtl:mk_new_reg_gcsafe(),
+ HalfTrueLab = hipe_rtl:mk_new_label(),
+ MapMask = ?TAG_HEADER_MASK,
+ [test_is_boxed(X, hipe_rtl:label_name(HalfTrueLab), FalseLab, Pred),
+ HalfTrueLab,
+ get_header(Tmp, X),
+ mask_and_compare(Tmp, MapMask, ?TAG_HEADER_MAP, TrueLab, FalseLab, Pred)].
+
test_ref(X, TrueLab, FalseLab, Pred) ->
Hdr = hipe_rtl:mk_new_reg_gcsafe(),
Tag = hipe_rtl:mk_new_reg_gcsafe(),
diff --git a/lib/hipe/test/Makefile b/lib/hipe/test/Makefile
index cedb150b5d..acb2849d0d 100644
--- a/lib/hipe/test/Makefile
+++ b/lib/hipe/test/Makefile
@@ -8,6 +8,10 @@ include $(ERL_TOP)/make/$(TARGET)/otp.mk
MODULES= \
hipe_SUITE
+# .erl files for these modules are automatically generated
+GEN_MODULES= \
+ bs_SUITE
+
ERL_FILES= $(MODULES:%=%.erl)
TARGET_FILES= $(MODULES:%=$(EBIN)/%.$(EMULATOR))
@@ -40,6 +44,8 @@ EBIN = .
make_emakefile:
$(ERL_TOP)/make/make_emakefile $(ERL_COMPILE_FLAGS) -o$(EBIN) $(MODULES) \
> $(EMAKEFILE)
+ $(ERL_TOP)/make/make_emakefile $(ERL_COMPILE_FLAGS) -o$(EBIN) $(GEN_MODULES) \
+ >> $(EMAKEFILE)
$(ERL_TOP)/make/make_emakefile $(ERL_COMPILE_FLAGS) -o$(EBIN) '*_SUITE_make' \
>> $(EMAKEFILE)
diff --git a/lib/hipe/test/hipe_testsuite_driver.erl b/lib/hipe/test/hipe_testsuite_driver.erl
index c8fdf1600c..5f05a716bc 100644
--- a/lib/hipe/test/hipe_testsuite_driver.erl
+++ b/lib/hipe/test/hipe_testsuite_driver.erl
@@ -85,7 +85,7 @@ list_testcases(Dirname) ->
list_dir(Dir, Extension, Dirs) ->
case file:list_dir(Dir) of
- {error, _} = Error-> Error;
+ {error, _} = Error -> Error;
{ok, Filenames} ->
FullFilenames = [filename:join(Dir, F) || F <- Filenames],
Matches1 = case Dirs of
@@ -173,10 +173,29 @@ run(TestCase, Dir, _OutDir) ->
%% end, DataFiles),
%% try
ok = TestCase:test(),
- HiPEOpts = try TestCase:hipe_options() catch _:_ -> [] end,
+ HiPEOpts = try TestCase:hipe_options() catch error:undef -> [] end,
{ok, TestCase} = hipe:c(TestCase, HiPEOpts),
- ok = TestCase:test().
+ ok = TestCase:test(),
+ case is_llvm_opt_available() of
+ true ->
+ {ok, TestCase} = hipe:c(TestCase, [to_llvm|HiPEOpts]),
+ ok = TestCase:test();
+ false -> ok
+ end.
%% after
%% lists:foreach(fun (DF) -> ok end, % = file:delete(DF) end,
%% [filename:join(OutDir, D) || D <- DataFiles])
%% end.
+
+
+%% This function, which is supposed to check whether the right LLVM
+%% infrastructure is available, should be probably written in a better
+%% and more portable way and moved to the hipe application.
+
+is_llvm_opt_available() ->
+ OptStr = os:cmd("opt -version"),
+ SubStr = "LLVM version ", N = length(SubStr),
+ case string:str(OptStr, SubStr) of
+ 0 -> false;
+ S -> P = S + N, string:sub_string(OptStr, P, P + 2) >= "3.4"
+ end.
diff --git a/lib/ic/doc/src/notes.xml b/lib/ic/doc/src/notes.xml
index 9ae464e028..03af316f75 100644
--- a/lib/ic/doc/src/notes.xml
+++ b/lib/ic/doc/src/notes.xml
@@ -30,7 +30,23 @@
<file>notes.xml</file>
</header>
- <section><title>IC 4.3.4</title>
+ <section><title>IC 4.3.5</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p> Added Latin-1 code directive in the generated files
+ to keep old behaviour. Updated IC so it can handle
+ Unicode characters in the path. </p>
+ <p>
+ Own Id: OTP-11783</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>IC 4.3.4</title>
<section><title>Fixed Bugs and Malfunctions</title>
<list>
diff --git a/lib/inets/doc/src/notes.xml b/lib/inets/doc/src/notes.xml
index f77214c589..e29144f014 100644
--- a/lib/inets/doc/src/notes.xml
+++ b/lib/inets/doc/src/notes.xml
@@ -32,7 +32,98 @@
<file>notes.xml</file>
</header>
- <section><title>Inets 5.9.8</title>
+ <section><title>Inets 5.10</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Fixed a spelling mistake in httpc doc (Thanks to Wasif
+ Riaz Malik)</p>
+ <p>
+ Own Id: OTP-11538</p>
+ </item>
+ <item>
+ <p>
+ Application upgrade (appup) files are corrected for the
+ following applications: </p>
+ <p>
+ <c>asn1, common_test, compiler, crypto, debugger,
+ dialyzer, edoc, eldap, erl_docgen, et, eunit, gs, hipe,
+ inets, observer, odbc, os_mon, otp_mibs, parsetools,
+ percept, public_key, reltool, runtime_tools, ssh,
+ syntax_tools, test_server, tools, typer, webtool, wx,
+ xmerl</c></p>
+ <p>
+ A new test utility for testing appup files is added to
+ test_server. This is now used by most applications in
+ OTP.</p>
+ <p>
+ (Thanks to Tobias Schlager)</p>
+ <p>
+ Own Id: OTP-11744</p>
+ </item>
+ <item>
+ <p>
+ ftp now sanitize file name, user name and passwords from
+ &lt;CR&gt; and &lt;LF&gt; tags (Thanks to Sergei Golovan)</p>
+ <p>
+ Own Id: OTP-11750</p>
+ </item>
+ <item>
+ <p>
+ Corrected error handling in the HTTP client, making it
+ behave more graceful.</p>
+ <p>
+ Thanks to Kirilll Zaborsky</p>
+ <p>
+ Own Id: OTP-11794</p>
+ </item>
+ <item>
+ <p>
+ Support identity transfer-encoding in httpc.</p>
+ <p>
+ Thanks to Anthony Ramine</p>
+ <p>
+ Own Id: OTP-11802</p>
+ </item>
+ <item>
+ <p>
+ Ignore empty Set-Cookie headers to increase
+ interoperability with servers that violate the RFC. </p>
+ <p>
+ Thanks to Kirilll Zaborsky</p>
+ <p>
+ Own Id: OTP-11803</p>
+ </item>
+ </list>
+ </section>
+
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p>
+ The commit 6189bc07 "inets: httpc improve pipelining" has
+ been reverted, as it turned out to break things rather
+ than improve pipelining utilization. It is instead up to
+ the user to configure httpc and use it wisely to be able
+ to get the most out of pipelining.</p>
+ <p>
+ Own Id: OTP-11756</p>
+ </item>
+ <item>
+ <p>
+ Handle all response codes in httpd_util:message/3</p>
+ <p>
+ Own Id: OTP-11838</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Inets 5.9.8</title>
<section><title>Improvements and New Features</title>
<list>
diff --git a/lib/inets/src/http_server/httpd_util.erl b/lib/inets/src/http_server/httpd_util.erl
index b0b18b9c3d..0d04a75205 100644
--- a/lib/inets/src/http_server/httpd_util.erl
+++ b/lib/inets/src/http_server/httpd_util.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2011. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2014. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -206,9 +206,6 @@ message(413, Reason,_) ->
"Entity: " ++ html_encode(Reason);
message(414,ReasonPhrase,_) ->
"Message " ++ html_encode(ReasonPhrase) ++ ".";
-message(416,ReasonPhrase,_) ->
- html_encode(ReasonPhrase);
-
message(500,_,ConfigDB) ->
ServerAdmin=lookup(ConfigDB,server_admin,"unknown@unknown"),
"The server encountered an internal error or "
@@ -233,7 +230,9 @@ message(501,{Method, RequestURI, HTTPVersion}, _ConfigDB) ->
end;
message(503, String, _ConfigDB) ->
- "This service in unavailable due to: " ++ html_encode(String).
+ "This service in unavailable due to: " ++ html_encode(String);
+message(_, ReasonPhrase, _) ->
+ html_encode(ReasonPhrase).
maybe_encode(URI) ->
Decoded = try http_uri:decode(URI) of
diff --git a/lib/inets/test/httpd_SUITE.erl b/lib/inets/test/httpd_SUITE.erl
index 3eb8a0818f..4be20d3a69 100644
--- a/lib/inets/test/httpd_SUITE.erl
+++ b/lib/inets/test/httpd_SUITE.erl
@@ -168,7 +168,12 @@ init_per_group(http_1_1, Config) ->
init_per_group(http_1_0, Config) ->
[{http_version, "HTTP/1.0"} | Config];
init_per_group(http_0_9, Config) ->
- [{http_version, "HTTP/0.9"} | Config];
+ case {os:type(), os:version()} of
+ {{win32, _}, {5,1,2600}} ->
+ {skip, "eaddrinuse XP problem"};
+ _ ->
+ [{http_version, "HTTP/0.9"} | Config]
+ end;
init_per_group(http_htaccess = Group, Config) ->
Path = ?config(doc_root, Config),
catch remove_htaccess(Path),
@@ -1099,7 +1104,7 @@ do_max_clients(Config) ->
BlockRequest = http_request("GET /eval?httpd_example:delay(2000) ", Version, Host),
{ok, Socket} = inets_test_lib:connect_bin(Type, Host, Port, transport_opts(Type, Config)),
inets_test_lib:send(Type, Socket, BlockRequest),
- ct:sleep(100),
+ ct:sleep(100), %% Avoid possible timing issues
ok = httpd_test_lib:verify_request(Type, Host,
Port,
transport_opts(Type, Config),
@@ -1112,6 +1117,7 @@ do_max_clients(Config) ->
ok
end,
inets_test_lib:close(Type, Socket),
+ ct:sleep(100), %% Avoid possible timing issues
ok = httpd_test_lib:verify_request(Type, Host,
Port,
transport_opts(Type, Config),
diff --git a/lib/inets/test/inets_sup_SUITE.erl b/lib/inets/test/inets_sup_SUITE.erl
index cf28f5a245..60979278fc 100644
--- a/lib/inets/test/inets_sup_SUITE.erl
+++ b/lib/inets/test/inets_sup_SUITE.erl
@@ -77,75 +77,32 @@ end_per_suite(_) ->
%% variable, but should NOT alter/remove any existing entries.
%%--------------------------------------------------------------------
init_per_testcase(httpd_subtree, Config) ->
- io:format("init_per_testcase(httpd_subtree) -> entry with"
- "~n Config: ~p"
- "~n", [Config]),
Dog = test_server:timetrap(?t:minutes(1)),
NewConfig = lists:keydelete(watchdog, 1, Config),
-
- DataDir = ?config(data_dir, Config),
PrivDir = ?config(priv_dir, Config),
- ServerROOT = filename:join(PrivDir, "server_root"),
- DocROOT = filename:join(PrivDir, "htdocs"),
- ConfDir = filename:join(ServerROOT, "conf"),
-
- io:format("init_per_testcase(httpd_subtree) -> create dir(s)"
- "~n", []),
- file:make_dir(ServerROOT), %% until http_test is cleaned up!
- ok = file:make_dir(DocROOT),
- ok = file:make_dir(ConfDir),
-
- io:format("init_per_testcase(httpd_subtree) -> copy file(s)"
- "~n", []),
- {ok, _} = inets_test_lib:copy_file("simple.conf", DataDir, PrivDir),
- {ok, _} = inets_test_lib:copy_file("mime.types", DataDir, ConfDir),
-
- io:format("init_per_testcase(httpd_subtree) -> write file(s)"
- "~n", []),
- ConfFile = filename:join(PrivDir, "simple.conf"),
- {ok, Fd} = file:open(ConfFile, [append]),
- ok = file:write(Fd, "ServerRoot " ++ ServerROOT ++ "\n"),
- ok = file:write(Fd, "DocumentRoot " ++ DocROOT ++ "\n"),
- ok = file:close(Fd),
-
- %% To make sure application:set_env is not overwritten by any
- %% app-file settings.
- io:format("init_per_testcase(httpd_subtree) -> load inets app"
- "~n", []),
- application:load(inets),
- io:format("init_per_testcase(httpd_subtree) -> update inets env"
- "~n", []),
- ok = application:set_env(inets, services, [{httpd, ConfFile}]),
-
+
+ SimpleConfig = [{port, 0},
+ {server_name,"www.test"},
+ {modules, [mod_get]},
+ {server_root, PrivDir},
+ {document_root, PrivDir},
+ {bind_address, any},
+ {ipfamily, inet}],
try
- io:format("init_per_testcase(httpd_subtree) -> start inets app"
- "~n", []),
- ok = inets:start(),
- io:format("init_per_testcase(httpd_subtree) -> done"
- "~n", []),
- [{watchdog, Dog}, {server_root, ServerROOT}, {doc_root, DocROOT},
- {conf_dir, ConfDir}| NewConfig]
+ inets:start(),
+ inets:start(httpd, SimpleConfig),
+ [{watchdog, Dog} | NewConfig]
catch
_:Reason ->
- io:format("init_per_testcase(httpd_subtree) -> "
- "failed starting inets - cleanup"
- "~n Reason: ~p"
- "~n", [Reason]),
- application:unset_env(inets, services),
- application:unload(inets),
+ inets:stop(),
exit({failed_starting_inets, Reason})
end;
-init_per_testcase(Case, Config) ->
- io:format("init_per_testcase(~p) -> entry with"
- "~n Config: ~p"
- "~n", [Case, Config]),
+init_per_testcase(_Case, Config) ->
Dog = test_server:timetrap(?t:minutes(5)),
NewConfig = lists:keydelete(watchdog, 1, Config),
- Stop = inets:stop(),
- io:format("init_per_testcase(~p) -> Stop: ~p"
- "~n", [Case, Stop]),
+ inets:stop(),
ok = inets:start(),
[{watchdog, Dog} | NewConfig].
@@ -280,30 +237,21 @@ httpd_subtree(doc) ->
httpd_subtree(suite) ->
[];
httpd_subtree(Config) when is_list(Config) ->
- io:format("httpd_subtree -> entry with"
- "~n Config: ~p"
- "~n", [Config]),
-
%% Check that we have the httpd top supervisor
- io:format("httpd_subtree -> verify inets~n", []),
{ok, _} = verify_child(inets_sup, httpd_sup, supervisor),
%% Check that we have the httpd instance supervisor
- io:format("httpd_subtree -> verify httpd~n", []),
{ok, Id} = verify_child(httpd_sup, httpd_instance_sup, supervisor),
{httpd_instance_sup, Addr, Port} = Id,
Instance = httpd_util:make_name("httpd_instance_sup", Addr, Port),
%% Check that we have the expected httpd instance children
- io:format("httpd_subtree -> verify httpd instance children "
- "(acceptor, misc and manager)~n", []),
{ok, _} = verify_child(Instance, httpd_connection_sup, supervisor),
{ok, _} = verify_child(Instance, httpd_acceptor_sup, supervisor),
{ok, _} = verify_child(Instance, httpd_misc_sup, supervisor),
{ok, _} = verify_child(Instance, httpd_manager, worker),
%% Check that the httpd instance acc supervisor has children
- io:format("httpd_subtree -> verify acc~n", []),
InstanceAcc = httpd_util:make_name("httpd_acceptor_sup", Addr, Port),
case supervisor:which_children(InstanceAcc) of
[_ | _] ->
@@ -328,15 +276,7 @@ httpd_subtree(Config) when is_list(Config) ->
verify_child(Parent, Child, Type) ->
-%% io:format("verify_child -> entry with"
-%% "~n Parent: ~p"
-%% "~n Child: ~p"
-%% "~n Type: ~p"
-%% "~n", [Parent, Child, Type]),
Children = supervisor:which_children(Parent),
-%% io:format("verify_child -> which children"
-%% "~n Children: ~p"
-%% "~n", [Children]),
verify_child(Children, Parent, Child, Type).
verify_child([], Parent, Child, _Type) ->
@@ -344,21 +284,12 @@ verify_child([], Parent, Child, _Type) ->
verify_child([{Id, _Pid, Type2, Mods}|Children], Parent, Child, Type) ->
case lists:member(Child, Mods) of
true when (Type2 =:= Type) ->
-%% io:format("verify_child -> found with expected type"
-%% "~n Id: ~p"
-%% "~n", [Id]),
{ok, Id};
true when (Type2 =/= Type) ->
-%% io:format("verify_child -> found with unexpected type"
-%% "~n Type2: ~p"
-%% "~n Id: ~p"
-%% "~n", [Type2, Id]),
{error, {wrong_type, Type2, Child, Parent}};
false ->
verify_child(Children, Parent, Child, Type)
end.
-
-
%%-------------------------------------------------------------------------
%% httpc_subtree
@@ -368,40 +299,19 @@ httpc_subtree(doc) ->
httpc_subtree(suite) ->
[];
httpc_subtree(Config) when is_list(Config) ->
- tsp("httpc_subtree -> entry with"
- "~n Config: ~p", [Config]),
+ {ok, Foo} = inets:start(httpc, [{profile, foo}]),
- tsp("httpc_subtree -> start inets service httpc with profile foo"),
- {ok, _Foo} = inets:start(httpc, [{profile, foo}]),
+ {ok, Bar} = inets:start(httpc, [{profile, bar}], stand_alone),
- tsp("httpc_subtree -> "
- "start stand-alone inets service httpc with profile bar"),
- {ok, _Bar} = inets:start(httpc, [{profile, bar}], stand_alone),
-
- tsp("httpc_subtree -> retreive list of httpc instances"),
HttpcChildren = supervisor:which_children(httpc_profile_sup),
- tsp("httpc_subtree -> HttpcChildren: ~n~p", [HttpcChildren]),
-
- tsp("httpc_subtree -> verify httpc stand-alone instances"),
+
{value, {httpc_manager, _, worker, [httpc_manager]}} =
lists:keysearch(httpc_manager, 1, HttpcChildren),
- tsp("httpc_subtree -> verify httpc (named) instances"),
- {value,{{httpc,foo}, Pid, worker, [httpc_manager]}} =
+ {value,{{httpc,foo}, _Pid, worker, [httpc_manager]}} =
lists:keysearch({httpc, foo}, 1, HttpcChildren),
false = lists:keysearch({httpc, bar}, 1, HttpcChildren),
- tsp("httpc_subtree -> stop inets"),
- inets:stop(httpc, Pid),
-
- tsp("httpc_subtree -> done"),
- ok.
-
-tsp(F) ->
- tsp(F, []).
-tsp(F, A) ->
- test_server:format("~p ~p:" ++ F ++ "~n", [self(), ?MODULE | A]).
-
-tsf(Reason) ->
- test_server:fail(Reason).
+ inets:stop(httpc, Foo),
+ exit(Bar, normal).
diff --git a/lib/inets/test/inets_sup_SUITE_data/mime.types b/lib/inets/test/inets_sup_SUITE_data/mime.types
deleted file mode 100644
index e52d345ff7..0000000000
--- a/lib/inets/test/inets_sup_SUITE_data/mime.types
+++ /dev/null
@@ -1,3 +0,0 @@
-# MIME type Extension
-text/html html htm
-text/plain asc txt
diff --git a/lib/inets/test/inets_sup_SUITE_data/simple.conf b/lib/inets/test/inets_sup_SUITE_data/simple.conf
deleted file mode 100644
index e1429b4a28..0000000000
--- a/lib/inets/test/inets_sup_SUITE_data/simple.conf
+++ /dev/null
@@ -1,6 +0,0 @@
-Port 8888
-ServerName www.test
-SocketType ip_comm
-Modules mod_get
-ServerAdmin [email protected]
-
diff --git a/lib/jinterface/doc/src/notes.xml b/lib/jinterface/doc/src/notes.xml
index 8c45d187bc..e81a9f82d2 100644
--- a/lib/jinterface/doc/src/notes.xml
+++ b/lib/jinterface/doc/src/notes.xml
@@ -30,6 +30,25 @@
</header>
<p>This document describes the changes made to the Jinterface application.</p>
+<section><title>Jinterface 1.5.9</title>
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p>
+ Implement support for Maps</p>
+ <p>
+ The API and implementation are simplistic, like for lists
+ and tuples, using arrays and without any connection to
+ java.util.Map. (Thanks to Vlad Dumitrescu)</p>
+ <p>
+ Own Id: OTP-11703</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>Jinterface 1.5.8</title>
<section><title>Fixed Bugs and Malfunctions</title>
diff --git a/lib/kernel/doc/src/application.xml b/lib/kernel/doc/src/application.xml
index 016151891c..7664fda4db 100644
--- a/lib/kernel/doc/src/application.xml
+++ b/lib/kernel/doc/src/application.xml
@@ -4,7 +4,7 @@
<erlref>
<header>
<copyright>
- <year>1996</year><year>2013</year>
+ <year>1996</year><year>2014</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -459,8 +459,7 @@ Nodes = [cp1@cave, {cp2@cave, cp3@cave}]</code>
<name>Module:start(StartType, StartArgs) -> {ok, Pid} | {ok, Pid, State} | {error, Reason}</name>
<fsummary>Start an application</fsummary>
<type>
- <v>StartType = normal | {takeover,Node} | {failover,Node}</v>
- <v>&nbsp;Node = node()</v>
+ <v>StartType = <seealso marker="#type-start_type">start_type()</seealso></v>
<v>StartArgs = term()</v>
<v>Pid = pid()</v>
<v>State = term()</v>
diff --git a/lib/kernel/doc/src/kernel_app.xml b/lib/kernel/doc/src/kernel_app.xml
index 49a93d2c70..00c6bc33d6 100644
--- a/lib/kernel/doc/src/kernel_app.xml
+++ b/lib/kernel/doc/src/kernel_app.xml
@@ -4,7 +4,7 @@
<appref>
<header>
<copyright>
- <year>1996</year><year>2013</year>
+ <year>1996</year><year>2014</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -35,7 +35,7 @@
Erlang/OTP consists of Kernel and STDLIB. The Kernel application
contains the following services:</p>
<list type="bulleted">
- <item>application controller, see <c>application(3)</c></item>
+ <item>application controller, see <seealso marker="application">application(3)</seealso></item>
<item><c>code</c></item>
<item><c>disk_log</c></item>
<item><c>dist_ac</c>, distributed application controller</item>
@@ -66,8 +66,8 @@
<section>
<title>Configuration</title>
<p>The following configuration parameters are defined for the Kernel
- application. See <c>app(3)</c> for more information about
- configuration parameters.</p>
+ application. See <seealso marker="app">app(4)</seealso> for more
+ information about configuration parameters.</p>
<taglist>
<tag><c>browser_cmd = string() | {M,F,A}</c></tag>
<item>
@@ -93,7 +93,8 @@
<item><c>Time = integer()>0</c></item>
<item><c>Nodes = [node() | {node(),...,node()}]</c></item>
</list>
- <p>The parameter is described in <c>application(3)</c>, function
+ <p>The parameter is described in
+ <seealso marker="application">application(3)</seealso>, function
<c>load/2</c>.</p>
</item>
<tag><c>dist_auto_connect = Value</c></tag>
@@ -105,11 +106,13 @@
<taglist>
<tag><c>never</c></tag>
<item>Connections are never automatically established, they
- must be explicitly connected. See <c>net_kernel(3)</c>.</item>
+ must be explicitly connected. See
+ <seealso marker="net_kernel">net_kernel(3)</seealso>.</item>
<tag><c>once</c></tag>
<item>Connections will be established automatically, but only
once per node. If a node goes down, it must thereafter be
- explicitly connected. See <c>net_kernel(3)</c>.</item>
+ explicitly connected. See
+ <seealso marker="net_kernel">net_kernel(3)</seealso>.</item>
</taglist>
</item>
<tag><c>permissions = [Perm]</c></tag>
@@ -121,7 +124,8 @@
<item><c>ApplName = atom()</c></item>
<item><c>Bool = boolean()</c></item>
</list>
- <p>Permissions are described in <c>application(3)</c>, function
+ <p>Permissions are described in
+ <seealso marker="application">application(3)</seealso>, function
<c>permit/2</c>.</p>
</item>
<tag><c>error_logger = Value</c></tag>
@@ -149,7 +153,8 @@
</item>
<tag><c>global_groups = [GroupTuple]</c></tag>
<item>
- <p>Defines global groups, see <c>global_group(3)</c>.</p>
+ <p>Defines global groups, see
+ <seealso marker="global_group">global_group(3)</seealso>.</p>
<list type="bulleted">
<item><c>GroupTuple = {GroupName, [Node]} | {GroupName, PublishType, [Node]}</c></item>
<item><c>GroupName = atom()</c></item>
@@ -160,18 +165,19 @@
<tag><c>inet_default_connect_options = [{Opt, Val}]</c></tag>
<item>
<p>Specifies default options for <c>connect</c> sockets,
- see <c>inet(3)</c>.</p>
+ see <seealso marker="inet">inet(3)</seealso>.</p>
</item>
<tag><c>inet_default_listen_options = [{Opt, Val}]</c></tag>
<item>
<p>Specifies default options for <c>listen</c> (and
- <c>accept</c>) sockets, see <c>inet(3)</c>.</p>
+ <c>accept</c>) sockets, see <seealso marker="inet">inet(3)</seealso>.</p>
</item>
<tag><c>{inet_dist_use_interface, ip_address()}</c></tag>
<item>
<p>If the host of an Erlang node has several network interfaces,
this parameter specifies which one to listen on. See
- <c>inet(3)</c> for the type definition of <c>ip_address()</c>.</p>
+ <seealso marker="inet">inet(3)</seealso> for the type definition
+ of <c>ip_address()</c>.</p>
</item>
<tag><c>{inet_dist_listen_min, First}</c></tag>
<item>
@@ -276,7 +282,8 @@ MaxT = TickTime + TickTime / 4</code>
<tag><c>start_boot_server = true | false</c></tag>
<item>
<p>Starts the <c>boot_server</c> if the parameter is <c>true</c>
- (see <c>erl_boot_server(3)</c>). This parameter should be
+ (see <seealso marker="erl_boot_server">erl_boot_server(3)</seealso>).
+ This parameter should be
set to <c>true</c> in an embedded system which uses this
service.</p>
<p>The default value is <c>false</c>.</p>
@@ -296,13 +303,15 @@ MaxT = TickTime + TickTime / 4</code>
<tag><c>start_disk_log = true | false</c></tag>
<item>
<p>Starts the <c>disk_log_server</c> if the parameter is
- <c>true</c> (see <c>disk_log(3)</c>). This parameter should be
+ <c>true</c> (see <seealso marker="disk_log">disk_log(3)</seealso>).
+ This parameter should be
set to true in an embedded system which uses this service.</p>
<p>The default value is <c>false</c>.</p>
</item>
<tag><c>start_pg2 = true | false</c></tag>
<item>
- <p>Starts the <c>pg2</c> server (see <c>pg2(3)</c>) if
+ <p>Starts the <c>pg2</c> server (see
+ <seealso marker="pg2">pg2(3)</seealso>) if
the parameter is <c>true</c>. This parameter should be set to
<c>true</c> in an embedded system which uses this service.</p>
<p>The default value is <c>false</c>.</p>
@@ -310,7 +319,8 @@ MaxT = TickTime + TickTime / 4</code>
<tag><c>start_timer = true | false</c></tag>
<item>
<p>Starts the <c>timer_server</c> if the parameter is
- <c>true</c> (see <c>timer(3)</c>). This parameter should be
+ <c>true</c> (see <seealso marker="stdlib:timer">timer(3)</seealso>).
+ This parameter should be
set to <c>true</c> in an embedded system which uses this
service.</p>
<p>The default value is <c>false</c>.</p>
@@ -351,6 +361,7 @@ MaxT = TickTime + TickTime / 4</code>
<seealso marker="pg2">pg2(3)</seealso>,
<seealso marker="rpc">rpc(3)</seealso>,
<seealso marker="seq_trace">seq_trace(3)</seealso>,
+ <seealso marker="stdlib:timer">timer(3)</seealso>,
<seealso marker="user">user(3)</seealso></p>
</section>
</appref>
diff --git a/lib/kernel/doc/src/notes.xml b/lib/kernel/doc/src/notes.xml
index b2e89ea850..c6538b7d05 100644
--- a/lib/kernel/doc/src/notes.xml
+++ b/lib/kernel/doc/src/notes.xml
@@ -30,6 +30,203 @@
</header>
<p>This document describes the changes made to the Kernel application.</p>
+<section><title>Kernel 3.0</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Fixed a deadlock possibility in terminate application</p>
+ <p>
+ Own Id: OTP-11171</p>
+ </item>
+ <item>
+ <p>
+ Fixed bug where sendfile would return the wrong error
+ code for a remotely closed socket if the socket was in
+ passive mode. (Thanks to Vincent Siliakus for reporting
+ the bug.)</p>
+ <p>
+ Own Id: OTP-11614</p>
+ </item>
+ <item>
+ <p>
+ The new option <c>persistent</c> is added to
+ <c>application:set_env/4</c> and
+ <c>application:unset_env/3</c>. An environment key set
+ with the <c>persistent</c> option will not be overridden
+ by the ones configured in the application resource file
+ on load. This means persistent values will stick after
+ the application is loaded and also on application reload.
+ (Thanks to José Valim)</p>
+ <p>
+ Own Id: OTP-11708</p>
+ </item>
+ <item>
+ <p>
+ The spec for file:set_cwd/1 is modified to also accept
+ binaries as arguments. This has always been allowed in
+ the code, but it was not reflected in the spec since
+ binaries are mostly used for raw file names. Raw file
+ names are names that are not encoded according to
+ file:native_name_encoding(), and these are not allowed in
+ file:set_cwd/1. The spec is now, however, more allowing
+ in order to avoid unnecessary dialyzer warnings. Raw file
+ names will still fail in runtime with reason
+ 'no_translation'. (Thanks to José Valim)</p>
+ <p>
+ Own Id: OTP-11787</p>
+ </item>
+ </list>
+ </section>
+
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p>
+ heart:set_cmd/1 is updated to allow unicode code points >
+ 255 in the given heart command</p>
+ <p>
+ Own Id: OTP-10843</p>
+ </item>
+ <item>
+ <p> Dialyzer's <c>unmatched_return</c> warnings have been
+ corrected. </p>
+ <p>
+ Own Id: OTP-10908</p>
+ </item>
+ <item>
+ <p>
+ Make erlang:open_port/2 spawn and spawn_executable handle
+ unicode.</p>
+ <p>
+ Own Id: OTP-11105</p>
+ </item>
+ <item>
+ <p>
+ Erlang/OTP has been ported to the realtime operating
+ system OSE. The port supports both smp and non-smp
+ emulator. For details around the port and how to started
+ see the User's Guide in the <seealso
+ marker="ose:ose_intro">ose</seealso> application. </p>
+ <p>
+ Note that not all parts of Erlang/OTP has been ported. </p>
+ <p>
+ Notable things that work are: non-smp and smp emulators,
+ OSE signal interaction, crypto, asn1, run_erl/to_erl,
+ tcp, epmd, distribution and most if not all non-os
+ specific functionality of Erlang.</p>
+ <p>
+ Notable things that does not work are: udp/sctp, os_mon,
+ erl_interface, binding of schedulers.</p>
+ <p>
+ Own Id: OTP-11334</p>
+ </item>
+ <item>
+ <p>
+ Add the {active,N} socket option for TCP, UDP, and SCTP,
+ where N is an integer in the range -32768..32767, to
+ allow a caller to specify the number of data messages to
+ be delivered to the controlling process. Once the
+ socket's delivered message count either reaches 0 or is
+ explicitly set to 0 with inet:setopts/2 or by including
+ {active,0} as an option when the socket is created, the
+ socket transitions to passive ({active, false}) mode and
+ the socket's controlling process receives a message to
+ inform it of the transition. TCP sockets receive
+ {tcp_passive,Socket}, UDP sockets receive
+ {udp_passive,Socket} and SCTP sockets receive
+ {sctp_passive,Socket}. </p>
+ <p>
+ The socket's delivered message counter defaults to 0, but
+ it can be set using {active,N} via any gen_tcp, gen_udp,
+ or gen_sctp function that takes socket options as
+ arguments, or via inet:setopts/2. New N values are added
+ to the socket's current counter value, and negative
+ numbers can be used to reduce the counter value.
+ Specifying a number that would cause the socket's counter
+ value to go above 32767 causes an einval error. If a
+ negative number is specified such that the counter value
+ would become negative, the socket's counter value is set
+ to 0 and the socket transitions to passive mode. If the
+ counter value is already 0 and inet:setopts(Socket,
+ [{active,0}]) is specified, the counter value remains at
+ 0 but the appropriate passive mode transition message is
+ generated for the socket.</p>
+ <p>
+ Thanks to Steve Vinoski</p>
+ <p>
+ Own Id: OTP-11368</p>
+ </item>
+ <item>
+ <p>
+ A call to either the <c>garbage_collect/1</c> BIF or the
+ <c>check_process_code/2</c> BIF may trigger garbage
+ collection of another processes than the process calling
+ the BIF. The previous implementations performed these
+ kinds of garbage collections without considering the
+ internal state of the process being garbage collected. In
+ order to be able to more easily and more efficiently
+ implement yielding native code, these types of garbage
+ collections have been rewritten. A garbage collection
+ like this is now triggered by an asynchronous request
+ signal, the actual garbage collection is performed by the
+ process being garbage collected itself, and finalized by
+ a reply signal to the process issuing the request. Using
+ this approach processes can disable garbage collection
+ and yield without having to set up the heap in a state
+ that can be garbage collected.</p>
+ <p>
+ The <seealso
+ marker="erts:erlang#garbage_collect/2"><c>garbage_collect/2</c></seealso>,
+ and <seealso
+ marker="erts:erlang#check_process_code/3"><c>check_process_code/3</c></seealso>
+ BIFs have been introduced. Both taking an option list as
+ last argument. Using these, one can issue asynchronous
+ requests.</p>
+ <p>
+ <c>code:purge/1</c> and <c>code:soft_purge/1</c> have
+ been rewritten to utilize asynchronous
+ <c>check_process_code</c> requests in order to
+ parallelize work.</p>
+ <p>
+ Characteristics impact: A call to the
+ <c>garbage_collect/1</c> BIF or the
+ <c>check_process_code/2</c> BIF will normally take longer
+ time to complete while the system as a whole wont be as
+ much negatively effected by the operation as before. A
+ call to <c>code:purge/1</c> and <c>code:soft_purge/1</c>
+ may complete faster or slower depending on the state of
+ the system while the system as a whole wont be as much
+ negatively effected by the operation as before.</p>
+ <p>
+ Own Id: OTP-11388 Aux Id: OTP-11535, OTP-11648 </p>
+ </item>
+ <item>
+ <p>
+ Add sync option to file:open/2.</p>
+ <p>
+ The sync option adds the POSIX O_SYNC flag to the open
+ system call on platforms that support the flag or its
+ equivalent, e.g., FILE_FLAG_WRITE_THROUGH on Windows. For
+ platforms that don't support it, file:open/2 returns
+ {error, enotsup} if the sync option is passed in. Thank
+ to Steve Vinoski and Joseph Blomstedt</p>
+ <p>
+ Own Id: OTP-11498</p>
+ </item>
+ <item>
+ <p> The contract of <c>inet:ntoa/1</c> has been
+ corrected. </p> <p> Thanks to Max Treskin. </p>
+ <p>
+ Own Id: OTP-11730</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>Kernel 2.16.4</title>
<section><title>Fixed Bugs and Malfunctions</title>
diff --git a/lib/kernel/src/application.erl b/lib/kernel/src/application.erl
index 76a80553b0..c4bef5188a 100644
--- a/lib/kernel/src/application.erl
+++ b/lib/kernel/src/application.erl
@@ -30,6 +30,8 @@
-export([get_application/0, get_application/1, info/0]).
-export([start_type/0]).
+-export_type([start_type/0]).
+
%%%-----------------------------------------------------------------
-type start_type() :: 'normal'
@@ -58,8 +60,7 @@
%%------------------------------------------------------------------
--callback start(StartType :: normal | {takeover, node()} | {failover, node()},
- StartArgs :: term()) ->
+-callback start(StartType :: start_type(), StartArgs :: term()) ->
{'ok', pid()} | {'ok', pid(), State :: term()} | {'error', Reason :: term()}.
-callback stop(State :: term()) ->
diff --git a/lib/kernel/src/application_controller.erl b/lib/kernel/src/application_controller.erl
index ed13035104..daad45b6c2 100644
--- a/lib/kernel/src/application_controller.erl
+++ b/lib/kernel/src/application_controller.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2013. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2014. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -829,12 +829,12 @@ handle_call({change_application_data, Applications, Config}, _From, S) ->
{reply, Error, S};
{'EXIT', R} ->
{reply, {error, R}, S};
- NewAppls ->
+ {NewAppls, NewConfig} ->
lists:foreach(fun(Appl) ->
ets:insert(ac_tab, {{loaded, Appl#appl.name},
Appl})
end, NewAppls),
- {reply, ok, S#state{conf_data = Config}}
+ {reply, ok, S#state{conf_data = NewConfig}}
end;
handle_call(prep_config_change, _From, S) ->
@@ -1550,18 +1550,19 @@ do_change_apps(Applications, Config, OldAppls) ->
end,
Errors),
- map(fun(Appl) ->
- AppName = Appl#appl.name,
- case is_loaded_app(AppName, Applications) of
- {true, Application} ->
- do_change_appl(make_appl(Application),
- Appl, SysConfig);
-
- %% ignored removed apps - handled elsewhere
- false ->
- Appl
- end
- end, OldAppls).
+ {map(fun(Appl) ->
+ AppName = Appl#appl.name,
+ case is_loaded_app(AppName, Applications) of
+ {true, Application} ->
+ do_change_appl(make_appl(Application),
+ Appl, SysConfig);
+
+ %% ignored removed apps - handled elsewhere
+ false ->
+ Appl
+ end
+ end, OldAppls),
+ SysConfig}.
is_loaded_app(AppName, [{application, AppName, App} | _]) ->
{true, {application, AppName, App}};
diff --git a/lib/kernel/test/application_SUITE.erl b/lib/kernel/test/application_SUITE.erl
index c6cbd1a0ef..036e238c85 100644
--- a/lib/kernel/test/application_SUITE.erl
+++ b/lib/kernel/test/application_SUITE.erl
@@ -1949,14 +1949,22 @@ config_change(Conf) when is_list(Conf) ->
%% Find out application data from boot script
Boot = filename:join([code:root_dir(), "bin", "start.boot"]),
{ok, Bin} = file:read_file(Boot),
- Appls = get_appls(binary_to_term(Bin)),
+ Appls0 = get_appls(binary_to_term(Bin)),
+
+ %% And add app1 in order to test OTP-11864 - included config files
+ %% not read for new (not already loaded) applications
+ Appls = [app1() | Appls0],
%% Simulate contents of "sys.config"
Config = [{stdlib, [{par1,sys},{par2,sys}]},
"t1",
"t2.config",
filename:join([DataDir, "subdir", "t3"]),
- {stdlib, [{par6,sys}]}],
+ {stdlib, [{par6,sys}]},
+ "t4.config"],
+
+ %% Check that app1 is not loaded
+ false = lists:keymember(app1,1,application:loaded_applications()),
%% Order application_controller to update configuration
ok = application_controller:change_application_data(Appls,
@@ -1971,6 +1979,13 @@ config_change(Conf) when is_list(Conf) ->
{value, {par5,t3}} = lists:keysearch(par5, 1, Env),
{value, {par6,sys}} = lists:keysearch(par6, 1, Env),
+ %% Check that app1 parameters are correctly set after loading
+ [] = application:get_all_env(app1),
+ application:load(app1()),
+ App1Env = application:get_all_env(app1),
+ {value, {par1,t4}} = lists:keysearch(par1, 1, App1Env),
+ application:unload(app1),
+
ok = file:set_cwd(CWD).
%% This function is stolen from SASL module release_handler, OTP R10B
@@ -1989,6 +2004,7 @@ get_appls([_ | T], Res) ->
get_appls([], Res) ->
Res.
+
persistent_env(suite) ->
[];
persistent_env(doc) ->
diff --git a/lib/kernel/test/application_SUITE_data/t4.config b/lib/kernel/test/application_SUITE_data/t4.config
new file mode 100644
index 0000000000..8b2bc52c01
--- /dev/null
+++ b/lib/kernel/test/application_SUITE_data/t4.config
@@ -0,0 +1 @@
+[{app1, [{par1,t4}]}]. \ No newline at end of file
diff --git a/lib/kernel/test/sendfile_SUITE.erl b/lib/kernel/test/sendfile_SUITE.erl
index 2c741232c4..123e849ccb 100644
--- a/lib/kernel/test/sendfile_SUITE.erl
+++ b/lib/kernel/test/sendfile_SUITE.erl
@@ -72,7 +72,12 @@ end_per_suite(Config) ->
file:delete(proplists:get_value(big_file, Config)).
init_per_group(async_threads,Config) ->
- [{sendfile_opts,[{use_threads,true}]}|Config];
+ case erlang:system_info(thread_pool_size) of
+ 0 ->
+ {skip,"No async threads"};
+ _ ->
+ [{sendfile_opts,[{use_threads,true}]}|Config]
+ end;
init_per_group(no_async_threads,Config) ->
[{sendfile_opts,[{use_threads,false}]}|Config].
diff --git a/lib/megaco/doc/src/notes.xml b/lib/megaco/doc/src/notes.xml
index f71166b1b1..dff36fd51c 100644
--- a/lib/megaco/doc/src/notes.xml
+++ b/lib/megaco/doc/src/notes.xml
@@ -36,7 +36,23 @@
section is the version number of Megaco.</p>
- <section><title>Megaco 3.17.0.3</title>
+ <section><title>Megaco 3.17.1</title>
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p> The default encoding of Erlang files has been changed
+ from ISO-8859-1 to UTF-8. </p> <p> The encoding of XML
+ files has also been changed to UTF-8. </p>
+ <p>
+ Own Id: OTP-10907</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Megaco 3.17.0.3</title>
<section><title>Improvements and New Features</title>
<list>
diff --git a/lib/mnesia/doc/src/notes.xml b/lib/mnesia/doc/src/notes.xml
index 0e9131190d..213c2b6d21 100644
--- a/lib/mnesia/doc/src/notes.xml
+++ b/lib/mnesia/doc/src/notes.xml
@@ -38,7 +38,69 @@
thus constitutes one section in this document. The title of each
section is the version number of Mnesia.</p>
- <section><title>Mnesia 4.11</title>
+ <section><title>Mnesia 4.12</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Some local implementations of removing the last element
+ from a list are replaced by <c>lists:droplast/1</c>. Note
+ that this requires at least <c>stdlib-2.0</c>, which is
+ the stdlib version delivered in OTP 17.0. (Thanks to Hans
+ Svensson)</p>
+ <p>
+ Own Id: OTP-11678</p>
+ </item>
+ <item>
+ <p>
+ Application upgrade (appup) files are corrected for the
+ following applications: </p>
+ <p>
+ <c>asn1, common_test, compiler, crypto, debugger,
+ dialyzer, edoc, eldap, erl_docgen, et, eunit, gs, hipe,
+ inets, observer, odbc, os_mon, otp_mibs, parsetools,
+ percept, public_key, reltool, runtime_tools, ssh,
+ syntax_tools, test_server, tools, typer, webtool, wx,
+ xmerl</c></p>
+ <p>
+ A new test utility for testing appup files is added to
+ test_server. This is now used by most applications in
+ OTP.</p>
+ <p>
+ (Thanks to Tobias Schlager)</p>
+ <p>
+ Own Id: OTP-11744</p>
+ </item>
+ </list>
+ </section>
+
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p>
+ To prevent a race condition if there is a short
+ communication problem when node-down and node-up events
+ are received. They are now stored and later checked if
+ the node came up just before mnesia flagged the node as
+ down. (Thanks to Jonas Falkevik )</p>
+ <p>
+ Own Id: OTP-11497</p>
+ </item>
+ <item>
+ <p>
+ Added <c>mnesia:sync_log/0</c> to explicit sync mnesias
+ transaction log.</p>
+ <p>
+ Own Id: OTP-11729</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Mnesia 4.11</title>
<section><title>Fixed Bugs and Malfunctions</title>
<list>
diff --git a/lib/observer/doc/src/notes.xml b/lib/observer/doc/src/notes.xml
index 9de00b8c16..a2c5eda9d7 100644
--- a/lib/observer/doc/src/notes.xml
+++ b/lib/observer/doc/src/notes.xml
@@ -31,6 +31,68 @@
<p>This document describes the changes made to the Observer
application.</p>
+<section><title>Observer 2.0</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ etop trace handler now works in smp environment (Thanks
+ to Péter Gömöri)</p>
+ <p>
+ Own Id: OTP-11633</p>
+ </item>
+ <item>
+ <p>
+ Application upgrade (appup) files are corrected for the
+ following applications: </p>
+ <p>
+ <c>asn1, common_test, compiler, crypto, debugger,
+ dialyzer, edoc, eldap, erl_docgen, et, eunit, gs, hipe,
+ inets, observer, odbc, os_mon, otp_mibs, parsetools,
+ percept, public_key, reltool, runtime_tools, ssh,
+ syntax_tools, test_server, tools, typer, webtool, wx,
+ xmerl</c></p>
+ <p>
+ A new test utility for testing appup files is added to
+ test_server. This is now used by most applications in
+ OTP.</p>
+ <p>
+ (Thanks to Tobias Schlager)</p>
+ <p>
+ Own Id: OTP-11744</p>
+ </item>
+ </list>
+ </section>
+
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p>
+ Removed gs based applications and gs based backends. The
+ <c>observer</c> application replaces the removed
+ applications.</p>
+ <p>
+ *** POTENTIAL INCOMPATIBILITY ***</p>
+ <p>
+ Own Id: OTP-10915</p>
+ </item>
+ <item>
+ <p>
+ The <c>crashdump_viewer</c> is re-written using
+ <c>wx</c>. The old <c>webtool</c> interface for
+ <c>crashdump_viewer</c> does no longer exist.</p>
+ <p>
+ *** POTENTIAL INCOMPATIBILITY ***</p>
+ <p>
+ Own Id: OTP-11179</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>Observer 1.3.1.2</title>
<section><title>Fixed Bugs and Malfunctions</title>
diff --git a/lib/observer/test/crashdump_viewer_SUITE.erl b/lib/observer/test/crashdump_viewer_SUITE.erl
index f6e7d18f65..e9567c82cb 100644
--- a/lib/observer/test/crashdump_viewer_SUITE.erl
+++ b/lib/observer/test/crashdump_viewer_SUITE.erl
@@ -301,10 +301,12 @@ wait_for_progress_done() ->
%%%-----------------------------------------------------------------
%%% General check of what is displayed for a dump
browse_file(File) ->
- io:format("Browsing file: ~s~n",[File]),
+ io:format("~nBrowsing file: ~s",[File]),
ok = start_backend(File),
+ io:format(" backend started",[]),
+
{ok,_GI=#general_info{},_GenTW} = crashdump_viewer:general_info(),
{ok,Procs,_ProcsTW} = crashdump_viewer:processes(),
{ok,Ports,_PortsTW} = crashdump_viewer:ports(),
@@ -321,10 +323,16 @@ browse_file(File) ->
{ok,_HashTabs,_HashTabsTW} = crashdump_viewer:hash_tables(),
{ok,_IndexTabs,_IndexTabsTW} = crashdump_viewer:index_tables(),
+ io:format(" info read",[]),
+
lookat_all_pids(Procs),
+ io:format(" pids ok",[]),
lookat_all_ports(Ports),
+ io:format(" ports ok",[]),
lookat_all_mods(Mods),
+ io:format(" mods ok",[]),
lookat_all_nodes(Nodes),
+ io:format(" nodes ok",[]),
Procs. % used as second arg to special/2
@@ -339,6 +347,7 @@ special(File,Procs) ->
[#proc{pid=Pid0}|_Rest] = lists:keysort(#proc.name,Procs),
Pid = pid_to_list(Pid0),
{ok,ProcDetails=#proc{},[]} = crashdump_viewer:proc_details(Pid),
+ io:format(" process details ok",[]),
#proc{dict=Dict} = ProcDetails,
@@ -350,6 +359,7 @@ special(File,Procs) ->
['#CDVBin',SOffset,SSize,SPos] = proplists:get_value(sub_bin,Dict),
{ok,<<_:SSize/binary>>} =
crashdump_viewer:expand_binary({SOffset,SSize,SPos}),
+ io:format(" expand binary ok",[]),
['#CDVPid',X1,Y1,Z1] = proplists:get_value(ext_pid,Dict),
ChannelStr1 = integer_to_list(X1),
@@ -359,22 +369,28 @@ special(File,Procs) ->
integer_to_list(Z1) ++ ">",
{error,{other_node,ChannelStr1}} =
crashdump_viewer:proc_details(ExtPid),
+ io:format(" process details external ok",[]),
['#CDVPort',X2,Y2] = proplists:get_value(port,Dict),
ChannelStr2 = integer_to_list(X2),
Port = "#Port<"++ChannelStr2++"."++integer_to_list(Y2)++">",
{ok,_PortDetails=#port{},[]} = crashdump_viewer:port(Port),
+ io:format(" port details ok",[]),
['#CDVPort',X3,Y3] = proplists:get_value(ext_port,Dict),
ChannelStr3 = integer_to_list(X3),
ExtPort = "#Port<"++ChannelStr3++"."++integer_to_list(Y3)++">",
{error,{other_node,ChannelStr3}} = crashdump_viewer:port(ExtPort),
+ io:format(" port details external ok",[]),
{ok,[_Ets=#ets_table{}],[]} = crashdump_viewer:ets_tables(Pid),
+ io:format(" ets tables ok",[]),
{ok,[_Timer=#timer{}],[]} = crashdump_viewer:timers(Pid),
+ io:format(" timers ok",[]),
{ok,Mod1=#loaded_mod{},[]} =
crashdump_viewer:loaded_mod_details(atom_to_list(?helper_mod)),
+ io:format(" modules ok",[]),
#loaded_mod{current_size=CS, old_size=OS,
old_attrib=A,old_comp_info=C}=Mod1,
true = is_integer(CS),
@@ -383,6 +399,7 @@ special(File,Procs) ->
true = (C=/=undefined),
{ok,Mod2=#loaded_mod{},[]} =
crashdump_viewer:loaded_mod_details("application"),
+ io:format(" module details ok",[]),
#loaded_mod{old_size="No old code exists",
old_attrib=undefined,
old_comp_info=undefined}=Mod2,
diff --git a/lib/odbc/doc/src/notes.xml b/lib/odbc/doc/src/notes.xml
index b254ca3bc9..0ba2b1ff3f 100644
--- a/lib/odbc/doc/src/notes.xml
+++ b/lib/odbc/doc/src/notes.xml
@@ -31,7 +31,57 @@
<p>This document describes the changes made to the odbc application.
</p>
- <section><title>ODBC 2.10.19</title>
+ <section><title>ODBC 2.10.20</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Application upgrade (appup) files are corrected for the
+ following applications: </p>
+ <p>
+ <c>asn1, common_test, compiler, crypto, debugger,
+ dialyzer, edoc, eldap, erl_docgen, et, eunit, gs, hipe,
+ inets, observer, odbc, os_mon, otp_mibs, parsetools,
+ percept, public_key, reltool, runtime_tools, ssh,
+ syntax_tools, test_server, tools, typer, webtool, wx,
+ xmerl</c></p>
+ <p>
+ A new test utility for testing appup files is added to
+ test_server. This is now used by most applications in
+ OTP.</p>
+ <p>
+ (Thanks to Tobias Schlager)</p>
+ <p>
+ Own Id: OTP-11744</p>
+ </item>
+ </list>
+ </section>
+
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p>
+ Removed warnings at compile time by adding missing
+ include file (Thanks to Anthony Ramine)</p>
+ <p>
+ Own Id: OTP-11569</p>
+ </item>
+ <item>
+ <p>
+ Apple has removed iODBC in OS X 10.9 Mavericks, but
+ forgot to remove all binaries, adopt configure so that
+ will be possible to build odbc with own installation.</p>
+ <p>
+ Own Id: OTP-11630</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>ODBC 2.10.19</title>
<section><title>Fixed Bugs and Malfunctions</title>
<list>
diff --git a/lib/orber/doc/src/notes.xml b/lib/orber/doc/src/notes.xml
index c4d13a5a2f..93dc403c47 100644
--- a/lib/orber/doc/src/notes.xml
+++ b/lib/orber/doc/src/notes.xml
@@ -33,7 +33,26 @@
</header>
- <section><title>Orber 3.6.26.1</title>
+ <section><title>Orber 3.6.27</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Some local implementations of removing the last element
+ from a list are replaced by <c>lists:droplast/1</c>. Note
+ that this requires at least <c>stdlib-2.0</c>, which is
+ the stdlib version delivered in OTP 17.0. (Thanks to Hans
+ Svensson)</p>
+ <p>
+ Own Id: OTP-11678</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Orber 3.6.26.1</title>
<section><title>Improvements and New Features</title>
<list>
diff --git a/lib/os_mon/doc/src/notes.xml b/lib/os_mon/doc/src/notes.xml
index 3a7d7793d4..5ac04d4f42 100644
--- a/lib/os_mon/doc/src/notes.xml
+++ b/lib/os_mon/doc/src/notes.xml
@@ -30,6 +30,48 @@
</header>
<p>This document describes the changes made to the OS_Mon application.</p>
+<section><title>Os_Mon 2.2.15</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Application upgrade (appup) files are corrected for the
+ following applications: </p>
+ <p>
+ <c>asn1, common_test, compiler, crypto, debugger,
+ dialyzer, edoc, eldap, erl_docgen, et, eunit, gs, hipe,
+ inets, observer, odbc, os_mon, otp_mibs, parsetools,
+ percept, public_key, reltool, runtime_tools, ssh,
+ syntax_tools, test_server, tools, typer, webtool, wx,
+ xmerl</c></p>
+ <p>
+ A new test utility for testing appup files is added to
+ test_server. This is now used by most applications in
+ OTP.</p>
+ <p>
+ (Thanks to Tobias Schlager)</p>
+ <p>
+ Own Id: OTP-11744</p>
+ </item>
+ </list>
+ </section>
+
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p>
+ Calls to erlang:open_port/2 with 'spawn' are updated to
+ handle space in the command path.</p>
+ <p>
+ Own Id: OTP-10842</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>Os_Mon 2.2.14</title>
<section><title>Fixed Bugs and Malfunctions</title>
diff --git a/lib/otp_mibs/doc/src/notes.xml b/lib/otp_mibs/doc/src/notes.xml
index 0c13fb2349..391c82b1c5 100644
--- a/lib/otp_mibs/doc/src/notes.xml
+++ b/lib/otp_mibs/doc/src/notes.xml
@@ -31,6 +31,55 @@
<p>This document describes the changes made to the OTP_Mibs
application.</p>
+<section><title>Otp_Mibs 1.0.9</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Add type based integer value truncation/reset.</p>
+ <p>
+ This fixes errors when querying e.g. the
+ erlNodeReductions, erlNodeInBytes and erlNodeOutBytes
+ objects in long-running Erlang/OTP systems.</p>
+ <p>
+ Update types of applicable MIB objects to 64bit based
+ types.</p>
+ <p>
+ Potential incompatibility: Type change of Counter32 to
+ Counter64 in OTP-MIB.mib</p>
+ <p>
+ (Thanks to Tobias Schlager)</p>
+ <p>
+ *** POTENTIAL INCOMPATIBILITY ***</p>
+ <p>
+ Own Id: OTP-11203</p>
+ </item>
+ <item>
+ <p>
+ Application upgrade (appup) files are corrected for the
+ following applications: </p>
+ <p>
+ <c>asn1, common_test, compiler, crypto, debugger,
+ dialyzer, edoc, eldap, erl_docgen, et, eunit, gs, hipe,
+ inets, observer, odbc, os_mon, otp_mibs, parsetools,
+ percept, public_key, reltool, runtime_tools, ssh,
+ syntax_tools, test_server, tools, typer, webtool, wx,
+ xmerl</c></p>
+ <p>
+ A new test utility for testing appup files is added to
+ test_server. This is now used by most applications in
+ OTP.</p>
+ <p>
+ (Thanks to Tobias Schlager)</p>
+ <p>
+ Own Id: OTP-11744</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>Otp_Mibs 1.0.8</title>
<section><title>Improvements and New Features</title>
diff --git a/lib/parsetools/doc/src/notes.xml b/lib/parsetools/doc/src/notes.xml
index 929daedf74..a8368740da 100644
--- a/lib/parsetools/doc/src/notes.xml
+++ b/lib/parsetools/doc/src/notes.xml
@@ -30,6 +30,42 @@
</header>
<p>This document describes the changes made to the Parsetools application.</p>
+<section><title>Parsetools 2.0.11</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Application upgrade (appup) files are corrected for the
+ following applications: </p>
+ <p>
+ <c>asn1, common_test, compiler, crypto, debugger,
+ dialyzer, edoc, eldap, erl_docgen, et, eunit, gs, hipe,
+ inets, observer, odbc, os_mon, otp_mibs, parsetools,
+ percept, public_key, reltool, runtime_tools, ssh,
+ syntax_tools, test_server, tools, typer, webtool, wx,
+ xmerl</c></p>
+ <p>
+ A new test utility for testing appup files is added to
+ test_server. This is now used by most applications in
+ OTP.</p>
+ <p>
+ (Thanks to Tobias Schlager)</p>
+ <p>
+ Own Id: OTP-11744</p>
+ </item>
+ <item>
+ <p>
+ A Yecc example has been updated in the documentation
+ (Thanks to Pierre Fenoll.)</p>
+ <p>
+ Own Id: OTP-11749</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>Parsetools 2.0.10</title>
<section><title>Fixed Bugs and Malfunctions</title>
diff --git a/lib/percept/doc/src/notes.xml b/lib/percept/doc/src/notes.xml
index 3cead186c4..bae999ed1a 100644
--- a/lib/percept/doc/src/notes.xml
+++ b/lib/percept/doc/src/notes.xml
@@ -32,6 +32,35 @@
</header>
<p>This document describes the changes made to the Percept application.</p>
+<section><title>Percept 0.8.9</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Application upgrade (appup) files are corrected for the
+ following applications: </p>
+ <p>
+ <c>asn1, common_test, compiler, crypto, debugger,
+ dialyzer, edoc, eldap, erl_docgen, et, eunit, gs, hipe,
+ inets, observer, odbc, os_mon, otp_mibs, parsetools,
+ percept, public_key, reltool, runtime_tools, ssh,
+ syntax_tools, test_server, tools, typer, webtool, wx,
+ xmerl</c></p>
+ <p>
+ A new test utility for testing appup files is added to
+ test_server. This is now used by most applications in
+ OTP.</p>
+ <p>
+ (Thanks to Tobias Schlager)</p>
+ <p>
+ Own Id: OTP-11744</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>Percept 0.8.8.2</title>
<section><title>Improvements and New Features</title>
diff --git a/lib/public_key/doc/src/cert_records.xml b/lib/public_key/doc/src/cert_records.xml
index 79e5cb219d..397c13b463 100644
--- a/lib/public_key/doc/src/cert_records.xml
+++ b/lib/public_key/doc/src/cert_records.xml
@@ -5,7 +5,7 @@
<header>
<copyright>
<year>2008</year>
- <year>2013</year>
+ <year>2014</year>
<holder>Ericsson AB, All Rights Reserved</holder>
</copyright>
<legalnotice>
@@ -39,7 +39,7 @@
The intent is to describe the data types and not to specify the meaning of each
component for this we refer you to <url
href="http://www.ietf.org/rfc/rfc5280.txt">RFC 5280</url> and
- <url href="http://www.rsa.com/rsalabs/node.asp?id=2124">PKCS-10</url>.
+ <url href="http://www.ietf.org/rfc/rfc5967.txt">PKCS-10</url>.
</p>
<p>Use the following include directive to get access to the
diff --git a/lib/public_key/doc/src/notes.xml b/lib/public_key/doc/src/notes.xml
index 1dce718ea3..592d3c797d 100644
--- a/lib/public_key/doc/src/notes.xml
+++ b/lib/public_key/doc/src/notes.xml
@@ -34,6 +34,70 @@
<file>notes.xml</file>
</header>
+<section><title>Public_Key 0.22</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Fix incorrect dialyzer spec and types, also enhance
+ documentation. </p>
+ <p>
+ Thanks to Ayaz Tuncer.</p>
+ <p>
+ Own Id: OTP-11627</p>
+ </item>
+ <item>
+ <p>
+ Application upgrade (appup) files are corrected for the
+ following applications: </p>
+ <p>
+ <c>asn1, common_test, compiler, crypto, debugger,
+ dialyzer, edoc, eldap, erl_docgen, et, eunit, gs, hipe,
+ inets, observer, odbc, os_mon, otp_mibs, parsetools,
+ percept, public_key, reltool, runtime_tools, ssh,
+ syntax_tools, test_server, tools, typer, webtool, wx,
+ xmerl</c></p>
+ <p>
+ A new test utility for testing appup files is added to
+ test_server. This is now used by most applications in
+ OTP.</p>
+ <p>
+ (Thanks to Tobias Schlager)</p>
+ <p>
+ Own Id: OTP-11744</p>
+ </item>
+ </list>
+ </section>
+
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p>
+ Moved elliptic curve definition from the crypto
+ NIF/OpenSSL into Erlang code, adds the RFC-5639 brainpool
+ curves and makes TLS use them (RFC-7027).</p>
+ <p>
+ Thanks to Andreas Schultz</p>
+ <p>
+ Own Id: OTP-11578</p>
+ </item>
+ <item>
+ <p>
+ Handle v1 CRLs, with no extensions and fixes issues with
+ IDP (Issuing Distribution Point) comparison during CRL
+ validation. </p>
+ <p>
+ Thanks to Andrew Thompson</p>
+ <p>
+ Own Id: OTP-11761</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>Public_Key 0.21</title>
<section><title>Improvements and New Features</title>
diff --git a/lib/public_key/doc/src/part.xml b/lib/public_key/doc/src/part.xml
index 51e628aa90..73146c8e2a 100644
--- a/lib/public_key/doc/src/part.xml
+++ b/lib/public_key/doc/src/part.xml
@@ -5,7 +5,7 @@
<header>
<copyright>
<year>2008</year>
- <year>2013</year>
+ <year>2014</year>
<holder>Ericsson AB, All Rights Reserved</holder>
</copyright>
<legalnotice>
@@ -34,7 +34,7 @@
<p> This application provides an API to public key infrastructure
from <url href="http://www.ietf.org/rfc/rfc5280.txt">RFC
5280</url> (X.509 certificates) and public key formats defined by
- the <url href="http://www.rsa.com/rsalabs/node.asp?id=2124">
+ the <url href="http://en.wikipedia.org/wiki/PKCS">
PKCS-standard</url></p>
</description>
<xi:include href="introduction.xml"/>
diff --git a/lib/public_key/doc/src/public_key.xml b/lib/public_key/doc/src/public_key.xml
index fc3479cb64..8e93f562d4 100644
--- a/lib/public_key/doc/src/public_key.xml
+++ b/lib/public_key/doc/src/public_key.xml
@@ -5,7 +5,7 @@
<header>
<copyright>
<year>2008</year>
- <year>2013</year>
+ <year>2014</year>
<holder>Ericsson AB, All Rights Reserved</holder>
</copyright>
<legalnotice>
@@ -48,12 +48,12 @@
<item>Supports <url href="http://www.ietf.org/rfc/rfc5280.txt">RFC 5280 </url> -
Internet X.509 Public Key Infrastructure Certificate and Certificate Revocation List (CRL) Profile </item>
- <item>Supports <url href="http://www.rsa.com/rsalabs/node.asp?id=2125"> PKCS-1 </url> - RSA Cryptography Standard </item>
+ <item>Supports <url href="http://www.ietf.org/rfc/rfc3447.txt"> PKCS-1 </url> - RSA Cryptography Standard </item>
<item>Supports <url href="http://csrc.nist.gov/publications/fips/fips186-3/fips_186-3.pdf"> DSS</url>- Digital Signature Standard (DSA - Digital Signature Algorithm)</item>
- <item>Supports <url href="http://www.rsa.com/rsalabs/node.asp?id=2126"> PKCS-3 </url> - Diffie-Hellman Key Agreement Standard </item>
- <item>Supports <url href="http://www.rsa.com/rsalabs/node.asp?id=2127"> PKCS-5</url> - Password-Based Cryptography Standard </item>
- <item>Supports <url href="http://www.rsa.com/rsalabs/node.asp?id=2130"> PKCS-8</url> - Private-Key Information Syntax Standard</item>
- <item>Supports <url href="http://www.rsa.com/rsalabs/node.asp?id=2132"> PKCS-10</url> - Certification Request Syntax Standard</item>
+ <item>Supports <url href="http://www.emc.com/emc-plus/rsa-labs/standards-initiatives/pkcs-3-diffie-hellman-key-agreement-standar.htm"> PKCS-3 </url> - Diffie-Hellman Key Agreement Standard </item>
+ <item>Supports <url href="http://www.ietf.org/rfc/rfc2898.txt"> PKCS-5</url> - Password-Based Cryptography Standard </item>
+ <item>Supports <url href="http://www.ietf.org/rfc/rfc5208.txt"> PKCS-8</url> - Private-Key Information Syntax Standard</item>
+ <item>Supports <url href="http://www.ietf.org/rfc/rfc5967.txt"> PKCS-10</url> - Certification Request Syntax Standard</item>
</list>
</section>
@@ -461,11 +461,14 @@
<p>The fun should be defined as:</p>
<code>
-fun(OtpCert :: #'OTPCertificate'{}, Event :: {bad_cert, Reason :: atom()} |
- {extension, #'Extension'{}},
+fun(OtpCert :: #'OTPCertificate'{},
+ Event :: {bad_cert, Reason :: atom()} |
+ {extension, #'Extension'{}},
InitialUserState :: term()) ->
- {valid, UserState :: term()} | {valid_peer, UserState :: term()} |
- {fail, Reason :: term()} | {unknown, UserState :: term()}.
+ {valid, UserState :: term()} |
+ {valid_peer, UserState :: term()} |
+ {fail, Reason :: term()} |
+ {unknown, UserState :: term()}.
</code>
<p>If the verify callback fun returns {fail, Reason}, the
@@ -511,7 +514,8 @@ fun(OtpCert :: #'OTPCertificate'{}, Event :: {bad_cert, Reason :: atom()} |
<item>
<p>The fun has the following type spec:</p>
- <code> fun(#'DistributionPoint'{}, #'CertificateList'{}) -> #'CertificateList'{}</code>
+ <code> fun(#'DistributionPoint'{}, #'CertificateList'{}) ->
+ #'CertificateList'{}</code>
<p>The fun should use the information in the distribution point to acesses
the lates possible version of the CRL. If this fun is not specified
@@ -519,6 +523,21 @@ fun(OtpCert :: #'OTPCertificate'{}, Event :: {bad_cert, Reason :: atom()} |
</p>
<code> fun(_DP, CRL) -> CRL end</code>
</item>
+
+ <tag>{issuer_fun, fun()}</tag>
+ <item>
+ <p>The fun has the following type spec:</p>
+
+ <code>
+fun(#'DistributionPoint'{}, #'CertificateList'{},
+ {rdnSequence,[#'AttributeTypeAndValue'{}]}, term()) ->
+ {ok, #'OTPCertificate'{}, [der_encoded]}</code>
+
+ <p>The fun should return the root certificate and certificate chain
+ that has signed the CRL.
+ </p>
+ <code> fun(DP, CRL, Issuer, UserState) -> {ok, RootCert, CertChain}</code>
+ </item>
</taglist>
</desc>
</func>
diff --git a/lib/reltool/doc/src/notes.xml b/lib/reltool/doc/src/notes.xml
index df81418677..969af2d745 100644
--- a/lib/reltool/doc/src/notes.xml
+++ b/lib/reltool/doc/src/notes.xml
@@ -37,7 +37,53 @@
thus constitutes one section in this document. The title of each
section is the version number of Reltool.</p>
- <section><title>Reltool 0.6.4.1</title>
+ <section><title>Reltool 0.6.5</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ When adding a regexp to a filter in reltool using
+ {add,Regexp}, and the existing regexp was undefined,
+ reltool would crash since it got an improper list. This
+ has been corrected. (Thanks to HÃ¥kan Mattsson)</p>
+ <p>
+ Own Id: OTP-11591</p>
+ </item>
+ <item>
+ <p>
+ Adapted reltool test server to common test usage of
+ tc_status. (Note that this code is not used by OTP daily
+ test runs.) (Thanks to HÃ¥kan Mattsson)</p>
+ <p>
+ Own Id: OTP-11592</p>
+ </item>
+ <item>
+ <p>
+ Application upgrade (appup) files are corrected for the
+ following applications: </p>
+ <p>
+ <c>asn1, common_test, compiler, crypto, debugger,
+ dialyzer, edoc, eldap, erl_docgen, et, eunit, gs, hipe,
+ inets, observer, odbc, os_mon, otp_mibs, parsetools,
+ percept, public_key, reltool, runtime_tools, ssh,
+ syntax_tools, test_server, tools, typer, webtool, wx,
+ xmerl</c></p>
+ <p>
+ A new test utility for testing appup files is added to
+ test_server. This is now used by most applications in
+ OTP.</p>
+ <p>
+ (Thanks to Tobias Schlager)</p>
+ <p>
+ Own Id: OTP-11744</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Reltool 0.6.4.1</title>
<section><title>Improvements and New Features</title>
<list>
diff --git a/lib/reltool/test/reltool_server_SUITE.erl b/lib/reltool/test/reltool_server_SUITE.erl
index bfe5d39d53..b3b7afd1a9 100644
--- a/lib/reltool/test/reltool_server_SUITE.erl
+++ b/lib/reltool/test/reltool_server_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2009-2013. All Rights Reserved.
+%% Copyright Ericsson AB 2009-2014. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -1205,14 +1205,9 @@ create_slim(Config) ->
RootDir = code:root_dir(),
Erl = filename:join([RootDir, "bin", "erl"]),
- EscapedQuote =
- case os:type() of
- {win32,_} -> "\\\"";
- _ -> "\""
- end,
Args = ["-boot_var", "RELTOOL_EXT_LIB", TargetLibDir,
"-boot", filename:join(TargetRelVsnDir,RelName),
- "-sasl", "releases_dir", EscapedQuote++TargetRelDir++EscapedQuote],
+ "-sasl", "releases_dir", "\""++TargetRelDir++"\""],
{ok, Node} = ?msym({ok, _}, start_node(?NODE_NAME, Erl, Args)),
?msym(RootDir, rpc:call(Node, code, root_dir, [])),
wait_for_app(Node,sasl,50),
diff --git a/lib/reltool/test/reltool_test_lib.erl b/lib/reltool/test/reltool_test_lib.erl
index 530d0a9985..fa12f19aa7 100644
--- a/lib/reltool/test/reltool_test_lib.erl
+++ b/lib/reltool/test/reltool_test_lib.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2009-2013. All Rights Reserved.
+%% Copyright Ericsson AB 2009-2014. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -20,12 +20,13 @@
-compile(export_all).
-include("reltool_test_lib.hrl").
+-define(timeout, 20). % minutes
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
init_per_suite(Config) when is_list(Config)->
global:register_name(reltool_global_logger, group_leader()),
- incr_timetrap(Config, 10).
+ incr_timetrap(Config, ?timeout).
end_per_suite(Config) when is_list(Config)->
global:unregister_name(reltool_global_logger),
@@ -51,7 +52,7 @@ set_kill_timer(Config) ->
Time =
case lookup_config(tc_timeout, Config) of
[] ->
- timer:minutes(10);
+ timer:minutes(?timeout);
ConfigTime when is_integer(ConfigTime) ->
ConfigTime
end,
diff --git a/lib/runtime_tools/doc/src/notes.xml b/lib/runtime_tools/doc/src/notes.xml
index 32b7d168f5..9b026aee11 100644
--- a/lib/runtime_tools/doc/src/notes.xml
+++ b/lib/runtime_tools/doc/src/notes.xml
@@ -31,6 +31,95 @@
<p>This document describes the changes made to the Runtime_Tools
application.</p>
+<section><title>Runtime_Tools 1.8.14</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ The documentation for the return value of
+ dbg:{stop,stop_clear} functions are now correct (Thanks
+ to Luca Favatella)</p>
+ <p>
+ Own Id: OTP-11603</p>
+ </item>
+ <item>
+ <p>
+ Fix DTrace build on Illumos. (Thanks to Ryan Zezeski.)</p>
+ <p>
+ Own Id: OTP-11622</p>
+ </item>
+ <item>
+ <p>
+ Do not turn off scheduler_wall_time, as it can interfere
+ with other applications usage.</p>
+ <p>
+ Own Id: OTP-11693 Aux Id: seq12528 </p>
+ </item>
+ <item>
+ <p>
+ Application upgrade (appup) files are corrected for the
+ following applications: </p>
+ <p>
+ <c>asn1, common_test, compiler, crypto, debugger,
+ dialyzer, edoc, eldap, erl_docgen, et, eunit, gs, hipe,
+ inets, observer, odbc, os_mon, otp_mibs, parsetools,
+ percept, public_key, reltool, runtime_tools, ssh,
+ syntax_tools, test_server, tools, typer, webtool, wx,
+ xmerl</c></p>
+ <p>
+ A new test utility for testing appup files is added to
+ test_server. This is now used by most applications in
+ OTP.</p>
+ <p>
+ (Thanks to Tobias Schlager)</p>
+ <p>
+ Own Id: OTP-11744</p>
+ </item>
+ </list>
+ </section>
+
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p>
+ Allow install path to have unicode characters.</p>
+ <p>
+ Own Id: OTP-10877</p>
+ </item>
+ <item>
+ <p>
+ The <c>erts_alloc_config</c> tool has been updated to
+ produce configurations that better fit todays SMP support
+ in the VM.</p>
+ <p>
+ Own Id: OTP-11662</p>
+ </item>
+ <item>
+ <p>
+ The <seealso
+ marker="kernel:app"><c>app</c></seealso>-file key
+ <seealso
+ marker="kernel:app#runtime_dependencies"><c>runtime_dependencies</c></seealso>
+ has been introduced.</p>
+ <p>
+ Runtime dependencies have been added to all app-files in
+ OTP. Note that these may not be completely correct during
+ OTP 17, but this is actively being worked on.</p>
+ <p>
+ The function <seealso
+ marker="runtime_tools:system_information#sanity_check/0"><c>system_information:sanity_check/0</c></seealso>
+ will verify all declared runtime dependencies in the
+ system when called.</p>
+ <p>
+ Own Id: OTP-11773</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>Runtime_Tools 1.8.13</title>
<section><title>Fixed Bugs and Malfunctions</title>
diff --git a/lib/sasl/doc/src/appup.xml b/lib/sasl/doc/src/appup.xml
index 85fcbed3ba..95f315d269 100644
--- a/lib/sasl/doc/src/appup.xml
+++ b/lib/sasl/doc/src/appup.xml
@@ -4,7 +4,7 @@
<fileref>
<header>
<copyright>
- <year>1997</year><year>2013</year>
+ <year>1997</year><year>2014</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -84,6 +84,9 @@
version identifier must be specified as a binary, e.g.</p>
<code type="none">&lt;&lt;"2\\.1\\.[0-9]+">></code>
<p>will match all versions <c>2.1.x</c>, where x is any number.</p>
+ <p>Note that the regular expression must match the complete
+ version string, so the above example will work for for
+ e.g. <c>2.1.1</c>, but not for <c>2.1.1.1</c></p>
</section>
<section>
@@ -339,7 +342,7 @@ restart_new_emulator
version of erts, kernel, stdlib and sasl are used when the
emulator restarts. Only one <c>restart_new_emulator</c>
instruction is allowed in the relup, and it shall be placed
- first. <seealso marker="systools#make_relup/3">systools:make_relup3,4</seealso>
+ first. <seealso marker="systools#make_relup/3">systools:make_relup/3,4</seealso>
will ensure this when the relup is generated. The rest of the
relup script is executed after the restart as a part of the boot
script.</p>
@@ -347,11 +350,25 @@ restart_new_emulator
completed. To programatically find out if the upgrade is
complete,
call <seealso marker="release_handler#which_releases/0">
- release_handler:which_releases</seealso> and check if the
+ release_handler:which_releases/0,1</seealso> and check if the
expected release has status <c>current</c>.</p>
<p>The new release must still be made permanent after the upgrade
is completed. Otherwise, the old emulator is started in case of
an emulator restart.</p>
+ <warning>
+ <p>As stated above, the <c>restart_new_emulator</c>
+ instruction causes the emulator to be restarted with new
+ versions of <c>erts</c>, <c>kernel</c>, <c>stdlib</c> and
+ <c>sasl</c>. All other applications, however, will at startup
+ be running their old versions in this new emulator. In most
+ cases this is no problem, but every now and then there will be
+ incompatible changes to the core applications which may cause
+ trouble in this setting. Such incompatible changes (when
+ functions are removed) are normally preceded by a deprecation
+ over two major releases. To make sure your application is not
+ crashed by an incompatible change, always remove any call to
+ deprecated functions as soon as possible.</p>
+ </warning>
<pre>
restart_emulator
</pre>
diff --git a/lib/sasl/doc/src/notes.xml b/lib/sasl/doc/src/notes.xml
index 09d97cbe7b..2928a12d22 100644
--- a/lib/sasl/doc/src/notes.xml
+++ b/lib/sasl/doc/src/notes.xml
@@ -30,6 +30,64 @@
</header>
<p>This document describes the changes made to the SASL application.</p>
+<section><title>SASL 2.4</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ The upgrade instruction 'restart_application' would
+ earlier ignore the restart type configured in the .rel
+ file and always restart the application as permanent.
+ This is now changed, and the restart type from the .rel
+ file is used. If restart type is 'load', the application
+ will only be loaded and not started. If the restart type
+ is 'none', the application will not be loaded nor
+ started, but all modules in the application will be
+ loaded. (Thanks to Tobias Schlager for reporting this
+ problem)</p>
+ <p>
+ *** POTENTIAL INCOMPATIBILITY ***</p>
+ <p>
+ Own Id: OTP-11716</p>
+ </item>
+ <item>
+ <p>
+ If <c>systools:make_script/2</c> failed with reason
+ <c>duplicate_modules</c>, and the <c>silent</c> flag was
+ not used, a crash with reason <c>function_clause</c>
+ would occur when <c>systools</c> tried to format the
+ error message. This has been corrected. (Thanks to
+ Jean-Sébastien Pédron)</p>
+ <p>
+ Own Id: OTP-11819</p>
+ </item>
+ </list>
+ </section>
+
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p>
+ Calls to erlang:open_port/2 with 'spawn' are updated to
+ handle space in the command path.</p>
+ <p>
+ Own Id: OTP-10842</p>
+ </item>
+ <item>
+ <p>
+ Some more documentation is added to explain the behavior
+ when an upgrade includes new versions of ERTS, Kernel,
+ STDLIB or SASL.</p>
+ <p>
+ Own Id: OTP-11717</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>SASL 2.3.4</title>
<section><title>Fixed Bugs and Malfunctions</title>
diff --git a/lib/sasl/examples/src/target_system.erl b/lib/sasl/examples/src/target_system.erl
index fb9e9aaaaf..a0ae016791 100644
--- a/lib/sasl/examples/src/target_system.erl
+++ b/lib/sasl/examples/src/target_system.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2011-2013. All Rights Reserved.
+%% Copyright Ericsson AB 2011-2014. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -65,7 +65,7 @@ create(RelFileName,SystoolsOpts) ->
[RelFileName, RelFileName]),
make_script(RelFileName,SystoolsOpts),
- TarFileName = filename:join(Dir,RelFileName ++ ".tar.gz"),
+ TarFileName = RelFileName ++ ".tar.gz",
io:fwrite("Creating tar file ~tp ...~n", [TarFileName]),
make_tar(RelFileName,SystoolsOpts),
@@ -100,6 +100,12 @@ create(RelFileName,SystoolsOpts) ->
copy_file(filename:join([ErtsBinDir, "to_erl"]),
filename:join([TmpBinDir, "to_erl"]), [preserve]),
+ %% This is needed if 'start' script created from 'start.src' shall
+ %% be used as it points out this directory as log dir for 'run_erl'
+ TmpLogDir = filename:join([TmpDir, "log"]),
+ io:fwrite("Creating temporary directory ~tp ...~n", [TmpLogDir]),
+ ok = file:make_dir(TmpLogDir),
+
StartErlDataFile = filename:join([TmpDir, "releases", "start_erl.data"]),
io:fwrite("Creating ~tp ...~n", [StartErlDataFile]),
StartErlData = io_lib:fwrite("~s ~s~n", [ErtsVsn, RelVsn]),
@@ -115,6 +121,7 @@ create(RelFileName,SystoolsOpts) ->
erl_tar:add(Tar, filename:join(TmpDir,ErtsDir), ErtsDir, []),
erl_tar:add(Tar, filename:join(TmpDir,"releases"), "releases", []),
erl_tar:add(Tar, filename:join(TmpDir,"lib"), "lib", []),
+ erl_tar:add(Tar, filename:join(TmpDir,"log"), "log", []),
erl_tar:close(Tar),
%% file:set_cwd(Cwd),
io:fwrite("Removing directory ~tp ...~n",[TmpDir]),
@@ -136,6 +143,11 @@ install(RelFileName, RootDir) ->
subst_src_scripts(["erl", "start", "start_erl"], ErtsBinDir, BinDir,
[{"FINAL_ROOTDIR", RootDir}, {"EMU", "beam"}],
[preserve]),
+ %%! Workaround for pre OTP 17.0: start.src and start_erl.src did
+ %%! not have correct permissions, so the above 'preserve' option did not help
+ ok = file:change_mode(filename:join(BinDir,"start"),8#0755),
+ ok = file:change_mode(filename:join(BinDir,"start_erl"),8#0755),
+
io:fwrite("Creating the RELEASES file ...\n"),
create_RELEASES(RootDir, filename:join([RootDir, "releases",
filename:basename(RelFileName)])).
diff --git a/lib/sasl/test/release_handler_SUITE.erl b/lib/sasl/test/release_handler_SUITE.erl
index ad2a8005b9..8a635796b7 100644
--- a/lib/sasl/test/release_handler_SUITE.erl
+++ b/lib/sasl/test/release_handler_SUITE.erl
@@ -667,6 +667,9 @@ release_handler_which_releases(Conf) ->
ok.
+release_handler_which_releases(cleanup,_Conf) ->
+ stop_node(node_name(release_handler_which_releases)).
+
%%-----------------------------------------------------------------
%% Ticket: OTP-2740
%% Slogan: vsn not numeric doesn't work so good in release_handling
@@ -1365,6 +1368,9 @@ upgrade_supervisor(Conf) when is_list(Conf) ->
ok.
+upgrade_supervisor(cleanup,_Condf) ->
+ stop_node(node_name(upgrade_supervisor)).
+
%% Check that if the supervisor fails, then the upgrade is rolled back
%% and an ok error message is returned
upgrade_supervisor_fail(Conf) when is_list(Conf) ->
@@ -1404,18 +1410,41 @@ upgrade_supervisor_fail(Conf) when is_list(Conf) ->
{error,{code_change_failed,_Pid,a_sup,_Vsn,
{error,{invalid_shutdown,brutal_kil}}}} =
- rpc:call(Node, release_handler, install_release, [RelVsn2]),
-
- %% Check that the upgrade is terminated - normally this would mean
- %% rollback, but since this testcase is very simplified the node
- %% is not started with heart supervision and will therefore not be
- %% restarted. So we just check that the node goes down.
+ rpc:call(Node, release_handler, install_release,
+ [RelVsn2, [{error_action,reboot}]]),
+
+ %% Check that the upgrade is terminated - normally this would be a
+ %% rollback, but
+ %%
+ %% 1. Default rollback is done with init:restart(), which does not
+ %% reboot the emulator, it only restarts the system inside the
+ %% running erlang node.
+ %%
+ %% 2. This does not work well on a slave node since, if timing is
+ %% right (bad), the slave node will get the nodedown from its
+ %% master (because distribution is terminated as part of
+ %% init:restart()) and then it will do halt() and thus never be
+ %% restarted (see slave:wloop/1)
+ %%
+ %% 3. Sometimes, though, init:restart() will manage to finish its
+ %% job before the nodedown is received, making the node
+ %% actually restart - in which case it might very well confuse
+ %% the next test case.
+ %%
+ %% 4. So, to avoid unstability we use {error_action,reboot} above,
+ %% to ensure that the node is actually stopped. Of course, in a
+ %% real system this must be used together with heart
+ %% supervision, and then the node will be restarted anyway. But
+ %% here in this simple test case we are satisfied to see that
+ %% the node terminates.
receive {nodedown,Node} -> ok
after 10000 -> ct:fail(failed_upgrade_never_restarted_node)
end,
ok.
+upgrade_supervisor_fail(cleanup,_Condf) ->
+ stop_node(node_name(upgrade_supervisor_fail)).
%% Test upgrade and downgrade of applications
eval_appup(Conf) when is_list(Conf) ->
@@ -2417,9 +2446,28 @@ check_gg_info(Node,OtherAlive,OtherDead,Synced) ->
?t:format("~ncheck_gg_info failed for ~p: ~p~nwhen GGI was: ~p~n"
"and GI was: ~p~n",
[Node,E,GGI,GI]),
+ %% An attempt to find out if it is only a timing issue
+ %% that makes this fail every now and then:
+ try_again_check(Node,GGI,GI,1),
?t:fail("check_gg_info failed")
end.
+try_again_check(_Node,_GGI,_GI,6) ->
+ ok;
+try_again_check(Node,GGI,GI,N) ->
+ timer:sleep(1000),
+ case {rpc:call(Node,global_group,info,[]),
+ rpc:call(Node,global,info,[])} of
+ {GGI,GI} ->
+ ?t:format("~nAfter one more sek, GGI and GI are still the same"),
+ try_again_check(Node,GGI,GI,N+1);
+ {NewGGI,NewGI} ->
+ ?t:format("~nAfter one more sek:~nNew GGI: ~p~nNew GI: ~p~n",
+ [NewGGI,NewGI]),
+ try_again_check(Node,NewGGI,NewGI,N+1)
+ end.
+
+
do_check_gg_info(OtherAlive,OtherDead,Synced,GGI,GI) ->
{_,gg1} = lists:keyfind(own_group_name,1,GGI),
{_,synced} = lists:keyfind(state,1,GGI),
@@ -2563,7 +2611,7 @@ start_nodes(Conf,Snames,Tag) ->
start_node_unix(Sname,NodeDir) ->
Script = filename:join([NodeDir,"bin","start"]),
- ?t:format("Starting ~p: ~tp~n", [Sname,Script]),
+ ?t:format("Starting ~p: ~ts~n", [Sname,Script]),
case rh_test_lib:cmd(Script,[],[{"NODENAME",atom_to_list(Sname)}]) of
ok ->
{ok,node_name(Sname)};
diff --git a/lib/sasl/test/systools_SUITE.erl b/lib/sasl/test/systools_SUITE.erl
index 1d3a71e94e..49a4303e0b 100644
--- a/lib/sasl/test/systools_SUITE.erl
+++ b/lib/sasl/test/systools_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2012-2013. All Rights Reserved.
+%% Copyright Ericsson AB 2012-2014. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -1615,9 +1615,19 @@ no_sasl_relup(Config) when is_list(Config) ->
%% make_relup: Check that application start type is used in relup
app_start_type_relup(Config) when is_list(Config) ->
+ %% This might fail if some applications are not available, if so
+ %% skip the test case.
+ try create_script(latest_app_start_type2,Config) of
+ {Dir2,Name2} ->
+ app_start_type_relup(Dir2,Name2,Config)
+ catch throw:{error,Reason} ->
+ {skip,Reason}
+ end.
+
+app_start_type_relup(Dir2,Name2,Config) ->
PrivDir = ?config(priv_dir, Config),
{Dir1,Name1} = create_script(latest_app_start_type1,Config),
- {Dir2,Name2} = create_script(latest_app_start_type2,Config),
+
Release1 = filename:join(Dir1,Name1),
Release2 = filename:join(Dir2,Name2),
@@ -2242,9 +2252,13 @@ app_vsns(AppVsns) ->
[{App,app_vsn(App,Vsn)} || {App,Vsn} <- AppVsns] ++
[{App,app_vsn(App,Vsn),Type} || {App,Vsn,Type} <- AppVsns].
app_vsn(App,current) ->
- application:load(App),
- {ok,Vsn} = application:get_key(App,vsn),
- Vsn;
+ case application:load(App) of
+ Ok when Ok==ok; Ok=={error,{already_loaded,App}} ->
+ {ok,Vsn} = application:get_key(App,vsn),
+ Vsn;
+ Error ->
+ throw(Error)
+ end;
app_vsn(_App,Vsn) ->
Vsn.
diff --git a/lib/snmp/doc/src/notes.xml b/lib/snmp/doc/src/notes.xml
index ab5514e550..06674095f2 100644
--- a/lib/snmp/doc/src/notes.xml
+++ b/lib/snmp/doc/src/notes.xml
@@ -33,7 +33,36 @@
</header>
- <section>
+ <section><title>SNMP 4.25.1</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Application upgrade (appup) files are corrected for the
+ following applications: </p>
+ <p>
+ <c>asn1, common_test, compiler, crypto, debugger,
+ dialyzer, edoc, eldap, erl_docgen, et, eunit, gs, hipe,
+ inets, observer, odbc, os_mon, otp_mibs, parsetools,
+ percept, public_key, reltool, runtime_tools, ssh,
+ syntax_tools, test_server, tools, typer, webtool, wx,
+ xmerl</c></p>
+ <p>
+ A new test utility for testing appup files is added to
+ test_server. This is now used by most applications in
+ OTP.</p>
+ <p>
+ (Thanks to Tobias Schlager)</p>
+ <p>
+ Own Id: OTP-11744</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section>
<title>SNMP Development Toolkit 4.25.0.1</title>
<p>Version 4.25.0.1 supports code replacement in runtime from/to
version 4.25, 4.24.2, 4.24.1 and 4.24. </p>
diff --git a/lib/ssh/doc/src/notes.xml b/lib/ssh/doc/src/notes.xml
index 0d88cbda7a..bce02966ae 100644
--- a/lib/ssh/doc/src/notes.xml
+++ b/lib/ssh/doc/src/notes.xml
@@ -29,6 +29,146 @@
<file>notes.xml</file>
</header>
+<section><title>Ssh 3.0.1</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Fixes the problem that ssh_cli in some cases could delay
+ the prompt if a tty was not requested by the client.</p>
+ <p>
+ Own Id: OTP-10732</p>
+ </item>
+ <item>
+ <p>
+ The variable NewCol is now correctly calculated allowing
+ for tab-completion of function calls even when preceded
+ with blank space (Thanks to Alexander Demidenko)</p>
+ <p>
+ Own Id: OTP-11566</p>
+ </item>
+ <item>
+ <p>
+ Fix incorrect dialyzer spec and types, also enhance
+ documentation. </p>
+ <p>
+ Thanks to Ayaz Tuncer.</p>
+ <p>
+ Own Id: OTP-11627</p>
+ </item>
+ <item>
+ <p>
+ Fixed a bug when ssh:exec executes a linux command on a
+ linux ssh daemon. If the result is sent back from
+ standard error, the length information was not stripped
+ off correctly.</p>
+ <p>
+ Own Id: OTP-11667</p>
+ </item>
+ <item>
+ <p>
+ Fixed a bug with the ssh file 'known_hosts' which made
+ the file grow with many equal entries.</p>
+ <p>
+ Own Id: OTP-11671</p>
+ </item>
+ <item>
+ <p>
+ Some local implementations of removing the last element
+ from a list are replaced by <c>lists:droplast/1</c>. Note
+ that this requires at least <c>stdlib-2.0</c>, which is
+ the stdlib version delivered in OTP 17.0. (Thanks to Hans
+ Svensson)</p>
+ <p>
+ Own Id: OTP-11678</p>
+ </item>
+ <item>
+ <p>
+ Bug fix for <c>ssh:daemon/2,3</c> so that the failfun is
+ called when it should.</p>
+ <p>
+ Own Id: OTP-11680</p>
+ </item>
+ <item>
+ <p>
+ Fixed bug which crashed ssh when SSH_MSG_KEX_DH_GEX_GROUP
+ is received. This could cause a vm-crash for eheap_alloc
+ during garbage collect.</p>
+ <p>
+ Own Id: OTP-11696 Aux Id: 12547, 12532 </p>
+ </item>
+ <item>
+ <p>
+ Fixes a bug that breaks keyboard-interactive
+ authentication. Thanks to Simon Cornish for reporting and
+ suggesting a fix.</p>
+ <p>
+ Own Id: OTP-11698</p>
+ </item>
+ <item>
+ <p>
+ dialyzer specs are now correct for <c>ssh:start/0</c>,
+ <c>ssh:start/1</c>, <c>ssh:stop/0</c> and
+ <c>ssh_connection_handler:open_channel/5</c>. (Thanks to
+ Johannes Weißl )</p>
+ <p>
+ Own Id: OTP-11705</p>
+ </item>
+ <item>
+ <p>
+ Application upgrade (appup) files are corrected for the
+ following applications: </p>
+ <p>
+ <c>asn1, common_test, compiler, crypto, debugger,
+ dialyzer, edoc, eldap, erl_docgen, et, eunit, gs, hipe,
+ inets, observer, odbc, os_mon, otp_mibs, parsetools,
+ percept, public_key, reltool, runtime_tools, ssh,
+ syntax_tools, test_server, tools, typer, webtool, wx,
+ xmerl</c></p>
+ <p>
+ A new test utility for testing appup files is added to
+ test_server. This is now used by most applications in
+ OTP.</p>
+ <p>
+ (Thanks to Tobias Schlager)</p>
+ <p>
+ Own Id: OTP-11744</p>
+ </item>
+ <item>
+ <p>
+ Fixed dialyzer warning for <c>ssh_connection:send</c>.</p>
+ <p>
+ Own Id: OTP-11821</p>
+ </item>
+ <item>
+ <p>
+ <c>ssh:daemon/2,3</c> : Added options
+ <c>negotiation_timeout</c> and <c>parallel_login</c> to
+ tune the authentication behaviour.</p>
+ <p>
+ Own Id: OTP-11823</p>
+ </item>
+ </list>
+ </section>
+
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p>
+ Ssh now fully supports unicode filenames, filecontents,
+ shell and cli. Please note that the underlying os and
+ emulator must also give support for unicode. You may want
+ to start the emulator with "<c>erl +fnu</c>" on Linux.</p>
+ <p>
+ Own Id: OTP-10953</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>Ssh 3.0</title>
<section><title>Fixed Bugs and Malfunctions</title>
diff --git a/lib/ssh/doc/src/ssh.xml b/lib/ssh/doc/src/ssh.xml
index 7fbd70c87e..5a141ced3c 100644
--- a/lib/ssh/doc/src/ssh.xml
+++ b/lib/ssh/doc/src/ssh.xml
@@ -307,18 +307,31 @@
<tag><c><![CDATA[{negotiation_timeout, integer()}]]></c></tag>
<item>
- <p>Max time in milliseconds for the authentication negotiation. The default value is 2 minutes.
+ <p>Max time in milliseconds for the authentication negotiation. The default value is 2 minutes. If the client fails to login within this time, the connection is closed.
+ </p>
+ </item>
+
+ <tag><c><![CDATA[{max_sessions, pos_integer()}]]></c></tag>
+ <item>
+ <p>The maximum number of simultaneous sessions that are accepted at any time for this daemon. This includes sessions that are being authorized. So if set to <c>N</c>, and <c>N</c> clients have connected but not started the login process, the <c>N+1</c> connection attempt will be aborted. If <c>N</c> connections are authenticated and still logged in, no more loggins will be accepted until one of the existing ones log out.
+ </p>
+ <p>The counter is per listening port, so if two daemons are started, one with <c>{max_sessions,N}</c> and the other with <c>{max_sessions,M}</c> there will be in total <c>N+M</c> connections accepted for the whole ssh application.
+ </p>
+ <p>Note that if <c>parallel_login</c> is <c>false</c>, only one client at a time may be in the authentication phase.
+ </p>
+ <p>As default, the option is not set. This means that the number is not limited.
</p>
</item>
<tag><c><![CDATA[{parallel_login, boolean()}]]></c></tag>
<item>
- <p>If set to false (the default value), only one login is handled a time. If set to true, an unlimited logins will be allowed simultanously. Note that this affects only the connections with authentication in progress, not the already authenticated connections.
+ <p>If set to false (the default value), only one login is handled a time. If set to true, an unlimited number of login attempts will be allowed simultanously.
+ </p>
+ <p>If the <c>max_sessions</c> option is set to <c>N</c> and <c>parallel_login</c> is set to <c>true</c>, the max number of simultaneous login attempts at any time is limited to <c>N-K</c> where <c>K</c> is the number of authenticated connections present at this daemon.
</p>
<warning>
- <p>Do not enable parallel_logins without protecting the server by other means like a firewall. If set to true, there is no protection against dos attacs.</p>
+ <p>Do not enable <c>parallel_logins</c> without protecting the server by other means, for example the <c>max_sessions</c> option or a firewall configuration. If set to <c>true</c>, there is no protection against DOS attacks.</p>
</warning>
-
</item>
<tag><c><![CDATA[{key_cb, atom()}]]></c></tag>
diff --git a/lib/ssh/doc/src/using_ssh.xml b/lib/ssh/doc/src/using_ssh.xml
index 4d73366f5e..9ab71260d3 100644
--- a/lib/ssh/doc/src/using_ssh.xml
+++ b/lib/ssh/doc/src/using_ssh.xml
@@ -33,7 +33,7 @@
all needed applications (crypto, public_key and ssh). All examples
are run in an Erlang shell, or in a bash shell using openssh to
illustrate how the erlang ssh application can be used. The
- exampels are run as the user otptest on a local network where the
+ examples are run as the user otptest on a local network where the
user is authorized to login in over ssh to the host "tarlop". If
nothing else is stated it is persumed that the otptest user has an
entry in tarlop's authorized_keys file (may log in via ssh without
@@ -88,7 +88,7 @@
[...]
</code>
- <p>Create the file /tmp/otptest_user/.ssh/authrized_keys and add the content
+ <p>Create the file /tmp/otptest_user/.ssh/authorized_keys and add the content
of /tmp/otptest_user/.ssh/id_rsa.pub Now we can do</p>
<code type="erl">
diff --git a/lib/ssh/src/ssh.erl b/lib/ssh/src/ssh.erl
index de6e8cc421..75081b7a61 100644
--- a/lib/ssh/src/ssh.erl
+++ b/lib/ssh/src/ssh.erl
@@ -332,6 +332,8 @@ handle_option([{idle_time, _} = Opt | Rest], SocketOptions, SshOptions) ->
handle_option(Rest, SocketOptions, [handle_ssh_option(Opt) | SshOptions]);
handle_option([{rekey_limit, _} = Opt|Rest], SocketOptions, SshOptions) ->
handle_option(Rest, SocketOptions, [handle_ssh_option(Opt) | SshOptions]);
+handle_option([{max_sessions, _} = Opt|Rest], SocketOptions, SshOptions) ->
+ handle_option(Rest, SocketOptions, [handle_ssh_option(Opt) | SshOptions]);
handle_option([{negotiation_timeout, _} = Opt|Rest], SocketOptions, SshOptions) ->
handle_option(Rest, SocketOptions, [handle_ssh_option(Opt) | SshOptions]);
handle_option([{parallel_login, _} = Opt|Rest], SocketOptions, SshOptions) ->
@@ -366,6 +368,8 @@ handle_ssh_option({pref_public_key_algs, Value} = Opt) when is_list(Value), leng
end;
handle_ssh_option({connect_timeout, Value} = Opt) when is_integer(Value); Value == infinity ->
Opt;
+handle_ssh_option({max_sessions, Value} = Opt) when is_integer(Value), Value>0 ->
+ Opt;
handle_ssh_option({negotiation_timeout, Value} = Opt) when is_integer(Value); Value == infinity ->
Opt;
handle_ssh_option({parallel_login, Value} = Opt) when Value==true ; Value==false ->
diff --git a/lib/ssh/src/ssh_acceptor.erl b/lib/ssh/src/ssh_acceptor.erl
index e57b07cee8..7302196674 100644
--- a/lib/ssh/src/ssh_acceptor.erl
+++ b/lib/ssh/src/ssh_acceptor.erl
@@ -80,18 +80,36 @@ acceptor_loop(Callback, Port, Address, Opts, ListenSocket, AcceptTimeout) ->
ListenSocket, AcceptTimeout)
end.
-handle_connection(_Callback, Address, Port, Options, Socket) ->
+handle_connection(Callback, Address, Port, Options, Socket) ->
SystemSup = ssh_system_sup:system_supervisor(Address, Port),
- {ok, SubSysSup} = ssh_system_sup:start_subsystem(SystemSup, Options),
- ConnectionSup = ssh_subsystem_sup:connection_supervisor(SubSysSup),
- Timeout = proplists:get_value(negotiation_timeout,
- proplists:get_value(ssh_opts, Options, []),
- 2*60*1000),
- ssh_connection_handler:start_connection(server, Socket,
- [{supervisors, [{system_sup, SystemSup},
- {subsystem_sup, SubSysSup},
- {connection_sup, ConnectionSup}]}
- | Options], Timeout).
+ SSHopts = proplists:get_value(ssh_opts, Options, []),
+ MaxSessions = proplists:get_value(max_sessions,SSHopts,infinity),
+ case number_of_connections(SystemSup) < MaxSessions of
+ true ->
+ {ok, SubSysSup} = ssh_system_sup:start_subsystem(SystemSup, Options),
+ ConnectionSup = ssh_subsystem_sup:connection_supervisor(SubSysSup),
+ Timeout = proplists:get_value(negotiation_timeout, SSHopts, 2*60*1000),
+ ssh_connection_handler:start_connection(server, Socket,
+ [{supervisors, [{system_sup, SystemSup},
+ {subsystem_sup, SubSysSup},
+ {connection_sup, ConnectionSup}]}
+ | Options], Timeout);
+ false ->
+ Callback:close(Socket),
+ IPstr = if is_tuple(Address) -> inet:ntoa(Address);
+ true -> Address
+ end,
+ Str = try io_lib:format('~s:~p',[IPstr,Port])
+ catch _:_ -> "port "++integer_to_list(Port)
+ end,
+ error_logger:info_report("Ssh login attempt to "++Str++" denied due to option "
+ "max_sessions limits to "++ io_lib:write(MaxSessions) ++
+ " sessions."
+ ),
+ {error,max_sessions}
+ end.
+
+
handle_error(timeout) ->
ok;
@@ -117,3 +135,10 @@ handle_error(Reason) ->
String = lists:flatten(io_lib:format("Accept error: ~p", [Reason])),
error_logger:error_report(String),
exit({accept_failed, String}).
+
+
+number_of_connections(SystemSup) ->
+ length([X ||
+ {R,X,supervisor,[ssh_subsystem_sup]} <- supervisor:which_children(SystemSup),
+ is_reference(R)
+ ]).
diff --git a/lib/ssh/src/ssh_auth.erl b/lib/ssh/src/ssh_auth.erl
index 409a1db6d5..45fd907383 100644
--- a/lib/ssh/src/ssh_auth.erl
+++ b/lib/ssh/src/ssh_auth.erl
@@ -196,7 +196,7 @@ handle_userauth_request(#ssh_msg_userauth_request{user = User,
{authorized, User,
ssh_transport:ssh_packet(#ssh_msg_userauth_success{}, Ssh)};
false ->
- {not_authorized, {User, {passwd, Password}},
+ {not_authorized, {User, {error,"Bad user or password"}},
ssh_transport:ssh_packet(#ssh_msg_userauth_failure{
authentications = "",
partial_success = false}, Ssh)}
@@ -228,7 +228,7 @@ handle_userauth_request(#ssh_msg_userauth_request{user = User,
ssh_transport:ssh_packet(
#ssh_msg_userauth_success{}, Ssh)};
false ->
- {not_authorized, {User, {error, "Invalid signature"}},
+ {not_authorized, {User, undefined},
ssh_transport:ssh_packet(#ssh_msg_userauth_failure{
authentications="publickey,password",
partial_success = false}, Ssh)}
diff --git a/lib/ssh/src/ssh_connection_handler.erl b/lib/ssh/src/ssh_connection_handler.erl
index 322da50f21..06866392da 100644
--- a/lib/ssh/src/ssh_connection_handler.erl
+++ b/lib/ssh/src/ssh_connection_handler.erl
@@ -1482,8 +1482,7 @@ ssh_channel_info([ _ | Rest], Channel, Acc) ->
log_error(Reason) ->
Report = io_lib:format("Erlang ssh connection handler failed with reason: "
- "~p ~n, Stacktace: ~p ~n"
- "please report this to [email protected] \n",
+ "~p ~n, Stacktrace: ~p ~n",
[Reason, erlang:get_stacktrace()]),
error_logger:error_report(Report),
"Internal error".
diff --git a/lib/ssh/test/ssh_basic_SUITE.erl b/lib/ssh/test/ssh_basic_SUITE.erl
index d2e52379fa..a8b64b1425 100644
--- a/lib/ssh/test/ssh_basic_SUITE.erl
+++ b/lib/ssh/test/ssh_basic_SUITE.erl
@@ -47,21 +47,26 @@ all() ->
daemon_already_started,
server_password_option,
server_userpassword_option,
- double_close].
+ double_close,
+ {group, hardening_tests}
+ ].
groups() ->
[{dsa_key, [], basic_tests()},
{rsa_key, [], basic_tests()},
{dsa_pass_key, [], [pass_phrase]},
{rsa_pass_key, [], [pass_phrase]},
- {internal_error, [], [internal_error]}
+ {internal_error, [], [internal_error]},
+ {hardening_tests, [], [max_sessions]}
].
+
basic_tests() ->
[send, close, peername_sockname,
exec, exec_compressed, shell, cli, known_hosts,
idle_time, rekey, openssh_zlib_basic_test].
+
%%--------------------------------------------------------------------
init_per_suite(Config) ->
case catch crypto:start() of
@@ -74,6 +79,8 @@ end_per_suite(_Config) ->
ssh:stop(),
crypto:stop().
%%--------------------------------------------------------------------
+init_per_group(hardening_tests, Config) ->
+ init_per_group(dsa_key, Config);
init_per_group(dsa_key, Config) ->
DataDir = ?config(data_dir, Config),
PrivDir = ?config(priv_dir, Config),
@@ -103,6 +110,8 @@ init_per_group(internal_error, Config) ->
init_per_group(_, Config) ->
Config.
+end_per_group(hardening_tests, Config) ->
+ end_per_group(dsa_key, Config);
end_per_group(dsa_key, Config) ->
PrivDir = ?config(priv_dir, Config),
ssh_test_lib:clean_dsa(PrivDir),
@@ -639,6 +648,49 @@ openssh_zlib_basic_test(Config) ->
ssh:stop_daemon(Pid).
%%--------------------------------------------------------------------
+
+max_sessions(Config) ->
+ SystemDir = filename:join(?config(priv_dir, Config), system),
+ UserDir = ?config(priv_dir, Config),
+ MaxSessions = 2,
+ {Pid, Host, Port} = ssh_test_lib:daemon([{system_dir, SystemDir},
+ {user_dir, UserDir},
+ {user_passwords, [{"carni", "meat"}]},
+ {parallel_login, true},
+ {max_sessions, MaxSessions}
+ ]),
+
+ Connect = fun() ->
+ R=ssh_test_lib:connect(Host, Port, [{silently_accept_hosts, true},
+ {user_dir, UserDir},
+ {user_interaction, false},
+ {user, "carni"},
+ {password, "meat"}
+ ]),
+ ct:log("Connection ~p up",[R])
+ end,
+
+ try [Connect() || _ <- lists:seq(1,MaxSessions)]
+ of
+ _ ->
+ ct:pal("Expect Info Report:",[]),
+ try Connect()
+ of
+ _ConnectionRef ->
+ ssh:stop_daemon(Pid),
+ {fail,"Too many connections accepted"}
+ catch
+ error:{badmatch,{error,"Connection closed"}} ->
+ ssh:stop_daemon(Pid),
+ ok
+ end
+ catch
+ error:{badmatch,{error,"Connection closed"}} ->
+ ssh:stop_daemon(Pid),
+ {fail,"Too few connections accepted"}
+ end.
+
+%%--------------------------------------------------------------------
%% Internal functions ------------------------------------------------
%%--------------------------------------------------------------------
diff --git a/lib/ssl/doc/src/notes.xml b/lib/ssl/doc/src/notes.xml
index 0b28b1ebd4..c61b2a9c2f 100644
--- a/lib/ssl/doc/src/notes.xml
+++ b/lib/ssl/doc/src/notes.xml
@@ -25,7 +25,164 @@
<file>notes.xml</file>
</header>
<p>This document describes the changes made to the SSL application.</p>
- <section><title>SSL 5.3.3</title>
+ <section><title>SSL 5.3.4</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Fix incorrect dialyzer spec and types, also enhance
+ documentation. </p>
+ <p>
+ Thanks to Ayaz Tuncer.</p>
+ <p>
+ Own Id: OTP-11627</p>
+ </item>
+ <item>
+ <p>
+ Fix possible mismatch between SSL/TLS version and default
+ ciphers. Could happen when you specified SSL/TLS-version
+ in optionlist to listen or accept.</p>
+ <p>
+ Own Id: OTP-11712</p>
+ </item>
+ <item>
+ <p>
+ Application upgrade (appup) files are corrected for the
+ following applications: </p>
+ <p>
+ <c>asn1, common_test, compiler, crypto, debugger,
+ dialyzer, edoc, eldap, erl_docgen, et, eunit, gs, hipe,
+ inets, observer, odbc, os_mon, otp_mibs, parsetools,
+ percept, public_key, reltool, runtime_tools, ssh,
+ syntax_tools, test_server, tools, typer, webtool, wx,
+ xmerl</c></p>
+ <p>
+ A new test utility for testing appup files is added to
+ test_server. This is now used by most applications in
+ OTP.</p>
+ <p>
+ (Thanks to Tobias Schlager)</p>
+ <p>
+ Own Id: OTP-11744</p>
+ </item>
+ </list>
+ </section>
+
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p>
+ Moved elliptic curve definition from the crypto
+ NIF/OpenSSL into Erlang code, adds the RFC-5639 brainpool
+ curves and makes TLS use them (RFC-7027).</p>
+ <p>
+ Thanks to Andreas Schultz</p>
+ <p>
+ Own Id: OTP-11578</p>
+ </item>
+ <item>
+ <p>
+ Unicode adaptations</p>
+ <p>
+ Own Id: OTP-11620</p>
+ </item>
+ <item>
+ <p>
+ Added option honor_cipher_order. This instructs the
+ server to prefer its own cipher ordering rather than the
+ client's and can help protect against things like BEAST
+ while maintaining compatability with clients which only
+ support older ciphers. </p>
+ <p>
+ Thanks to Andrew Thompson for the implementation, and
+ Andreas Schultz for the test cases.</p>
+ <p>
+ Own Id: OTP-11621</p>
+ </item>
+ <item>
+ <p>
+ Replace boolean checking in validate_option with
+ is_boolean guard. </p>
+ <p>
+ Thanks to Andreas Schultz.</p>
+ <p>
+ Own Id: OTP-11634</p>
+ </item>
+ <item>
+ <p>
+ Some function specs are corrected or moved and some edoc
+ comments are corrected in order to allow use of edoc.
+ (Thanks to Pierre Fenoll)</p>
+ <p>
+ Own Id: OTP-11702</p>
+ </item>
+ <item>
+ <p>
+ Correct clean up of certificate database when certs are
+ inputed in pure DER format.The incorrect code could cause
+ a memory leek when certs where inputed in DER. Thanks to
+ Bernard Duggan for reporting this.</p>
+ <p>
+ Own Id: OTP-11733</p>
+ </item>
+ <item>
+ <p>
+ Improved documentation of the cacertfile option</p>
+ <p>
+ Own Id: OTP-11759 Aux Id: seq12535 </p>
+ </item>
+ <item>
+ <p>
+ Avoid next protocol negotiation failure due to incorrect
+ option format.</p>
+ <p>
+ Own Id: OTP-11760</p>
+ </item>
+ <item>
+ <p>
+ Handle v1 CRLs, with no extensions and fixes issues with
+ IDP (Issuing Distribution Point) comparison during CRL
+ validation. </p>
+ <p>
+ Thanks to Andrew Thompson</p>
+ <p>
+ Own Id: OTP-11761</p>
+ </item>
+ <item>
+ <p>
+ Server now ignores client ECC curves that it does not
+ support instead of crashing. </p>
+ <p>
+ Thanks to Danil Zagoskin for reporting the issue and
+ suggesting a solution.</p>
+ <p>
+ Own Id: OTP-11780</p>
+ </item>
+ <item>
+ <p>
+ Handle SNI (Server Name Indication) alert
+ unrecognized_name and gracefully deal with unexpected
+ alerts. </p>
+ <p>
+ Thanks to Masatake Daimon for reporting this.</p>
+ <p>
+ Own Id: OTP-11815</p>
+ </item>
+ <item>
+ <p>
+ Add possibility to specify ssl options when calling
+ ssl:ssl_accept</p>
+ <p>
+ Own Id: OTP-11837</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>SSL 5.3.3</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 4bc1a9a644..ffee4bd1af 100644
--- a/lib/ssl/doc/src/ssl.xml
+++ b/lib/ssl/doc/src/ssl.xml
@@ -768,39 +768,45 @@ fun(srp, Username :: string(), UserState :: term()) ->
</func>
<func>
- <name>ssl_accept(ListenSocket) -> </name>
- <name>ssl_accept(ListenSocket, Timeout) -> ok | {error, Reason}</name>
- <fsummary>Perform server-side SSL handshake</fsummary>
+ <name>ssl_accept(Socket) -> </name>
+ <name>ssl_accept(Socket, Timeout) -> ok | {error, Reason}</name>
+ <fsummary>Perform server-side SSL/TLS handshake</fsummary>
<type>
- <v>ListenSocket = sslsocket()</v>
+ <v>Socket = sslsocket()</v>
<v>Timeout = integer()</v>
<v>Reason = term()</v>
</type>
<desc>
- <p>The <c>ssl_accept</c> function establish the SSL connection
- on the server side. It should be called directly after
- <c>transport_accept</c>, in the spawned server-loop.</p>
+ <p> Performs the SSL/TLS server-side handshake <c>Socket</c> is a socket as returned
+ by <seealso
+ marker="#transport_accept-2">ssl:transport_accept/[1,2]</seealso>
+ </p>
</desc>
</func>
<func>
- <name>ssl_accept(ListenSocket, SslOptions) -> </name>
- <name>ssl_accept(ListenSocket, SslOptions, Timeout) -> {ok, Socket} | {error, Reason}</name>
- <fsummary>Perform server-side SSL handshake</fsummary>
+ <name>ssl_accept(Socket, SslOptions) -> </name>
+ <name>ssl_accept(Socket, SslOptions, Timeout) -> {ok, Socket} | ok | {error, Reason}</name>
+ <fsummary>Perform server-side SSL/TLS handshake</fsummary>
<type>
- <v>ListenSocket = socket()</v>
+ <v>Socket = socket() | sslsocket() </v>
<v>SslOptions = ssloptions()</v>
<v>Timeout = integer()</v>
<v>Reason = term()</v>
</type>
<desc>
- <p> Upgrades a gen_tcp, or
- equivalent, socket to an ssl socket i.e. performs the
- ssl server-side handshake.</p>
+ <p> If <c>Socket</c> is a socket() - upgrades a gen_tcp, or equivalent, socket to an ssl socket
+ i.e. performs the SSL/TLS server-side handshake and returns the ssl socket.
+ </p>
+
<warning><p>Note that the listen socket should be in {active, false} mode
before telling the client that the server is ready to upgrade
- and calling this function, otherwise the upgrade may
+ by calling this function, otherwise the upgrade may
or may not succeed depending on timing.</p></warning>
+
+ <p> If <c>Socket</c> is an sslsocket() - provides additional SSL/TLS options to those specified in <seealso
+ marker="#listen-2">ssl:listen/2 </seealso> and then performs the SSL/TLS handshake.
+ </p>
</desc>
</func>
@@ -842,33 +848,38 @@ fun(srp, Username :: string(), UserState :: term()) ->
</func>
<func>
- <name>transport_accept(Socket) -></name>
- <name>transport_accept(Socket, Timeout) ->
+ <name>transport_accept(ListenSocket) -></name>
+ <name>transport_accept(ListenSocket, Timeout) ->
{ok, NewSocket} | {error, Reason}</name>
<fsummary>Accept an incoming connection and
prepare for <c>ssl_accept</c></fsummary>
<type>
- <v>Socket = NewSocket = sslsocket()</v>
+ <v>ListenSocket = NewSocket = sslsocket()</v>
<v>Timeout = integer()</v>
<v>Reason = reason()</v>
</type>
<desc>
<p>Accepts an incoming connection request on a listen socket.
- <c>ListenSocket</c> must be a socket returned from
- <c>listen/2</c>. The socket returned should be passed to
- <c>ssl_accept</c> to complete ssl handshaking and
- establishing the connection.</p>
+ <c>ListenSocket</c> must be a socket returned from
+ <seealso
+ marker="#listen-2"> ssl:listen/2</seealso>.
+ The socket returned should be passed to
+ <seealso marker="#ssl_accept-2"> ssl:ssl_accept[2,3]</seealso>
+ to complete handshaking i.e
+ establishing the SSL/TLS connection.</p>
<warning>
- <p>The socket returned can only be used with <c>ssl_accept</c>,
- no traffic can be sent or received before that call.</p>
+ <p>The socket returned can only be used with
+ <seealso marker="#ssl_accept-2"> ssl:ssl_accept[2,3]</seealso>
+ no traffic can be sent or received before that call.</p>
</warning>
<p>The accepted socket inherits the options set for
- <c>ListenSocket</c> in <c>listen/2</c>.</p>
+ <c>ListenSocket</c> in <seealso
+ marker="#listen-2"> ssl:listen/2</seealso>.</p>
<p>The default
- value for <c>Timeout</c> is <c>infinity</c>. If
- <c>Timeout</c> is specified, and no connection is accepted
- within the given time, <c>{error, timeout}</c> is
- returned.</p>
+ value for <c>Timeout</c> is <c>infinity</c>. If
+ <c>Timeout</c> is specified, and no connection is accepted
+ within the given time, <c>{error, timeout}</c> is
+ returned.</p>
</desc>
</func>
diff --git a/lib/ssl/internal_doc/ssl-implementation.txt b/lib/ssl/internal_doc/ssl-implementation.txt
deleted file mode 100644
index e5d6ac8cd0..0000000000
--- a/lib/ssl/internal_doc/ssl-implementation.txt
+++ /dev/null
@@ -1,52 +0,0 @@
-
-Important modules:
-
- module behaviour children
- ------ ---------
- ssl_app application ssl_sup
- ssl_sup supervisor ssl_server, ssl_broker_sup
- ssl_server gen_server -
- ssl_broker_sup supervisor ssl_broker
- ssl_broker gen_server -
-
-The ssl_server controls a port program that implements the SSL functionality.
-That port program uses the OpenSSL package.
-
-Each socket has a corresponding broker (listen, accept or connect). A broker
-is created and supervised by the ssl_broker_sup.
-
-All communication is between a user and a broker. The broker communicates
-with the ssl_server, that sends its commands to the port program and handles
-the port program responses, that are distributed to users through the
-brokers.
-
-There is a distinction between commands and data flow between the ssl_server
-and the port program. Each established connection between the user and the
-outside world consists of a local erlang socket (owned by the broker) that
-is read from and written to by the broker. At the other end of the local
-connection is a local socket in the port program.
-
-The "real" socket that connects to the outside world is in the port program
-(including listen sockets). The main purpose of the port program is to
-shuffle data between local sockets and outside world sockets, and detect and
-propagate read and write errors (including detection of closed sockets) to
-the ssl_server.
-
-There is documentation in the ssl_broker.erl module.
-
-There is also documentation in the esock.c and esock_openssl.c files.
-
-The ssl_pem.erl, ssl_pkix.erl and ssl_base64.erl modules are support
-modules for reading SSL certificates. Modules for parsing certificates
-are generated from ASN.1 modules in the `pkix' directory.
-
-The `examples' directory contains functions for generating certificates.
-Those certificates are used in the test suites.
-
-
-
-
-
-
-
-
diff --git a/lib/ssl/src/dtls_connection.erl b/lib/ssl/src/dtls_connection.erl
index 57f8dd86d3..508983ddac 100644
--- a/lib/ssl/src/dtls_connection.erl
+++ b/lib/ssl/src/dtls_connection.erl
@@ -202,13 +202,14 @@ hello(Hello = #client_hello{client_version = ClientVersion,
session_cache = Cache,
session_cache_cb = CacheCb,
ssl_options = SslOpts}) ->
- HashSign = ssl_handshake:select_hashsign(HashSigns, Cert),
case dtls_handshake:hello(Hello, SslOpts, {Port, Session0, Cache, CacheCb,
ConnectionStates0, Cert}, Renegotiation) of
{Version, {Type, Session},
ConnectionStates,
#hello_extensions{ec_point_formats = EcPointFormats,
elliptic_curves = EllipticCurves} = ServerHelloExt} ->
+ HashSign = ssl_handshake:select_hashsign(HashSigns, Cert,
+ dtls_v1:corresponding_tls_version(Version)),
ssl_connection:hello({common_client_hello, Type, ServerHelloExt, HashSign},
State#state{connection_states = ConnectionStates,
negotiated_version = Version,
diff --git a/lib/ssl/src/ssl.erl b/lib/ssl/src/ssl.erl
index a88bf45293..866312f332 100644
--- a/lib/ssl/src/ssl.erl
+++ b/lib/ssl/src/ssl.erl
@@ -195,7 +195,8 @@ transport_accept(#sslsocket{pid = {ListenSocket,
-spec ssl_accept(#sslsocket{} | port(), timeout()| [ssl_option()
| transport_option()]) ->
ok | {ok, #sslsocket{}} | {error, reason()}.
--spec ssl_accept(port(), [ssl_option()| transport_option()], timeout()) ->
+
+-spec ssl_accept(#sslsocket{} | port(), [ssl_option()] | [ssl_option()| transport_option()], timeout()) ->
{ok, #sslsocket{}} | {error, reason()}.
%%
%% Description: Performs accept on an ssl listen socket. e.i. performs
@@ -210,6 +211,15 @@ ssl_accept(#sslsocket{} = Socket, Timeout) ->
ssl_accept(ListenSocket, SslOptions) when is_port(ListenSocket) ->
ssl_accept(ListenSocket, SslOptions, infinity).
+ssl_accept(#sslsocket{} = Socket, [], Timeout) ->
+ ssl_accept(#sslsocket{} = Socket, Timeout);
+ssl_accept(#sslsocket{} = Socket, SslOptions, Timeout) ->
+ try
+ {ok, #config{ssl = SSL}} = handle_options(SslOptions, server),
+ ssl_connection:handshake(Socket, SSL, Timeout)
+ catch
+ Error = {error, _Reason} -> Error
+ end;
ssl_accept(Socket, SslOptions, Timeout) when is_port(Socket) ->
{Transport,_,_,_} =
proplists:get_value(cb_info, SslOptions, {gen_tcp, tcp, tcp_closed, tcp_error}),
@@ -347,11 +357,7 @@ cipher_suites(openssl) ->
[ssl_cipher:openssl_suite_name(S) || S <- ssl_cipher:suites(Version)];
cipher_suites(all) ->
Version = tls_record:highest_protocol_version([]),
- Supported = ssl_cipher:suites(Version)
- ++ ssl_cipher:anonymous_suites()
- ++ ssl_cipher:psk_suites(Version)
- ++ ssl_cipher:srp_suites(),
- [suite_definition(S) || S <- Supported].
+ [suite_definition(S) || S <- ssl_cipher:all_suites(Version)].
%%--------------------------------------------------------------------
-spec getopts(#sslsocket{}, [gen_tcp:option_name()]) ->
@@ -943,7 +949,7 @@ handle_cipher_option(Value, Version) when is_list(Value) ->
error:_->
throw({error, {options, {ciphers, Value}}})
end.
-binary_cipher_suites(Version, []) -> %% Defaults to all supported suits
+binary_cipher_suites(Version, []) -> % Defaults to all supported suites
ssl_cipher:suites(Version);
binary_cipher_suites(Version, [{_,_,_,_}| _] = Ciphers0) -> %% Backwards compatibility
Ciphers = [{KeyExchange, Cipher, Hash} || {KeyExchange, Cipher, Hash, _} <- Ciphers0],
diff --git a/lib/ssl/src/ssl_cipher.erl b/lib/ssl/src/ssl_cipher.erl
index 78a328ace8..a3ec419c2a 100644
--- a/lib/ssl/src/ssl_cipher.erl
+++ b/lib/ssl/src/ssl_cipher.erl
@@ -34,7 +34,8 @@
-export([security_parameters/2, security_parameters/3, suite_definition/1,
decipher/5, cipher/5,
- suite/1, suites/1, ec_keyed_suites/0, anonymous_suites/0, psk_suites/1, srp_suites/0,
+ suite/1, suites/1, all_suites/1,
+ ec_keyed_suites/0, anonymous_suites/0, psk_suites/1, srp_suites/0,
openssl_suite/1, openssl_suite_name/1, filter/2, filter_suites/1,
hash_algorithm/1, sign_algorithm/1, is_acceptable_hash/2]).
@@ -224,6 +225,11 @@ suites({3, 0}) ->
suites({3, N}) ->
tls_v1:suites(N).
+all_suites(Version) ->
+ suites(Version)
+ ++ ssl_cipher:anonymous_suites()
+ ++ ssl_cipher:psk_suites(Version)
+ ++ ssl_cipher:srp_suites().
%%--------------------------------------------------------------------
-spec anonymous_suites() -> [cipher_suite()].
%%
diff --git a/lib/ssl/src/ssl_connection.erl b/lib/ssl/src/ssl_connection.erl
index ed9e4d344f..1eda926bcb 100644
--- a/lib/ssl/src/ssl_connection.erl
+++ b/lib/ssl/src/ssl_connection.erl
@@ -36,7 +36,7 @@
-include_lib("public_key/include/public_key.hrl").
%% Setup
--export([connect/8, ssl_accept/7, handshake/2,
+-export([connect/8, ssl_accept/7, handshake/2, handshake/3,
socket_control/4]).
%% User Events
@@ -100,6 +100,20 @@ handshake(#sslsocket{pid = Pid}, Timeout) ->
Error ->
Error
end.
+
+%%--------------------------------------------------------------------
+-spec handshake(#sslsocket{}, #ssl_options{}, timeout()) -> ok | {error, reason()}.
+%%
+%% Description: Starts ssl handshake with some new options
+%%--------------------------------------------------------------------
+handshake(#sslsocket{pid = Pid}, SslOptions, Timeout) ->
+ case sync_send_all_state_event(Pid, {start, SslOptions, Timeout}) of
+ connected ->
+ ok;
+ Error ->
+ Error
+ end.
+
%--------------------------------------------------------------------
-spec socket_control(tls_connection | dtls_connection, port(), pid(), atom()) ->
{ok, #sslsocket{}} | {error, reason()}.
@@ -276,12 +290,11 @@ hello(#hello_request{}, #state{role = client} = State0, Connection) ->
{Record, State} = Connection:next_record(State0),
Connection:next_state(hello, hello, Record, State);
-hello({common_client_hello, Type, ServerHelloExt, HashSign},
- #state{session = #session{cipher_suite = CipherSuite},
- negotiated_version = Version} = State, Connection) ->
- {KeyAlg, _, _, _} = ssl_cipher:suite_definition(CipherSuite),
- NegotiatedHashSign = negotiated_hashsign(HashSign, KeyAlg, Version),
+hello({common_client_hello, Type, ServerHelloExt, NegotiatedHashSign},
+ State, Connection) ->
do_server_hello(Type, ServerHelloExt,
+ %% Note NegotiatedHashSign is only negotiated for real if
+ %% if TLS version is at least TLS-1.2
State#state{hashsign_algorithm = NegotiatedHashSign}, Connection);
hello(timeout, State, _) ->
@@ -418,7 +431,8 @@ certify(#server_key_exchange{exchange_keys = Keys},
calculate_secret(Params#server_key_params.params,
State#state{hashsign_algorithm = HashSign}, Connection);
false ->
- ?ALERT_REC(?FATAL, ?DECRYPT_ERROR)
+ Connection:handle_own_alert(?ALERT_REC(?FATAL, ?DECRYPT_ERROR),
+ Version, certify, State)
end
end;
@@ -427,8 +441,9 @@ certify(#server_key_exchange{} = Msg,
Connection:handle_unexpected_message(Msg, certify_server_keyexchange, State);
certify(#certificate_request{hashsign_algorithms = HashSigns},
- #state{session = #session{own_certificate = Cert}} = State0, Connection) ->
- HashSign = ssl_handshake:select_hashsign(HashSigns, Cert),
+ #state{session = #session{own_certificate = Cert},
+ negotiated_version = Version} = State0, Connection) ->
+ HashSign = ssl_handshake:select_hashsign(HashSigns, Cert, Version),
{Record, State} = Connection:next_record(State0#state{client_certificate_requested = true}),
Connection:next_state(certify, certify, Record,
State#state{cert_hashsign_algorithm = HashSign});
@@ -545,7 +560,7 @@ cipher(#certificate_verify{signature = Signature, hashsign_algorithm = CertHashS
tls_handshake_history = Handshake
} = State0, Connection) ->
- HashSign = ssl_handshake:select_cert_hashsign(CertHashSign, Algo, Version),
+ HashSign = ssl_handshake:select_hashsign_algs(CertHashSign, Algo, Version),
case ssl_handshake:certificate_verify(Signature, PublicKeyInfo,
Version, HashSign, MasterSecret, Handshake) of
valid ->
@@ -650,6 +665,10 @@ handle_sync_event({start, Timeout}, StartFrom, StateName, State) ->
{next_state, StateName, State#state{start_or_recv_from = StartFrom,
timer = Timer}, get_timeout(State)};
+handle_sync_event({start, Opts, Timeout}, From, StateName, #state{ssl_options = SslOpts} = State) ->
+ NewOpts = new_ssl_options(Opts, SslOpts),
+ handle_sync_event({start, Timeout}, From, StateName, State#state{ssl_options = NewOpts});
+
handle_sync_event(close, _, StateName, #state{protocol_cb = Connection} = State) ->
%% Run terminate before returning
%% so that the reuseaddr inet-option will work
@@ -678,7 +697,11 @@ handle_sync_event({shutdown, How0}, _, StateName,
Error ->
{stop, normal, Error, State}
end;
-
+
+handle_sync_event({recv, _N, _Timeout}, _RecvFrom, StateName,
+ #state{socket_options = #socket_options{active = Active}} = State) when Active =/= false ->
+ {reply, {error, einval}, StateName, State, get_timeout(State)};
+
handle_sync_event({recv, N, Timeout}, RecvFrom, connection = StateName,
#state{protocol_cb = Connection} = State0) ->
Timer = start_or_recv_cancel_timer(Timeout, RecvFrom),
@@ -1541,60 +1564,6 @@ cipher_role(server, Data, Session, #state{connection_states = ConnectionStates0
session = Session}, cipher, Connection),
Connection:next_state_connection(cipher, ack_connection(State#state{session = Session})).
-negotiated_hashsign(undefined, Algo, Version) ->
- default_hashsign(Version, Algo);
-negotiated_hashsign(HashSign = {_, _}, _, _) ->
- HashSign.
-
-%% RFC 5246, Sect. 7.4.1.4.1. Signature Algorithms
-%% If the client does not send the signature_algorithms extension, the
-%% server MUST do the following:
-%%
-%% - If the negotiated key exchange algorithm is one of (RSA, DHE_RSA,
-%% DH_RSA, RSA_PSK, ECDH_RSA, ECDHE_RSA), behave as if client had
-%% sent the value {sha1,rsa}.
-%%
-%% - If the negotiated key exchange algorithm is one of (DHE_DSS,
-%% DH_DSS), behave as if the client had sent the value {sha1,dsa}.
-%%
-%% - If the negotiated key exchange algorithm is one of (ECDH_ECDSA,
-%% ECDHE_ECDSA), behave as if the client had sent value {sha1,ecdsa}.
-
-default_hashsign(_Version = {Major, Minor}, KeyExchange)
- when Major >= 3 andalso Minor >= 3 andalso
- (KeyExchange == rsa orelse
- KeyExchange == dhe_rsa orelse
- KeyExchange == dh_rsa orelse
- KeyExchange == ecdhe_rsa orelse
- KeyExchange == ecdh_rsa orelse
- KeyExchange == srp_rsa) ->
- {sha, rsa};
-default_hashsign(_Version, KeyExchange)
- when KeyExchange == rsa;
- KeyExchange == dhe_rsa;
- KeyExchange == dh_rsa;
- KeyExchange == ecdhe_rsa;
- KeyExchange == ecdh_rsa;
- KeyExchange == srp_rsa ->
- {md5sha, rsa};
-default_hashsign(_Version, KeyExchange)
- when KeyExchange == ecdhe_ecdsa;
- KeyExchange == ecdh_ecdsa ->
- {sha, ecdsa};
-default_hashsign(_Version, KeyExchange)
- when KeyExchange == dhe_dss;
- KeyExchange == dh_dss;
- KeyExchange == srp_dss ->
- {sha, dsa};
-default_hashsign(_Version, KeyExchange)
- when KeyExchange == dh_anon;
- KeyExchange == ecdh_anon;
- KeyExchange == psk;
- KeyExchange == dhe_psk;
- KeyExchange == rsa_psk;
- KeyExchange == srp_anon ->
- {null, anon}.
-
select_curve(#state{client_ecc = {[Curve|_], _}}) ->
{namedCurve, Curve};
select_curve(_) ->
@@ -1855,3 +1824,26 @@ make_premaster_secret({MajVer, MinVer}, rsa) ->
<<?BYTE(MajVer), ?BYTE(MinVer), Rand/binary>>;
make_premaster_secret(_, _) ->
undefined.
+
+%% One day this can be maps instead, but we have to be backwards compatible for now
+new_ssl_options(New, Old) ->
+ new_ssl_options(tuple_to_list(New), tuple_to_list(Old), []).
+
+new_ssl_options([], [], Acc) ->
+ list_to_tuple(lists:reverse(Acc));
+new_ssl_options([undefined | Rest0], [Head1| Rest1], Acc) ->
+ new_ssl_options(Rest0, Rest1, [Head1 | Acc]);
+new_ssl_options([Head0 | Rest0], [_| Rest1], Acc) ->
+ new_ssl_options(Rest0, Rest1, [Head0 | Acc]).
+
+negotiated_hashsign(undefined, Alg, Version) ->
+ %% Not negotiated choose default
+ case is_anonymous(Alg) of
+ true ->
+ {null, anon};
+ false ->
+ ssl_handshake:select_hashsign_algs(Alg, Version)
+ end;
+negotiated_hashsign(HashSign = {_, _}, _, _) ->
+ HashSign.
+
diff --git a/lib/ssl/src/ssl_handshake.erl b/lib/ssl/src/ssl_handshake.erl
index 1108edcf48..fc67d2c28d 100644
--- a/lib/ssl/src/ssl_handshake.erl
+++ b/lib/ssl/src/ssl_handshake.erl
@@ -73,7 +73,8 @@
]).
%% MISC
--export([select_version/3, prf/5, select_hashsign/2, select_cert_hashsign/3,
+-export([select_version/3, prf/5, select_hashsign/3,
+ select_hashsign_algs/2, select_hashsign_algs/3,
premaster_secret/2, premaster_secret/3, premaster_secret/4]).
%%====================================================================
@@ -590,23 +591,25 @@ prf({3,1}, Secret, Label, Seed, WantedLength) ->
{ok, tls_v1:prf(?MD5SHA, Secret, Label, Seed, WantedLength)};
prf({3,_N}, Secret, Label, Seed, WantedLength) ->
{ok, tls_v1:prf(?SHA256, Secret, Label, Seed, WantedLength)}.
+
+
%%--------------------------------------------------------------------
--spec select_hashsign(#hash_sign_algos{}| undefined, undefined | binary()) ->
- [{atom(), atom()}] | undefined.
+-spec select_hashsign(#hash_sign_algos{}| undefined, undefined | binary(), ssl_record:ssl_version()) ->
+ {atom(), atom()} | undefined.
%%
%% Description:
%%--------------------------------------------------------------------
-select_hashsign(_, undefined) ->
+select_hashsign(_, undefined, _Version) ->
{null, anon};
-select_hashsign(undefined, Cert) ->
+select_hashsign(undefined, Cert, Version) ->
#'OTPCertificate'{tbsCertificate = TBSCert} = public_key:pkix_decode_cert(Cert, otp),
#'OTPSubjectPublicKeyInfo'{algorithm = {_,Algo, _}} = TBSCert#'OTPTBSCertificate'.subjectPublicKeyInfo,
- select_cert_hashsign(undefined, Algo, {undefined, undefined});
-select_hashsign(#hash_sign_algos{hash_sign_algos = HashSigns}, Cert) ->
+ select_hashsign_algs(undefined, Algo, Version);
+select_hashsign(#hash_sign_algos{hash_sign_algos = HashSigns}, Cert, Version) ->
#'OTPCertificate'{tbsCertificate = TBSCert} =public_key:pkix_decode_cert(Cert, otp),
#'OTPSubjectPublicKeyInfo'{algorithm = {_,Algo, _}} = TBSCert#'OTPTBSCertificate'.subjectPublicKeyInfo,
- DefaultHashSign = {_, Sign} = select_cert_hashsign(undefined, Algo, {undefined, undefined}),
+ DefaultHashSign = {_, Sign} = select_hashsign_algs(undefined, Algo, Version),
case lists:filter(fun({sha, dsa}) ->
true;
({_, dsa}) ->
@@ -622,26 +625,59 @@ select_hashsign(#hash_sign_algos{hash_sign_algos = HashSigns}, Cert) ->
[HashSign| _] ->
HashSign
end.
+
%%--------------------------------------------------------------------
--spec select_cert_hashsign(#hash_sign_algos{}| undefined, oid(), ssl_record:ssl_version() | {undefined, undefined}) ->
+-spec select_hashsign_algs(#hash_sign_algos{}| undefined, oid(), ssl_record:ssl_version()) ->
{atom(), atom()}.
+%% Description: For TLS 1.2 hash function and signature algorithm pairs can be
+%% negotiated with the signature_algorithms extension,
+%% for previous versions always use appropriate defaults.
+%% RFC 5246, Sect. 7.4.1.4.1. Signature Algorithms
+%% If the client does not send the signature_algorithms extension, the
+%% server MUST do the following: (e.i defaults for TLS 1.2)
+%%
+%% - If the negotiated key exchange algorithm is one of (RSA, DHE_RSA,
+%% DH_RSA, RSA_PSK, ECDH_RSA, ECDHE_RSA), behave as if client had
+%% sent the value {sha1,rsa}.
+%%
+%% - If the negotiated key exchange algorithm is one of (DHE_DSS,
+%% DH_DSS), behave as if the client had sent the value {sha1,dsa}.
%%
-%% Description: For TLS 1.2 selected cert_hash_sign will be recived
-%% in the handshake message, for previous versions use appropriate defaults.
-%% This function is also used by select_hashsign to extract
-%% the alogrithm of the server cert key.
+%% - If the negotiated key exchange algorithm is one of (ECDH_ECDSA,
+%% ECDHE_ECDSA), behave as if the client had sent value {sha1,ecdsa}.
+
%%--------------------------------------------------------------------
-select_cert_hashsign(HashSign, _, {Major, Minor}) when HashSign =/= undefined andalso
+select_hashsign_algs(HashSign, _, {Major, Minor}) when HashSign =/= undefined andalso
Major >= 3 andalso Minor >= 3 ->
HashSign;
-select_cert_hashsign(undefined,?'id-ecPublicKey', _) ->
+select_hashsign_algs(undefined, ?rsaEncryption, {Major, Minor}) when Major >= 3 andalso Minor >= 3 ->
+ {sha, rsa};
+select_hashsign_algs(undefined,?'id-ecPublicKey', _) ->
{sha, ecdsa};
-select_cert_hashsign(undefined, ?rsaEncryption, _) ->
+select_hashsign_algs(undefined, ?rsaEncryption, _) ->
{md5sha, rsa};
-select_cert_hashsign(undefined, ?'id-dsa', _) ->
+select_hashsign_algs(undefined, ?'id-dsa', _) ->
{sha, dsa}.
+-spec select_hashsign_algs(atom(), ssl_record:ssl_version()) -> {atom(), atom()}.
+%% Wrap function to keep the knowledge of the default values in
+%% one place only
+select_hashsign_algs(Alg, Version) when (Alg == rsa orelse
+ Alg == dhe_rsa orelse
+ Alg == dh_rsa orelse
+ Alg == ecdhe_rsa orelse
+ Alg == ecdh_rsa orelse
+ Alg == srp_rsa) ->
+ select_hashsign_algs(undefined, ?rsaEncryption, Version);
+select_hashsign_algs(Alg, Version) when (Alg == dhe_dss orelse
+ Alg == dh_dss orelse
+ Alg == srp_dss) ->
+ select_hashsign_algs(undefined, ?'id-dsa', Version);
+select_hashsign_algs(Alg, Version) when (Alg == ecdhe_ecdsa orelse
+ Alg == ecdh_ecdsa) ->
+ select_hashsign_algs(undefined, ?'id-ecPublicKey', Version).
+
%%--------------------------------------------------------------------
-spec master_secret(atom(), ssl_record:ssl_version(), #session{} | binary(), #connection_states{},
client | server) -> {binary(), #connection_states{}} | #alert{}.
@@ -1017,12 +1053,9 @@ decode_suites('3_bytes', Dec) ->
%%-------------Cipeher suite handling --------------------------------
available_suites(UserSuites, Version) ->
- case UserSuites of
- [] ->
- ssl_cipher:suites(Version);
- _ ->
- UserSuites
- end.
+ lists:filtermap(fun(Suite) ->
+ lists:member(Suite, ssl_cipher:all_suites(Version))
+ end, UserSuites).
available_suites(ServerCert, UserSuites, Version, Curve) ->
ssl_cipher:filter(ServerCert, available_suites(UserSuites, Version))
diff --git a/lib/ssl/src/ssl_internal.hrl b/lib/ssl/src/ssl_internal.hrl
index cec5d8fbb1..8bf5b30a83 100644
--- a/lib/ssl/src/ssl_internal.hrl
+++ b/lib/ssl/src/ssl_internal.hrl
@@ -101,7 +101,6 @@
reuse_sessions :: boolean(),
renegotiate_at,
secure_renegotiate,
- debug,
%% undefined if not hibernating, or number of ms of
%% inactivity after which ssl_connection will go into
%% hibernation
diff --git a/lib/ssl/src/ssl_record.erl b/lib/ssl/src/ssl_record.erl
index b0e9943e6d..7337225bc4 100644
--- a/lib/ssl/src/ssl_record.erl
+++ b/lib/ssl/src/ssl_record.erl
@@ -377,7 +377,7 @@ cipher(Version, Fragment,
ssl_cipher:cipher(BulkCipherAlgo, CipherS0, MacHash, Fragment, Version),
{CipherFragment, WriteState0#connection_state{cipher_state = CipherS1}}.
%%--------------------------------------------------------------------
--spec decipher(ssl_version(), binary(), #connection_state{}) -> {binary(), binary(), #connection_state{}}.
+-spec decipher(ssl_version(), binary(), #connection_state{}) -> {binary(), binary(), #connection_state{}} | #alert{}.
%%
%% Description: Payload decryption
%%--------------------------------------------------------------------
diff --git a/lib/ssl/src/tls_connection.erl b/lib/ssl/src/tls_connection.erl
index ffa04ee8ba..930706cde6 100644
--- a/lib/ssl/src/tls_connection.erl
+++ b/lib/ssl/src/tls_connection.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2007-2013. All Rights Reserved.
+%% Copyright Ericsson AB 2007-2014. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -208,11 +208,11 @@ hello(Hello = #client_hello{client_version = ClientVersion,
session_cache = Cache,
session_cache_cb = CacheCb,
ssl_options = SslOpts}) ->
- HashSign = ssl_handshake:select_hashsign(HashSigns, Cert),
case tls_handshake:hello(Hello, SslOpts, {Port, Session0, Cache, CacheCb,
ConnectionStates0, Cert}, Renegotiation) of
{Version, {Type, Session},
ConnectionStates, ServerHelloExt} ->
+ HashSign = ssl_handshake:select_hashsign(HashSigns, Cert, Version),
ssl_connection:hello({common_client_hello, Type, ServerHelloExt, HashSign},
State#state{connection_states = ConnectionStates,
negotiated_version = Version,
@@ -751,7 +751,11 @@ handle_tls_handshake(Handle, StateName,
handle_tls_handshake(Handle, NextStateName, State);
{stop, _,_} = Stop ->
Stop
- end.
+ end;
+
+handle_tls_handshake(_Handle, _StateName, #state{}) ->
+ throw(?ALERT_REC(?FATAL, ?HANDSHAKE_FAILURE)).
+
write_application_data(Data0, From,
#state{socket = Socket,
negotiated_version = Version,
@@ -859,7 +863,8 @@ handle_alert(#alert{level = ?WARNING, description = ?NO_RENEGOTIATION} = Alert,
{Record, State} = next_record(State0),
next_state(StateName, connection, Record, State);
-handle_alert(#alert{level = ?WARNING, description = ?USER_CANCELED} = Alert, StateName,
+%% Gracefully log and ignore all other warning alerts
+handle_alert(#alert{level = ?WARNING} = Alert, StateName,
#state{ssl_options = SslOpts} = State0) ->
log_alert(SslOpts#ssl_options.log_alert, StateName, Alert),
{Record, State} = next_record(State0),
diff --git a/lib/ssl/src/tls_record.erl b/lib/ssl/src/tls_record.erl
index 4da08e9c51..f50ea22f39 100644
--- a/lib/ssl/src/tls_record.erl
+++ b/lib/ssl/src/tls_record.erl
@@ -154,21 +154,24 @@ decode_cipher_text(#ssl_tls{type = Type, version = Version,
sequence_number = Seq,
security_parameters = SecParams} = ReadState0,
CompressAlg = SecParams#security_parameters.compression_algorithm,
- {PlainFragment, Mac, ReadState1} = ssl_record:decipher(Version, CipherFragment, ReadState0),
- MacHash = calc_mac_hash(Type, Version, PlainFragment, ReadState1),
- case ssl_record:is_correct_mac(Mac, MacHash) of
- true ->
- {Plain, CompressionS1} = ssl_record:uncompress(CompressAlg,
- PlainFragment, CompressionS0),
- ConnnectionStates = ConnnectionStates0#connection_states{
- current_read = ReadState1#connection_state{
- sequence_number = Seq + 1,
- compression_state = CompressionS1}},
- {CipherText#ssl_tls{fragment = Plain}, ConnnectionStates};
- false ->
- ?ALERT_REC(?FATAL, ?BAD_RECORD_MAC)
- end.
-
+ case ssl_record:decipher(Version, CipherFragment, ReadState0) of
+ {PlainFragment, Mac, ReadState1} ->
+ MacHash = calc_mac_hash(Type, Version, PlainFragment, ReadState1),
+ case ssl_record:is_correct_mac(Mac, MacHash) of
+ true ->
+ {Plain, CompressionS1} = ssl_record:uncompress(CompressAlg,
+ PlainFragment, CompressionS0),
+ ConnnectionStates = ConnnectionStates0#connection_states{
+ current_read = ReadState1#connection_state{
+ sequence_number = Seq + 1,
+ compression_state = CompressionS1}},
+ {CipherText#ssl_tls{fragment = Plain}, ConnnectionStates};
+ false ->
+ ?ALERT_REC(?FATAL, ?BAD_RECORD_MAC)
+ end;
+ #alert{} = Alert ->
+ Alert
+ end.
%%--------------------------------------------------------------------
-spec protocol_version(tls_atom_version() | tls_version()) ->
tls_version() | tls_atom_version().
diff --git a/lib/ssl/test/make_certs.erl b/lib/ssl/test/make_certs.erl
index c438ae2b87..15a7e118ff 100644
--- a/lib/ssl/test/make_certs.erl
+++ b/lib/ssl/test/make_certs.erl
@@ -32,6 +32,7 @@
v2_crls = true,
ecc_certs = false,
issuing_distribution_point = false,
+ crl_port = 8000,
openssl_cmd = "openssl"}).
@@ -57,6 +58,8 @@ make_config([{default_bits, Bits}|T], C) when is_integer(Bits) ->
make_config(T, C#config{default_bits = Bits});
make_config([{v2_crls, Bool}|T], C) when is_boolean(Bool) ->
make_config(T, C#config{v2_crls = Bool});
+make_config([{crl_port, Port}|T], C) when is_integer(Port) ->
+ make_config(T, C#config{crl_port = Port});
make_config([{ecc_certs, Bool}|T], C) when is_boolean(Bool) ->
make_config(T, C#config{ecc_certs = Bool});
make_config([{issuing_distribution_point, Bool}|T], C) when is_boolean(Bool) ->
@@ -344,7 +347,7 @@ req_cnf(C) ->
"default_bits = ", integer_to_list(C#config.default_bits), "\n"
"RANDFILE = $ROOTDIR/RAND\n"
"encrypt_key = no\n"
- "default_md = sha1\n"
+ "default_md = md5\n"
"#string_mask = pkix\n"
"x509_extensions = ca_ext\n"
"prompt = no\n"
@@ -390,7 +393,7 @@ ca_cnf(C) ->
["crl_extensions = crl_ext\n" || C#config.v2_crls],
"unique_subject = no\n"
"default_days = 3600\n"
- "default_md = sha256\n"
+ "default_md = md5\n"
"preserve = no\n"
"policy = policy_match\n"
"\n"
@@ -423,7 +426,7 @@ ca_cnf(C) ->
"[crl_section]\n"
%% intentionally invalid
"URI.1=http://localhost/",C#config.commonName,"/crl.pem\n"
- "URI.2=http://localhost:8000/",C#config.commonName,"/crl.pem\n"
+ "URI.2=http://localhost:",integer_to_list(C#config.crl_port),"/",C#config.commonName,"/crl.pem\n"
"\n"
"[user_cert_digital_signature_only]\n"
diff --git a/lib/ssl/test/ssl_basic_SUITE.erl b/lib/ssl/test/ssl_basic_SUITE.erl
index 0148e1f5bc..406be65c3b 100644
--- a/lib/ssl/test/ssl_basic_SUITE.erl
+++ b/lib/ssl/test/ssl_basic_SUITE.erl
@@ -115,11 +115,13 @@ options_tests() ->
reuseaddr,
tcp_reuseaddr,
honor_server_cipher_order,
- honor_client_cipher_order
+ honor_client_cipher_order,
+ ciphersuite_vs_version
].
api_tests() ->
- [connection_info,
+ [new_options_in_accept,
+ connection_info,
peername,
peercert,
peercert_with_client_cert,
@@ -186,7 +188,10 @@ error_handling_tests()->
tcp_error_propagation_in_active_mode,
tcp_connect,
tcp_connect_big,
- close_transport_accept
+ close_transport_accept,
+ recv_active,
+ recv_active_once,
+ dont_crash_on_handshake_garbage
].
rizzo_tests() ->
@@ -325,6 +330,37 @@ alerts(Config) when is_list(Config) ->
end
end, Alerts).
%%--------------------------------------------------------------------
+new_options_in_accept() ->
+ [{doc,"Test that you can set ssl options in ssl_accept/3 and not tcp upgrade"}].
+new_options_in_accept(Config) when is_list(Config) ->
+ ClientOpts = ?config(client_opts, Config),
+ ServerOpts = ?config(server_opts, Config),
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+ Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {ssl_opts, [{versions, [sslv3]},
+ {ciphers,[{rsa,rc4_128,sha}]}]}, %% To be set in ssl_accept/3
+ {mfa, {?MODULE, connection_info_result, []}},
+ {options, ServerOpts}]),
+
+ Port = ssl_test_lib:inet_port(Server),
+ Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {mfa, {?MODULE, connection_info_result, []}},
+ {options, [{versions, [sslv3]} | ClientOpts]}]),
+
+ ct:log("Testcase ~p, Client ~p Server ~p ~n",
+ [self(), Client, Server]),
+
+ ServerMsg = ClientMsg = {ok, {sslv3, {rsa, rc4_128, sha}}},
+
+ ssl_test_lib:check_result(Server, ServerMsg, Client, ClientMsg),
+
+ ssl_test_lib:close(Server),
+ ssl_test_lib:close(Client).
+%%--------------------------------------------------------------------
+
connection_info() ->
[{doc,"Test the API function ssl:connection_info/1"}].
connection_info(Config) when is_list(Config) ->
@@ -1122,6 +1158,57 @@ close_transport_accept(Config) when is_list(Config) ->
Other ->
exit({?LINE, Other})
end.
+%%--------------------------------------------------------------------
+recv_active() ->
+ [{doc,"Test recv on active socket"}].
+
+recv_active(Config) when is_list(Config) ->
+ ClientOpts = ?config(client_opts, Config),
+ ServerOpts = ?config(server_opts, Config),
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+ Server =
+ ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {mfa, {?MODULE, try_recv_active, []}},
+ {options, [{active, true} | ServerOpts]}]),
+ Port = ssl_test_lib:inet_port(Server),
+ Client =
+ ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {mfa, {?MODULE, try_recv_active, []}},
+ {options, [{active, true} | ClientOpts]}]),
+
+ ssl_test_lib:check_result(Server, ok, Client, ok),
+
+ ssl_test_lib:close(Server),
+ ssl_test_lib:close(Client).
+
+%%--------------------------------------------------------------------
+recv_active_once() ->
+ [{doc,"Test recv on active socket"}].
+
+recv_active_once(Config) when is_list(Config) ->
+ ClientOpts = ?config(client_opts, Config),
+ ServerOpts = ?config(server_opts, Config),
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+ Server =
+ ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {mfa, {?MODULE, try_recv_active_once, []}},
+ {options, [{active, once} | ServerOpts]}]),
+ Port = ssl_test_lib:inet_port(Server),
+ Client =
+ ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {mfa, {?MODULE, try_recv_active_once, []}},
+ {options, [{active, once} | ClientOpts]}]),
+
+ ssl_test_lib:check_result(Server, ok, Client, ok),
+
+ ssl_test_lib:close(Server),
+ ssl_test_lib:close(Client).
%%--------------------------------------------------------------------
dh_params() ->
@@ -2527,6 +2614,81 @@ honor_cipher_order(Config, Honor, ServerCiphers, ClientCiphers, Expected) ->
ssl_test_lib:close(Client).
%%--------------------------------------------------------------------
+ciphersuite_vs_version(Config) when is_list(Config) ->
+
+ {_ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+ ServerOpts = ?config(server_opts, Config),
+
+ Server = ssl_test_lib:start_server_error([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {options, ServerOpts}]),
+ Port = ssl_test_lib:inet_port(Server),
+
+ {ok, Socket} = gen_tcp:connect(Hostname, Port, [binary, {active, false}]),
+ ok = gen_tcp:send(Socket,
+ <<22, 3,0, 49:16, % handshake, SSL 3.0, length
+ 1, 45:24, % client_hello, length
+ 3,0, % SSL 3.0
+ 16#deadbeef:256, % 32 'random' bytes = 256 bits
+ 0, % no session ID
+ %% three cipher suites -- null, one with sha256 hash and one with sha hash
+ 6:16, 0,255, 0,61, 0,57,
+ 1, 0 % no compression
+ >>),
+ {ok, <<22, RecMajor:8, RecMinor:8, _RecLen:16, 2, HelloLen:24>>} = gen_tcp:recv(Socket, 9, 10000),
+ {ok, <<HelloBin:HelloLen/binary>>} = gen_tcp:recv(Socket, HelloLen, 5000),
+ ServerHello = tls_handshake:decode_handshake({RecMajor, RecMinor}, 2, HelloBin),
+ case ServerHello of
+ #server_hello{server_version = {3,0}, cipher_suite = <<0,57>>} ->
+ ok;
+ _ ->
+ ct:fail({unexpected_server_hello, ServerHello})
+ end.
+
+%%--------------------------------------------------------------------
+
+dont_crash_on_handshake_garbage() ->
+ [{doc, "Ensure SSL server worker thows an alert on garbage during handshake "
+ "instead of crashing and exposing state to user code"}].
+
+dont_crash_on_handshake_garbage(Config) ->
+ ServerOpts = ?config(server_opts, Config),
+
+ {_ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+
+ Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {mfa, {ssl_test_lib, send_recv_result_active, []}},
+ {options, ServerOpts}]),
+ unlink(Server), monitor(process, Server),
+ Port = ssl_test_lib:inet_port(Server),
+
+ {ok, Socket} = gen_tcp:connect(Hostname, Port, [binary, {active, false}]),
+
+ % Send hello and garbage record
+ ok = gen_tcp:send(Socket,
+ [<<22, 3,3, 49:16, 1, 45:24, 3,3, % client_hello
+ 16#deadbeef:256, % 32 'random' bytes = 256 bits
+ 0, 6:16, 0,255, 0,61, 0,57, 1, 0 >>, % some hello values
+
+ <<22, 3,3, 5:16, 92,64,37,228,209>> % garbage
+ ]),
+ % Send unexpected change_cipher_spec
+ ok = gen_tcp:send(Socket, <<20, 0,0,12, 111,40,244,7,137,224,16,109,197,110,249,152>>),
+
+ % Ensure we receive an alert, not sudden disconnect
+ {ok, <<21, _/binary>>} = drop_handshakes(Socket, 1000).
+
+drop_handshakes(Socket, Timeout) ->
+ {ok, <<RecType:8, _RecMajor:8, _RecMinor:8, RecLen:16>> = Header} = gen_tcp:recv(Socket, 5, Timeout),
+ {ok, <<Frag:RecLen/binary>>} = gen_tcp:recv(Socket, RecLen, Timeout),
+ case RecType of
+ 22 -> drop_handshakes(Socket, Timeout);
+ _ -> {ok, <<Header/binary, Frag/binary>>}
+ end.
+
+
+%%--------------------------------------------------------------------
hibernate() ->
[{doc,"Check that an SSL connection that is started with option "
@@ -3550,3 +3712,11 @@ version_option_test(Config, Version) ->
ssl_test_lib:close(Server),
ssl_test_lib:close(Client).
+
+try_recv_active(Socket) ->
+ ssl:send(Socket, "Hello world"),
+ {error, einval} = ssl:recv(Socket, 11),
+ ok.
+try_recv_active_once(Socket) ->
+ {error, einval} = ssl:recv(Socket, 11),
+ ok.
diff --git a/lib/ssl/test/ssl_crl_SUITE.erl b/lib/ssl/test/ssl_crl_SUITE.erl
index da0349904c..bad0949ec4 100644
--- a/lib/ssl/test/ssl_crl_SUITE.erl
+++ b/lib/ssl/test/ssl_crl_SUITE.erl
@@ -48,8 +48,8 @@ all() ->
].
groups() ->
- [{basic, [], basic_tests()},
- {v1_crl, [], v1_crl_tests()},
+ [{basic, [], basic_tests()},
+ {v1_crl, [], v1_crl_tests()},
{idp_crl, [], idp_crl_tests()}].
basic_tests() ->
@@ -72,8 +72,8 @@ init_per_suite(Config0) ->
_ ->
TLSVersion = ?config(tls_version, Config0),
OpenSSL_version = (catch os:cmd("openssl version")),
- ct:log("TLS version: ~p~nOpenSSL version: ~p~n~n~p:module_info(): ~p~n~nssh:module_info(): ~p~n",
- [TLSVersion, OpenSSL_version, ?MODULE, ?MODULE:module_info(), ssh:module_info()]),
+ ct:log("TLS version: ~p~nOpenSSL version: ~p~n~n~p:module_info(): ~p~n~nssl:module_info(): ~p~n",
+ [TLSVersion, OpenSSL_version, ?MODULE, ?MODULE:module_info(), ssl:module_info()]),
case ssl_test_lib:enough_openssl_crl_support(OpenSSL_version) of
false ->
{skip, io_lib:format("Bad openssl version: ~p",[OpenSSL_version])};
@@ -82,7 +82,13 @@ init_per_suite(Config0) ->
try crypto:start() of
ok ->
ssl:start(),
- [{watchdog, Dog}, {openssl_version,OpenSSL_version} | Config0]
+ {ok, Hostname0} = inet:gethostname(),
+ IPfamily =
+ case lists:member(list_to_atom(Hostname0), ct:get_config(ipv6_hosts,[])) of
+ true -> inet6;
+ false -> inet
+ end,
+ [{ipfamily,IPfamily}, {watchdog, Dog}, {openssl_version,OpenSSL_version} | Config0]
catch _C:_E ->
ct:log("crypto:start() caught ~p:~p",[_C,_E]),
{skip, "Crypto did not start"}
@@ -98,21 +104,23 @@ end_per_suite(_Config) ->
%%% Group init/end
init_per_group(Group, Config) ->
- ct:log("~p:~p~nlisteners to port 8000:~n~p~n)",[?MODULE,?LINE,os:cmd("netstat -tln|grep ':8000'")]),
ssl:start(),
inets:start(),
CertDir = filename:join(?config(priv_dir, Config), Group),
DataDir = ?config(data_dir, Config),
ServerRoot = make_dir_path([?config(priv_dir,Config), Group, tmp]),
- Result = make_certs:all(DataDir, CertDir, cert_opts(Group)),
- ct:log("~p:~p~nmake_certs:all(~n DataDir=~p,~n CertDir=~p,~n ServerRoot=~p~n Opts=~p~n) returned ~p~n", [?MODULE,?LINE,DataDir, CertDir, ServerRoot, cert_opts(Group), Result]),
%% start a HTTP server to serve the CRLs
- {ok, Httpd} = inets:start(httpd, [{server_name, "localhost"}, {port, 8000},
+ {ok, Httpd} = inets:start(httpd, [{ipfamily, ?config(ipfamily,Config)},
+ {server_name, "localhost"}, {port, 0},
{server_root, ServerRoot},
{document_root, CertDir},
{modules, [mod_get]}
]),
- ct:log("~p:~p~nlisteners to port 8000:~n~p~n)",[?MODULE,?LINE,os:cmd("netstat -tln|grep ':8000'")]),
+ [{port,Port}] = httpd:info(Httpd, [port]),
+ ct:log("~p:~p~nHTTPD IP family=~p, port=~p~n", [?MODULE, ?LINE, ?config(ipfamily,Config), Port]),
+ CertOpts = [{crl_port,Port}|cert_opts(Group)],
+ Result = make_certs:all(DataDir, CertDir, CertOpts),
+ ct:log("~p:~p~nmake_certs:all(~n DataDir=~p,~n CertDir=~p,~n ServerRoot=~p~n Opts=~p~n) returned ~p~n", [?MODULE,?LINE,DataDir, CertDir, ServerRoot, CertOpts, Result]),
[{make_cert_result, Result}, {cert_dir, CertDir}, {httpd, Httpd} | Config].
cert_opts(v1_crl) -> [{v2_crls, false}];
@@ -134,7 +142,6 @@ end_per_group(_GroupName, Config) ->
,ct:log("Stopped",[])
end,
inets:stop(),
- ct:log("~p:~p~nlisteners to port 8000:~n~p~n)",[?MODULE,?LINE,os:cmd("netstat -tln|grep ':8000'")]),
Config.
%%%================================================================
@@ -481,7 +488,6 @@ fetch([]) ->
not_available;
fetch([{uniformResourceIdentifier, "http"++_=URL}|Rest]) ->
ct:log("~p:~p~ngetting CRL from ~p~n", [?MODULE,?LINE, URL]),
- ct:log("~p:~p~nlisteners to port 8000:~n~p~n)",[?MODULE,?LINE,os:cmd("netstat -tln|grep ':8000'")]),
case httpc:request(get, {URL, []}, [], [{body_format, binary}]) of
{ok, {_Status, _Headers, Body}} ->
case Body of
@@ -494,9 +500,15 @@ fetch([{uniformResourceIdentifier, "http"++_=URL}|Rest]) ->
_ ->
ct:log("~p:~p~npublic_key:pem_entry_decode,~nBody=~p~n)",[?MODULE,?LINE,{'CertificateList', Body, not_encrypted}]),
%% assume DER encoded
- CertList = public_key:pem_entry_decode(
- {'CertificateList', Body, not_encrypted}),
- {Body, CertList}
+ try
+ public_key:pem_entry_decode({'CertificateList', Body, not_encrypted})
+ of
+ CertList -> {Body, CertList}
+ catch
+ _C:_E ->
+ ct:log("~p:~p~nfailed DER assumption~nRest=~p", [?MODULE,?LINE,Rest]),
+ fetch(Rest)
+ end
end;
{error, _Reason} ->
ct:log("~p:~p~nfailed to get CRL ~p~n", [?MODULE,?LINE, _Reason]),
diff --git a/lib/ssl/test/ssl_handshake_SUITE.erl b/lib/ssl/test/ssl_handshake_SUITE.erl
index 6d020c472b..5f36842f9e 100644
--- a/lib/ssl/test/ssl_handshake_SUITE.erl
+++ b/lib/ssl/test/ssl_handshake_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2013. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2014. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -26,6 +26,7 @@
-include_lib("common_test/include/ct.hrl").
-include("ssl_internal.hrl").
-include("tls_handshake.hrl").
+-include_lib("public_key/include/public_key.hrl").
%%--------------------------------------------------------------------
%% Common Test interface functions -----------------------------------
@@ -36,7 +37,8 @@ all() -> [decode_hello_handshake,
decode_single_hello_extension_correctly,
decode_supported_elliptic_curves_hello_extension_correctly,
decode_unknown_hello_extension_correctly,
- encode_single_hello_sni_extension_correctly].
+ encode_single_hello_sni_extension_correctly,
+ select_proper_tls_1_2_rsa_default_hashsign].
%%--------------------------------------------------------------------
%% Test Cases --------------------------------------------------------
@@ -95,3 +97,11 @@ encode_single_hello_sni_extension_correctly(_Config) ->
HelloExt = <<ExtSize:16/unsigned-big-integer, SNI/binary>>,
Encoded = ssl_handshake:encode_hello_extensions(Exts),
HelloExt = Encoded.
+
+select_proper_tls_1_2_rsa_default_hashsign(_Config) ->
+ % RFC 5246 section 7.4.1.4.1 tells to use {sha1,rsa} as default signature_algorithm for RSA key exchanges
+ {sha, rsa} = ssl_handshake:select_hashsign_algs(undefined, ?rsaEncryption, {3,3}),
+ % Older versions use MD5/SHA1 combination
+ {md5sha, rsa} = ssl_handshake:select_hashsign_algs(undefined, ?rsaEncryption, {3,2}),
+ {md5sha, rsa} = ssl_handshake:select_hashsign_algs(undefined, ?rsaEncryption, {3,0}).
+
diff --git a/lib/ssl/test/ssl_test_lib.erl b/lib/ssl/test/ssl_test_lib.erl
index 7d8ece8d19..59f10d53a6 100644
--- a/lib/ssl/test/ssl_test_lib.erl
+++ b/lib/ssl/test/ssl_test_lib.erl
@@ -106,7 +106,8 @@ connect(#sslsocket{} = ListenSocket, Opts) ->
Node = proplists:get_value(node, Opts),
ReconnectTimes = proplists:get_value(reconnect_times, Opts, 0),
Timeout = proplists:get_value(timeout, Opts, infinity),
- AcceptSocket = connect(ListenSocket, Node, 1 + ReconnectTimes, dummy, Timeout),
+ SslOpts = proplists:get_value(ssl_opts, Opts, []),
+ AcceptSocket = connect(ListenSocket, Node, 1 + ReconnectTimes, dummy, Timeout, SslOpts),
case ReconnectTimes of
0 ->
AcceptSocket;
@@ -121,24 +122,30 @@ connect(ListenSocket, Opts) ->
[ListenSocket]),
AcceptSocket.
-connect(_, _, 0, AcceptSocket, _) ->
+connect(_, _, 0, AcceptSocket, _, _) ->
AcceptSocket;
-connect(ListenSocket, Node, N, _, Timeout) ->
- ct:log("~p:~p~nssl:transport_accept(~p)~n", [?MODULE,?LINE, ListenSocket]),
+
+connect(ListenSocket, Node, N, _, Timeout, []) ->
+ ct:log("ssl:transport_accept(~p)~n", [ListenSocket]),
{ok, AcceptSocket} = rpc:call(Node, ssl, transport_accept,
[ListenSocket]),
ct:log("~p:~p~nssl:ssl_accept(~p, ~p)~n", [?MODULE,?LINE, AcceptSocket, Timeout]),
case rpc:call(Node, ssl, ssl_accept, [AcceptSocket, Timeout]) of
ok ->
-ct:log("~p:~p~nok from ssl:ssl_accept@~p",[?MODULE,?LINE, Node]),
- connect(ListenSocket, Node, N-1, AcceptSocket, Timeout);
+ connect(ListenSocket, Node, N-1, AcceptSocket, Timeout, []);
Result ->
-ct:log("~p:~p~nssl:ssl_accept@~p ret ~p",[?MODULE,?LINE, Node,Result]),
+ ct:log("~p:~p~nssl:ssl_accept@~p ret ~p",[?MODULE,?LINE, Node,Result]),
Result
- end.
+ end;
+connect(ListenSocket, Node, _, _, Timeout, Opts) ->
+ ct:log("ssl:transport_accept(~p)~n", [ListenSocket]),
+ {ok, AcceptSocket} = rpc:call(Node, ssl, transport_accept,
+ [ListenSocket]),
+ ct:log("ssl:ssl_accept(~p,~p, ~p)~n", [AcceptSocket, Opts, Timeout]),
+ rpc:call(Node, ssl, ssl_accept, [AcceptSocket, Opts, Timeout]),
+ AcceptSocket.
-
remove_close_msg(0) ->
ok;
remove_close_msg(ReconnectTimes) ->
diff --git a/lib/stdlib/doc/src/notes.xml b/lib/stdlib/doc/src/notes.xml
index e94a4d6a55..15e6fdfa9f 100644
--- a/lib/stdlib/doc/src/notes.xml
+++ b/lib/stdlib/doc/src/notes.xml
@@ -30,6 +30,390 @@
</header>
<p>This document describes the changes made to the STDLIB application.</p>
+<section><title>STDLIB 2.0</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ The option dupnames did not work as intended in re. When
+ looking for names with {capture, [Name, ...]}, re:run
+ returned a random instance of the match for that name,
+ instead of the leftmost matching instance, which was what
+ the documentation stated. This is now corrected to adhere
+ to the documentation. The option {capture,all_names}
+ along with a re:inspect/2 function is also added to
+ further help in using named subpatterns.</p>
+ <p>
+ Own Id: OTP-11205</p>
+ </item>
+ <item>
+ <p>
+ If option 'binary' was set for standard_input, then c:i()
+ would hang if the output was more than one page long -
+ i.e. then input after "(c)ontinue (q)uit --&gt;" could
+ not be read. This has been corrected. (Thanks to José
+ Valim)</p>
+ <p>
+ Own Id: OTP-11589</p>
+ </item>
+ <item>
+ <p>
+ stdlib/lists: Add function droplast/1 This functions
+ drops the last element of a non-empty list. lists:last/1
+ and lists:droplast/1 are the dual of hd/1 and tl/1 but
+ for the end of a list. (Thanks to Hans Svensson)</p>
+ <p>
+ Own Id: OTP-11677</p>
+ </item>
+ <item>
+ <p>
+ Allow all auto imports to be suppressed at once.
+ Introducing the no_auto_import attribute:
+ -compile(no_auto_import). Useful for code generation
+ tools that always use the qualified function names and
+ want to avoid the auto imported functions clashing with
+ local ones. (Thanks to José Valim.)</p>
+ <p>
+ Own Id: OTP-11682</p>
+ </item>
+ <item>
+ <p>
+ supervisor_bridge does no longer report normal
+ termination of children. The reason is that in some
+ cases, for instance when the restart strategy is
+ simple_one_for_one, the log could be completely
+ overloaded with reports about normally terminating
+ processes. (Thanks to Artem Ocheredko)</p>
+ <p>
+ Own Id: OTP-11685</p>
+ </item>
+ <item>
+ <p> The type annotations for alternative registries using
+ the {via, Module, Name} syntax for sup_name() and
+ sup_ref() in the supervisor module are now consistent
+ with the documentation. Dialyzer should no longer
+ complain about valid supervisor:start_link() and
+ supervisor:start_child() calls. (Thanks to Caleb
+ Helbling.) </p>
+ <p>
+ Own Id: OTP-11707</p>
+ </item>
+ <item>
+ <p> Two Dets bugs have been fixed. When trying to open a
+ short file that is not a Dets file, the file was deleted
+ even with just read access. Calling
+ <c>dets:is_dets_file/1</c> with a file that is not a Dets
+ file, a file descriptor was left open. (Thanks to HÃ¥kan
+ Mattsson for reporting the bugs.) </p>
+ <p>
+ Own Id: OTP-11709</p>
+ </item>
+ <item>
+ <p>
+ Fix race bug in <c>ets:all</c>. Concurrent creation of
+ tables could cause other tables to not be included in the
+ result. (Thanks to Florian Schintke for bug report)</p>
+ <p>
+ Own Id: OTP-11726</p>
+ </item>
+ <item>
+ <p>
+ erl_eval now properly evaluates '=='/2 when it is used in
+ guards. (Thanks to José Valim)</p>
+ <p>
+ Own Id: OTP-11747</p>
+ </item>
+ <item>
+ <p>
+ Calls to proplists:get_value/3 are replaced by the faster
+ lists:keyfind/3 in io_lib_pretty. Elements in the list
+ are always 2-tuples. (Thanks to Andrew Thompson)</p>
+ <p>
+ Own Id: OTP-11752</p>
+ </item>
+ <item>
+ <p> A qlc bug where filters were erroneously optimized
+ away has been fixed. Thanks to Sam Bobroff for reporting
+ the bug. </p>
+ <p>
+ Own Id: OTP-11758</p>
+ </item>
+ <item>
+ <p>
+ A number of compiler errors where unusual or nonsensical
+ code would crash the compiler have been reported by Ulf
+ Norell and corrected by Anthony Ramine.</p>
+ <p>
+ Own Id: OTP-11770</p>
+ </item>
+ <item>
+ <p> Since Erlang/OTP R16B the Erlang Core Linter
+ (<c>erl_lint</c>) has not emitted errors when built-in
+ types were re-defined. This bug has been fixed. (Thanks
+ to Roberto Aloi.) </p>
+ <p>
+ Own Id: OTP-11772</p>
+ </item>
+ <item>
+ <p>
+ The functions <c>sys:get_state/1,2</c> and
+ <c>sys:replace_state/2,3</c> are fixed so they can now be
+ run while the process is sys suspended. To accomplish
+ this, the new callbacks <c>Mod:system_get_state/1</c> and
+ <c>Mod:system_replace_state/2</c> are added, which are
+ also implemented by the generic behaviours
+ <c>gen_server</c>, <c>gen_event</c> and <c>gen_fsm</c>.</p>
+ <p>
+ The potential incompatibility refers to</p>
+ <p>
+ <list> <item>The previous behaviour of intercepting the
+ system message and passing a tuple of size 2 as the last
+ argument to <c>sys:handle_system_msg/6</c> is no longer
+ supported.</item> <item>The error handling when
+ <c>StateFun</c> in <c>sys:replace_state/2,3</c> fails is
+ changed from being totally silent to possibly (if the
+ callback module does not catch) throw an exception in the
+ client process.</item> </list></p>
+ <p>
+ (Thanks to James Fish and Steve Vinoski)</p>
+ <p>
+ *** POTENTIAL INCOMPATIBILITY ***</p>
+ <p>
+ Own Id: OTP-11817</p>
+ </item>
+ </list>
+ </section>
+
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p>
+ Options to set match_limit and match_limit_recursion are
+ added to re:run. The option report_errors is also added
+ to get more information when re:run fails due to limits
+ or compilation errors.</p>
+ <p>
+ Own Id: OTP-10285</p>
+ </item>
+ <item>
+ <p> The pre-defined types <c>array/0</c>, <c>dict/0</c>,
+ <c>digraph/0</c>, <c>gb_set/0</c>, <c>gb_tree/0</c>,
+ <c>queue/0</c>, <c>set/0</c>, and <c>tid/0</c> have been
+ deprecated. They will be removed in Erlang/OTP 18.0. </p>
+ <p> Instead the types <c>array:array/0</c>,
+ <c>dict:dict/0</c>, <c>digraph:graph/0</c>,
+ <c>gb_set:set/0</c>, <c>gb_tree:tree/0</c>,
+ <c>queue:queue/0</c>, <c>sets:set/0</c>, and
+ <c>ets:tid/0</c> can be used. (Note: it has always been
+ necessary to use <c>ets:tid/0</c>.) </p> <p> It is
+ allowed in Erlang/OTP 17.0 to locally re-define the types
+ <c>array/0</c>, <c>dict/0</c>, and so on. </p> <p> New
+ types <c>array:array/1</c>, <c>dict:dict/2</c>,
+ <c>gb_sets:set/1</c>, <c>gb_trees:tree/2</c>,
+ <c>queue:queue/1</c>, and <c>sets:set/1</c> have been
+ added. </p> <p> A compiler option,
+ <c>nowarn_deprecated_type</c>, has been introduced. By
+ including the attribute </p> <c>
+ -compile(nowarn_deprecated_type).</c> <p> in an Erlang
+ source file, warnings about deprecated types can be
+ avoided in Erlang/OTP 17.0. </p> <p> The option can also
+ be given as a compiler flag: </p> <c> erlc
+ +nowarn_deprecated_type file.erl</c>
+ <p>
+ Own Id: OTP-10342</p>
+ </item>
+ <item>
+ <p>
+ Calls to erlang:open_port/2 with 'spawn' are updated to
+ handle space in the command path.</p>
+ <p>
+ Own Id: OTP-10842</p>
+ </item>
+ <item>
+ <p> Dialyzer's <c>unmatched_return</c> warnings have been
+ corrected. </p>
+ <p>
+ Own Id: OTP-10908</p>
+ </item>
+ <item>
+ <p>
+ Forbid unsized fields in patterns of binary generators
+ and simplified v3_core's translation of bit string
+ generators. (Thanks to Anthony Ramine.)</p>
+ <p>
+ Own Id: OTP-11186</p>
+ </item>
+ <item>
+ <p>
+ The version of the PCRE library Used by Erlang's re
+ module is raised to 8.33 from 7.6. This means, among
+ other things, better Unicode and Unicode Character
+ Properties support. New options connected to PCRE 8.33
+ are also added to the re module (ucd, notempty_atstart,
+ no_start_optimize). PCRE has extended the regular
+ expression syntax between 7.6 and 8.33, why this imposes
+ a potential incompatibility. Only very complicated
+ regular expressions may be affected, but if you know you
+ are using obscure features, please test run your regular
+ expressions and verify that their behavior has not
+ changed.</p>
+ <p>
+ *** POTENTIAL INCOMPATIBILITY ***</p>
+ <p>
+ Own Id: OTP-11204</p>
+ </item>
+ <item>
+ <p>
+ Added dict:is_empty/1 and orddict:is_empty/1. (Thanks to
+ Magnus Henoch.)</p>
+ <p>
+ Own Id: OTP-11353</p>
+ </item>
+ <item>
+ <p>
+ A call to either the <c>garbage_collect/1</c> BIF or the
+ <c>check_process_code/2</c> BIF may trigger garbage
+ collection of another processes than the process calling
+ the BIF. The previous implementations performed these
+ kinds of garbage collections without considering the
+ internal state of the process being garbage collected. In
+ order to be able to more easily and more efficiently
+ implement yielding native code, these types of garbage
+ collections have been rewritten. A garbage collection
+ like this is now triggered by an asynchronous request
+ signal, the actual garbage collection is performed by the
+ process being garbage collected itself, and finalized by
+ a reply signal to the process issuing the request. Using
+ this approach processes can disable garbage collection
+ and yield without having to set up the heap in a state
+ that can be garbage collected.</p>
+ <p>
+ The <seealso
+ marker="erts:erlang#garbage_collect/2"><c>garbage_collect/2</c></seealso>,
+ and <seealso
+ marker="erts:erlang#check_process_code/3"><c>check_process_code/3</c></seealso>
+ BIFs have been introduced. Both taking an option list as
+ last argument. Using these, one can issue asynchronous
+ requests.</p>
+ <p>
+ <c>code:purge/1</c> and <c>code:soft_purge/1</c> have
+ been rewritten to utilize asynchronous
+ <c>check_process_code</c> requests in order to
+ parallelize work.</p>
+ <p>
+ Characteristics impact: A call to the
+ <c>garbage_collect/1</c> BIF or the
+ <c>check_process_code/2</c> BIF will normally take longer
+ time to complete while the system as a whole wont be as
+ much negatively effected by the operation as before. A
+ call to <c>code:purge/1</c> and <c>code:soft_purge/1</c>
+ may complete faster or slower depending on the state of
+ the system while the system as a whole wont be as much
+ negatively effected by the operation as before.</p>
+ <p>
+ Own Id: OTP-11388 Aux Id: OTP-11535, OTP-11648 </p>
+ </item>
+ <item>
+ <p> Improve the documentation of the supervisor's
+ <c>via</c> reference. (Thanks to MaximMinin.) </p>
+ <p>
+ Own Id: OTP-11399</p>
+ </item>
+ <item>
+ <p><c>orddict:from_list/1</c> now uses the optimized sort
+ routines in the <c>lists</c> module instead of
+ (essentially) an insertion sort. Depending on the input
+ data, the speed of the new <c>from_list/1</c> is anything
+ from slightly faster up to several orders of magnitude
+ faster than the old <c>from_list/1</c>.</p> (Thanks to
+ Steve Vinoski.)
+ <p>
+ Own Id: OTP-11552</p>
+ </item>
+ <item>
+ <p>
+ EEP43: New data type - Maps</p>
+ <p>
+ With Maps you may for instance: <taglist> <item><c>M0 =
+ #{ a =&gt; 1, b =&gt; 2}, % create
+ associations</c></item> <item><c>M1 = M0#{ a := 10 }, %
+ update values</c></item> <item><c>M2 = M1#{ "hi" =&gt;
+ "hello"}, % add new associations</c></item> <item><c>#{
+ "hi" := V1, a := V2, b := V3} = M2. % match keys with
+ values</c></item> </taglist></p>
+ <p>
+ For information on how to use Maps please see the
+ <seealso marker="doc/reference_manual:maps">Reference
+ Manual</seealso>.</p>
+ <p>
+ The current implementation is without the following
+ features: <taglist> <item>No variable keys</item>
+ <item>No single value access</item> <item>No map
+ comprehensions</item> </taglist></p>
+ <p>
+ Note that Maps is <em>experimental</em> during OTP 17.0.</p>
+ <p>
+ Own Id: OTP-11616</p>
+ </item>
+ <item>
+ <p>
+ When tab completing the erlang shell now expands
+ zero-arity functions all the way to closing parenthesis,
+ unless there is another function with the same name and a
+ different arity. (Thanks to Pierre Fenoll.)</p>
+ <p>
+ Own Id: OTP-11684</p>
+ </item>
+ <item>
+ <p> The Erlang Code Preprocessor (<c>epp</c>) could loop
+ when encountering a circular macro definition in an
+ included file. This bug has been fixed. </p> <p> Thanks
+ to Maruthavanan Subbarayan for reporting the bug, and to
+ Richard Carlsson for providing a bug fix. </p>
+ <p>
+ Own Id: OTP-11728</p>
+ </item>
+ <item>
+ <p> The Erlang Code Linter (<c>erl_lint</c>) has since
+ Erlang/OTP R13B emitted warnings whenever any of the
+ types <c>arity()</c>, <c>bitstring()</c>,
+ <c>iodata()</c>, or <c>boolean()</c> were re-defined. Now
+ errors are emitted instead. </p>
+ <p>
+ *** POTENTIAL INCOMPATIBILITY ***</p>
+ <p>
+ Own Id: OTP-11771</p>
+ </item>
+ <item>
+ <p> The <c>encoding</c> option of
+ <c>erl_parse:abstract/2</c> has been extended to include
+ <c>none</c> and a callback function (a predicate). </p>
+ <p>
+ Own Id: OTP-11807</p>
+ </item>
+ <item>
+ <p>
+ Export zip option types to allow referal from other
+ modules.</p>
+ <p>
+ Thanks to Pierre Fenoll and HÃ¥kan Mattson</p>
+ <p>
+ Own Id: OTP-11828</p>
+ </item>
+ <item>
+ <p>
+ The module <c>pg</c> has been deprecated and will be
+ removed in Erlang/OTP 18.</p>
+ <p>
+ Own Id: OTP-11840</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>STDLIB 1.19.4</title>
<section><title>Fixed Bugs and Malfunctions</title>
diff --git a/lib/stdlib/doc/src/pg.xml b/lib/stdlib/doc/src/pg.xml
index 7cc1b805b4..a3b69884b6 100644
--- a/lib/stdlib/doc/src/pg.xml
+++ b/lib/stdlib/doc/src/pg.xml
@@ -5,7 +5,7 @@
<header>
<copyright>
<year>1996</year>
- <year>2013</year>
+ <year>2014</year>
<holder>Ericsson AB, All Rights Reserved</holder>
</copyright>
<legalnotice>
@@ -32,6 +32,9 @@
<module>pg</module>
<modulesummary>Distributed, Named Process Groups</modulesummary>
<description>
+ <warning>
+ <p>This module is deprecated and will be removed in Erlang/OTP 18.</p>
+ </warning>
<p>This (experimental) module implements process groups. A process
group is a group of processes that can be accessed by a common
name. For example, a group named <c>foobar</c> can include a set
diff --git a/lib/stdlib/examples/erl_id_trans.erl b/lib/stdlib/examples/erl_id_trans.erl
index 5fcb74310e..e71e26e51a 100644
--- a/lib/stdlib/examples/erl_id_trans.erl
+++ b/lib/stdlib/examples/erl_id_trans.erl
@@ -148,7 +148,7 @@ pattern({map,Line,Ps0}) ->
Ps1 = pattern_list(Ps0),
{map,Line,Ps1};
pattern({map_field_exact,Line,K,V}) ->
- Ke = pattern(K),
+ Ke = expr(K),
Ve = pattern(V),
{map_field_exact,Line,Ke,Ve};
%%pattern({struct,Line,Tag,Ps0}) ->
diff --git a/lib/stdlib/src/erl_expand_records.erl b/lib/stdlib/src/erl_expand_records.erl
index f53c6e1278..57e768ba9d 100644
--- a/lib/stdlib/src/erl_expand_records.erl
+++ b/lib/stdlib/src/erl_expand_records.erl
@@ -135,10 +135,10 @@ pattern({tuple,Line,Ps}, St0) ->
pattern({map,Line,Ps}, St0) ->
{TPs,St1} = pattern_list(Ps, St0),
{{map,Line,TPs},St1};
-pattern({map_field_exact,Line,Key0,V0}, St0) ->
- {Key,St1} = pattern(Key0, St0),
+pattern({map_field_exact,Line,K0,V0}, St0) ->
+ {K,St1} = expr(K0, St0),
{V,St2} = pattern(V0, St1),
- {{map_field_exact,Line,Key,V},St2};
+ {{map_field_exact,Line,K,V},St2};
%%pattern({struct,Line,Tag,Ps}, St0) ->
%% {TPs,TPsvs,St1} = pattern_list(Ps, St0),
%% {{struct,Line,Tag,TPs},TPsvs,St1};
diff --git a/lib/stdlib/src/erl_lint.erl b/lib/stdlib/src/erl_lint.erl
index c4c94fbee4..39cc03cf7a 100644
--- a/lib/stdlib/src/erl_lint.erl
+++ b/lib/stdlib/src/erl_lint.erl
@@ -1046,9 +1046,10 @@ check_undefined_types(#lint{usage=Usage,types=Def}=St0) ->
Used = Usage#usage.used_types,
UTAs = dict:fetch_keys(Used),
Undef = [{TA,dict:fetch(TA, Used)} ||
- TA <- UTAs,
+ {T,_}=TA <- UTAs,
not dict:is_key(TA, Def),
- not is_default_type(TA)],
+ not is_default_type(TA),
+ not is_newly_introduced_var_arity_type(T)],
foldl(fun ({TA,L}, St) ->
add_error(L, {undefined_type,TA}, St)
end, St0, Undef).
@@ -1407,7 +1408,7 @@ pattern({map,_Line,Ps}, Vt, Old, Bvt, St) ->
({map_field_assoc,L,_,_}, {Psvt,Bvt0,St0}) ->
{Psvt,Bvt0,add_error(L, illegal_pattern, St0)};
({map_field_exact,L,KP,VP}, {Psvt,Bvt0,St0}) ->
- case is_valid_map_key(KP, St0) of
+ case is_valid_map_key(KP, pattern, St0) of
true ->
{Pvt,Bvt1,St1} = pattern(VP, Vt, Old, Bvt, St0),
{vtmerge_pat(Pvt, Psvt),vtmerge_pat(Bvt0, Bvt1), St1};
@@ -2322,14 +2323,16 @@ is_valid_call(Call) ->
%% check for value expression without variables
is_valid_map_key(K,St) ->
+ is_valid_map_key(K,expr,St).
+is_valid_map_key(K,Ctx,St) ->
case expr(K,[],St) of
{[],_} ->
- is_valid_map_key_value(K);
+ is_valid_map_key_value(K,Ctx);
{[Var|_],_} ->
{false,variable,element(1,Var)}
end.
-is_valid_map_key_value(K) ->
+is_valid_map_key_value(K,Ctx) ->
case K of
{char,_,_} -> true;
{integer,_,_} -> true;
@@ -2338,34 +2341,36 @@ is_valid_map_key_value(K) ->
{nil,_} -> true;
{atom,_,_} -> true;
{cons,_,H,T} ->
- is_valid_map_key_value(H) andalso
- is_valid_map_key_value(T);
+ is_valid_map_key_value(H,Ctx) andalso
+ is_valid_map_key_value(T,Ctx);
{tuple,_,Es} ->
foldl(fun(E,B) ->
- B andalso is_valid_map_key_value(E)
+ B andalso is_valid_map_key_value(E,Ctx)
end,true,Es);
{map,_,Arg,Ps} ->
% only check for value expressions to be valid
% invalid map expressions are later checked in
% core and kernel
- is_valid_map_key_value(Arg) andalso foldl(fun
+ is_valid_map_key_value(Arg,Ctx) andalso foldl(fun
({Tag,_,Ke,Ve},B) when Tag =:= map_field_assoc;
- Tag =:= map_field_exact ->
- B andalso is_valid_map_key_value(Ke)
- andalso is_valid_map_key_value(Ve)
+ Tag =:= map_field_exact, Ctx =:= expr ->
+ B andalso is_valid_map_key_value(Ke,Ctx)
+ andalso is_valid_map_key_value(Ve,Ctx);
+ (_,_) -> false
end,true,Ps);
{map,_,Ps} ->
foldl(fun
({Tag,_,Ke,Ve},B) when Tag =:= map_field_assoc;
- Tag =:= map_field_exact ->
- B andalso is_valid_map_key_value(Ke)
- andalso is_valid_map_key_value(Ve)
+ Tag =:= map_field_exact, Ctx =:= expr ->
+ B andalso is_valid_map_key_value(Ke,Ctx)
+ andalso is_valid_map_key_value(Ve,Ctx);
+ (_,_) -> false
end, true, Ps);
{record,_,_,Fs} ->
foldl(fun
({record_field,_,Ke,Ve},B) ->
- B andalso is_valid_map_key_value(Ke)
- andalso is_valid_map_key_value(Ve)
+ B andalso is_valid_map_key_value(Ke,Ctx)
+ andalso is_valid_map_key_value(Ve,Ctx)
end,true,Fs);
{bin,_,Es} ->
% only check for value expressions to be valid
@@ -2373,7 +2378,7 @@ is_valid_map_key_value(K) ->
% core and kernel
foldl(fun
({bin_element,_,E,_,_},B) ->
- B andalso is_valid_map_key_value(E)
+ B andalso is_valid_map_key_value(E,Ctx)
end,true,Es);
_ -> false
end.
diff --git a/lib/stdlib/src/erl_pp.erl b/lib/stdlib/src/erl_pp.erl
index 9dbe89da91..82bc2c1460 100644
--- a/lib/stdlib/src/erl_pp.erl
+++ b/lib/stdlib/src/erl_pp.erl
@@ -256,6 +256,10 @@ ltype({type,_Line,nonempty_list,[T]}) ->
{seq,$[,$],[$,],[ltype(T),leaf("...")]};
ltype({type,Line,nil,[]}) ->
lexpr({nil,Line}, 0, options(none));
+ltype({type,Line,map,any}) ->
+ simple_type({atom,Line,map}, []);
+ltype({type,_Line,map,Pairs}) ->
+ map_type(Pairs);
ltype({type,Line,tuple,any}) ->
simple_type({atom,Line,tuple}, []);
ltype({type,_Line,tuple,Ts}) ->
@@ -289,6 +293,15 @@ binary_type(I1, I2) ->
E2 = [[leaf("_:_*"),lexpr(I2, P, options(none))] || U],
{seq,'<<','>>',[$,],E1++E2}.
+map_type(Fs) ->
+ {first,[$#],map_pair_types(Fs)}.
+
+map_pair_types(Fs) ->
+ tuple_type(Fs, fun map_pair_type/1).
+
+map_pair_type({type,_Line,map_field_assoc,Ktype,Vtype}) ->
+ {seq,[],[]," =>",[ltype(Ktype),ltype(Vtype)]}.
+
record_type(Name, Fields) ->
{first,[record_name(Name)],field_types(Fields)}.
diff --git a/lib/stdlib/src/io_lib_pretty.erl b/lib/stdlib/src/io_lib_pretty.erl
index 4057abd8d5..aece06afa6 100644
--- a/lib/stdlib/src/io_lib_pretty.erl
+++ b/lib/stdlib/src/io_lib_pretty.erl
@@ -25,8 +25,6 @@
-export([print/1,print/2,print/3,print/4,print/5,print/6]).
--compile(no_native).
-
%%%
%%% Exported functions
%%%
diff --git a/lib/stdlib/src/maps.erl b/lib/stdlib/src/maps.erl
index 1f94d9e69d..fd6d56fa47 100644
--- a/lib/stdlib/src/maps.erl
+++ b/lib/stdlib/src/maps.erl
@@ -43,8 +43,6 @@
values/1
]).
--compile(no_native).
-
-spec get(Key,Map) -> Value when
Key :: term(),
Map :: map(),
diff --git a/lib/stdlib/src/otp_internal.erl b/lib/stdlib/src/otp_internal.erl
index 971a2e2baa..c0ee8799c8 100644
--- a/lib/stdlib/src/otp_internal.erl
+++ b/lib/stdlib/src/otp_internal.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1999-2013. All Rights Reserved.
+%% Copyright Ericsson AB 1999-2014. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -83,18 +83,18 @@ obsolete_1(crypto, sha_init, 0) ->
{deprecated, {crypto, hash_init, 1}};
obsolete_1(crypto, md4_update, 2) ->
- {deprecated, {crypto, hash_update, 3}};
+ {deprecated, {crypto, hash_update, 2}};
obsolete_1(crypto, md5_update, 2) ->
- {deprecated, {crypto, hash_update, 3}};
+ {deprecated, {crypto, hash_update, 2}};
obsolete_1(crypto, sha_update, 2) ->
- {deprecated, {crypto, hash_update, 3}};
+ {deprecated, {crypto, hash_update, 2}};
obsolete_1(crypto, md4_final, 1) ->
- {deprecated, {crypto, hash_final, 2}};
+ {deprecated, {crypto, hash_final, 1}};
obsolete_1(crypto, md5_final, 1) ->
- {deprecated, {crypto, hash_final, 2}};
+ {deprecated, {crypto, hash_final, 1}};
obsolete_1(crypto, sha_final, 1) ->
- {deprecated, {crypto, hash_final, 2}};
+ {deprecated, {crypto, hash_final, 1}};
obsolete_1(crypto, md5_mac, 2) ->
{deprecated, {crypto, hmac, 3}};
@@ -104,9 +104,9 @@ obsolete_1(crypto, sha_mac, 3) ->
{deprecated, {crypto, hmac, 4}};
obsolete_1(crypto, sha_mac_96, 2) ->
- {deprecated, {crypto, hmac_n, 3}};
+ {deprecated, {crypto, hmac, 4}};
obsolete_1(crypto, md5_mac_96, 2) ->
- {deprecated, {crypto, hmac_n, 3}};
+ {deprecated, {crypto, hmac, 4}};
obsolete_1(crypto, rsa_sign, 2) ->
{deprecated, {crypto, sign, 4}};
@@ -123,9 +123,9 @@ obsolete_1(crypto, dss_sign, 3) ->
{deprecated, {crypto, sign, 4}};
obsolete_1(crypto, dss_verify, 3) ->
- {deprecated, {crypto, verify, 4}};
+ {deprecated, {crypto, verify, 5}};
obsolete_1(crypto, dss_verify, 4) ->
- {deprecated, {crypto, verify, 4}};
+ {deprecated, {crypto, verify, 5}};
obsolete_1(crypto, mod_exp, 3) ->
{deprecated, {crypto, mod_pow, 3}};
@@ -133,7 +133,7 @@ obsolete_1(crypto, mod_exp, 3) ->
obsolete_1(crypto, dh_compute_key, 3) ->
{deprecated, {crypto, compute_key, 4}};
obsolete_1(crypto, dh_generate_key, 1) ->
- {deprecated, {crypto, generate_key, 3}};
+ {deprecated, {crypto, generate_key, 2}};
obsolete_1(crypto, dh_generate_key, 2) ->
{deprecated, {crypto, generate_key, 3}};
@@ -577,6 +577,8 @@ obsolete_1(asn1rt, utf8_binary_to_list, 1) ->
{deprecated,{unicode,characters_to_list,1}};
obsolete_1(asn1rt, utf8_list_to_binary, 1) ->
{deprecated,{unicode,characters_to_binary,1}};
+obsolete_1(pg, _, _) ->
+ {deprecated,"deprecated; will be removed in OTP 18"};
obsolete_1(_, _, _) ->
no.
diff --git a/lib/stdlib/src/pg.erl b/lib/stdlib/src/pg.erl
index ee177e4e0b..a41fd329c2 100644
--- a/lib/stdlib/src/pg.erl
+++ b/lib/stdlib/src/pg.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2011. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2014. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -17,6 +17,7 @@
%% %CopyrightEnd%
%%
-module(pg).
+-deprecated(module).
%% pg provides a process group facility. Messages
%% can be multicasted to all members in the group
diff --git a/lib/stdlib/test/erl_lint_SUITE.erl b/lib/stdlib/test/erl_lint_SUITE.erl
index bb14de333d..ea61b2082b 100644
--- a/lib/stdlib/test/erl_lint_SUITE.erl
+++ b/lib/stdlib/test/erl_lint_SUITE.erl
@@ -52,7 +52,7 @@
guard/1, otp_4886/1, otp_4988/1, otp_5091/1, otp_5276/1, otp_5338/1,
otp_5362/1, otp_5371/1, otp_7227/1, otp_5494/1, otp_5644/1, otp_5878/1,
otp_5917/1, otp_6585/1, otp_6885/1, otp_10436/1, otp_11254/1,
- otp_11772/1, otp_11771/1,
+ otp_11772/1, otp_11771/1, otp_11872/1,
export_all/1,
bif_clash/1,
behaviour_basic/1, behaviour_multiple/1,
@@ -88,7 +88,7 @@ all() ->
otp_4886, otp_4988, otp_5091, otp_5276, otp_5338,
otp_5362, otp_5371, otp_7227, otp_5494, otp_5644,
otp_5878, otp_5917, otp_6585, otp_6885, otp_10436, otp_11254,
- otp_11772, otp_11771, export_all,
+ otp_11772, otp_11771, otp_11872, export_all,
bif_clash, behaviour_basic, behaviour_multiple,
otp_7550, otp_8051, format_warn, {group, on_load},
too_many_arguments, basic_errors, bin_syntax_errors, predef,
@@ -2630,6 +2630,29 @@ otp_11771(Config) when is_list(Config) ->
[]} = run_test2(Config, Ts, []),
ok.
+otp_11872(doc) ->
+ "OTP-11872. The type map() undefined when exported.";
+otp_11872(suite) -> [];
+otp_11872(Config) when is_list(Config) ->
+ Ts = <<"
+ -module(map).
+
+ -compile(export_all).
+
+ -export_type([map/0, product/0]).
+
+ -opaque map() :: dict().
+
+ -spec t() -> map().
+
+ t() ->
+ 1.
+ ">>,
+ {error,[{6,erl_lint,{undefined_type,{product,0}}}],
+ [{8,erl_lint,{new_var_arity_type,map}}]} =
+ run_test2(Config, Ts, []),
+ ok.
+
export_all(doc) ->
"OTP-7392. Warning for export_all.";
export_all(Config) when is_list(Config) ->
@@ -3406,7 +3429,19 @@ maps(Config) ->
{4,erl_lint,illegal_map_key},
{6,erl_lint,illegal_map_key},
{8,erl_lint,illegal_map_key},
- {10,erl_lint,illegal_map_key}],[]}}],
+ {10,erl_lint,illegal_map_key}],[]}},
+ {errors_in_map_keys_pattern,
+ <<"t(#{ a := 2,
+ #{} := A,
+ #{ 3 => 33 } := hi,
+ #{ 3 := 33 } := hi,
+ #{ hi => 54, \"hello\" => 45 } := hi,
+ #{ V => 33 } := hi }) ->
+ A.
+ ">>,
+ [],
+ {errors,[{4,erl_lint,illegal_map_key},
+ {6,erl_lint,{illegal_map_key_variable,'V'}}],[]}}],
[] = run(Config, Ts),
ok.
diff --git a/lib/stdlib/test/erl_pp_SUITE.erl b/lib/stdlib/test/erl_pp_SUITE.erl
index 390322a5fa..babf3a49eb 100644
--- a/lib/stdlib/test/erl_pp_SUITE.erl
+++ b/lib/stdlib/test/erl_pp_SUITE.erl
@@ -993,6 +993,16 @@ maps_syntax(Config) when is_list(Config) ->
ok = pp_expr(<<"#{ a => 1, <<\"hi\">> => \"world\", 33 => 1.0 }">>),
ok = pp_expr(<<"#{ a := V1, <<\"hi\">> := V2 } = M">>),
ok = pp_expr(<<"M#{ a => V1, <<\"hi\">> := V2 }">>),
+ F = <<"-module(maps_type_syntax).\n"
+ "-compile(export_all).\n"
+ "-type t1() :: map().\n"
+ "-type t2() :: #{ atom() => integer(), atom() => float() }.\n"
+ "-spec f1(t1()) -> 'true'.\n"
+ "f1(M) when is_map(M) -> true.\n"
+ "-spec f2(t2()) -> integer().\n"
+ "f2(#{a := V1,b := V2}) -> V1 + V2.\n"
+ "\n">>,
+ ok = pp_forms(F),
ok.
diff --git a/lib/syntax_tools/doc/src/notes.xml b/lib/syntax_tools/doc/src/notes.xml
index a9d3f68d1d..4e1e6d8cb1 100644
--- a/lib/syntax_tools/doc/src/notes.xml
+++ b/lib/syntax_tools/doc/src/notes.xml
@@ -31,6 +31,56 @@
<p>This document describes the changes made to the Syntax_Tools
application.</p>
+<section><title>Syntax_Tools 1.6.14</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Application upgrade (appup) files are corrected for the
+ following applications: </p>
+ <p>
+ <c>asn1, common_test, compiler, crypto, debugger,
+ dialyzer, edoc, eldap, erl_docgen, et, eunit, gs, hipe,
+ inets, observer, odbc, os_mon, otp_mibs, parsetools,
+ percept, public_key, reltool, runtime_tools, ssh,
+ syntax_tools, test_server, tools, typer, webtool, wx,
+ xmerl</c></p>
+ <p>
+ A new test utility for testing appup files is added to
+ test_server. This is now used by most applications in
+ OTP.</p>
+ <p>
+ (Thanks to Tobias Schlager)</p>
+ <p>
+ Own Id: OTP-11744</p>
+ </item>
+ </list>
+ </section>
+
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p>
+ Add implementation of having erl_tidy print to screen
+ instead of writing to the file provided. (Thanks to Aaron
+ France)</p>
+ <p>
+ Own Id: OTP-11632</p>
+ </item>
+ <item>
+ <p>
+ Support Maps syntax in syntax_tools (Thanks to Anthony
+ Ramine).</p>
+ <p>
+ Own Id: OTP-11663</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>Syntax_Tools 1.6.13</title>
<section><title>Fixed Bugs and Malfunctions</title>
diff --git a/lib/test_server/doc/src/notes.xml b/lib/test_server/doc/src/notes.xml
index d05626094a..556fe94a2a 100644
--- a/lib/test_server/doc/src/notes.xml
+++ b/lib/test_server/doc/src/notes.xml
@@ -32,6 +32,48 @@
<file>notes.xml</file>
</header>
+<section><title>Test_Server 3.7</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Application upgrade (appup) files are corrected for the
+ following applications: </p>
+ <p>
+ <c>asn1, common_test, compiler, crypto, debugger,
+ dialyzer, edoc, eldap, erl_docgen, et, eunit, gs, hipe,
+ inets, observer, odbc, os_mon, otp_mibs, parsetools,
+ percept, public_key, reltool, runtime_tools, ssh,
+ syntax_tools, test_server, tools, typer, webtool, wx,
+ xmerl</c></p>
+ <p>
+ A new test utility for testing appup files is added to
+ test_server. This is now used by most applications in
+ OTP.</p>
+ <p>
+ (Thanks to Tobias Schlager)</p>
+ <p>
+ Own Id: OTP-11744</p>
+ </item>
+ </list>
+ </section>
+
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p>
+ Calls to erlang:open_port/2 with 'spawn' are updated to
+ handle space in the command path.</p>
+ <p>
+ Own Id: OTP-10842</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>Test_Server 3.6.4</title>
<section><title>Fixed Bugs and Malfunctions</title>
diff --git a/lib/test_server/doc/src/test_server_ctrl.xml b/lib/test_server/doc/src/test_server_ctrl.xml
index f4aae724e0..0cda531716 100644
--- a/lib/test_server/doc/src/test_server_ctrl.xml
+++ b/lib/test_server/doc/src/test_server_ctrl.xml
@@ -773,11 +773,14 @@ test_server_ctrl:cross_cover_analyse(Level,[{s1,S1LogDir},{s2,S2LogDir}])
<p><c>What = tests_start, Data = {Name,NumCases}</c><br></br>
<c>What = loginfo, Data = [{topdir,TestRootDir},{rundir,CurrLogDir}]</c><br></br>
<c>What = tests_done, Data = {Ok,Failed,{UserSkipped,AutoSkipped}}</c><br></br>
- <c>What = tc_start, Data = {{Mod,Func},TCLogFile}</c><br></br>
- <c>What = tc_done, Data = {Mod,Func,Result}</c><br></br>
- <c>What = tc_user_skip, Data = {Mod,Func,Comment}</c><br></br>
- <c>What = tc_auto_skip, Data = {Mod,Func,Comment}</c><br></br>
+ <c>What = tc_start, Data = {{Mod,{Func,GroupName}},TCLogFile}</c><br></br>
+ <c>What = tc_done, Data = {Mod,{Func,GroupName},Result}</c><br></br>
+ <c>What = tc_user_skip, Data = {Mod,{Func,GroupName},Comment}</c><br></br>
+ <c>What = tc_auto_skip, Data = {Mod,{Func,GroupName},Comment}</c><br></br>
<c>What = framework_error, Data = {{FWMod,FWFunc},Error}</c></p>
+ <p>Note that for a test case function that doesn't belong to a group,
+ <c>GroupName</c> has value <c>undefined</c>, otherwise the name of the test
+ case group.</p>
</desc>
</func>
<func>
diff --git a/lib/test_server/src/test_server.erl b/lib/test_server/src/test_server.erl
index 9b05bddf63..70dc7a1441 100644
--- a/lib/test_server/src/test_server.erl
+++ b/lib/test_server/src/test_server.erl
@@ -444,7 +444,7 @@ run_test_case_apply(Mod, Func, Args, Name, RunInit, TimetrapData) ->
%% If this process (group leader of the test case) terminates before
%% all messages have been replied back to the io server, the io server
%% hangs. Fixed by the 20 milli timeout check here, and by using monitor in
-%% io.erl (livrem OCH hangslen mao :)
+%% io.erl.
%%
%% A test case is known to have failed if it returns {'EXIT', _} tuple,
%% or sends a message {failed, File, Line} to it's group_leader
@@ -673,7 +673,7 @@ handle_tc_exit({testcase_aborted,{user_timetrap_error,_}=Msg,_}, St) ->
spawn_fw_call(Mod, Func, Config, Pid, Msg, unknown, self()),
St;
handle_tc_exit(Reason, #st{status={framework,FwMod,FwFunc},
- config=Config,pid=Pid}=St) ->
+ config=Config,pid=Pid}=St) ->
R = case Reason of
{timetrap_timeout,TVal,_} ->
{timetrap,TVal};
diff --git a/lib/test_server/test/test_server_SUITE_data/test_server_parallel01_SUITE.erl b/lib/test_server/test/test_server_SUITE_data/test_server_parallel01_SUITE.erl
index f38f768f3b..9658191289 100644
--- a/lib/test_server/test/test_server_SUITE_data/test_server_parallel01_SUITE.erl
+++ b/lib/test_server/test/test_server_SUITE_data/test_server_parallel01_SUITE.erl
@@ -191,7 +191,7 @@ conf1_end(Config) ->
%% check 2s & 3s < 4s
Ms = timer:now_diff(now(),?config(t0,Config)),
test_server:comment(io_lib:format("~p",[now()])),
- if Ms > 3500000 -> exit({bad_parallel_exec,Ms});
+ if Ms > 4000000 -> exit({bad_parallel_exec,Ms});
Ms < 3000000 -> exit({bad_parallel_exec,Ms});
true -> ok
end.
@@ -204,7 +204,7 @@ conf2_end(Config) ->
%% check 3s & 2s < 4s
Ms = timer:now_diff(now(),?config(t0,Config)),
test_server:comment(io_lib:format("~p",[now()])),
- if Ms > 3500000 -> exit({bad_parallel_exec,Ms});
+ if Ms > 4000000 -> exit({bad_parallel_exec,Ms});
Ms < 3000000 -> exit({bad_parallel_exec,Ms});
true -> ok
end.
@@ -217,7 +217,7 @@ conf3_end(Config) ->
%% check 6s & 6s & (2s & 3s) & 1s = ~6s
Ms = timer:now_diff(now(),?config(t0,Config)),
test_server:comment(io_lib:format("~p",[now()])),
- if Ms > 6500000 -> exit({bad_parallel_exec,Ms});
+ if Ms > 7000000 -> exit({bad_parallel_exec,Ms});
Ms < 6000000 -> exit({bad_parallel_exec,Ms});
true -> ok
end.
@@ -230,7 +230,7 @@ conf4_end(Config) ->
%% check 2s & 3s >= 5s
Ms = timer:now_diff(now(),?config(t0,Config)),
test_server:comment(io_lib:format("~p",[now()])),
- if Ms > 5500000 -> exit({bad_parallel_exec,Ms});
+ if Ms > 6000000 -> exit({bad_parallel_exec,Ms});
Ms < 5000000 -> exit({bad_parallel_exec,Ms});
true -> ok
end.
@@ -243,7 +243,7 @@ conf5_end(Config) ->
%% check 1s & 1s & (3s & 2s) & 1s = ~6s
Ms = timer:now_diff(now(),?config(t0,Config)),
test_server:comment(io_lib:format("~p",[now()])),
- if Ms > 7000000 -> exit({bad_parallel_exec,Ms});
+ if Ms > 7500000 -> exit({bad_parallel_exec,Ms});
Ms < 6000000 -> exit({bad_parallel_exec,Ms});
true -> ok
end.
@@ -257,7 +257,7 @@ conf6_end(Config) ->
%% check 3s & 2s < 5s
Ms = timer:now_diff(now(),?config(t0,Config)),
test_server:comment(io_lib:format("~p",[now()])),
- if Ms > 3500000 -> exit({bad_parallel_exec,Ms});
+ if Ms > 4500000 -> exit({bad_parallel_exec,Ms});
Ms < 3000000 -> exit({bad_parallel_exec,Ms});
true -> ok
end.
@@ -277,7 +277,7 @@ conf7_end(Config) ->
%% check 1s & 1s & (2s & 2s) & 1s = ~3s
Ms = timer:now_diff(now(),?config(t0,Config)),
test_server:comment(io_lib:format("~p",[now()])),
- if Ms > 3500000 -> exit({bad_parallel_exec,Ms});
+ if Ms > 4000000 -> exit({bad_parallel_exec,Ms});
Ms < 3000000 -> exit({bad_parallel_exec,Ms});
true -> ok
end.
@@ -291,7 +291,7 @@ conf8_end(Config) ->
%% check 2s & 2s < 4s
Ms = timer:now_diff(now(),?config(t0,Config)),
test_server:comment(io_lib:format("~p",[now()])),
- if Ms > 2500000 -> exit({bad_parallel_exec,Ms});
+ if Ms > 3000000 -> exit({bad_parallel_exec,Ms});
Ms < 2000000 -> exit({bad_parallel_exec,Ms});
true -> ok
end.
diff --git a/lib/tools/doc/src/notes.xml b/lib/tools/doc/src/notes.xml
index 2e4c354fbd..136e0a3127 100644
--- a/lib/tools/doc/src/notes.xml
+++ b/lib/tools/doc/src/notes.xml
@@ -30,6 +30,82 @@
</header>
<p>This document describes the changes made to the Tools application.</p>
+<section><title>Tools 2.6.14</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Removed the support for the query keyword from emacs mode
+ (Thanks to Paul Oliver)</p>
+ <p>
+ Own Id: OTP-11568</p>
+ </item>
+ <item>
+ <p>
+ Emacs mode improvements (Thanks to Steve Vinoski)</p>
+ <p>
+ Own Id: OTP-11601</p>
+ </item>
+ <item>
+ <p>
+ Application upgrade (appup) files are corrected for the
+ following applications: </p>
+ <p>
+ <c>asn1, common_test, compiler, crypto, debugger,
+ dialyzer, edoc, eldap, erl_docgen, et, eunit, gs, hipe,
+ inets, observer, odbc, os_mon, otp_mibs, parsetools,
+ percept, public_key, reltool, runtime_tools, ssh,
+ syntax_tools, test_server, tools, typer, webtool, wx,
+ xmerl</c></p>
+ <p>
+ A new test utility for testing appup files is added to
+ test_server. This is now used by most applications in
+ OTP.</p>
+ <p>
+ (Thanks to Tobias Schlager)</p>
+ <p>
+ Own Id: OTP-11744</p>
+ </item>
+ <item>
+ <p>
+ The emacs erlang mode now match erlang keywords more
+ carefully (Thanks to Steve Vinoski)</p>
+ <p>
+ Own Id: OTP-11786</p>
+ </item>
+ <item>
+ <p>
+ The emacs erlang-mode now auto loads for more file types
+ (Thanks to Phil Hagelberg)</p>
+ <p>
+ Own Id: OTP-11788</p>
+ </item>
+ </list>
+ </section>
+
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p>
+ <c>cover</c> can run on itself. Also, support for reading
+ BEAM files produced by ancient OTP versions before R9C
+ has been removed.</p>
+ <p>
+ Own Id: OTP-11692</p>
+ </item>
+ <item>
+ <p>
+ Support maps in cover</p>
+ <p>
+ Own Id: OTP-11764</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>Tools 2.6.13</title>
<section><title>Fixed Bugs and Malfunctions</title>
diff --git a/lib/tools/test/eprof_SUITE.erl b/lib/tools/test/eprof_SUITE.erl
index 1227d5b841..04b522de4a 100644
--- a/lib/tools/test/eprof_SUITE.erl
+++ b/lib/tools/test/eprof_SUITE.erl
@@ -104,7 +104,7 @@ basic(Config) when is_list(Config) ->
profiling = eprof:profile([A]),
true = exit(A, kill_it),
profiling_stopped = eprof:stop_profiling(),
- {error,_} = eprof:profile(fun() -> a = b end),
+ {error,_} = eprof:profile(fun() -> a = id(b) end),
%% with mfa
@@ -149,8 +149,7 @@ basic_option_1(Config) ->
% vanilla
{ok, _} = eprof:profile(fun() -> eprof_test:do(10) end, [{set_on_spawn, true}]),
- [{_, MfasDo1},{_, MfasLists1}] = eprof:dump(),
- Mfas1 = MfasDo1 ++ MfasLists1,
+ Mfas1 = lists:foldl(fun({_,Mfas},Out) -> Mfas ++ Out end, [], eprof:dump()),
{value, {_, {11, _}}} = lists:keysearch({eprof_test,dec,1}, 1, Mfas1),
{value, {_, { 1, _}}} = lists:keysearch({eprof_test, go,1}, 1, Mfas1),
@@ -159,8 +158,7 @@ basic_option_1(Config) ->
{ok, _} = eprof:profile(fun() -> eprof_test:do(10) end, [set_on_spawn]),
- [{_, MfasDo2},{_, MfasLists2}] = eprof:dump(),
- Mfas2 = MfasDo2 ++ MfasLists2,
+ Mfas2 = lists:foldl(fun({_,Mfas},Out) -> Mfas ++ Out end, [], eprof:dump()),
{value, {_, {11, _}}} = lists:keysearch({eprof_test,dec,1}, 1, Mfas2),
{value, {_, { 1, _}}} = lists:keysearch({eprof_test, go,1}, 1, Mfas2),
{value, {_, { 9, _}}} = lists:keysearch({lists, split_2,5}, 1, Mfas2),
@@ -255,3 +253,5 @@ ensure_eprof_stopped() ->
Pid ->
stopped=eprof:stop()
end.
+
+id(I) -> I.
diff --git a/lib/typer/Makefile b/lib/typer/Makefile
index 40a82e9bba..d4396abc9d 100644
--- a/lib/typer/Makefile
+++ b/lib/typer/Makefile
@@ -29,7 +29,7 @@ include $(ERL_TOP)/make/$(TARGET)/otp.mk
# Macros
#
-SUB_DIRECTORIES = src
+SUB_DIRECTORIES = src doc/src
include vsn.mk
VSN = $(TYPER_VSN)
diff --git a/lib/typer/doc/Makefile b/lib/typer/doc/Makefile
new file mode 100644
index 0000000000..4ea0137202
--- /dev/null
+++ b/lib/typer/doc/Makefile
@@ -0,0 +1,39 @@
+#
+# %CopyrightBegin%
+#
+# Copyright Ericsson AB 2006-2012. 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
+# compliance with the License. You should have received a copy of the
+# Erlang Public License along with this software. If not, it can be
+# retrieved online at http://www.erlang.org/.
+#
+# Software distributed under the License is distributed on an "AS IS"
+# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+# the License for the specific language governing rights and limitations
+# under the License.
+#
+# %CopyrightEnd%
+#
+SHELL=/bin/sh
+
+include $(ERL_TOP)/make/target.mk
+include $(ERL_TOP)/make/$(TARGET)/otp.mk
+
+clean:
+ -rm -f *.html edoc-info stylesheet.css erlang.png
+
+distclean: clean
+realclean: clean
+
+# ----------------------------------------------------
+# Special Build Targets
+# ----------------------------------------------------
+
+
+
+# ----------------------------------------------------
+# Release Target
+# ----------------------------------------------------
+include $(ERL_TOP)/make/otp_release_targets.mk
diff --git a/lib/typer/doc/html/.gitignore b/lib/typer/doc/html/.gitignore
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/lib/typer/doc/html/.gitignore
diff --git a/lib/typer/doc/pdf/.gitignore b/lib/typer/doc/pdf/.gitignore
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/lib/typer/doc/pdf/.gitignore
diff --git a/lib/typer/doc/src/Makefile b/lib/typer/doc/src/Makefile
new file mode 100644
index 0000000000..2683c08679
--- /dev/null
+++ b/lib/typer/doc/src/Makefile
@@ -0,0 +1,117 @@
+#
+# %CopyrightBegin%
+#
+# Copyright Ericsson AB 2006-2012. 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
+# compliance with the License. You should have received a copy of the
+# Erlang Public License along with this software. If not, it can be
+# retrieved online at http://www.erlang.org/.
+#
+# Software distributed under the License is distributed on an "AS IS"
+# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+# the License for the specific language governing rights and limitations
+# under the License.
+#
+# %CopyrightEnd%
+#
+include $(ERL_TOP)/make/target.mk
+include $(ERL_TOP)/make/$(TARGET)/otp.mk
+
+# ----------------------------------------------------
+# Application version
+# ----------------------------------------------------
+include ../../vsn.mk
+VSN=$(TYPER_VSN)
+APPLICATION=typer
+
+# ----------------------------------------------------
+# Release directory specification
+# ----------------------------------------------------
+RELSYSDIR = $(RELEASE_PATH)/lib/$(APPLICATION)-$(VSN)
+
+# ----------------------------------------------------
+# Target Specs
+# ----------------------------------------------------
+XML_APPLICATION_FILES = ref_man.xml
+XML_REF3_FILES =
+
+XML_PART_FILES = part_notes.xml
+XML_CHAPTER_FILES = notes.xml
+
+BOOK_FILES = book.xml
+
+XML_FILES = \
+ $(BOOK_FILES) $(XML_CHAPTER_FILES) \
+ $(XML_PART_FILES) $(XML_REF3_FILES) $(XML_APPLICATION_FILES)
+
+GIF_FILES =
+
+# ----------------------------------------------------
+
+HTML_FILES = $(XML_APPLICATION_FILES:%.xml=$(HTMLDIR)/%.html) \
+ $(XML_PART_FILES:%.xml=$(HTMLDIR)/%.html)
+
+INFO_FILE = ../../info
+EXTRA_FILES = \
+ $(DEFAULT_GIF_FILES) \
+ $(DEFAULT_HTML_FILES) \
+ $(XML_REF3_FILES:%.xml=$(HTMLDIR)/%.html) \
+ $(XML_CHAPTER_FILES:%.xml=$(HTMLDIR)/%.html)
+
+MAN3_FILES = $(XML_REF3_FILES:%.xml=$(MAN3DIR)/%.3)
+
+HTML_REF_MAN_FILE = $(HTMLDIR)/index.html
+
+TOP_PDF_FILE = $(PDFDIR)/$(APPLICATION)-$(VSN).pdf
+
+# ----------------------------------------------------
+# FLAGS
+# ----------------------------------------------------
+XML_FLAGS +=
+
+# ----------------------------------------------------
+# Targets
+# ----------------------------------------------------
+$(HTMLDIR)/%.gif: %.gif
+ $(INSTALL_DATA) $< $@
+
+docs: pdf html man
+
+$(TOP_PDF_FILE): $(XML_FILES)
+
+pdf: $(TOP_PDF_FILE)
+
+html: gifs $(HTML_REF_MAN_FILE)
+
+man: $(MAN3_FILES)
+
+gifs: $(GIF_FILES:%=$(HTMLDIR)/%)
+
+debug opt:
+
+clean clean_docs:
+ rm -rf $(HTMLDIR)/*
+ rm -f $(MAN3DIR)/*
+ rm -f $(TOP_PDF_FILE) $(TOP_PDF_FILE:%.pdf=%.fo)
+ rm -f errs core *~
+
+distclean: clean
+realclean: clean
+
+# ----------------------------------------------------
+# Release Target
+# ----------------------------------------------------
+include $(ERL_TOP)/make/otp_release_targets.mk
+
+release_docs_spec: docs
+ $(INSTALL_DIR) "$(RELSYSDIR)/doc/pdf"
+ $(INSTALL_DATA) $(TOP_PDF_FILE) "$(RELSYSDIR)/doc/pdf"
+ $(INSTALL_DIR) "$(RELSYSDIR)/doc/html"
+ $(INSTALL_DATA) $(HTMLDIR)/* \
+ "$(RELSYSDIR)/doc/html"
+ $(INSTALL_DATA) $(INFO_FILE) "$(RELSYSDIR)"
+
+
+release_spec:
diff --git a/lib/typer/doc/src/book.xml b/lib/typer/doc/src/book.xml
new file mode 100644
index 0000000000..5cc85a3022
--- /dev/null
+++ b/lib/typer/doc/src/book.xml
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<!DOCTYPE book SYSTEM "book.dtd">
+
+<book xmlns:xi="http://www.w3.org/2001/XInclude">
+ <header titlestyle="normal">
+ <copyright>
+ <year>2006</year><year>2013</year>
+ <holder>Ericsson AB. All Rights Reserved.</holder>
+ </copyright>
+ <legalnotice>
+ The contents of this file are subject to the Erlang Public License,
+ Version 1.1, (the "License"); you may not use this file except in
+ compliance with the License. You should have received a copy of the
+ Erlang Public License along with this software. If not, it can be
+ retrieved online at http://www.erlang.org/.
+
+ Software distributed under the License is distributed on an "AS IS"
+ basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ the License for the specific language governing rights and limitations
+ under the License.
+
+ </legalnotice>
+
+ <title>TypEr</title>
+ <prepared></prepared>
+ <docno></docno>
+ <date></date>
+ <rev></rev>
+ </header>
+ <pagetext></pagetext>
+ <preamble>
+ </preamble>
+ <pagetext>TypEr</pagetext>
+ <applications>
+ <xi:include href="ref_man.xml"/>
+ </applications>
+ <releasenotes>
+ <xi:include href="notes.xml"/>
+ </releasenotes>
+</book>
+
diff --git a/lib/typer/doc/src/fascicules.xml b/lib/typer/doc/src/fascicules.xml
new file mode 100644
index 0000000000..b15610fa8b
--- /dev/null
+++ b/lib/typer/doc/src/fascicules.xml
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<!DOCTYPE fascicules SYSTEM "fascicules.dtd">
+
+<fascicules>
+ <fascicule file="part_notes" href="part_notes_frame.html" entry="yes">
+ Release Notes
+ </fascicule>
+ <fascicule file="" href="../../../../doc/print.html" entry="no">
+ Off-Print
+ </fascicule>
+</fascicules>
+
diff --git a/lib/typer/doc/src/notes.xml b/lib/typer/doc/src/notes.xml
new file mode 100644
index 0000000000..53d554820d
--- /dev/null
+++ b/lib/typer/doc/src/notes.xml
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<!DOCTYPE chapter SYSTEM "chapter.dtd">
+
+<chapter>
+ <header>
+ <copyright>
+ <year>2014</year>
+ <holder>Ericsson AB. All Rights Reserved.</holder>
+ </copyright>
+ <legalnotice>
+ The contents of this file are subject to the Erlang Public License,
+ Version 1.1, (the "License"); you may not use this file except in
+ compliance with the License. You should have received a copy of the
+ Erlang Public License along with this software. If not, it can be
+ retrieved online at http://www.erlang.org/.
+
+ Software distributed under the License is distributed on an "AS IS"
+ basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ the License for the specific language governing rights and limitations
+ under the License.
+
+ </legalnotice>
+
+ <title>TypEr Release Notes</title>
+ <prepared>otp_appnotes</prepared>
+ <docno>nil</docno>
+ <date>nil</date>
+ <rev>nil</rev>
+ <file>notes.xml</file>
+ </header>
+ <p>This document describes the changes made to TypEr.</p>
+
+<section><title>TypEr 0.9.7</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Added initial documentation framework for TypEr.</p>
+ <p>
+ Own Id: OTP-11860</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+
+
+</chapter>
+
diff --git a/lib/typer/doc/src/part_notes.xml b/lib/typer/doc/src/part_notes.xml
new file mode 100644
index 0000000000..b4ccd3ed77
--- /dev/null
+++ b/lib/typer/doc/src/part_notes.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<!DOCTYPE part SYSTEM "part.dtd">
+
+<part xmlns:xi="http://www.w3.org/2001/XInclude">
+ <header>
+ <copyright>
+ <year>2006</year><year>2013</year>
+ <holder>Ericsson AB. All Rights Reserved.</holder>
+ </copyright>
+ <legalnotice>
+ The contents of this file are subject to the Erlang Public License,
+ Version 1.1, (the "License"); you may not use this file except in
+ compliance with the License. You should have received a copy of the
+ Erlang Public License along with this software. If not, it can be
+ retrieved online at http://www.erlang.org/.
+
+ Software distributed under the License is distributed on an "AS IS"
+ basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ the License for the specific language governing rights and limitations
+ under the License.
+
+ </legalnotice>
+
+ <title>TypEr Release Notes</title>
+ <prepared></prepared>
+ <docno></docno>
+ <date></date>
+ <rev></rev>
+ </header>
+ <description>
+ <p><em>TypEr</em></p>
+ </description>
+ <xi:include href="notes.xml"/>
+</part>
+
diff --git a/lib/typer/doc/src/ref_man.xml b/lib/typer/doc/src/ref_man.xml
new file mode 100644
index 0000000000..b54a5f5947
--- /dev/null
+++ b/lib/typer/doc/src/ref_man.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<!DOCTYPE application SYSTEM "application.dtd">
+
+<application xmlns:xi="http://www.w3.org/2001/XInclude">
+ <header>
+ <copyright>
+ <year>2014</year>
+ <holder>Ericsson AB. All Rights Reserved.</holder>
+ </copyright>
+ <legalnotice>
+ The contents of this file are subject to the Erlang Public License,
+ Version 1.1, (the "License"); you may not use this file except in
+ compliance with the License. You should have received a copy of the
+ Erlang Public License along with this software. If not, it can be
+ retrieved online at http://www.erlang.org/.
+
+ Software distributed under the License is distributed on an "AS IS"
+ basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ the License for the specific language governing rights and limitations
+ under the License.
+
+ </legalnotice>
+
+ <title>TypEr</title>
+ <prepared></prepared>
+ <docno></docno>
+ <date></date>
+ <rev></rev>
+ <file>ref_man.xml</file>
+ </header>
+ <description>
+ </description>
+ <xi:include href="typer_app.xml"/>
+</application>
+
diff --git a/lib/typer/doc/src/typer_app.xml b/lib/typer/doc/src/typer_app.xml
new file mode 100644
index 0000000000..469a9be108
--- /dev/null
+++ b/lib/typer/doc/src/typer_app.xml
@@ -0,0 +1,43 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<!DOCTYPE appref SYSTEM "appref.dtd">
+
+<appref>
+ <header>
+ <copyright>
+ <year>2014</year>
+ <holder>Ericsson AB. All Rights Reserved.</holder>
+ </copyright>
+ <legalnotice>
+ The contents of this file are subject to the Erlang Public License,
+ Version 1.1, (the "License"); you may not use this file except in
+ compliance with the License. You should have received a copy of the
+ Erlang Public License along with this software. If not, it can be
+ retrieved online at http://www.erlang.org/.
+
+ Software distributed under the License is distributed on an "AS IS"
+ basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ the License for the specific language governing rights and limitations
+ under the License.
+
+ </legalnotice>
+
+ <title>TypEr</title>
+ <prepared></prepared>
+ <responsible></responsible>
+ <docno></docno>
+ <approved></approved>
+ <checked></checked>
+ <date></date>
+ <rev></rev>
+ <file>typer.xml</file>
+ </header>
+ <app>TypEr</app>
+ <appsummary>The TypEr Application</appsummary>
+ <description>
+ <p>An Erlang/OTP application that shows type information
+ for Erlang modules to the user. Additionally, it can
+ annotate the code of files with such type information.</p>
+ </description>
+
+</appref>
+
diff --git a/lib/typer/info b/lib/typer/info
new file mode 100644
index 0000000000..5145fbcfff
--- /dev/null
+++ b/lib/typer/info
@@ -0,0 +1,2 @@
+group: tools
+short: TypEr
diff --git a/lib/typer/src/Makefile b/lib/typer/src/Makefile
index 13af466755..a7059de971 100644
--- a/lib/typer/src/Makefile
+++ b/lib/typer/src/Makefile
@@ -63,7 +63,7 @@ APPUP_TARGET= $(EBIN)/$(APPUP_FILE)
# ----------------------------------------------------
# FLAGS
# ----------------------------------------------------
-ERL_COMPILE_FLAGS += +warn_exported_vars +warn_untyped_record +warn_missing_spec
+ERL_COMPILE_FLAGS += +warn_export_vars +warn_untyped_record +warn_missing_spec
# ----------------------------------------------------
# Targets
diff --git a/lib/typer/vsn.mk b/lib/typer/vsn.mk
index 49fdda756e..9cc044c621 100644
--- a/lib/typer/vsn.mk
+++ b/lib/typer/vsn.mk
@@ -1 +1 @@
-TYPER_VSN = 0.9.6
+TYPER_VSN = 0.9.7
diff --git a/lib/webtool/doc/src/notes.xml b/lib/webtool/doc/src/notes.xml
index 74e5fd88c1..e571668c91 100644
--- a/lib/webtool/doc/src/notes.xml
+++ b/lib/webtool/doc/src/notes.xml
@@ -31,6 +31,35 @@
<p>This document describes the changes made to the Webtool
application.</p>
+<section><title>WebTool 0.8.10</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Application upgrade (appup) files are corrected for the
+ following applications: </p>
+ <p>
+ <c>asn1, common_test, compiler, crypto, debugger,
+ dialyzer, edoc, eldap, erl_docgen, et, eunit, gs, hipe,
+ inets, observer, odbc, os_mon, otp_mibs, parsetools,
+ percept, public_key, reltool, runtime_tools, ssh,
+ syntax_tools, test_server, tools, typer, webtool, wx,
+ xmerl</c></p>
+ <p>
+ A new test utility for testing appup files is added to
+ test_server. This is now used by most applications in
+ OTP.</p>
+ <p>
+ (Thanks to Tobias Schlager)</p>
+ <p>
+ Own Id: OTP-11744</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>WebTool 0.8.9.2</title>
<section><title>Improvements and New Features</title>
diff --git a/lib/wx/doc/src/notes.xml b/lib/wx/doc/src/notes.xml
index 6e653cf828..daa61fda1e 100644
--- a/lib/wx/doc/src/notes.xml
+++ b/lib/wx/doc/src/notes.xml
@@ -31,6 +31,59 @@
<p>This document describes the changes made to the wxErlang
application.</p>
+<section><title>Wx 1.2</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Refactored C++ code, fixed crashes and a deadlock on
+ linux.</p>
+ <p>
+ Own Id: OTP-11586</p>
+ </item>
+ <item>
+ <p>
+ Some local implementations of removing the last element
+ from a list are replaced by <c>lists:droplast/1</c>. Note
+ that this requires at least <c>stdlib-2.0</c>, which is
+ the stdlib version delivered in OTP 17.0. (Thanks to Hans
+ Svensson)</p>
+ <p>
+ Own Id: OTP-11678</p>
+ </item>
+ <item>
+ <p>
+ Reworked the internal event handling to avoid crashes in
+ destroy objects. Thanks Tom for the bug report.</p>
+ <p>
+ Own Id: OTP-11699</p>
+ </item>
+ <item>
+ <p>
+ Application upgrade (appup) files are corrected for the
+ following applications: </p>
+ <p>
+ <c>asn1, common_test, compiler, crypto, debugger,
+ dialyzer, edoc, eldap, erl_docgen, et, eunit, gs, hipe,
+ inets, observer, odbc, os_mon, otp_mibs, parsetools,
+ percept, public_key, reltool, runtime_tools, ssh,
+ syntax_tools, test_server, tools, typer, webtool, wx,
+ xmerl</c></p>
+ <p>
+ A new test utility for testing appup files is added to
+ test_server. This is now used by most applications in
+ OTP.</p>
+ <p>
+ (Thanks to Tobias Schlager)</p>
+ <p>
+ Own Id: OTP-11744</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>Wx 1.1.2</title>
<section><title>Fixed Bugs and Malfunctions</title>
diff --git a/lib/xmerl/doc/src/notes.xml b/lib/xmerl/doc/src/notes.xml
index b020b9bfa3..3fa1f01a79 100644
--- a/lib/xmerl/doc/src/notes.xml
+++ b/lib/xmerl/doc/src/notes.xml
@@ -31,6 +31,35 @@
<p>This document describes the changes made to the Xmerl application.</p>
+<section><title>Xmerl 1.3.7</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Application upgrade (appup) files are corrected for the
+ following applications: </p>
+ <p>
+ <c>asn1, common_test, compiler, crypto, debugger,
+ dialyzer, edoc, eldap, erl_docgen, et, eunit, gs, hipe,
+ inets, observer, odbc, os_mon, otp_mibs, parsetools,
+ percept, public_key, reltool, runtime_tools, ssh,
+ syntax_tools, test_server, tools, typer, webtool, wx,
+ xmerl</c></p>
+ <p>
+ A new test utility for testing appup files is added to
+ test_server. This is now used by most applications in
+ OTP.</p>
+ <p>
+ (Thanks to Tobias Schlager)</p>
+ <p>
+ Own Id: OTP-11744</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>Xmerl 1.3.6</title>
<section><title>Fixed Bugs and Malfunctions</title>
diff --git a/otp_build b/otp_build
index 6400b411ab..fb001fc38f 100755
--- a/otp_build
+++ b/otp_build
@@ -52,9 +52,6 @@ usage ()
echo " release [-a] <target_dir> - creates full release to <target_dir>"
echo " smp [-a] - build an Erlang system, smp flavor only"
echo " tests <dir> - Build testsuites to <dir>"
- echo " patch_app [-f] <target_dir> <app1>... - build given apps to <target_dir>"
- echo " If core apps are patched, new start scripts will be created"
- echo " and 'Install' must be run again."
echo ""
echo "These are for cleaning up an open source distribution"
echo "with prebuilt files, so that it resembles the clean developers"
@@ -1192,141 +1189,6 @@ do_release ()
release || exit 1
}
-do_patch_app ()
-{
- # If target dir exists and has an installation of same major release, then
- # build given apps.
- # If patch includes erts, kernel, stdlib, sasl, then find latest
- # erts, kernel, stdlib, sasl and create .rel files.
- # Create .script/.boot
-
- if [ $# -lt 2 ]; then
- usage
- exit 1
- fi
-
- setup_make
- if [ X`$MAKE is_cross_configured` = Xyes ]; then
- TARGET=`$MAKE target_configured`
- fi
- if [ "x$1" = "x-f" ]; then
- force="-force"
- shift
- else
- force=
- fi
- target_dir=$1
- if [ ! -d "$target_dir/releases/$otp_major_vsn" ]; then
- echo "No OTP $otp_major_vsn installation in $target_dir" 1>&2
- exit 1
- fi
-
- shift
-
- otp_version=`cat "$target_dir/releases/$otp_major_vsn/OTP_VERSION"` || { echo "Not able to read $target_dir/releases/$otp_major_vsn/OTP_VERSION" 1>&2; exit 1; }
- { echo "$otp_version" | sed "s|^\([^\*]*\)\**|\1\*\*|g" > "$target_dir/releases/$otp_major_vsn/OTP_VERSION"; } 2>/dev/null || { echo "Not able to update $target_dir/OTP_VERSION" 1>&2; exit 1; }
-
- PATH="$ERL_TOP/bootstrap/bin:$PATH" $ERL_TOP/make/verify_runtime_dependencies -release "$otp_major_vsn" -source "$ERL_TOP" -target "$target_dir" $force "$@"
-
- if [ $? -ne 0 ]; then
- exit $?
- fi
-
- # Build all applications to target
- for app in "$@"; do
- if [ "$app" = "erts" ] && [ -d $ERL_TOP/$app ]; then
- (cd $ERL_TOP/$app && $MAKE MAKE="$MAKE" TARGET=$TARGET \
- TESTROOT="$target_dir" release) || exit 1
- elif [ "$app" != "erts" ] && [ -d $ERL_TOP/lib/$app ]; then
- (cd $ERL_TOP/lib/$app && $MAKE MAKE="$MAKE" TARGET=$TARGET \
- TESTROOT="$target_dir" release) || exit 1
- else
- echo "Invalid application $app" 1>&2
- exit 1
- fi
- done
-
- # If erts, kernel, stdlib or sasl is included, find versions
- for app in "$@"; do
- if [ "$app" = "erts" ]; then
- erts_vsn=`grep '^VSN' erts/vsn.mk | sed "s|^VSN.*=[^0-9]*\([0-9].*\)$|\1|g"`
- update_rel=true
- elif [ "$app" = "kernel" ]; then
- kernel_vsn=`sed "s|^KERNEL_VSN[^=]*=[^0-9]*\([0-9].*\)$|\1|g" lib/kernel/vsn.mk`
- update_rel=true
- elif [ "$app" = "stdlib" ]; then
- stdlib_vsn=`sed "s|^STDLIB_VSN[^=]*=[^0-9]*\([0-9].*\)$|\1|g" lib/stdlib/vsn.mk`
- update_rel=true
- elif [ "$app" = "sasl" ]; then
- sasl_vsn=`sed "s|^SASL_VSN[^=]*=[^0-9]*\([0-9].*\)$|\1|g" lib/sasl/vsn.mk`
- update_rel=true
- fi
- done
-
- # and find the old versions for those not included
- if [ "X$update_rel" != "X" ]; then
- if [ "X$erts_vsn" = "X" ]; then
- erts_vsns=`ls -d "$target_dir"/erts-* | sed "s|$target_dir/erts-\([0-9\.].*\)|\1|g"`
- erts_vsn=`echo "$erts_vsns" | sort -t '.' -g | tail -n 1`
- fi
- if [ "X$kernel_vsn" = "X" ]; then
- kernel_vsns=`ls -d "$target_dir"/lib/kernel-* | sed "s|$target_dir/lib/kernel-\([0-9\.].*\)|\1|g"`
- kernel_vsn=`echo "$kernel_vsns" | sort -t '.' -g | tail -n 1`
- fi
- if [ "X$stdlib_vsn" = "X" ]; then
- stdlib_vsns=`ls -d "$target_dir"/lib/stdlib-* | sed "s|$target_dir/lib/stdlib-\([0-9\.].*\)|\1|g"`
- stdlib_vsn=`echo "$stdlib_vsns" | sort -t '.' -g | tail -n 1`
- fi
- if [ "X$sasl_vsn" = "X" ]; then
- sasl_vsns=`ls -d "$target_dir"/lib/sasl-* | sed "s|$target_dir/lib/sasl-\([0-9\.].*\)|\1|g"`
- sasl_vsn=`echo "$sasl_vsns" | sort -t '.' -g | tail -n 1`
- fi
-
- # Generate .rel, .script and .boot - to tmp dir
- start_clean="{release, {\"Erlang/OTP\",\"$otp_major_vsn\"}, {erts, \"$erts_vsn\"},\n [{kernel,\"$kernel_vsn\"},\n {stdlib,\"$stdlib_vsn\"}]}.\n"
- start_sasl="{release, {\"Erlang/OTP\",\"$otp_major_vsn\"}, {erts, \"$erts_vsn\"},\n [{kernel,\"$kernel_vsn\"},\n {stdlib,\"$stdlib_vsn\"},\n {sasl,\"$sasl_vsn\"}]}.\n"
-
- tmp_dir="$target_dir/tmp";
- if [ ! -d "$tmp_dir" ]; then
- mkdir "$tmp_dir"
- fi
- echo "$start_sasl" > "$tmp_dir/start_sasl.rel"
- echo "$start_clean" > "$tmp_dir/start_clean.rel"
- echo "$start_clean" > "$tmp_dir/no_dot_erlang.rel"
-
- erlc="$ERL_TOP/bootstrap/bin/erlc"
- if [ ! -x "$erlc" ]; then
- echo "erlc not found, can not create .script and .boot files" 1>&2
- exit 1
- fi
-
- $erlc -I"$target_dir"/lib/*/ebin -o$tmp_dir $tmp_dir/start_sasl.rel || exit 1
- $erlc -I"$target_dir"/lib/*/ebin -o$tmp_dir +no_warn_sasl $tmp_dir/start_clean.rel || exit 1
- $erlc -I"$target_dir"/lib/*/ebin -o$tmp_dir +no_warn_sasl +no_dot_erlang $tmp_dir/no_dot_erlang.rel || exit 1
-
- # Generate RELEASES file
- erl="$ERL_TOP/bootstrap/bin/erl"
- if [ ! -x "$erl" ]; then
- echo "erl not found, can not create RELEASES file" 1>&2
- exit 1
- fi
- "$erl" -noinput +B -eval "release_handler:create_RELEASES(\"%ERL_ROOT%\", \"$tmp_dir\", \"$tmp_dir/start_sasl.rel\", []), halt()" || exit 1
-
- # If all good so far, move generated files into target area
- mv "$tmp_dir/RELEASES" "$target_dir/releases/RELEASES.src"
- mv "$tmp_dir"/* "$target_dir/releases/$otp_major_vsn"
- rmdir "$tmp_dir"
-
- # Remove old start scripts (forces a new run of Install)
- rm -f "$target_dir"/releases/RELEASES
- rm -f "$target_dir"/bin/*.script
- rm -f "$target_dir"/bin/*.boot
- rm -f "$target_dir"/bin/erl
- fi
-
-}
-
-
do_tests ()
{
setup_make
@@ -1587,9 +1449,6 @@ case "$1" in
shift
fi;
do_release "$2";;
- patch_app)
- shift;
- do_patch_app "$@";;
tests)
if [ $minus_a_flag = true ]; then
shift
diff --git a/otp_versions.table b/otp_versions.table
index e69de29bb2..a8a40df85a 100644
--- a/otp_versions.table
+++ b/otp_versions.table
@@ -0,0 +1,2 @@
+OTP-17.0.1 : erts-6.0.1 typer-0.9.7 # asn1-3.0 common_test-1.8 compiler-5.0 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.3 debugger-4.0 dialyzer-2.7 diameter-1.6 edoc-0.7.13 eldap-1.0.3 erl_docgen-0.3.5 erl_interface-3.7.16 et-1.5 eunit-2.2.7 gs-1.5.16 hipe-3.10.3 ic-4.3.5 inets-5.10 jinterface-1.5.9 kernel-3.0 megaco-3.17.1 mnesia-4.12 observer-2.0 odbc-2.10.20 orber-3.6.27 os_mon-2.2.15 ose-1.0 otp_mibs-1.0.9 parsetools-2.0.11 percept-0.8.9 public_key-0.22 reltool-0.6.5 runtime_tools-1.8.14 sasl-2.4 snmp-4.25.1 ssh-3.0.1 ssl-5.3.4 stdlib-2.0 syntax_tools-1.6.14 test_server-3.7 tools-2.6.14 webtool-0.8.10 wx-1.2 xmerl-1.3.7 :
+OTP-17.0 : asn1-3.0 common_test-1.8 compiler-5.0 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.3 debugger-4.0 dialyzer-2.7 diameter-1.6 edoc-0.7.13 eldap-1.0.3 erl_docgen-0.3.5 erl_interface-3.7.16 erts-6.0 et-1.5 eunit-2.2.7 gs-1.5.16 hipe-3.10.3 ic-4.3.5 inets-5.10 jinterface-1.5.9 kernel-3.0 megaco-3.17.1 mnesia-4.12 observer-2.0 odbc-2.10.20 orber-3.6.27 os_mon-2.2.15 ose-1.0 otp_mibs-1.0.9 parsetools-2.0.11 percept-0.8.9 public_key-0.22 reltool-0.6.5 runtime_tools-1.8.14 sasl-2.4 snmp-4.25.1 ssh-3.0.1 ssl-5.3.4 stdlib-2.0 syntax_tools-1.6.14 test_server-3.7 tools-2.6.14 typer-0.9.6 webtool-0.8.10 wx-1.2 xmerl-1.3.7 # :
diff --git a/system/doc/design_principles/applications.xml b/system/doc/design_principles/applications.xml
index 228ca1f2bf..7b030115df 100644
--- a/system/doc/design_principles/applications.xml
+++ b/system/doc/design_principles/applications.xml
@@ -4,7 +4,7 @@
<chapter>
<header>
<copyright>
- <year>1997</year><year>2013</year>
+ <year>1997</year><year>2014</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -157,8 +157,9 @@ ch_app:stop([])</code>
all applications have dependencies to at least <c>kernel</c>
and <c>stdlib</c>.</item>
</taglist>
- <p>The syntax and contents of of the application resource file
- are described in detail in <c>app(4)</c>.</p>
+ <note><p>The syntax and contents of of the application resource file
+ are described in detail in the<seealso marker="kernel:app">
+ Application resource file reference</seealso>.</p></note>
</section>
<section>
diff --git a/system/doc/design_principles/release_handling.xml b/system/doc/design_principles/release_handling.xml
index 2a5831b89f..ba8a88d1c2 100644
--- a/system/doc/design_principles/release_handling.xml
+++ b/system/doc/design_principles/release_handling.xml
@@ -4,7 +4,7 @@
<chapter>
<header>
<copyright>
- <year>2003</year><year>2013</year>
+ <year>2003</year><year>2014</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -329,13 +329,26 @@
automatically ensured.</p>
<p>When the release handler encounters the instruction, it first
generates a temporary boot file, which starts the new versions
- of the emulator and the core applications. Then it shuts down
+ of the emulator and the core applications, and the old version
+ of all other applications. Then it shuts down
the current emulator by calling <c>init:reboot()</c>, see
<c>init(3)</c>. All processes are terminated gracefully and
the system is rebooted by the heart program, using the
temporary boot file. After the reboot, the rest of the relup
instructions are executed. This is done as a part of the
temporary boot script.</p>
+ <warning>
+ <p>Since this mechanism causes the new versions of the
+ emulator and core applications to run with the old version of
+ other applications during startup, extra care must be taken to
+ avoid incompatibility. Incompatible changes in the core
+ applications may in some situations be necessary. If possible,
+ such changes are preceded by deprecation over two major
+ releases before the actual change. To make sure your
+ application is not crashed by an incompatible change, always
+ remove any call to deprecated functions as soon as
+ possible.</p>
+ </warning>
<p>An info report is written when the upgrade is completed. To
programatically find out if the upgrade is complete,
call <c>release_handler:which_releases(current)</c> and check
diff --git a/system/doc/getting_started/seq_prog.xml b/system/doc/getting_started/seq_prog.xml
index 3830a34e5a..fd49102263 100644
--- a/system/doc/getting_started/seq_prog.xml
+++ b/system/doc/getting_started/seq_prog.xml
@@ -419,6 +419,129 @@ list_length([First | Rest]) ->
</section>
<section>
+ <title>Maps</title>
+ <p>Maps are a set of key to value associations. These associations
+ are encapsulated with "#{" and "}". To create an association from
+ "key" to value 42, we write:</p>
+<code type="none">
+> #{ "key" => 42 }.
+#{"key" => 42}</code>
+ <p>We will jump straight into the deep end with an example using some
+ interesting features.</p>
+ <p>The following example shows how we calculate alpha blending using
+ maps to reference color and alpha channels:</p>
+ <code type="none">
+-module(color).
+
+-export([new/4, blend/2]).
+
+-define(is_channel(V), (is_float(V) andalso V &gt;= 0.0 andalso V =&lt; 1.0)).
+
+new(R,G,B,A) when ?is_channel(R), ?is_channel(G),
+ ?is_channel(B), ?is_channel(A) ->
+ #{red =&gt; R, green =&gt; G, blue =&gt; B, alpha =&gt; A}.
+
+blend(Src,Dst) ->
+ blend(Src,Dst,alpha(Src,Dst)).
+
+blend(Src,Dst,Alpha) when Alpha > 0.0 ->
+ Dst#{
+ red := red(Src,Dst) / Alpha,
+ green := green(Src,Dst) / Alpha,
+ blue := blue(Src,Dst) / Alpha,
+ alpha := Alpha
+ };
+blend(_,Dst,_) ->
+ Dst#{
+ red := 0.0,
+ green := 0.0,
+ blue := 0.0,
+ alpha := 0.0
+ }.
+
+alpha(#{alpha := SA}, #{alpha := DA}) ->
+ SA + DA*(1.0 - SA).
+
+red(#{red := SV, alpha := SA}, #{red := DV, alpha := DA}) ->
+ SV*SA + DV*DA*(1.0 - SA).
+green(#{green := SV, alpha := SA}, #{green := DV, alpha := DA}) ->
+ SV*SA + DV*DA*(1.0 - SA).
+blue(#{blue := SV, alpha := SA}, #{blue := DV, alpha := DA}) ->
+ SV*SA + DV*DA*(1.0 - SA).</code>
+ <p>Compile (file <c>color.erl</c>) and test:</p>
+ <pre>
+> <input>c(color).</input>
+{ok,color}
+> <input>C1 = color:new(0.3,0.4,0.5,1.0).</input>
+#{alpha => 1.0,blue => 0.5,green => 0.4,red => 0.3}
+> <input>C2 = color:new(1.0,0.8,0.1,0.3).</input>
+#{alpha => 0.3,blue => 0.1,green => 0.8,red => 1.0}
+> <input>color:blend(C1,C2).</input>
+#{alpha => 1.0,blue => 0.5,green => 0.4,red => 0.3}
+> <input>color:blend(C2,C1).</input>
+#{alpha => 1.0,blue => 0.38,green => 0.52,red => 0.51}
+</pre>
+ <p>This example warrant some explanation:</p>
+ <code type="none">
+-define(is_channel(V), (is_float(V) andalso V &gt;= 0.0 andalso V =&lt; 1.0)).</code>
+ <p>
+ First we define a macro <c>is_channel</c> to help with our guard tests.
+ This is only here for convenience and to reduce syntax cluttering.
+
+ You can read more about <seealso marker="doc/reference_manual:macros">Macros</seealso>
+ in the Erlang Reference Manual.
+ </p>
+ <code type="none">
+new(R,G,B,A) when ?is_channel(R), ?is_channel(G),
+ ?is_channel(B), ?is_channel(A) ->
+ #{red =&gt; R, green =&gt; G, blue =&gt; B, alpha =&gt; A}.</code>
+ <p>
+ The function <c>new/4</c> creates a new map term with and lets the keys
+ <c>red</c>, <c>green</c>, <c>blue</c> and <c>alpha</c> be associated
+ with an initial value. In this case we only allow for float
+ values between and including 0.0 and 1.0 as ensured by the <c>?is_channel/1</c> macro
+ for each argument. Only the <c>=></c> operator is allowed when creating a new map.
+ </p>
+ <p>
+ By calling <c>blend/2</c> on any color term created by <c>new/4</c> we can calculate
+ the resulting color as determined by the two maps terms.
+ </p>
+ <p>
+ The first thing <c>blend/2</c> does is to calculate the resulting alpha channel.
+ </p>
+ <code type="none">
+alpha(#{alpha := SA}, #{alpha := DA}) ->
+ SA + DA*(1.0 - SA).</code>
+ <p>
+ We fetch the value associated with key <c>alpha</c> for both arguments using
+ the <c>:=</c> operator. Any other keys
+ in the map are ignored, only the key <c>alpha</c> is required and checked for.
+ </p>
+ <p>This is also the case for functions <c>red/2</c>, <c>blue/2</c> and <c>green/2</c>.</p>
+ <code type="none">
+red(#{red := SV, alpha := SA}, #{red := DV, alpha := DA}) ->
+ SV*SA + DV*DA*(1.0 - SA).</code>
+ <p>
+ The difference here is that we check for two keys in each map argument. The other keys
+ are ignored.
+ </p>
+ <p>
+ Finally we return the resulting color in <c>blend/3</c>.
+ </p>
+ <code type="none">
+blend(Src,Dst,Alpha) when Alpha > 0.0 ->
+ Dst#{
+ red := red(Src,Dst) / Alpha,
+ green := green(Src,Dst) / Alpha,
+ blue := blue(Src,Dst) / Alpha,
+ alpha := Alpha
+ };</code>
+ <p>
+ We update the <c>Dst</c> map with new channel values. The syntax for updating an existing key with a new value is done with <c>:=</c> operator.
+ </p>
+ </section>
+
+ <section>
<title>Standard Modules and Manual Pages</title>
<p>Erlang has a lot of standard modules to help you do things. For
example, the module <c>io</c> contains a lot of functions to help
diff --git a/system/doc/installation_guide/Makefile b/system/doc/installation_guide/Makefile
index 6923f52d8a..83210bd21f 100644
--- a/system/doc/installation_guide/Makefile
+++ b/system/doc/installation_guide/Makefile
@@ -1,7 +1,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 1996-2012. All Rights Reserved.
+# Copyright Ericsson AB 1996-2014. All Rights Reserved.
#
# The contents of this file are subject to the Erlang Public License,
# Version 1.1, (the "License"); you may not use this file except in
@@ -58,8 +58,7 @@ XML_FILES = \
GENERATED_XML_FILES = \
INSTALL.xml \
INSTALL-CROSS.xml \
- INSTALL-WIN32.xml \
- MARKDOWN.xml
+ INSTALL-WIN32.xml
# ----------------------------------------------------
@@ -74,8 +73,7 @@ REDIRECT_HTML_DIR = $(HTMLDIR)/source
REDIRECT_HTML_FILES = \
$(REDIRECT_HTML_DIR)/INSTALL.html \
$(REDIRECT_HTML_DIR)/INSTALL-CROSS.html \
- $(REDIRECT_HTML_DIR)/INSTALL-WIN32.html \
- $(REDIRECT_HTML_DIR)/MARKDOWN.html
+ $(REDIRECT_HTML_DIR)/INSTALL-WIN32.html
# ----------------------------------------------------
# FLAGS
diff --git a/system/doc/installation_guide/install-binary.xml b/system/doc/installation_guide/install-binary.xml
index 07027a39f6..af7dab6e44 100644
--- a/system/doc/installation_guide/install-binary.xml
+++ b/system/doc/installation_guide/install-binary.xml
@@ -4,7 +4,7 @@
<chapter>
<header>
<copyright>
- <year>2000</year><year>2013</year>
+ <year>2000</year><year>2014</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -31,117 +31,40 @@
<rev>C</rev>
<file>install-binary.xml</file>
</header>
-
- <section>
- <title>UNIX</title>
-
- <section>
- <title>Introduction</title>
- <p>The system is delivered as a single compressed tar file.</p>
- <p>To browse the on-line HTML documentation, Netscape or an equivalent
- browser supporting frames is needed.</p>
- </section>
-
- <section>
- <title>Installation Procedure</title>
- <p>When installed, the entire system, except for a small start-up
- script, resides in a single directory tree. The location of this
- directory tree can be chosen arbitrarily by the installer, and it
- does not need to be in the user's <c>$PATH</c>. The only requirements
- are that the file system where it is placed has enough free space,
- and that the users who run Erlang/OTP have read access to it. In the
- example below, the directory tree is assumed to be located at
- <c>/usr/local/erlang</c>, which is here called the <em>top-level directory</em>.</p>
- <p>It is assumed that you have the compressed tar file, the name of
- which is <c><![CDATA[<PREFIX>.tar.gz]]></c>, where <c><![CDATA[<PREFIX>]]></c> is a string
- denoting the particular Erlang/OTP release, e.g.
- <c>otp_LXA_11930_sunos5_R9B</c>.</p>
- <p>Wherever the string <c><![CDATA[<PREFIX>]]></c> is used below, it should
- be replaced by the actual name prefix of the compressed tar file.</p>
- <p>The tape archive file does not have one single directory in which
- all other files are rooted. Therefore the tape archive file must be
- extracted into an empty (newly created) directory.</p>
- <list type="ordered">
- <item>
- <p>If the <em>top-level directory</em> does not already exist,
- create it:</p>
- <pre>
-mkdir /usr/local/erlang</pre>
- </item>
- <item>
- <p>Change the current directory to the <em>top level directory</em>:</p>
- <pre>
-cd /usr/local/erlang</pre>
- </item>
- <item>
- <p>Create the <em>installation directory</em> with an appropriate
- name. For example:</p>
- <pre>
-mkdir otp_r7b</pre>
- </item>
- <item>
- <p>Change to the <em>installation directory</em>, e.g.</p>
- <pre>
-cd otp_r7b</pre>
- </item>
- <item>
- <p>Assuming the compressed tar file resides in the directory
- <c><![CDATA[<SOME-DIR>]]></c>,. extract the compressed tar file into the
- current directory:</p>
- <pre>
-gunzip -c &lt;SOME-DIR&gt;/&lt;PREFIX&gt;.tar.gz | tar xfp -</pre>
- </item>
- <item>
- <p>Read the <c>README</c> file in the installation directory for
- last minute updates, before proceeding.</p>
- </item>
- <item>
- <p>Run the <c>Install</c> script in the installation directory,
- with the absolute path of the installation directory as argument,</p>
- <pre>
-./Install /usr/local/erlang/otp_r7b</pre>
- <p>and supply answers to the prompts.</p>
- <p>In most cases, there is a default answer in square brackets
- (<c>[]</c>). If the default is satisfactory, just press
- <c><![CDATA[<Return>]]></c>. In general you are only prompted for one thing:</p>
- <list type="bulleted">
- <item>
- <p>"Do you want to use a minimal system startup instead of the
- SASL startup?" <br></br>
-
- In a minimal system, only the Kernel and STDLIB applications
- are loaded and started. If the SASL startup is used, the SASL
- application is included as well. Normally, the minimal system
- is enough.</p>
- </item>
- </list>
- </item>
- <item>
- <p>Make Erlang/OTP available for users, either by putting the path
- <c>/usr/local/erlang/otp_r7b/bin</c> in users <c>$PATH</c>
- variable, or link the executable
- <c>/usr/local/erlang/otp_r7b/bin/erl</c> accordingly, e.g.:</p>
- <pre>
-ln -s /usr/local/erlang/otp_r7b/bin/erl /usr/local/bin/erl </pre>
- </item>
- </list>
- </section>
- </section>
-
<section>
<title>Windows</title>
<section>
<title>Introduction</title>
- <p>The system is delivered as a single <c>.exe</c> file.</p>
- <p>To browse the on-line HTML documentation, Netscape or an equivalent
- browser supporting frames is needed.</p>
+ <p>The system is delivered as a Windows Installer executable.
+ Get it from our <url href="http://www.erlang.org/download.html">download page</url>.</p>
</section>
<section>
- <title>Installation Procedure</title>
+ <title>Installation</title>
<p>The installation procedure is is automated. Double-click the
<c>.exe</c> file icon and follow the instructions.</p>
</section>
+ <section>
+ <title>Verification</title>
+ <list type="bulleted">
+ <item>
+ <p>Start Erlang/OTP by double-clicking on the Erlang shortcut icon on the
+ desktop.</p>
+ <p>Expect a command line window to pop up with an output looking something like this:</p>
+ <pre>
+ Erlang/OTP 17 [erts-6.0] [64-bit] [smp:2:2]
+
+ Eshell V6.0 (abort with ^G)
+ 1></pre>
+ </item>
+ <item>
+ <p>Exit by entering the command <c>halt()</c>,</p>
+ <pre>
+ 2> <input>halt().</input></pre>
+ <p>which will close the Erlang/OTP shell. </p>
+ </item>
+ </list>
+ </section>
</section>
</chapter>
diff --git a/system/doc/installation_guide/part.xml b/system/doc/installation_guide/part.xml
index 19808fd165..02bf98db7c 100644
--- a/system/doc/installation_guide/part.xml
+++ b/system/doc/installation_guide/part.xml
@@ -4,7 +4,7 @@
<part xmlns:xi="http://www.w3.org/2001/XInclude">
<header>
<copyright>
- <year>2000</year><year>2013</year>
+ <year>2000</year><year>2014</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -32,9 +32,7 @@
<p>How to install Erlang/OTP on UNIX or Windows.</p>
</description>
<xi:include href="install-binary.xml"/>
- <xi:include href="verification.xml"/>
<xi:include href="INSTALL.xml"/>
<xi:include href="INSTALL-CROSS.xml"/>
<xi:include href="INSTALL-WIN32.xml"/>
- <xi:include href="MARKDOWN.xml"/>
</part> \ No newline at end of file
diff --git a/system/doc/installation_guide/verification.xml b/system/doc/installation_guide/verification.xml
deleted file mode 100644
index 391ddfb7b8..0000000000
--- a/system/doc/installation_guide/verification.xml
+++ /dev/null
@@ -1,102 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<!DOCTYPE chapter SYSTEM "chapter.dtd">
-
-<chapter>
- <header>
- <copyright>
- <year>2000</year><year>2013</year>
- <holder>Ericsson AB. All Rights Reserved.</holder>
- </copyright>
- <legalnotice>
- The contents of this file are subject to the Erlang Public License,
- Version 1.1, (the "License"); you may not use this file except in
- compliance with the License. You should have received a copy of the
- Erlang Public License along with this software. If not, it can be
- retrieved online at http://www.erlang.org/.
-
- Software distributed under the License is distributed on an "AS IS"
- basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
- the License for the specific language governing rights and limitations
- under the License.
-
- </legalnotice>
-
- <title>Installation Verification</title>
- <prepared>Peter H&ouml;gfeldt</prepared>
- <responsible>Peter H&ouml;gfeldt</responsible>
- <docno></docno>
- <approved>(Peter H&ouml;gfeldt</approved>
- <checked></checked>
- <date>1997-05-26</date>
- <rev>C</rev>
- <file>verification.xml</file>
- </header>
- <p>This chapter is about verifying your installation by performing
- a few simple tests to see that your system is properly installed.</p>
-
- <section>
- <title>UNIX</title>
- <list type="bulleted">
- <item>
- <p>Start Erlang/OTP from the command line,</p>
- <pre>
- unix> erl</pre>
- <p>Expect the following output:</p>
- <pre>
- Erlang (BEAM) emulator version 5.0.1 [threads]
-
- Eshell V5.0.1 (abort with ^G)
- 1></pre>
- </item>
- <item>
- <p>Start the GS-based toolbar from the Erlang shell, </p>
- <pre>
- 1> <input>toolbar:start().</input></pre>
- <p>and check that the toolbar window pops up.
- </p>
- <p><em>Note:</em> The trailing full stop (<c>"."</c>) is an end marker
- for all commands in the Erlang shell, and must be entered for a
- command to begin execution.</p>
- </item>
- <item>
- <p>Exit by entering the command <c>halt()</c>,</p>
- <pre>
- 2> <input>halt().</input></pre>
- <p>which should end both the toolbar window and the command line window. </p>
- </item>
- </list>
- </section>
-
- <section>
- <title>Windows</title>
- <list type="bulleted">
- <item>
- <p>Start Erlang/OTP by double-clicking on the Erlang shortcut icon on the
- desktop.</p>
- <p>Expect a command line window to pop up with the following output,</p>
- <pre>
- Erlang (BEAM) emulator version 5.0.1 [threads]
-
- Eshell V5.0.1 (abort with ^G)
- 1></pre>
- </item>
- <item>
- <p>Start the GS-based toolbar from the Erlang shell, </p>
- <pre>
- 1> <input>toolbar:start().</input></pre>
- <p>and check that the toolbar window pops up.
- </p>
- <p><em>Note:</em> The trailing full stop (<c>"."</c>) is an end marker
- for all commands in the Erlang shell, and must be entered for a
- command to begin execution.</p>
- </item>
- <item>
- <p>Exit by entering the command <c>halt()</c>,</p>
- <pre>
- 2> <input>halt().</input></pre>
- <p>which should end both the toolbar window and the command line window. </p>
- </item>
- </list>
- </section>
-</chapter>
-
diff --git a/system/doc/installation_guide/xmlfiles.mk b/system/doc/installation_guide/xmlfiles.mk
index 3995c607af..c443334cd7 100644
--- a/system/doc/installation_guide/xmlfiles.mk
+++ b/system/doc/installation_guide/xmlfiles.mk
@@ -1,7 +1,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 2009-2013. All Rights Reserved.
+# Copyright Ericsson AB 2009-2014. All Rights Reserved.
#
# The contents of this file are subject to the Erlang Public License,
# Version 1.1, (the "License"); you may not use this file except in
@@ -18,8 +18,6 @@
#
INST_GUIDE_CHAPTER_FILES = \
install-binary.xml \
- verification.xml \
INSTALL.xml \
INSTALL-CROSS.xml \
- INSTALL-WIN32.xml \
- MARKDOWN.xml
+ INSTALL-WIN32.xml
diff --git a/system/doc/reference_manual/data_types.xml b/system/doc/reference_manual/data_types.xml
index 8c690d6b86..0031664dfb 100644
--- a/system/doc/reference_manual/data_types.xml
+++ b/system/doc/reference_manual/data_types.xml
@@ -190,6 +190,38 @@ adam
</section>
<section>
+ <title>Map</title>
+ <p>Compound data type with a variable number of key-value associations:</p>
+ <pre>
+#{Key1=>Value1,...,KeyN=>ValueN}</pre>
+ <p>Each key-value association in the map is called an
+ <em>association pair</em>. The key and value parts of the pair are
+ called <em>elements</em>. The number of association pairs is said to be
+ the <em>size</em> of the map.</p>
+ <p>There exists a number of BIFs to manipulate maps.</p>
+ <p>Examples:</p>
+ <pre>
+1> <input>M1 = #{name=>adam,age=>24,date=>{july,29}}.</input>
+#{age => 24,date => {july,29},name => adam}
+2> <input>maps:get(name,M1).</input>
+adam
+3> <input>maps:get(date,M1).</input>
+{july,29}
+4> <input>M2 = maps:update(age,25,M1).</input>
+#{age => 25,date => {july,29},name => adam}
+5> <input>map_size(M).</input>
+3
+6> <input>map_size(#{}).</input>
+0</pre>
+ <p>A collection of maps processing functions can be found in
+ the STDLIB module <seealso marker="stdlib:maps"><c>maps</c></seealso>.</p>
+ <p>Read more about <seealso marker="maps">Maps</seealso>.</p>
+ <note>
+ <p>Maps are considered experimental during OTP 17.</p>
+ </note>
+ </section>
+
+ <section>
<title>List</title>
<p>Compound data type with a variable number of terms.</p>
<pre>
diff --git a/system/doc/reference_manual/expressions.xml b/system/doc/reference_manual/expressions.xml
index e9de3e006e..37208710fe 100644
--- a/system/doc/reference_manual/expressions.xml
+++ b/system/doc/reference_manual/expressions.xml
@@ -56,7 +56,7 @@ Expr1 + Expr2</code>
<marker id="term"></marker>
<title>Terms</title>
<p>The simplest form of expression is a term, that is an integer,
- float, atom, string, list or tuple.
+ float, atom, string, list, map or tuple.
The return value is the term itself.</p>
</section>
@@ -1348,6 +1348,9 @@ end</pre>
<cell align="left" valign="middle"><c>is_list/1</c></cell>
</row>
<row>
+ <cell align="left" valign="middle"><c>is_map/1</c></cell>
+ </row>
+ <row>
<cell align="left" valign="middle"><c>is_number/1</c></cell>
</row>
<row>
@@ -1398,6 +1401,9 @@ end</pre>
<cell align="left" valign="middle"><c>length(List)</c></cell>
</row>
<row>
+ <cell align="left" valign="middle"><c>map_size(Map)</c></cell>
+ </row>
+ <row>
<cell align="left" valign="middle"><c>node()</c></cell>
</row>
<row>
diff --git a/system/doc/reference_manual/maps.xml b/system/doc/reference_manual/maps.xml
new file mode 100644
index 0000000000..78808ce4a2
--- /dev/null
+++ b/system/doc/reference_manual/maps.xml
@@ -0,0 +1,274 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<!DOCTYPE chapter SYSTEM "chapter.dtd">
+
+<chapter>
+ <header>
+ <copyright>
+ <year>2014</year>
+ <holder>Ericsson AB. All Rights Reserved.</holder>
+ </copyright>
+ <legalnotice>
+ The contents of this file are subject to the Erlang Public License,
+ Version 1.1, (the "License"); you may not use this file except in
+ compliance with the License. You should have received a copy of the
+ Erlang Public License along with this software. If not, it can be
+ retrieved online at http://www.erlang.org/.
+
+ Software distributed under the License is distributed on an "AS IS"
+ basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ the License for the specific language governing rights and limitations
+ under the License.
+ </legalnotice>
+
+ <title>Maps</title>
+ <prepared></prepared>
+ <docno></docno>
+ <date></date>
+ <rev></rev>
+ <file>maps.xml</file>
+ </header>
+
+ <note>
+ <p>Maps are considered experimental during OTP 17 and may be subject to change.</p>
+ <p>The documentation below describes it being possible to use arbitrary
+ expressions or variables as keys, this is <em>NOT</em> implemented in the current
+ version of Erlang/OTP.</p>
+ <p>Exceptions returns <c>badarg</c> instead of <c>badmap</c>, this will change in
+ the future releases.</p>
+ </note>
+
+ <section>
+ <title>Creating Maps</title>
+ <p>
+ Constructing a new map is done by letting an expression <c>K</c> be associated with
+ another expression <c>V</c>:
+ </p>
+ <code>#{ K => V }</code>
+ <p>
+ New maps may include multiple associations at construction by listing every
+ association:
+ </p>
+ <code>#{ K1 => V1, .., Kn => Vn }</code>
+ <p>
+ An empty map is constructed by not associating any terms with each other:
+ </p>
+ <code>#{}</code>
+ <p>
+ All keys and values in the map are terms. Any expression is first evaluated and
+ then the resulting terms are used as <em>key</em> and <em>value</em> respectively.
+ </p>
+ <p>
+ Keys and values are separated by the <c>=></c> arrow and associations are
+ separated by <c>,</c>.
+ </p>
+
+ <p>
+ Examples:
+ </p>
+ <code>
+M0 = #{}, % empty map
+M1 = #{a => &lt;&lt;"hello"&gt;&gt;}, % single association with literals
+M2 = #{1 => 2, b => b}, % multiple associations with literals
+M3 = #{k => {A,B}}, % single association with variables
+M4 = #{{"w", 1} => f()}. % compound key associated with an evaluated expression</code>
+ <p>
+ where, <c>A</c> and <c>B</c> are any expressions and <c>M0</c> through <c>M4</c>
+ are the resulting map terms.
+ </p>
+ <p>
+ If two matching keys are declared, the latter key will take precedence.
+ </p>
+ <p>
+ Example:
+ </p>
+
+<pre>
+1> <input>#{1 => a, 1 => b}.</input>
+#{1 => b }
+2> <input>#{1.0 => a, 1 => b}.</input>
+#{1 => b, 1.0 => a}
+</pre>
+ <p>
+ The order in which the expressions constructing the keys and their
+ associated values are evaluated is not defined. The syntactic order of
+ the key-value pairs in the construction is of no relevance, except in
+ the above mentioned case of two matching keys.
+ </p>
+ </section>
+
+ <section>
+ <title>Updating Maps</title>
+ <p>
+ Updating a map has similar syntax as constructing it.
+ </p>
+ <p>
+ An expression defining the map to be updated is put in front of the expression
+ defining the keys to be updated and their respective values.
+ </p>
+ <code>M#{ K => V }</code>
+ <p>
+ where <c>M</c> is a term of type map and <c>K</c> and <c>V</c> are any expression.
+ </p>
+ <p>
+ If key <c>K</c> does not match any existing key in the map, a new association
+ will be created from key <c>K</c> to value <c>V</c>. If key <c>K</c> matches
+ an existing key in map <c>M</c> its associated value will be replaced by the
+ new value <c>V</c>. In both cases the evaluated map expression will return a new map.
+ </p>
+ <p>
+ If <c>M</c> is not of type map an exception of type <c>badmap</c> is thrown.
+ </p>
+ <p>
+ To only update an existing value, the following syntax is used,
+ </p>
+ <code>M#{ K := V } </code>
+ <p>
+ where <c>M</c> is an term of type map, <c>V</c> is an expression and <c>K</c>
+ is an expression which evaluates to an existing key in <c>M</c>.
+ </p>
+ <p>
+ If key <c>K</c> does not match any existing keys in map <c>M</c> an exception
+ of type <c>badarg</c> will be triggered at runtime. If a matching key <c>K</c>
+ is present in map <c>M</c> its associated value will be replaced by the new
+ value <c>V</c> and the evaluated map expression returns a new map.
+ </p>
+ <p>
+ If <c>M</c> is not of type map an exception of type <c>badmap</c> is thrown.
+ </p>
+ <p>
+ Examples:
+ </p>
+ <code>
+M0 = #{},
+M1 = M0#{a => 0},
+M2 = M1#{a => 1, b => 2},
+M3 = M2#{"function" => fun() -> f() end},
+M4 = M3#{a := 2, b := 3}. % 'a' and 'b' was added in `M1` and `M2`.</code>
+ <p>
+ where <c>M0</c> is any map. It follows that <c>M1 .. M4</c> are maps as well.
+ </p>
+ <p>
+ More Examples:
+ </p>
+<pre>
+1> <input>M = #{1 => a}.</input>
+#{1 => a }
+2> <input>M#{1.0 => b}.</input>
+#{1 => a, 1.0 => b}.
+3> <input>M#{1 := b}.</input>
+#{1 => b}
+4> <input>M#{1.0 := b}.</input>
+** exception error: bad argument
+</pre>
+ <p>
+ As in construction, the order in which the key and value expressions
+ are evaluated is not defined. The
+ syntactic order of the key-value pairs in the update is of no
+ relevance, except in the case where two keys match, in which
+ case the latter value is used.
+ </p>
+ </section>
+
+ <section>
+ <title>Maps in Patterns</title>
+ <p>
+ Matching of key-value associations from maps is done in the following way:
+ </p>
+
+ <code>#{ K := V } = M</code>
+ <p>
+ where <c>M</c> is any map. The key <c>K</c> has to be an expression with bound
+ variables or a literals, and <c>V</c> can be any pattern with either bound or
+ unbound variables.
+ </p>
+ <p>
+ If the variable <c>V</c> is unbound, it will be bound to the value associated
+ with the key <c>K</c>, which has to exist in the map <c>M</c>. If the variable
+ <c>V</c> is bound, it has to match the value associated with <c>K</c> in <c>M</c>.
+ </p>
+ <p> Example: </p>
+<code>
+1> <input>M = #{"tuple" => {1,2}}.</input>
+#{"tuple" => {1,2}}
+2> <input>#{"tuple" := {1,B}} = M.</input>
+#{"tuple" => {1,2}}
+3> <input>B.</input>
+2.</code>
+ <p>
+ This will bind variable <c>B</c> to integer <c>2</c>.
+ </p>
+ <p>
+ Similarly, multiple values from the map may be matched:
+ </p>
+ <code>#{ K1 := V1, .., Kn := Vn } = M</code>
+ <p>
+ where keys <c>K1 .. Kn</c> are any expressions with literals or bound variables. If all
+ keys exist in map <c>M</c> all variables in <c>V1 .. Vn</c> will be matched to the
+ associated values of their respective keys.
+ </p>
+ <p>
+ If the matching conditions are not met, the match will fail, either with
+ </p>
+ <list>
+ <item>
+ a <c>badmatch</c> exception, if used in the context of the matching operator
+ as in the example,
+ </item>
+ <item>
+ or resulting in the next clause being tested in function heads and
+ case expressions.
+ </item>
+ </list>
+ <p>
+ Matching in maps only allows for <c>:=</c> as delimiters of associations.
+ The order in which keys are declared in matching has no relevance.
+ </p>
+ <p>
+ Duplicate keys are allowed in matching and will match each pattern associated
+ to the keys.
+ </p>
+ <code>#{ K := V1, K := V2 } = M</code>
+ <p>
+ Matching an expression against an empty map literal will match its type but
+ no variables will be bound:
+ </p>
+ <code>#{} = Expr</code>
+ <p>
+ This expression will match if the expression <c>Expr</c> is of type map, otherwise
+ it will fail with an exception <c>badmatch</c>.
+ </p>
+ <section>
+ <title>Matching syntax: Example with literals in function heads</title>
+ <p>
+ Matching of literals as keys are allowed in function heads.
+ </p>
+ <code>
+%% only start if not_started
+handle_call(start, From, #{ state := not_started } = S) ->
+...
+ {reply, ok, S#{ state := start }};
+
+%% only change if started
+handle_call(change, From, #{ state := start } = S) ->
+...
+ {reply, ok, S#{ state := changed }};</code>
+ </section>
+ </section>
+ <section>
+ <title>Maps in Guards</title>
+ <p>
+ Maps are allowed in guards as long as all sub-expressions are valid guard expressions.
+ </p>
+ <p>
+ Two guard BIFs handles maps:
+ </p>
+ <list>
+ <item>
+ <seealso marker="erts:erlang#is_map/1">is_map/1</seealso>
+ </item>
+ <item>
+ <seealso marker="erts:erlang#map_size/1">map_size/1</seealso>
+ </item>
+ </list>
+ </section>
+</chapter>
diff --git a/system/doc/reference_manual/modules.xml b/system/doc/reference_manual/modules.xml
index cd4c3a1b1b..f0ec7ef165 100644
--- a/system/doc/reference_manual/modules.xml
+++ b/system/doc/reference_manual/modules.xml
@@ -53,10 +53,10 @@ fact(0) -> % |
<pre>
-Tag(Value).</pre>
<p><c>Tag</c> must be an atom, while <c>Value</c> must be a literal
- term. As a convenience in user-defined attributes, the literal term
- <c>Value</c> the syntax <c>Name/Arity</c>
- (where <c>Name</c> is an atom and <c>Arity</c> a positive integer)
- will be translated to <c>{Name,Arity}</c>.</p>
+ term. As a convenience in user-defined attributes, if the literal term
+ <c>Value</c> has the syntax <c>Name/Arity</c>
+ (where <c>Name</c> is an atom and <c>Arity</c> a positive integer),
+ the term <c>Name/Arity</c> will be translated to <c>{Name,Arity}</c>.</p>
<p>Any module attribute can be specified. The attributes are stored
in the compiled code and can be retrieved by calling
diff --git a/system/doc/reference_manual/part.xml b/system/doc/reference_manual/part.xml
index ee8f3dd7eb..36fb888748 100644
--- a/system/doc/reference_manual/part.xml
+++ b/system/doc/reference_manual/part.xml
@@ -36,6 +36,7 @@
<xi:include href="typespec.xml"/>
<xi:include href="expressions.xml"/>
<xi:include href="macros.xml"/>
+ <xi:include href="maps.xml"/>
<xi:include href="records.xml"/>
<xi:include href="errors.xml"/>
<xi:include href="processes.xml"/>
diff --git a/system/doc/reference_manual/typespec.xml b/system/doc/reference_manual/typespec.xml
index 71aec732cf..cc35c6eb21 100644
--- a/system/doc/reference_manual/typespec.xml
+++ b/system/doc/reference_manual/typespec.xml
@@ -100,6 +100,7 @@
| Fun
| Integer
| List
+ | Map
| Tuple
| Union
| UserDefined %% described in Section 6.3
@@ -126,10 +127,17 @@
| nonempty_improper_list(Type1, Type2) %% Type1 and Type2 as above
| nonempty_list(Type) %% Proper non-empty list
+ Map :: map() %% stands for a map of any size
+ | #{} %% stands for a map of any size
+ | #{PairList}
+
Tuple :: tuple() %% stands for a tuple of any size
| {}
| {TList}
+ PairList :: Type => Type
+ | Type => Type, PairList
+
TList :: Type
| Type, TList
@@ -275,6 +283,10 @@
Records have been extended to possibly contain type information.
This is described in the sub-section <seealso marker="#typeinrecords">"Type information in record declarations"</seealso> below.
</p>
+ <note>
+ <p>Map types, both <c>map()</c> and <c>#{ ... }</c>, are considered experimental during OTP 17.</p>
+ <p>No type information of maps pairs, only the containing map types, are used by Dialyzer in OTP 17.</p>
+ </note>
</section>
<section>
diff --git a/system/doc/reference_manual/xmlfiles.mk b/system/doc/reference_manual/xmlfiles.mk
index 6886c8c7cf..181e6f8042 100644
--- a/system/doc/reference_manual/xmlfiles.mk
+++ b/system/doc/reference_manual/xmlfiles.mk
@@ -24,6 +24,7 @@ REF_MAN_CHAPTER_FILES = \
functions.xml \
expressions.xml \
macros.xml \
+ maps.xml \
records.xml \
errors.xml \
processes.xml \
diff --git a/system/doc/system_principles/create_target.xmlsrc b/system/doc/system_principles/create_target.xmlsrc
index fbc935d708..b5f8d8ac4d 100644
--- a/system/doc/system_principles/create_target.xmlsrc
+++ b/system/doc/system_principles/create_target.xmlsrc
@@ -4,7 +4,7 @@
<chapter>
<header>
<copyright>
- <year>2002</year><year>2013</year>
+ <year>2002</year><year>2014</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -21,7 +21,7 @@
</legalnotice>
- <title>Creating a First Target System</title>
+ <title>Creating and Upgrading a Target System</title>
<prepared>Peter H&ouml;gfeldt</prepared>
<responsible></responsible>
<docno></docno>
@@ -71,23 +71,24 @@
</section>
<section>
+ <marker id="create"/>
<title>Creating a Target System</title>
<p>It is assumed that you have a working Erlang/OTP system structured
according to the OTP Design Principles.</p>
- <p><em>Step 1.</em> First create a <c>.rel</c> file (see
- <c>rel(4)</c>) that specifies the <c>erts</c> version
- and lists all applications that should be included in the new
- basic target system. An example is the following
+ <p><em>Step 1.</em> First create a <c>.rel</c> file (see <seealso
+ marker="sasl:rel">rel(4)</seealso>) that specifies the <c>erts</c>
+ version and lists all applications that should be included in the
+ new basic target system. An example is the following
<c>mysystem.rel</c> file:</p>
<code type="none">
%% mysystem.rel
{release,
{"MYSYSTEM", "FIRST"},
- {erts, "5.1"},
- [{kernel, "2.7"},
- {stdlib, "1.10"},
- {sasl, "1.9.3"},
- {pea, "1.0"}]}. </code>
+ {erts, "5.10.4"},
+ [{kernel, "2.16.4"},
+ {stdlib, "1.19.4"},
+ {sasl, "2.3.4"},
+ {pea, "1.0"}]}.</code>
<p>The listed applications are not only original Erlang/OTP
applications but possibly also new applications that you have
written yourself (here examplified by the application
@@ -116,13 +117,13 @@ os> <input>erl -pa /home/user/target_system/myapps/pea-1.0/ebin</input></pre>
<c>systools:make_tar/2</c>. That file has the following
contents:</p>
<code type="none">
-erts-5.1/bin/
+erts-5.10.4/bin/
releases/FIRST/start.boot
releases/FIRST/mysystem.rel
releases/mysystem.rel
-lib/kernel-2.7/
-lib/stdlib-1.10/
-lib/sasl-1.9.3/
+lib/kernel-2.16.4/
+lib/stdlib-1.19.4/
+lib/sasl-2.3.4/
lib/pea-1.0/ </code>
<p>The file <c>releases/FIRST/start.boot</c> is a copy of our
<c>mysystem.boot</c></p>
@@ -142,16 +143,19 @@ lib/pea-1.0/ </code>
<item>Creates the temporary directory <c>tmp</c> and extracts the tar file
<c>mysystem.tar.gz</c> into that directory. </item>
<item>Deletes the <c>erl</c> and <c>start</c> files from
- <c>tmp/erts-5.1/bin</c>. These files will be created again from
+ <c>tmp/erts-5.10.4/bin</c>. These files will be created again from
source when installing the release.</item>
<item>Creates the directory <c>tmp/bin</c>.</item>
<item>Copies the previously created file <c>plain.boot</c> to
<c>tmp/bin/start.boot</c>.</item>
<item>Copies the files <c>epmd</c>, <c>run_erl</c>, and
- <c>to_erl</c> from the directory <c>tmp/erts-5.1/bin</c> to
+ <c>to_erl</c> from the directory <c>tmp/erts-5.10.4/bin</c> to
the directory <c>tmp/bin</c>.</item>
+ <item>Creates the directory <c>tmp/log</c>, which will be used
+ if the system is started as embedded with the <c>bin/start</c>
+ script.</item>
<item>Creates the file <c>tmp/releases/start_erl.data</c> with
- the contents "5.1 FIRST". This file is to be passed as data
+ the contents "5.10.4 FIRST". This file is to be passed as data
file to the <c>start_erl</c> script.
</item>
<item>Recreates the file <c>mysystem.tar.gz</c> from the directories
@@ -171,11 +175,11 @@ lib/pea-1.0/ </code>
<item>Extracts the tar file <c>mysystem.tar.gz</c> into the target
directory <c>/usr/local/erl-target</c>.</item>
<item>In the target directory reads the file <c>releases/start_erl.data</c>
- in order to find the Erlang runtime system version ("5.1").</item>
+ in order to find the Erlang runtime system version ("5.10.4").</item>
<item>Substitutes <c>%FINAL_ROOTDIR%</c> and <c>%EMU%</c> for
<c>/usr/local/erl-target</c> and <c>beam</c>, respectively, in
the files <c>erl.src</c>, <c>start.src</c>, and
- <c>start_erl.src</c> of the target <c>erts-5.1/bin</c>
+ <c>start_erl.src</c> of the target <c>erts-5.10.4/bin</c>
directory, and puts the resulting files <c>erl</c>,
<c>start</c>, and <c>run_erl</c> in the target <c>bin</c>
directory.</item>
@@ -185,6 +189,7 @@ lib/pea-1.0/ </code>
</section>
<section>
+ <marker id="start"/>
<title>Starting a Target System</title>
<p>Now we have a target system that can be started in various ways.</p>
<p>We start it as a <em>basic target system</em> by invoking</p>
@@ -193,7 +198,7 @@ os> <input>/usr/local/erl-target/bin/erl</input></pre>
<p>where only the <c>kernel</c> and <c>stdlib</c> applications are
started, i.e. the system is started as an ordinary development
system. There are only two files needed for all this to work:
- <c>bin/erl</c> file (obtained from <c>erts-5.1/bin/erl.src</c>)
+ <c>bin/erl</c> file (obtained from <c>erts-5.10.4/bin/erl.src</c>)
and the <c>bin/start.boot</c> file (a copy of <c>plain.boot</c>).</p>
<p>We can also start a distributed system (requires <c>bin/epmd</c>).</p>
<p>To start all applications specified in the original
@@ -208,9 +213,10 @@ os> <input>/usr/local/erl-target/bin/erl -boot /usr/local/erl-target/releases/FI
<c>bin/run_erl</c>, which in turn calls <c>bin/start_erl</c>
(roughly, <c>start_erl</c> is an embedded variant of
<c>erl</c>). </p>
- <p>The shell script <c>start</c> is only an example. You should
- edit it to suite your needs. Typically it is executed when the
- UNIX system boots.</p>
+ <p>The shell script <c>start</c>, which is generated from
+ erts-5.10.4/bin/start.src during installation, is only an
+ example. You should edit it to suite your needs. Typically it is
+ executed when the UNIX system boots.</p>
<p><c>run_erl</c> is a wrapper that provides logging of output from
the run-time system to file. It also provides a simple mechanism
for attaching to the Erlang shell (<c>to_erl</c>).</p>
@@ -218,7 +224,7 @@ os> <input>/usr/local/erl-target/bin/erl -boot /usr/local/erl-target/releases/FI
(<c>"/usr/local/erl-target"</c>), the releases directory
(<c>"/usr/local/erl-target/releases"</c>), and the location of
the <c>start_erl.data</c> file. It reads the run-time system
- version (<c>"5.1"</c>) and release version (<c>"FIRST"</c>) from
+ version (<c>"5.10.4"</c>) and release version (<c>"FIRST"</c>) from
the <c>start_erl.data</c> file, starts the run-time system of the
version found, and provides <c>-boot</c> flag specifying the boot
file of the release version found
@@ -258,6 +264,198 @@ os> <input>/usr/local/erl-target/bin/erl -boot /usr/local/erl-target/releases/FI
</section>
<section>
+ <title>Creating the Next Version</title>
+
+ <p>
+ In this example the <c>pea</c> application has been changed, and
+ so are <c>erts</c>, <c>kernel</c>, <c>stdlib</c> and
+ <c>sasl</c>.
+ </p>
+
+ <p>
+ <em>Step 1.</em> Create the <c>.rel</c> file:
+ </p>
+ <code type="none">
+%% mysystem2.rel
+{release,
+ {"MYSYSTEM", "SECOND"},
+ {erts, "6.0"},
+ [{kernel, "3.0"},
+ {stdlib, "2.0"},
+ {sasl, "2.4"},
+ {pea, "2.0"}]}.</code>
+ <p>
+ <em>Step 2.</em> Create the application upgrade file (see
+ <seealso marker="sasl:appup">appup(4)</seealso>) for <c>pea</c>,
+ for example:
+ </p>
+ <code type="none">
+%% pea.appup
+{"2.0",
+ [{"1.0",[{load_module,pea_lib}]}],
+ [{"1.0",[{load_module,pea_lib}]}]}.</code>
+ <p>
+ <em>Step 3.</em> From the directory where the
+ <c>mysystem2.rel</c> file reside, start the Erlang/OTP system:
+ </p>
+ <pre>
+os> <input>erl -pa /home/user/target_system/myapps/pea-2.0/ebin</input></pre>
+ <p>giving the path to the new version of <c>pea</c>. </p>
+
+ <p>
+ <em>Step 4.</em> Create the release upgrade file (see <seealso
+ marker="sasl:relup">relup(4)</seealso>):
+ </p>
+ <pre>
+1> <input>systools:make_relup("mysystem2",["mysystem"],["mysystem"],[{path,["/home/user/target_system/myapps/pea-1.0/ebin","/my/old/erlang/lib/*/ebin"]}]).</input></pre>
+ <p>
+ where <c>"mysystem"</c> is the base release and
+ <c>"mysystem2"</c> is the release to upgrade to.
+ </p>
+ <p>
+ Note that the <c>path</c> option is used for pointing out the
+ old version of all applications. (The new versions are already
+ in the code path - assuming of course that the erlang node on
+ which this is executed is running the correct version of
+ Erlang/OTP.)
+ </p>
+ <p>
+ <em>Step 5.</em> Create the new release:
+ </p>
+ <pre>
+2> <input>target_system:create("mysystem2").</input></pre>
+ <p>
+ Given that the <c>relup</c> file generated in step 4 above is
+ now located in the current directory, it will automatically be
+ included in the release package.
+ </p>
+ </section>
+
+ <section>
+ <title>Upgrading the Target System</title>
+ <p>
+ This part is done on the target node, and for this example we
+ want the node to be running as an embedded system with the
+ <c>-heart</c> option, allowing automatic restart of the
+ node. See <seealso marker="#start">Starting a Target
+ System</seealso> above for more information.
+ </p>
+ <p>
+ We add <c>-heart</c> to <c>bin/start</c>:
+ </p>
+ <code type="none">
+#!/bin/sh
+ROOTDIR=/usr/local/erl-target/
+
+if [ -z "$RELDIR" ]
+then
+ RELDIR=$ROOTDIR/releases
+fi
+
+START_ERL_DATA=${1:-$RELDIR/start_erl.data}
+
+$ROOTDIR/bin/run_erl -daemon /tmp/ $ROOTDIR/log "exec $ROOTDIR/bin/start_erl $ROOTDIR $RELDIR $START_ERL_DATA -heart</code>
+ <p>
+ And we use the simplest possible <c>sys.config</c>, which we
+ store in <c>releases/FIRST</c>:
+ </p>
+ <code type="none">
+%% sys.config
+[].</code>
+ <p>
+ Finally, in order to prepare the upgrade, we need to put the new
+ release package in the <c>releases</c> directory of the first
+ target system:
+ </p>
+ <pre>
+os> <input>cp mysystem2.tar.gz /usr/local/erl-target/releases</input></pre>
+ <p>
+ And assuming that the node has been started like this:
+ </p>
+ <pre>
+os> <input>/usr/local/erl-target/bin/start</input></pre>
+ <p>
+ it can be accessed like this:
+ </p>
+ <pre>
+os> <input>/usr/local/erl-target/bin/to_erl /tmp/erlang.pipe.1</input></pre>
+ <p>
+ Also note that logs can be found in
+ <c>/usr/local/erl-target/log</c>. This directory is specified as
+ an argument to <c>run_erl</c>in the start script listed above.
+ </p>
+ <p>
+ <em>Step 1.</em> Unpack the release:
+ </p>
+ <pre>
+1> <input>{ok,Vsn} = release_handler:unpack_release("mysystem2").</input></pre>
+ <p>
+ <em>Step 2.</em> Install the release:
+ </p>
+ <pre>
+2> <input>release_handler:install_release(Vsn).</input>
+<output>{continue_after_restart,"FIRST",[]}
+heart: Tue Apr 1 12:15:10 2014: Erlang has closed.
+heart: Tue Apr 1 12:15:11 2014: Executed "/usr/local/erl-target/bin/start /usr/local/erl-target/releases/new_start_erl.data" -> 0. Terminating.
+[End]</output></pre>
+ <p>
+ The above return value and output after the call to
+ <c>release_handler:install_release/1</c> means that the
+ <c>release_handler</c> has restarted the node by using
+ <c>heart</c>. This will always be done when the upgrade involves
+ a change of <c>erts</c>, <c>kernel</c>, <c>stdlib</c> or
+ <c>sasl</c>. See <seealso marker="upgrade">Upgrade when
+ Erlang/OTP has Changed</seealso> for more infomation about this.
+ </p>
+ <p>
+ The node will be accessable via a new pipe:
+ </p>
+ <pre>
+os> <input>/usr/local/erl-target/bin/to_erl /tmp/erlang.pipe.2</input></pre>
+ <p>
+ Let's see which releases we have in our system:
+ </p>
+ <pre>
+1> <input>release_handler:which_releases().</input>
+<output>[{"MYSYSTEM","SECOND",
+ ["kernel-3.0","stdlib-2.0","sasl-2.4","pea-2.0"],
+ current},
+ {"MYSYSTEM","FIRST",
+ ["kernel-2.16.4","stdlib-1.19.4","sasl-2.3.4","pea-1.0"],
+ permanent}]</output></pre>
+ <p>
+ Our new release, "SECOND", is now the current release, but we
+ can also see that our "FIRST" release is still permanent. This
+ means that if the node would be restarted at this point, it
+ would come up running the "FIRST" release again.
+ </p>
+ <p>
+ <em>Step 3.</em> Make the new release permanent:
+ </p>
+ <pre>
+2> <input>release_handler:make_permanent("SECOND").</input></pre>
+
+ <p>
+ Now look at the releases again:
+ </p>
+
+ <pre>
+3> <input>release_handler:which_releases().</input>
+<output>[{"MYSYSTEM","SECOND",
+ ["kernel-3.0","stdlib-2.0","sasl-2.4","pea-2.0"],
+ permanent},
+ {"MYSYSTEM","FIRST",
+ ["kernel-2.16.4","stdlib-1.19.4","sasl-2.3.4","pea-1.0"],
+ old}]</output></pre>
+
+ <p>
+ Here we see that the new release version is <c>permanent</c>, so
+ it would be safe to restart the node.
+ </p>
+
+ </section>
+
+ <section>
<title>Listing of target_system.erl</title>
<p>This module can also be found in the <c>examples</c> directory
of the <c>sasl</c> application.</p>
diff --git a/system/doc/system_principles/part.xml b/system/doc/system_principles/part.xml
index 811428baae..d05c89fde8 100644
--- a/system/doc/system_principles/part.xml
+++ b/system/doc/system_principles/part.xml
@@ -4,7 +4,7 @@
<part xmlns:xi="http://www.w3.org/2001/XInclude">
<header>
<copyright>
- <year>1997</year><year>2013</year>
+ <year>1997</year><year>2014</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -31,6 +31,6 @@
<xi:include href="system_principles.xml"/>
<xi:include href="error_logging.xml"/>
<xi:include href="create_target.xml"/>
+ <xi:include href="upgrade.xml"/>
<xi:include href="versions.xml"/>
</part>
-
diff --git a/system/doc/system_principles/system_principles.xml b/system/doc/system_principles/system_principles.xml
index 4f2202fdd1..70c69b1dab 100644
--- a/system/doc/system_principles/system_principles.xml
+++ b/system/doc/system_principles/system_principles.xml
@@ -4,7 +4,7 @@
<chapter>
<header>
<copyright>
- <year>1996</year><year>2013</year>
+ <year>1996</year><year>2014</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -34,13 +34,12 @@
<p>An Erlang runtime system is started with the command <c>erl</c>:</p>
<pre>
% <input>erl</input>
-Erlang (BEAM) emulator version 5.2.3.5 [hipe] [threads:0]
+Erlang/OTP 17 [erts-6.0] [hipe] [smp:8:8]
-Eshell V5.2.3.5 (abort with ^G)
+Eshell V6.0 (abort with ^G)
1> </pre>
<p><c>erl</c> understands a number of command line arguments, see
- <c>erl(1)</c>. A number of them are also described in this
- chapter.</p>
+ <c>erl(1)</c>. A number of them are also described in this chapter.</p>
<p>Application programs can access the values of the command line
arguments by calling one of the functions
<c>init:get_argument(Key)</c>, or <c>init:get_arguments()</c>.
diff --git a/system/doc/system_principles/upgrade.xml b/system/doc/system_principles/upgrade.xml
new file mode 100644
index 0000000000..68e48da0b8
--- /dev/null
+++ b/system/doc/system_principles/upgrade.xml
@@ -0,0 +1,118 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<!DOCTYPE chapter SYSTEM "chapter.dtd">
+
+<chapter>
+ <header>
+ <copyright>
+ <year>2014</year>
+ <holder>Ericsson AB. All Rights Reserved.</holder>
+ </copyright>
+ <legalnotice>
+ The contents of this file are subject to the Erlang Public License,
+ Version 1.1, (the "License"); you may not use this file except in
+ compliance with the License. You should have received a copy of the
+ Erlang Public License along with this software. If not, it can be
+ retrieved online at http://www.erlang.org/.
+
+ Software distributed under the License is distributed on an "AS IS"
+ basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ the License for the specific language governing rights and limitations
+ under the License.
+
+ </legalnotice>
+
+ <title>Upgrade when Erlang/OTP has Changed</title>
+ <prepared></prepared>
+ <responsible></responsible>
+ <docno></docno>
+ <approved></approved>
+ <checked></checked>
+ <date>2014-02-19</date>
+ <rev></rev>
+ <file>upgrade.xml</file>
+ </header>
+
+ <section>
+ <title>Introduction</title>
+ <p>
+ As of Erlang/OTP 17, most applications deliver a valid
+ application upgrade (<c>appup</c>) file. In earlier releases, a
+ majority of the applications in Erlang/OTP did not support
+ upgrade at all. Many of the applications use the
+ <c>restart_application</c> instruction. These are applications
+ for which it is not crucial to support real soft upgrade, for
+ instance tools and library applications. The
+ <c>restart_application</c> instruction
+ ensures that all modules in the application are reloaded and
+ thereby running the new code.
+ </p>
+ </section>
+
+ <section>
+ <title>Upgrade of core applications</title>
+ <p>
+ The core applications ERTS, Kernel, STDLIB
+ and SASL never allow real soft upgrade, but require the
+ Erlang emulator to be restarted. This is indicated to the
+ <c>release_handler</c> by the upgrade instruction
+ <c>restart_new_emulator</c>. This instruction will always be the
+ very first instruction executed, and it will restart the
+ emulator with the new versions of the above mentioned core
+ applications and the old versions of all other
+ applications. When the node is back up all other upgrade instructions are
+ executed, making sure each application is finally running its
+ new version.
+ </p>
+
+ <p>
+ It might seem strange to do a two-step upgrade instead of
+ just restarting the emulator with the new version of all
+ applications. The reason for this design decision is to allow
+ <c>code_change</c> functions to have side effects, for example changing
+ data on disk. It also makes sure that the upgrade mechanism for
+ non-core applications does not differ depending on whether or not
+ core applications are changed at the same time.
+ </p>
+
+ <p>
+ If, however, the more brutal variant is preferred, it is
+ possible to handwrite the release upgrade file using only the
+ single upgrade instruction <c>restart_emulator</c>. This
+ instruction, in contrast to <c>restart_new_emulator</c>, will
+ cause the emulator to restart with the new versions of
+ <em>all</em> applications.
+ </p>
+
+ <p>
+ <em>Note</em> that if other instructions are included before
+ <c>restart_emulator</c> in the handwritten <c>relup</c> file,
+ they will be executed in the old emulator. This is a big risk
+ since there is no guarantee that new beam code can be loaded
+ into the old emulator. Adding instructions after
+ <c>restart_emulator</c> has no effect as the
+ <c>release_handler</c> will not do any attempt at executing
+ them.
+ </p>
+
+ <p>
+ See <seealso marker="sasl:relup">relup(4)</seealso> for
+ information about the release upgrade file, and <seealso
+ marker="sasl:appup">appup(4)</seealso> for further information
+ about upgrade instructions.
+ </p>
+ </section>
+
+ <section>
+ <title>Applications that still do not allow code upgrade</title>
+ <p>
+ A few applications, for instance HiPE do not support
+ upgrade at all. This is indicated by an application upgrade file
+ containing only <c>{Vsn,[],[]}</c>. Any attempt at creating a release
+ upgrade file with such input will fail.
+ The only way to force an upgrade involving applications like this is to
+ handwrite the <c>relup</c> file, preferably as described above
+ with only the <c>restart_emulator</c> instruction.
+ </p>
+
+ </section>
+</chapter>
diff --git a/system/doc/system_principles/versions.xml b/system/doc/system_principles/versions.xml
index 2bf0d18010..c63913d867 100644
--- a/system/doc/system_principles/versions.xml
+++ b/system/doc/system_principles/versions.xml
@@ -61,14 +61,13 @@
<c>filename:join([<seealso marker="kernel:code#root_dir/0">code:root_dir()</seealso>, "releases", <seealso marker="erts:erlang#system_info_otp_release">erlang:system_info(otp_release)</seealso>, "OTP_VERSION"]).</c></p>
<p>If the version read from the <c>OTP_VERSION</c> file in a
development system has a <c>**</c> suffix, the system has been
- patched using the
- <seealso marker="doc/installation_guide:PATCH-APP"><c>$ERL_TOP/otp_build patch_app</c></seealso>
- tool. In this case, the system consists of application versions from
- multiple OTP versions. The version preceding the <c>**</c>
+ patched using the <c>otp_patch_apply</c> tool available to
+ licensed customers. In this case, the system consists of application
+ versions from multiple OTP versions. The version preceding the <c>**</c>
suffix corresponds to the OTP version of the base system that
has been patched. Note that if a development system is updated by
- other means than <c>$ERL_TOP/otp_build patch_app</c>, the
- <c>OTP_VERSION</c> file may identify wrong OTP version.</p>
+ other means than <c>otp_patch_apply</c>, the <c>OTP_VERSION</c> file
+ may identify wrong OTP version.</p>
<p>No <c>OTP_VERSION</c> file will be placed in a
<seealso marker="create_target">target system</seealso> created
diff --git a/system/doc/system_principles/xmlfiles.mk b/system/doc/system_principles/xmlfiles.mk
index 9743949798..c60ffbad28 100644
--- a/system/doc/system_principles/xmlfiles.mk
+++ b/system/doc/system_principles/xmlfiles.mk
@@ -1,7 +1,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 2009. All Rights Reserved.
+# Copyright Ericsson AB 2009-2014. All Rights Reserved.
#
# The contents of this file are subject to the Erlang Public License,
# Version 1.1, (the "License"); you may not use this file except in
@@ -20,4 +20,5 @@ SYSTEM_PRINCIPLES_CHAPTER_FILES = \
system_principles.xml \
error_logging.xml \
create_target.xml \
+ upgrade.xml \
versions.xml