aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--bootstrap/lib/compiler/ebin/beam_block.beambin11940 -> 12036 bytes
-rw-r--r--bootstrap/lib/compiler/ebin/beam_bs.beambin5476 -> 5464 bytes
-rw-r--r--bootstrap/lib/compiler/ebin/beam_bsm.beambin11948 -> 11936 bytes
-rw-r--r--bootstrap/lib/compiler/ebin/beam_clean.beambin6384 -> 6552 bytes
-rw-r--r--bootstrap/lib/compiler/ebin/beam_dead.beambin13068 -> 13052 bytes
-rw-r--r--bootstrap/lib/compiler/ebin/beam_dict.beambin5068 -> 5060 bytes
-rw-r--r--bootstrap/lib/compiler/ebin/beam_disasm.beambin21684 -> 21680 bytes
-rw-r--r--bootstrap/lib/compiler/ebin/beam_except.beambin3216 -> 3216 bytes
-rw-r--r--bootstrap/lib/compiler/ebin/beam_flatten.beambin2956 -> 2988 bytes
-rw-r--r--bootstrap/lib/compiler/ebin/beam_jump.beambin8976 -> 8968 bytes
-rw-r--r--bootstrap/lib/compiler/ebin/beam_receive.beambin6112 -> 6112 bytes
-rw-r--r--bootstrap/lib/compiler/ebin/beam_reorder.beambin1908 -> 1904 bytes
-rw-r--r--bootstrap/lib/compiler/ebin/beam_split.beambin2132 -> 2168 bytes
-rw-r--r--bootstrap/lib/compiler/ebin/beam_trim.beambin7508 -> 7508 bytes
-rw-r--r--bootstrap/lib/compiler/ebin/beam_type.beambin17964 -> 17964 bytes
-rw-r--r--bootstrap/lib/compiler/ebin/beam_utils.beambin21876 -> 21896 bytes
-rw-r--r--bootstrap/lib/compiler/ebin/beam_validator.beambin29648 -> 30012 bytes
-rw-r--r--bootstrap/lib/compiler/ebin/cerl.beambin30048 -> 30040 bytes
-rw-r--r--bootstrap/lib/compiler/ebin/cerl_inline.beambin37736 -> 37664 bytes
-rw-r--r--bootstrap/lib/compiler/ebin/compile.beambin41340 -> 41332 bytes
-rw-r--r--bootstrap/lib/compiler/ebin/core_lint.beambin12716 -> 12716 bytes
-rw-r--r--bootstrap/lib/compiler/ebin/core_pp.beambin11704 -> 11704 bytes
-rw-r--r--bootstrap/lib/compiler/ebin/core_scan.beambin6684 -> 6672 bytes
-rw-r--r--bootstrap/lib/compiler/ebin/sys_core_fold.beambin47508 -> 47428 bytes
-rw-r--r--bootstrap/lib/compiler/ebin/sys_core_inline.beambin3984 -> 3976 bytes
-rw-r--r--bootstrap/lib/compiler/ebin/sys_pre_attributes.beambin2724 -> 2716 bytes
-rw-r--r--bootstrap/lib/compiler/ebin/v3_codegen.beambin64932 -> 64756 bytes
-rw-r--r--bootstrap/lib/compiler/ebin/v3_core.beambin57744 -> 57684 bytes
-rw-r--r--bootstrap/lib/compiler/ebin/v3_kernel.beambin55940 -> 55868 bytes
-rw-r--r--bootstrap/lib/compiler/ebin/v3_kernel_pp.beambin12456 -> 12456 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/application_controller.beambin30752 -> 30688 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/application_master.beambin6352 -> 6344 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/application_starter.beambin1196 -> 1188 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/code_server.beambin23948 -> 24000 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/disk_log.beambin31896 -> 31848 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/disk_log_1.beambin23960 -> 23888 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/dist_ac.beambin24872 -> 24844 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/dist_util.beambin12140 -> 12140 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/erl_boot_server.beambin5760 -> 5744 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/file_io_server.beambin15716 -> 15700 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/global.beambin31240 -> 31240 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/global_group.beambin17020 -> 16916 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/group_history.beambin5728 -> 5720 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/hipe_unified_loader.beambin12500 -> 12496 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/inet_db.beambin26412 -> 26404 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/inet_dns.beambin19112 -> 19112 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/inet_gethost_native.beambin10092 -> 10084 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/inet_res.beambin14256 -> 14256 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/net_kernel.beambin25608 -> 25580 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/os.beambin5148 -> 5148 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/user.beambin11496 -> 11488 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/wrap_log_reader.beambin3124 -> 3124 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/array.beambin11776 -> 11776 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/dets.beambin48872 -> 48872 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/dets_server.beambin6740 -> 6732 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/dets_utils.beambin27264 -> 27260 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/dets_v9.beambin47832 -> 47804 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/digraph.beambin7872 -> 7852 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/epp.beambin27712 -> 27708 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/erl_bits.beambin2468 -> 2452 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/erl_eval.beambin30276 -> 30268 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/erl_expand_records.beambin21736 -> 21732 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/erl_lint.beambin92164 -> 92104 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/erl_parse.beambin97420 -> 97400 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/erl_pp.beambin26616 -> 26616 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/erl_tar.beambin33404 -> 33388 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/escript.beambin16864 -> 16848 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/ets.beambin22224 -> 22268 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/file_sorter.beambin29156 -> 29132 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/gen_event.beambin13440 -> 13432 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/gen_statem.beambin19684 -> 19656 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/io.beambin6028 -> 6020 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/io_lib_pretty.beambin17048 -> 17048 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/lib.beambin14976 -> 14968 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/ms_transform.beambin19452 -> 19440 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/qlc.beambin68840 -> 68796 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/qlc_pt.beambin75052 -> 75004 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/sofs.beambin37500 -> 37420 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/string.beambin35360 -> 35368 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/supervisor.beambin21912 -> 21880 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/sys.beambin8364 -> 8356 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/uri_string.beambin26548 -> 26712 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/zip.beambin26172 -> 26148 bytes
-rw-r--r--erts/doc/src/erlang.xml1594
-rw-r--r--erts/doc/src/notes.xml2
-rw-r--r--erts/emulator/beam/bif.c15
-rw-r--r--erts/emulator/beam/erl_init.c1
-rw-r--r--erts/emulator/beam/erl_message.c6
-rw-r--r--erts/emulator/beam/erl_port.h38
-rw-r--r--erts/emulator/beam/erl_port_task.c25
-rw-r--r--erts/emulator/beam/erl_process.c178
-rw-r--r--erts/emulator/beam/erl_process.h153
-rw-r--r--erts/emulator/beam/erl_process_dump.c4
-rw-r--r--erts/emulator/beam/io.c16
-rw-r--r--erts/emulator/sys/unix/erl_child_setup.c15
-rw-r--r--erts/emulator/test/efile_SUITE.erl21
-rw-r--r--erts/etc/common/inet_gethost.c4
-rw-r--r--erts/etc/unix/etp-commands.in4
-rw-r--r--erts/preloaded/src/erlang.erl9
-rw-r--r--lib/asn1/src/asn1ct_gen_per.erl18
-rw-r--r--lib/compiler/src/beam_block.erl12
-rw-r--r--lib/compiler/src/beam_type.erl619
-rw-r--r--lib/compiler/test/beam_type_SUITE.erl25
-rw-r--r--lib/crypto/test/engine_SUITE.erl7
-rw-r--r--lib/diameter/doc/src/diameter.xml14
-rw-r--r--lib/diameter/src/base/diameter_reg.erl17
-rw-r--r--lib/diameter/src/base/diameter_service.erl22
-rw-r--r--lib/diameter/src/diameter.appup.src15
-rw-r--r--lib/diameter/vsn.mk4
-rw-r--r--lib/inets/doc/src/http_client.xml15
-rw-r--r--lib/inets/doc/src/http_uri.xml35
-rw-r--r--lib/inets/doc/src/httpc.xml18
-rw-r--r--lib/inets/src/http_client/httpc.erl56
-rw-r--r--lib/inets/src/http_client/httpc_handler.erl30
-rw-r--r--lib/inets/src/http_client/httpc_internal.hrl6
-rw-r--r--lib/inets/src/http_client/httpc_manager.erl10
-rw-r--r--lib/inets/src/http_lib/http_uri.erl43
-rw-r--r--lib/inets/src/inets_app/inets.appup.src4
-rw-r--r--lib/inets/test/http_test_lib.erl21
-rw-r--r--lib/inets/test/httpc_SUITE.erl70
-rw-r--r--lib/inets/vsn.mk2
-rw-r--r--lib/kernel/doc/src/inet.xml19
-rw-r--r--lib/kernel/doc/src/inet_res.xml6
-rw-r--r--lib/kernel/doc/src/rpc.xml11
-rw-r--r--lib/kernel/src/inet.erl17
-rw-r--r--lib/kernel/src/inet_hosts.erl5
-rw-r--r--lib/kernel/src/inet_res.erl28
-rw-r--r--lib/kernel/src/rpc.erl10
-rw-r--r--lib/kernel/test/inet_SUITE.erl25
-rw-r--r--lib/sasl/doc/src/release_handler.xml2
-rw-r--r--lib/sasl/doc/src/systools.xml6
-rw-r--r--lib/sasl/src/systools_make.erl20
-rw-r--r--lib/sasl/test/systools_SUITE.erl37
-rw-r--r--lib/ssh/doc/src/notes.xml107
-rw-r--r--lib/ssh/src/ssh.erl3
-rw-r--r--lib/ssh/src/ssh_connection_handler.erl46
-rw-r--r--lib/ssh/test/ssh_connection_SUITE.erl17
-rw-r--r--lib/ssh/vsn.mk1
-rw-r--r--lib/ssl/doc/src/ssl.xml5
-rw-r--r--lib/ssl/src/ssl.erl2
-rw-r--r--lib/ssl/src/ssl_cipher.erl11
-rw-r--r--lib/ssl/src/ssl_handshake.erl9
-rw-r--r--lib/ssl/test/ssl_basic_SUITE.erl31
-rw-r--r--lib/ssl/test/ssl_engine_SUITE.erl39
-rw-r--r--lib/ssl/test/ssl_to_openssl_SUITE.erl122
-rw-r--r--lib/stdlib/doc/src/erl_tar.xml2
-rw-r--r--otp_versions.table1
-rw-r--r--system/doc/design_principles/release_structure.xml6
-rw-r--r--system/doc/system_principles/create_target.xmlsrc8
149 files changed, 2448 insertions, 1296 deletions
diff --git a/bootstrap/lib/compiler/ebin/beam_block.beam b/bootstrap/lib/compiler/ebin/beam_block.beam
index edfd5f4039..18f5dc6967 100644
--- a/bootstrap/lib/compiler/ebin/beam_block.beam
+++ b/bootstrap/lib/compiler/ebin/beam_block.beam
Binary files differ
diff --git a/bootstrap/lib/compiler/ebin/beam_bs.beam b/bootstrap/lib/compiler/ebin/beam_bs.beam
index aa5bdc0a80..1361b0b08d 100644
--- a/bootstrap/lib/compiler/ebin/beam_bs.beam
+++ b/bootstrap/lib/compiler/ebin/beam_bs.beam
Binary files differ
diff --git a/bootstrap/lib/compiler/ebin/beam_bsm.beam b/bootstrap/lib/compiler/ebin/beam_bsm.beam
index 2897650a23..6bf3b576b2 100644
--- a/bootstrap/lib/compiler/ebin/beam_bsm.beam
+++ b/bootstrap/lib/compiler/ebin/beam_bsm.beam
Binary files differ
diff --git a/bootstrap/lib/compiler/ebin/beam_clean.beam b/bootstrap/lib/compiler/ebin/beam_clean.beam
index 853f1b929e..ab18a32fa8 100644
--- a/bootstrap/lib/compiler/ebin/beam_clean.beam
+++ b/bootstrap/lib/compiler/ebin/beam_clean.beam
Binary files differ
diff --git a/bootstrap/lib/compiler/ebin/beam_dead.beam b/bootstrap/lib/compiler/ebin/beam_dead.beam
index da3c5cd96f..33ee4dea87 100644
--- a/bootstrap/lib/compiler/ebin/beam_dead.beam
+++ b/bootstrap/lib/compiler/ebin/beam_dead.beam
Binary files differ
diff --git a/bootstrap/lib/compiler/ebin/beam_dict.beam b/bootstrap/lib/compiler/ebin/beam_dict.beam
index 9c66f6d9f3..2e9c7d0f00 100644
--- a/bootstrap/lib/compiler/ebin/beam_dict.beam
+++ b/bootstrap/lib/compiler/ebin/beam_dict.beam
Binary files differ
diff --git a/bootstrap/lib/compiler/ebin/beam_disasm.beam b/bootstrap/lib/compiler/ebin/beam_disasm.beam
index 3bf7fe79f3..5983f341f5 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/beam_except.beam b/bootstrap/lib/compiler/ebin/beam_except.beam
index 494c5855b9..6eed82587a 100644
--- a/bootstrap/lib/compiler/ebin/beam_except.beam
+++ b/bootstrap/lib/compiler/ebin/beam_except.beam
Binary files differ
diff --git a/bootstrap/lib/compiler/ebin/beam_flatten.beam b/bootstrap/lib/compiler/ebin/beam_flatten.beam
index 903a29b02d..8758e98a71 100644
--- a/bootstrap/lib/compiler/ebin/beam_flatten.beam
+++ b/bootstrap/lib/compiler/ebin/beam_flatten.beam
Binary files differ
diff --git a/bootstrap/lib/compiler/ebin/beam_jump.beam b/bootstrap/lib/compiler/ebin/beam_jump.beam
index 831d051efb..5551ba9f90 100644
--- a/bootstrap/lib/compiler/ebin/beam_jump.beam
+++ b/bootstrap/lib/compiler/ebin/beam_jump.beam
Binary files differ
diff --git a/bootstrap/lib/compiler/ebin/beam_receive.beam b/bootstrap/lib/compiler/ebin/beam_receive.beam
index 878501d1e9..8d16d7d39d 100644
--- a/bootstrap/lib/compiler/ebin/beam_receive.beam
+++ b/bootstrap/lib/compiler/ebin/beam_receive.beam
Binary files differ
diff --git a/bootstrap/lib/compiler/ebin/beam_reorder.beam b/bootstrap/lib/compiler/ebin/beam_reorder.beam
index 5f04b10e37..05562e19ea 100644
--- a/bootstrap/lib/compiler/ebin/beam_reorder.beam
+++ b/bootstrap/lib/compiler/ebin/beam_reorder.beam
Binary files differ
diff --git a/bootstrap/lib/compiler/ebin/beam_split.beam b/bootstrap/lib/compiler/ebin/beam_split.beam
index d52cbd3dff..8165aab002 100644
--- a/bootstrap/lib/compiler/ebin/beam_split.beam
+++ b/bootstrap/lib/compiler/ebin/beam_split.beam
Binary files differ
diff --git a/bootstrap/lib/compiler/ebin/beam_trim.beam b/bootstrap/lib/compiler/ebin/beam_trim.beam
index 9143b1615d..75fcff822e 100644
--- a/bootstrap/lib/compiler/ebin/beam_trim.beam
+++ b/bootstrap/lib/compiler/ebin/beam_trim.beam
Binary files differ
diff --git a/bootstrap/lib/compiler/ebin/beam_type.beam b/bootstrap/lib/compiler/ebin/beam_type.beam
index 9aaed00cea..0c8341a6c9 100644
--- a/bootstrap/lib/compiler/ebin/beam_type.beam
+++ b/bootstrap/lib/compiler/ebin/beam_type.beam
Binary files differ
diff --git a/bootstrap/lib/compiler/ebin/beam_utils.beam b/bootstrap/lib/compiler/ebin/beam_utils.beam
index 5d00f77e92..1e9c30d00a 100644
--- a/bootstrap/lib/compiler/ebin/beam_utils.beam
+++ b/bootstrap/lib/compiler/ebin/beam_utils.beam
Binary files differ
diff --git a/bootstrap/lib/compiler/ebin/beam_validator.beam b/bootstrap/lib/compiler/ebin/beam_validator.beam
index 0463b03d3b..25f8772409 100644
--- a/bootstrap/lib/compiler/ebin/beam_validator.beam
+++ b/bootstrap/lib/compiler/ebin/beam_validator.beam
Binary files differ
diff --git a/bootstrap/lib/compiler/ebin/cerl.beam b/bootstrap/lib/compiler/ebin/cerl.beam
index 5a10584227..61515da20a 100644
--- a/bootstrap/lib/compiler/ebin/cerl.beam
+++ b/bootstrap/lib/compiler/ebin/cerl.beam
Binary files differ
diff --git a/bootstrap/lib/compiler/ebin/cerl_inline.beam b/bootstrap/lib/compiler/ebin/cerl_inline.beam
index 1891c09bd2..36888f6363 100644
--- a/bootstrap/lib/compiler/ebin/cerl_inline.beam
+++ b/bootstrap/lib/compiler/ebin/cerl_inline.beam
Binary files differ
diff --git a/bootstrap/lib/compiler/ebin/compile.beam b/bootstrap/lib/compiler/ebin/compile.beam
index bcda9ba1ba..82d601c128 100644
--- a/bootstrap/lib/compiler/ebin/compile.beam
+++ b/bootstrap/lib/compiler/ebin/compile.beam
Binary files differ
diff --git a/bootstrap/lib/compiler/ebin/core_lint.beam b/bootstrap/lib/compiler/ebin/core_lint.beam
index 177de1981b..f3b420121a 100644
--- a/bootstrap/lib/compiler/ebin/core_lint.beam
+++ b/bootstrap/lib/compiler/ebin/core_lint.beam
Binary files differ
diff --git a/bootstrap/lib/compiler/ebin/core_pp.beam b/bootstrap/lib/compiler/ebin/core_pp.beam
index 4ace82ae7d..59503a2933 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/core_scan.beam b/bootstrap/lib/compiler/ebin/core_scan.beam
index 949abb1981..bc0190fdb1 100644
--- a/bootstrap/lib/compiler/ebin/core_scan.beam
+++ b/bootstrap/lib/compiler/ebin/core_scan.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 c4b2708363..62e56d92b0 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_core_inline.beam b/bootstrap/lib/compiler/ebin/sys_core_inline.beam
index b0cb95430a..40f6ebf167 100644
--- a/bootstrap/lib/compiler/ebin/sys_core_inline.beam
+++ b/bootstrap/lib/compiler/ebin/sys_core_inline.beam
Binary files differ
diff --git a/bootstrap/lib/compiler/ebin/sys_pre_attributes.beam b/bootstrap/lib/compiler/ebin/sys_pre_attributes.beam
index 2dd8388c18..91a29c5266 100644
--- a/bootstrap/lib/compiler/ebin/sys_pre_attributes.beam
+++ b/bootstrap/lib/compiler/ebin/sys_pre_attributes.beam
Binary files differ
diff --git a/bootstrap/lib/compiler/ebin/v3_codegen.beam b/bootstrap/lib/compiler/ebin/v3_codegen.beam
index 22c9416347..bf1bcaafd2 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 af6f7cde54..b4672b1315 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 1a09753a22..082bd6b75d 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_kernel_pp.beam b/bootstrap/lib/compiler/ebin/v3_kernel_pp.beam
index 57f30e63d8..fb780c2a43 100644
--- a/bootstrap/lib/compiler/ebin/v3_kernel_pp.beam
+++ b/bootstrap/lib/compiler/ebin/v3_kernel_pp.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/application_controller.beam b/bootstrap/lib/kernel/ebin/application_controller.beam
index fe9f168f12..5e63aa4e8a 100644
--- a/bootstrap/lib/kernel/ebin/application_controller.beam
+++ b/bootstrap/lib/kernel/ebin/application_controller.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/application_master.beam b/bootstrap/lib/kernel/ebin/application_master.beam
index e7c9136475..4bafc43619 100644
--- a/bootstrap/lib/kernel/ebin/application_master.beam
+++ b/bootstrap/lib/kernel/ebin/application_master.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/application_starter.beam b/bootstrap/lib/kernel/ebin/application_starter.beam
index 0602f44d4b..ca7b77abcb 100644
--- a/bootstrap/lib/kernel/ebin/application_starter.beam
+++ b/bootstrap/lib/kernel/ebin/application_starter.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/code_server.beam b/bootstrap/lib/kernel/ebin/code_server.beam
index fd064ca340..922c5e6308 100644
--- a/bootstrap/lib/kernel/ebin/code_server.beam
+++ b/bootstrap/lib/kernel/ebin/code_server.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/disk_log.beam b/bootstrap/lib/kernel/ebin/disk_log.beam
index ce9a424724..76264b975b 100644
--- a/bootstrap/lib/kernel/ebin/disk_log.beam
+++ b/bootstrap/lib/kernel/ebin/disk_log.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/disk_log_1.beam b/bootstrap/lib/kernel/ebin/disk_log_1.beam
index 441db153b1..05c002ba67 100644
--- a/bootstrap/lib/kernel/ebin/disk_log_1.beam
+++ b/bootstrap/lib/kernel/ebin/disk_log_1.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/dist_ac.beam b/bootstrap/lib/kernel/ebin/dist_ac.beam
index c59c245f66..7419ba7c27 100644
--- a/bootstrap/lib/kernel/ebin/dist_ac.beam
+++ b/bootstrap/lib/kernel/ebin/dist_ac.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/dist_util.beam b/bootstrap/lib/kernel/ebin/dist_util.beam
index c8defc4f52..3a4d230a7f 100644
--- a/bootstrap/lib/kernel/ebin/dist_util.beam
+++ b/bootstrap/lib/kernel/ebin/dist_util.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/erl_boot_server.beam b/bootstrap/lib/kernel/ebin/erl_boot_server.beam
index 226052b9ac..d921ffabd9 100644
--- a/bootstrap/lib/kernel/ebin/erl_boot_server.beam
+++ b/bootstrap/lib/kernel/ebin/erl_boot_server.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/file_io_server.beam b/bootstrap/lib/kernel/ebin/file_io_server.beam
index 00c19eb71c..d37ed85781 100644
--- a/bootstrap/lib/kernel/ebin/file_io_server.beam
+++ b/bootstrap/lib/kernel/ebin/file_io_server.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/global.beam b/bootstrap/lib/kernel/ebin/global.beam
index b175e25a4f..8b057dff1a 100644
--- a/bootstrap/lib/kernel/ebin/global.beam
+++ b/bootstrap/lib/kernel/ebin/global.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/global_group.beam b/bootstrap/lib/kernel/ebin/global_group.beam
index 9d119f0c96..b072f96e5d 100644
--- a/bootstrap/lib/kernel/ebin/global_group.beam
+++ b/bootstrap/lib/kernel/ebin/global_group.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/group_history.beam b/bootstrap/lib/kernel/ebin/group_history.beam
index 4a071216da..97f98ebe2f 100644
--- a/bootstrap/lib/kernel/ebin/group_history.beam
+++ b/bootstrap/lib/kernel/ebin/group_history.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/hipe_unified_loader.beam b/bootstrap/lib/kernel/ebin/hipe_unified_loader.beam
index 3b14e184fc..16841cc417 100644
--- a/bootstrap/lib/kernel/ebin/hipe_unified_loader.beam
+++ b/bootstrap/lib/kernel/ebin/hipe_unified_loader.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/inet_db.beam b/bootstrap/lib/kernel/ebin/inet_db.beam
index 1fb6322536..e86ce51920 100644
--- a/bootstrap/lib/kernel/ebin/inet_db.beam
+++ b/bootstrap/lib/kernel/ebin/inet_db.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/inet_dns.beam b/bootstrap/lib/kernel/ebin/inet_dns.beam
index 312e52fd6f..c437ed85d7 100644
--- a/bootstrap/lib/kernel/ebin/inet_dns.beam
+++ b/bootstrap/lib/kernel/ebin/inet_dns.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/inet_gethost_native.beam b/bootstrap/lib/kernel/ebin/inet_gethost_native.beam
index 62414aa72e..ccd9f21cd4 100644
--- a/bootstrap/lib/kernel/ebin/inet_gethost_native.beam
+++ b/bootstrap/lib/kernel/ebin/inet_gethost_native.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/inet_res.beam b/bootstrap/lib/kernel/ebin/inet_res.beam
index a2d5924dd0..8c18d0d1ad 100644
--- a/bootstrap/lib/kernel/ebin/inet_res.beam
+++ b/bootstrap/lib/kernel/ebin/inet_res.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/net_kernel.beam b/bootstrap/lib/kernel/ebin/net_kernel.beam
index c3e4cc96eb..d9abceade5 100644
--- a/bootstrap/lib/kernel/ebin/net_kernel.beam
+++ b/bootstrap/lib/kernel/ebin/net_kernel.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/os.beam b/bootstrap/lib/kernel/ebin/os.beam
index bb190ba66a..f2a003d44f 100644
--- a/bootstrap/lib/kernel/ebin/os.beam
+++ b/bootstrap/lib/kernel/ebin/os.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/user.beam b/bootstrap/lib/kernel/ebin/user.beam
index bb4037943a..e57d6896bd 100644
--- a/bootstrap/lib/kernel/ebin/user.beam
+++ b/bootstrap/lib/kernel/ebin/user.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/wrap_log_reader.beam b/bootstrap/lib/kernel/ebin/wrap_log_reader.beam
index b38ddd7288..a0f24625b4 100644
--- a/bootstrap/lib/kernel/ebin/wrap_log_reader.beam
+++ b/bootstrap/lib/kernel/ebin/wrap_log_reader.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/array.beam b/bootstrap/lib/stdlib/ebin/array.beam
index 4ec44e7d34..1dd8846725 100644
--- a/bootstrap/lib/stdlib/ebin/array.beam
+++ b/bootstrap/lib/stdlib/ebin/array.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/dets.beam b/bootstrap/lib/stdlib/ebin/dets.beam
index 52ee0b4642..9384a4379f 100644
--- a/bootstrap/lib/stdlib/ebin/dets.beam
+++ b/bootstrap/lib/stdlib/ebin/dets.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/dets_server.beam b/bootstrap/lib/stdlib/ebin/dets_server.beam
index 540a1a2997..31f0f2701a 100644
--- a/bootstrap/lib/stdlib/ebin/dets_server.beam
+++ b/bootstrap/lib/stdlib/ebin/dets_server.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/dets_utils.beam b/bootstrap/lib/stdlib/ebin/dets_utils.beam
index 7fa23bb92b..265facaa57 100644
--- a/bootstrap/lib/stdlib/ebin/dets_utils.beam
+++ b/bootstrap/lib/stdlib/ebin/dets_utils.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/dets_v9.beam b/bootstrap/lib/stdlib/ebin/dets_v9.beam
index d295ebbeb7..f53f9fcf85 100644
--- a/bootstrap/lib/stdlib/ebin/dets_v9.beam
+++ b/bootstrap/lib/stdlib/ebin/dets_v9.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/digraph.beam b/bootstrap/lib/stdlib/ebin/digraph.beam
index e411e04ccd..c51ecf54fc 100644
--- a/bootstrap/lib/stdlib/ebin/digraph.beam
+++ b/bootstrap/lib/stdlib/ebin/digraph.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/epp.beam b/bootstrap/lib/stdlib/ebin/epp.beam
index c37fb1be5e..58e29d0c3b 100644
--- a/bootstrap/lib/stdlib/ebin/epp.beam
+++ b/bootstrap/lib/stdlib/ebin/epp.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/erl_bits.beam b/bootstrap/lib/stdlib/ebin/erl_bits.beam
index 5b2a46aec1..b9b75ecaef 100644
--- a/bootstrap/lib/stdlib/ebin/erl_bits.beam
+++ b/bootstrap/lib/stdlib/ebin/erl_bits.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/erl_eval.beam b/bootstrap/lib/stdlib/ebin/erl_eval.beam
index aa71f417dc..eb913d070d 100644
--- a/bootstrap/lib/stdlib/ebin/erl_eval.beam
+++ b/bootstrap/lib/stdlib/ebin/erl_eval.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 790037359b..1869788f7b 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 bdcec0f3fb..b8350e8975 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_parse.beam b/bootstrap/lib/stdlib/ebin/erl_parse.beam
index e0bbaa83d1..bfc5843912 100644
--- a/bootstrap/lib/stdlib/ebin/erl_parse.beam
+++ b/bootstrap/lib/stdlib/ebin/erl_parse.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/erl_pp.beam b/bootstrap/lib/stdlib/ebin/erl_pp.beam
index 2e0b4cd9ee..ca3d18a5db 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/erl_tar.beam b/bootstrap/lib/stdlib/ebin/erl_tar.beam
index 1f3e651d7b..ba7382f874 100644
--- a/bootstrap/lib/stdlib/ebin/erl_tar.beam
+++ b/bootstrap/lib/stdlib/ebin/erl_tar.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/escript.beam b/bootstrap/lib/stdlib/ebin/escript.beam
index e068621f8c..5ae2752a6d 100644
--- a/bootstrap/lib/stdlib/ebin/escript.beam
+++ b/bootstrap/lib/stdlib/ebin/escript.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/ets.beam b/bootstrap/lib/stdlib/ebin/ets.beam
index e676ce6b8f..f2a649e0d1 100644
--- a/bootstrap/lib/stdlib/ebin/ets.beam
+++ b/bootstrap/lib/stdlib/ebin/ets.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/file_sorter.beam b/bootstrap/lib/stdlib/ebin/file_sorter.beam
index 504fc72130..8a9e501e1b 100644
--- a/bootstrap/lib/stdlib/ebin/file_sorter.beam
+++ b/bootstrap/lib/stdlib/ebin/file_sorter.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/gen_event.beam b/bootstrap/lib/stdlib/ebin/gen_event.beam
index 6cdcd0fdb7..21806df360 100644
--- a/bootstrap/lib/stdlib/ebin/gen_event.beam
+++ b/bootstrap/lib/stdlib/ebin/gen_event.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/gen_statem.beam b/bootstrap/lib/stdlib/ebin/gen_statem.beam
index afabd64a65..c79b4a16f9 100644
--- a/bootstrap/lib/stdlib/ebin/gen_statem.beam
+++ b/bootstrap/lib/stdlib/ebin/gen_statem.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/io.beam b/bootstrap/lib/stdlib/ebin/io.beam
index dd5ea1a0a8..e1841e184c 100644
--- a/bootstrap/lib/stdlib/ebin/io.beam
+++ b/bootstrap/lib/stdlib/ebin/io.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/io_lib_pretty.beam b/bootstrap/lib/stdlib/ebin/io_lib_pretty.beam
index bcf407eaa2..bf9e95e6be 100644
--- a/bootstrap/lib/stdlib/ebin/io_lib_pretty.beam
+++ b/bootstrap/lib/stdlib/ebin/io_lib_pretty.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/lib.beam b/bootstrap/lib/stdlib/ebin/lib.beam
index 5281d1f49a..7d342a59a9 100644
--- a/bootstrap/lib/stdlib/ebin/lib.beam
+++ b/bootstrap/lib/stdlib/ebin/lib.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/ms_transform.beam b/bootstrap/lib/stdlib/ebin/ms_transform.beam
index e6507e4d1b..8228a076ba 100644
--- a/bootstrap/lib/stdlib/ebin/ms_transform.beam
+++ b/bootstrap/lib/stdlib/ebin/ms_transform.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/qlc.beam b/bootstrap/lib/stdlib/ebin/qlc.beam
index 14da40af23..6c2895ac79 100644
--- a/bootstrap/lib/stdlib/ebin/qlc.beam
+++ b/bootstrap/lib/stdlib/ebin/qlc.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/qlc_pt.beam b/bootstrap/lib/stdlib/ebin/qlc_pt.beam
index 2c4fbaa3e1..d40c197029 100644
--- a/bootstrap/lib/stdlib/ebin/qlc_pt.beam
+++ b/bootstrap/lib/stdlib/ebin/qlc_pt.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/sofs.beam b/bootstrap/lib/stdlib/ebin/sofs.beam
index 941c397b22..bfefd0c3a9 100644
--- a/bootstrap/lib/stdlib/ebin/sofs.beam
+++ b/bootstrap/lib/stdlib/ebin/sofs.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/string.beam b/bootstrap/lib/stdlib/ebin/string.beam
index 841cb8ff76..feeeec6a84 100644
--- a/bootstrap/lib/stdlib/ebin/string.beam
+++ b/bootstrap/lib/stdlib/ebin/string.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/supervisor.beam b/bootstrap/lib/stdlib/ebin/supervisor.beam
index 8446b160a4..61e8fca92c 100644
--- a/bootstrap/lib/stdlib/ebin/supervisor.beam
+++ b/bootstrap/lib/stdlib/ebin/supervisor.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/sys.beam b/bootstrap/lib/stdlib/ebin/sys.beam
index abf6451cb0..0cec9f4be8 100644
--- a/bootstrap/lib/stdlib/ebin/sys.beam
+++ b/bootstrap/lib/stdlib/ebin/sys.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/uri_string.beam b/bootstrap/lib/stdlib/ebin/uri_string.beam
index e618d6c360..95b7a2e6ae 100644
--- a/bootstrap/lib/stdlib/ebin/uri_string.beam
+++ b/bootstrap/lib/stdlib/ebin/uri_string.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/zip.beam b/bootstrap/lib/stdlib/ebin/zip.beam
index cafbc013bd..3e19c83090 100644
--- a/bootstrap/lib/stdlib/ebin/zip.beam
+++ b/bootstrap/lib/stdlib/ebin/zip.beam
Binary files differ
diff --git a/erts/doc/src/erlang.xml b/erts/doc/src/erlang.xml
index 771897ba94..56eaa47af4 100644
--- a/erts/doc/src/erlang.xml
+++ b/erts/doc/src/erlang.xml
@@ -6753,17 +6753,20 @@ lists:map(
be included in the result. That is, all scheduler threads
that are expected to handle CPU bound work. If you also
want information about dirty I/O schedulers, use
- <seealso marker="#statistics_scheduler_wall_time_all"><c>statistics(scheduler_wall_time_all)</c></seealso>
+ <seealso marker="#statistics_scheduler_wall_time_all">
+ <c>statistics(scheduler_wall_time_all)</c></seealso>
instead.</p>
<p>Normal schedulers will have scheduler identifiers in
the range <c>1 =&lt; <anno>SchedulerId</anno> =&lt;
- </c><seealso marker="#system_info_schedulers"><c>erlang:system_info(schedulers)</c></seealso>.
+ </c><seealso marker="#system_info_schedulers">
+ <c>erlang:system_info(schedulers)</c></seealso>.
Dirty CPU schedulers will have scheduler identifiers in
the range <c>erlang:system_info(schedulers) &lt;
<anno>SchedulerId</anno> =&lt; erlang:system_info(schedulers)
+
- </c><seealso marker="#system_info_dirty_cpu_schedulers"><c>erlang:system_info(dirty_cpu_schedulers)</c></seealso>.
+ </c><seealso marker="#system_info_dirty_cpu_schedulers">
+ <c>erlang:system_info(dirty_cpu_schedulers)</c></seealso>.
</p>
<note><p>The different types of schedulers handle
specific types of jobs. Every job is assigned to a specific
@@ -6839,13 +6842,16 @@ ok
schedulers.</p>
<p>Dirty IO schedulers will have scheduler identifiers in
the range
- <seealso marker="#system_info_schedulers"><c>erlang:system_info(schedulers)</c></seealso><c>
+ <seealso marker="#system_info_schedulers">
+ <c>erlang:system_info(schedulers)</c></seealso><c>
+
- </c><seealso marker="#system_info_dirty_cpu_schedulers"><c>erlang:system_info(dirty_cpu_schedulers)</c></seealso><c> &lt;
+ </c><seealso marker="#system_info_dirty_cpu_schedulers">
+ <c>erlang:system_info(dirty_cpu_schedulers)</c></seealso><c> &lt;
<anno>SchedulerId</anno> =&lt; erlang:system_info(schedulers)
+ erlang:system_info(dirty_cpu_schedulers)
+
- </c><seealso marker="#system_info_dirty_io_schedulers"><c>erlang:system_info(dirty_io_schedulers)</c></seealso>.</p>
+ </c><seealso marker="#system_info_dirty_io_schedulers">
+ <c>erlang:system_info(dirty_io_schedulers)</c></seealso>.</p>
<note><p>Note that work executing on dirty I/O schedulers
are expected to mainly wait for I/O. That is, when you
get high scheduler utilization on dirty I/O schedulers,
@@ -7484,11 +7490,144 @@ ok
</func>
<func>
- <name name="system_info" arity="1" clause_i="1"/>
- <name name="system_info" arity="1" clause_i="2"/>
- <name name="system_info" arity="1" clause_i="3"/>
- <name name="system_info" arity="1" clause_i="4"/>
- <name name="system_info" arity="1" clause_i="5"/>
+ <name name="system_info" arity="1" clause_i="75"/>
+ <fsummary>System info overview.</fsummary>
+ <desc>
+ <p>Returns information about the current system.
+ The documentation of this function is broken into the following
+ sections in order to make it easier to navigate.</p>
+ <taglist>
+ <tag><seealso marker="#system_info_allocator">
+ <c>Memory Allocation</c></seealso></tag>
+ <item>
+ <p>
+ <seealso marker="#system_info_allocated_areas"><c>allocated_areas</c></seealso>,
+ <seealso marker="#system_info_allocator"><c>allocator</c></seealso>,
+ <seealso marker="#system_info_alloc_util_allocators"><c>alloc_util_allocators</c></seealso>,
+ <seealso marker="#system_info_allocator_sizes"><c>allocator_sizes</c></seealso>,
+ <seealso marker="#system_info_elib_malloc"><c>elib_malloc</c></seealso>
+ </p>
+ </item>
+ <tag><seealso marker="#system_info_cpu_topology">
+ <c>CPU Topology</c></seealso></tag>
+ <item>
+ <p>
+ <seealso marker="#system_info_cpu_topology"><c>cpu_topology</c></seealso>,
+ <seealso marker="#system_info_logical_processors"><c>logical_processors</c></seealso>,
+ <seealso marker="#system_info_update_cpu_info"><c>update_cpu_info</c></seealso>
+ </p>
+ </item>
+ <tag><seealso marker="#system_info_process">
+ <c>Process Information</c></seealso></tag>
+ <item>
+ <p>
+ <seealso marker="#system_info_fullsweep_after"><c>fullsweep_after</c></seealso>,
+ <seealso marker="#system_info_garbage_collection"><c>garbage_collection</c></seealso>,
+ <seealso marker="#system_info_heap_sizes"><c>heap_sizes</c></seealso>,
+ <seealso marker="#system_info_heap_type"><c>heap_type</c></seealso>,
+ <seealso marker="#system_info_max_heap_size"><c>max_heap_size</c></seealso>,
+ <seealso marker="#system_info_message_queue_data"><c>message_queue_data</c></seealso>,
+ <seealso marker="#system_info_min_heap_size"><c>min_heap_size</c></seealso>,
+ <seealso marker="#system_info_min_bin_vheap_size"><c>min_bin_vheap_size</c></seealso>,
+ <seealso marker="#system_info_procs"><c>procs</c></seealso>
+ </p>
+ </item>
+ <tag><seealso marker="#system_info_limits">
+ <c>System Limits</c></seealso></tag>
+ <item>
+ <p>
+ <seealso marker="#system_info_atom_count"><c>atom_count</c></seealso>,
+ <seealso marker="#system_info_atom_limit"><c>atom_limit</c></seealso>,
+ <seealso marker="#system_info_ets_limit"><c>ets_limit</c></seealso>,
+ <seealso marker="#system_info_port_count"><c>port_count</c></seealso>,
+ <seealso marker="#system_info_port_limit"><c>port_limit</c></seealso>,
+ <seealso marker="#system_info_process_count"><c>process_count</c></seealso>,
+ <seealso marker="#system_info_process_limit"><c>process_limit</c></seealso>
+ </p>
+ </item>
+ <tag><seealso marker="#system_info_time">
+ <c>System Time</c></seealso></tag>
+ <item>
+ <p>
+ <seealso marker="#system_info_end_time"><c>end_time</c></seealso>,
+ <seealso marker="#system_info_os_monotonic_time_source"><c>os_monotonic_time_source</c></seealso>,
+ <seealso marker="#system_info_os_system_time_source"><c>os_system_time_source</c></seealso>,
+ <seealso marker="#system_info_start_time"><c>start_time</c></seealso>,
+ <seealso marker="#system_info_time_correction"><c>time_correction</c></seealso>,
+ <seealso marker="#system_info_time_offset"><c>time_offset</c></seealso>,
+ <seealso marker="#system_info_time_warp_mode"><c>time_warp_mode</c></seealso>,
+ <seealso marker="#system_info_tolerant_timeofday"><c>tolerant_timeofday</c></seealso>
+ </p>
+ </item>
+ <tag><seealso marker="#system_info_scheduler">
+ <c>Scheduler Information</c></seealso></tag>
+ <item>
+ <p>
+ <seealso marker="#system_info_dirty_cpu_schedulers"><c>dirty_cpu_schedulers</c></seealso>,
+ <seealso marker="#system_info_dirty_cpu_schedulers_online"><c>dirty_cpu_schedulers_online</c></seealso>,
+ <seealso marker="#system_info_dirty_io_schedulers"><c>dirty_io_schedulers</c></seealso>,
+ <seealso marker="#system_info_multi_scheduling"><c>multi_scheduling</c></seealso>,
+ <seealso marker="#system_info_multi_scheduling_blockers"><c>multi_scheduling_blockers</c></seealso>,
+ <seealso marker="#system_info_normal_multi_scheduling_blockers"><c>normal_multi_scheduling_blockers</c></seealso>,
+ <seealso marker="#system_info_scheduler_bind_type"><c>scheduler_bind_type</c></seealso>,
+ <seealso marker="#system_info_scheduler_bindings"><c>scheduler_bindings</c></seealso>,
+ <seealso marker="#system_info_scheduler_id"><c>scheduler_id</c></seealso>,
+ <seealso marker="#system_info_schedulers"><c>schedulers</c></seealso>,
+ <seealso marker="#system_info_smp_support"><c>smp_support</c></seealso>,
+ <seealso marker="#system_info_threads"><c>threads</c></seealso>,
+ <seealso marker="#system_info_thread_pool_size"><c>thread_pool_size</c></seealso>
+ </p>
+ </item>
+ <tag><seealso marker="#system_info_dist">
+ <c>Distribution Information</c></seealso></tag>
+ <item>
+ <p>
+ <seealso marker="#system_info_creation"><c>creation</c></seealso>,
+ <seealso marker="#system_info_delayed_node_table_gc"><c>delayed_node_table_gc</c></seealso>,
+ <seealso marker="#system_info_dist"><c>dist</c></seealso>,
+ <seealso marker="#system_info_dist_buf_busy_limit"><c>dist_buf_busy_limit</c></seealso>,
+ <seealso marker="#system_info_dist_ctrl"><c>dist_ctrl</c></seealso>
+ </p>
+ </item>
+ <tag><seealso marker="#system_info_misc">
+ <c>System Information</c></seealso></tag>
+ <item>
+ <p>
+ <seealso marker="#system_info_build_type"><c>build_type</c></seealso>,
+ <seealso marker="#system_info_c_compiler_used"><c>c_compiler_used</c></seealso>,
+ <seealso marker="#system_info_check_io"><c>check_io</c></seealso>,
+ <seealso marker="#system_info_compat_rel"><c>compat_rel</c></seealso>,
+ <seealso marker="#system_info_debug_compiled"><c>debug_compiled</c></seealso>,
+ <seealso marker="#system_info_driver_version"><c>driver_version</c></seealso>,
+ <seealso marker="#system_info_dynamic_trace"><c>dynamic_trace</c></seealso>,
+ <seealso marker="#system_info_dynamic_trace_probes"><c>dynamic_trace_probes</c></seealso>,
+ <seealso marker="#system_info_info"><c>info</c></seealso>,
+ <seealso marker="#system_info_kernel_poll"><c>kernel_poll</c></seealso>,
+ <seealso marker="#system_info_loaded"><c>loaded</c></seealso>,
+ <seealso marker="#system_info_machine"><c>machine</c></seealso>,
+ <seealso marker="#system_info_modified_timing_level"><c>modified_timing_level</c></seealso>,
+ <seealso marker="#system_info_nif_version"><c>nif_version</c></seealso>,
+ <seealso marker="#system_info_otp_release"><c>otp_release</c></seealso>,
+ <seealso marker="#system_info_port_parallelism"><c>port_parallelism</c></seealso>,
+ <seealso marker="#system_info_system_version"><c>system_version</c></seealso>,
+ <seealso marker="#system_info_system_architecture"><c>system_architecture</c></seealso>,
+ <seealso marker="#system_info_trace_control_word"><c>trace_control_word</c></seealso>,
+ <seealso marker="#system_info_version"><c>version</c></seealso>,
+ <seealso marker="#system_info_wordsize"><c>wordsize</c></seealso>
+ </p>
+ </item>
+ </taglist>
+ </desc>
+ </func>
+
+ <func>
+ <name name="system_info" arity="1" clause_i="1"
+ anchor="system_info_allocator"/> <!-- allocated_areas -->
+ <name name="system_info" arity="1" clause_i="2"/> <!-- allocator -->
+ <name name="system_info" arity="1" clause_i="3"/> <!-- {allocator, _} -->
+ <name name="system_info" arity="1" clause_i="4"/> <!-- alloc_util_allocators -->
+ <name name="system_info" arity="1" clause_i="5"/> <!-- {allocator_sizes, _} -->
+ <name name="system_info" arity="1" clause_i="27"/> <!-- elib_malloc -->
<fsummary>Information about the system allocators.</fsummary>
<type variable="Allocator" name_i="2"/>
<type variable="Version" name_i="2"/>
@@ -7497,12 +7636,13 @@ ok
<type variable="Alloc" name_i="3"/>
<desc>
<marker id="system_info_allocator_tags"></marker>
- <p>Returns various information about the allocators of the
- current system (emulator) as specified by
+ <p>Returns various information about the memory allocators
+ of the current system (emulator) as specified by
<c><anno>Item</anno></c>:</p>
<marker id="system_info_allocated_areas"></marker>
<taglist>
- <tag><c>allocated_areas</c></tag>
+ <tag><marker id="system_info_allocated_areas"/>
+ <c>allocated_areas</c></tag>
<item>
<p>Returns a list of tuples with information about
miscellaneous allocated memory areas.</p>
@@ -7524,9 +7664,9 @@ ok
<seealso marker="#memory/0">
<c>erlang:memory/0,1</c></seealso>.</p>
</item>
- <tag><c>allocator</c></tag>
+ <tag><marker id="system_info_allocator"/>
+ <c>allocator</c></tag>
<item>
- <marker id="system_info_allocator"></marker>
<p>Returns <c>{<anno>Allocator</anno>, <anno>Version</anno>,
<anno>Features</anno>, <anno>Settings</anno></c>, where:</p>
<list type="bulleted">
@@ -7559,19 +7699,9 @@ ok
<seealso marker="erts:erts_alloc#flags">
<c>erts_alloc(3)</c></seealso>.</p>
</item>
- <tag><c>alloc_util_allocators</c></tag>
- <item>
- <marker id="system_info_alloc_util_allocators"></marker>
- <p>Returns a list of the names of all allocators using
- the ERTS internal <c>alloc_util</c> framework
- as atoms. For more information, see section
- <seealso marker="erts:erts_alloc#alloc_util">The
- alloc_util framework</seealso>
- in <c>erts_alloc(3)</c>.</p>
- </item>
- <tag><c>{allocator, <anno>Alloc</anno>}</c></tag>
+ <tag><marker id="system_info_allocator_tuple"></marker>
+ <c>{allocator, <anno>Alloc</anno>}</c></tag>
<item>
- <marker id="system_info_allocator_tuple"></marker>
<p>Returns information about the specified allocator.
As from ERTS 5.6.1, the return value is a list
of <c>{instance, InstanceNo, InstanceInfo}</c> tuples,
@@ -7616,9 +7746,19 @@ ok
values. The first value is the memory pool size and
the second value is the used memory size.</p>
</item>
- <tag><c>{allocator_sizes, <anno>Alloc</anno>}</c></tag>
+ <tag><marker id="system_info_alloc_util_allocators"/>
+ <c>alloc_util_allocators</c></tag>
+ <item>
+ <p>Returns a list of the names of all allocators using
+ the ERTS internal <c>alloc_util</c> framework
+ as atoms. For more information, see section
+ <seealso marker="erts:erts_alloc#alloc_util">The
+ alloc_util framework</seealso>
+ in <c>erts_alloc(3)</c>.</p>
+ </item>
+ <tag><marker id="system_info_allocator_sizes"/>
+ <c>{allocator_sizes, <anno>Alloc</anno>}</c></tag>
<item>
- <marker id="system_info_allocator_sizes"></marker>
<p>Returns various size information for the specified
allocator. The information returned is a subset of the
information returned by
@@ -7626,14 +7766,23 @@ ok
<c>erlang:system_info({allocator,
<anno>Alloc</anno>})</c></seealso>.</p>
</item>
+ <tag><marker id="system_info_elib_malloc"/>
+ <c>elib_malloc</c></tag>
+ <item>
+ <p>This option will be removed in a future release.
+ The return value will always be <c>false</c>, as the
+ <c>elib_malloc</c> allocator has been removed.</p>
+ </item>
</taglist>
</desc>
</func>
<func>
<name name="system_info" arity="1" clause_i="12"
- anchor="system_info_cpu_topology"/>
- <name name="system_info" arity="1" clause_i="13"/>
+ anchor="system_info_cpu_topology"/> <!-- cpu_topology -->
+ <name name="system_info" arity="1" clause_i="13"/> <!-- {cpu_topology, _} -->
+ <name name="system_info" arity="1" clause_i="37"/> <!-- logical_processors -->
+ <name name="system_info" arity="1" clause_i="72"/> <!-- update_cpu_info -->
<fsummary>Information about the CPU topology of the system.</fsummary>
<type name="cpu_topology"/>
<type name="level_entry"/>
@@ -7664,7 +7813,8 @@ ok
the current system (emulator) as specified by
<c><anno>Item</anno></c>:</p>
<taglist>
- <tag><c>cpu_topology</c></tag>
+ <tag><marker id="system_info_cpu_topology"/>
+ <c>cpu_topology</c></tag>
<item>
<p>Returns the <c><anno>CpuTopology</anno></c> currently used by
the emulator. The CPU topology is used when binding schedulers
@@ -7727,31 +7877,89 @@ ok
<seealso marker="#system_info_cpu_topology">
<c>cpu_topology</c></seealso>.</p>
</item>
+ <tag><marker id="system_info_logical_processors"/>
+ <c>logical_processors</c></tag>
+ <item>
+ <p>Returns the detected number of logical processors configured
+ in the system. The return value is either an integer, or
+ the atom <c>unknown</c> if the emulator cannot
+ detect the configured logical processors.</p>
+ </item>
+ <tag><marker id="system_info_logical_processors_available"/>
+ <c>logical_processors_available</c></tag>
+ <item>
+ <p>Returns the detected number of logical processors available
+ to the Erlang runtime system. The return value is either an
+ integer, or the atom <c>unknown</c> if the emulator
+ cannot detect the available logical processors. The number
+ of available logical processors is less than or equal to
+ the number of <seealso marker="#system_info_logical_processors_online">
+ logical processors online</seealso>.</p>
+ </item>
+ <tag><marker id="system_info_logical_processors_online"/>
+ <c>logical_processors_online</c></tag>
+ <item>
+ <p>Returns the detected number of logical processors online on
+ the system. The return value is either an integer,
+ or the atom <c>unknown</c> if the emulator cannot
+ detect logical processors online. The number of logical
+ processors online is less than or equal to the number of
+ <seealso marker="#system_info_logical_processors">logical processors
+ configured</seealso>.</p>
+ </item>
+ <tag><marker id="system_info_update_cpu_info"/>
+ <c>update_cpu_info</c></tag>
+ <item>
+ <p>The runtime system rereads the CPU information available
+ and updates its internally stored information about the
+ <seealso marker="#system_info_cpu_topology_detected">detected
+ CPU topology</seealso> and the number of logical processors
+ <seealso marker="#system_info_logical_processors">configured</seealso>,
+ <seealso marker="#system_info_logical_processors_online">online</seealso>,
+ and <seealso marker="#system_info_logical_processors_available">
+ available</seealso>.</p>
+ <p>If the CPU information has changed since the last time
+ it was read, the atom <c>changed</c> is returned, otherwise
+ the atom <c>unchanged</c>. If the CPU information has changed,
+ you probably want to
+ <seealso marker="#system_flag_schedulers_online">adjust the
+ number of schedulers online</seealso>. You typically want
+ to have as many schedulers online as
+ <seealso marker="#system_info_logical_processors_available">logical
+ processors available</seealso>.</p>
+ </item>
</taglist>
</desc>
</func>
<func>
- <name name="system_info" arity="1" clause_i="29"/>
- <name name="system_info" arity="1" clause_i="30"/>
- <name name="system_info" arity="1" clause_i="38"/>
- <name name="system_info" arity="1" clause_i="39"/>
- <name name="system_info" arity="1" clause_i="40"/>
- <name name="system_info" arity="1" clause_i="41"/>
+ <name name="system_info" arity="1" clause_i="30"
+ anchor="system_info_process"/> <!-- fullsweep_after -->
+ <name name="system_info" arity="1" clause_i="31"/> <!-- garbage_collection -->
+ <name name="system_info" arity="1" clause_i="32"/> <!-- heap_sizes -->
+ <name name="system_info" arity="1" clause_i="33"/> <!-- heap_type -->
+ <name name="system_info" arity="1" clause_i="39"/> <!-- max_heap_size -->
+ <name name="system_info" arity="1" clause_i="40"/> <!-- message_queue_data -->
+ <name name="system_info" arity="1" clause_i="41"/> <!-- min_heap_size -->
+ <name name="system_info" arity="1" clause_i="42"/> <!-- min_bin_vheap_size -->
+ <name name="system_info" arity="1" clause_i="56"/> <!-- procs -->
<fsummary>Information about the default process heap settings.</fsummary>
<type name="message_queue_data"/>
<type name="max_heap_size"/>
<desc>
+ <marker id="system_info_process_tags"/>
<p>Returns information about the default process heap settings:</p>
<taglist>
- <tag><c>fullsweep_after</c></tag>
+ <tag><marker id="system_info_fullsweep_after"/>
+ <c>fullsweep_after</c></tag>
<item>
<p>Returns <c>{fullsweep_after, integer() >= 0}</c>, which is
the <c>fullsweep_after</c> garbage collection setting used
by default. For more information, see
<c>garbage_collection</c> described below.</p>
</item>
- <tag><c>garbage_collection</c></tag>
+ <tag><marker id="system_info_garbage_collection"/>
+ <c>garbage_collection</c></tag>
<item>
<p>Returns a list describing the default garbage collection
settings. A process spawned on the local node by a
@@ -7764,7 +7972,30 @@ ok
can spawn a process that does not use the default
settings.</p>
</item>
- <tag><c>max_heap_size</c></tag>
+ <tag><marker id="system_info_heap_sizes"/>
+ <c>heap_sizes</c></tag>
+ <item>
+ <p>Returns a list of integers representing valid heap sizes
+ in words. All Erlang heaps are sized from sizes in this
+ list.</p>
+ </item>
+ <tag><marker id="system_info_heap_type"/>
+ <c>heap_type</c></tag>
+ <item>
+ <p>Returns the heap type used by the current emulator. One
+ heap type exists:</p>
+ <taglist>
+ <tag><c>private</c></tag>
+ <item>
+ Each process has a heap reserved for its use and no
+ references between heaps of different processes are
+ allowed. Messages passed between processes are copied
+ between heaps.
+ </item>
+ </taglist>
+ </item>
+ <tag><marker id="system_info_max_heap_size"/>
+ <c>max_heap_size</c></tag>
<item>
<p>Returns <c>{max_heap_size, <anno>MaxHeapSize</anno>}</c>,
where <c><anno>MaxHeapSize</anno></c> is the current
@@ -7792,173 +8023,364 @@ ok
<seealso marker="#process_flag_message_queue_data">
<c>process_flag(message_queue_data, MQD)</c></seealso>.</p>
</item>
- <tag><c>min_heap_size</c></tag>
+ <tag><marker id="system_info_min_heap_size"/>
+ <c>min_heap_size</c></tag>
<item>
<p>Returns <c>{min_heap_size, <anno>MinHeapSize</anno>}</c>,
where <c><anno>MinHeapSize</anno></c> is the current
system-wide minimum heap size for spawned processes.</p>
</item>
- <tag><c>min_bin_vheap_size</c></tag>
+ <tag><marker id="system_info_min_bin_vheap_size"/>
+ <c>min_bin_vheap_size</c></tag>
<item>
<p>Returns <c>{min_bin_vheap_size,
<anno>MinBinVHeapSize</anno>}</c>, where
<c><anno>MinBinVHeapSize</anno></c> is the current system-wide
minimum binary virtual heap size for spawned processes.</p>
</item>
+ <tag><marker id="system_info_procs"/>
+ <c>procs</c></tag>
+ <item>
+ <p>Returns a binary containing a string of process and port
+ information formatted as in Erlang crash dumps. For more
+ information, see section <seealso marker="erts:crash_dump">
+ How to interpret the Erlang crash dumps</seealso>
+ in the User's Guide.</p>
+ </item>
</taglist>
</desc>
</func>
<func>
- <name name="system_info" arity="1" clause_i="6"/>
- <name name="system_info" arity="1" clause_i="7"/>
- <name name="system_info" arity="1" clause_i="8"/>
- <name name="system_info" arity="1" clause_i="9"/>
- <name name="system_info" arity="1" clause_i="10"/>
- <name name="system_info" arity="1" clause_i="11"/>
- <name name="system_info" arity="1" clause_i="14"/>
- <name name="system_info" arity="1" clause_i="15"/>
- <name name="system_info" arity="1" clause_i="16"/>
- <name name="system_info" arity="1" clause_i="17"/>
- <name name="system_info" arity="1" clause_i="18"/>
- <name name="system_info" arity="1" clause_i="19"/>
- <name name="system_info" arity="1" clause_i="20"/>
- <name name="system_info" arity="1" clause_i="21"/>
- <name name="system_info" arity="1" clause_i="22"/>
- <name name="system_info" arity="1" clause_i="23"/>
- <name name="system_info" arity="1" clause_i="24"/>
- <name name="system_info" arity="1" clause_i="25"/>
- <name name="system_info" arity="1" clause_i="26"/>
- <name name="system_info" arity="1" clause_i="27"/>
- <name name="system_info" arity="1" clause_i="28"/>
- <name name="system_info" arity="1" clause_i="31"/>
- <name name="system_info" arity="1" clause_i="32"/>
- <name name="system_info" arity="1" clause_i="33"/>
- <name name="system_info" arity="1" clause_i="34"/>
- <name name="system_info" arity="1" clause_i="35"/>
- <name name="system_info" arity="1" clause_i="36"/>
- <name name="system_info" arity="1" clause_i="37"/>
- <name name="system_info" arity="1" clause_i="42"/>
- <name name="system_info" arity="1" clause_i="43"/>
- <name name="system_info" arity="1" clause_i="44"/>
- <name name="system_info" arity="1" clause_i="45"/>
- <name name="system_info" arity="1" clause_i="46"/>
- <name name="system_info" arity="1" clause_i="47"/>
- <name name="system_info" arity="1" clause_i="48"/>
- <name name="system_info" arity="1" clause_i="49"/>
- <name name="system_info" arity="1" clause_i="50"/>
- <name name="system_info" arity="1" clause_i="51"/>
- <name name="system_info" arity="1" clause_i="52"/>
- <name name="system_info" arity="1" clause_i="53"/>
- <name name="system_info" arity="1" clause_i="54"/>
- <name name="system_info" arity="1" clause_i="55"/>
- <name name="system_info" arity="1" clause_i="56"/>
- <name name="system_info" arity="1" clause_i="57"/>
- <name name="system_info" arity="1" clause_i="58"/>
- <name name="system_info" arity="1" clause_i="59"/>
- <name name="system_info" arity="1" clause_i="60"/>
- <name name="system_info" arity="1" clause_i="61"/>
- <name name="system_info" arity="1" clause_i="62"/>
- <name name="system_info" arity="1" clause_i="63"/>
- <name name="system_info" arity="1" clause_i="64"/>
- <name name="system_info" arity="1" clause_i="65"/>
- <name name="system_info" arity="1" clause_i="66"/>
- <name name="system_info" arity="1" clause_i="67"/>
- <name name="system_info" arity="1" clause_i="68"/>
- <name name="system_info" arity="1" clause_i="69"/>
- <name name="system_info" arity="1" clause_i="70"/>
- <name name="system_info" arity="1" clause_i="71"/>
- <fsummary>Information about the system.</fsummary>
+ <name name="system_info" arity="1" clause_i="6"
+ anchor="system_info_limits"/> <!-- atom_count -->
+ <name name="system_info" arity="1" clause_i="7"/> <!-- atom_limit -->
+ <name name="system_info" arity="1" clause_i="29"/> <!-- ets_limit -->
+ <name name="system_info" arity="1" clause_i="52"/> <!-- port_count -->
+ <name name="system_info" arity="1" clause_i="53"/> <!-- port_limit -->
+ <name name="system_info" arity="1" clause_i="54"/> <!-- process_count -->
+ <name name="system_info" arity="1" clause_i="55"/> <!-- process_limit -->
+ <fsummary>Information about various system limits.</fsummary>
<desc>
- <p>Returns various information about the current system
- (emulator) as specified by <c><anno>Item</anno></c>:</p>
+ <marker id="system_info_limits"/>
+ <p>Returns information about the current system
+ (emulator) limits as specified by <c><anno>Item</anno></c>:</p>
<taglist>
- <tag><c>atom_count</c></tag>
+ <tag><marker id="system_info_atom_count"/>
+ <c>atom_count</c></tag>
<item>
- <marker id="system_info_atom_count"></marker>
<p>Returns the number of atoms currently existing at the
- local node. The value is given as an integer.</p>
+ local node. The value is given as an integer.</p>
</item>
- <tag><c>atom_limit</c></tag>
+ <tag><marker id="system_info_atom_limit"/>
+ <c>atom_limit</c></tag>
<item>
- <marker id="system_info_atom_limit"></marker>
<p>Returns the maximum number of atoms allowed.
- This limit can be increased at startup by passing
- command-line flag
- <seealso marker="erts:erl#+t"><c>+t</c></seealso> to
- <c>erl(1)</c>.
+ This limit can be increased at startup by passing
+ command-line flag
+ <seealso marker="erts:erl#+t"><c>+t</c></seealso> to
+ <c>erl(1)</c>.
</p>
</item>
- <tag><c>build_type</c></tag>
+ <tag><marker id="system_info_ets_limit"/>
+ <c>ets_limit</c></tag>
<item>
- <p>Returns an atom describing the build type of the runtime
- system. This is normally the atom <c>opt</c> for optimized.
- Other possible return values are <c>debug</c>, <c>purify</c>,
- <c>quantify</c>, <c>purecov</c>, <c>gcov</c>, <c>valgrind</c>,
- <c>gprof</c>, and <c>lcnt</c>. Possible return values
- can be added or removed at any time without prior notice.</p>
+ <p>Returns the maximum number of ETS tables allowed. This
+ limit can be increased at startup by passing
+ command-line flag
+ <seealso marker="erts:erl#+e"><c>+e</c></seealso> to
+ <c>erl(1)</c> or by setting environment variable
+ <c>ERL_MAX_ETS_TABLES</c> before starting the Erlang
+ runtime system.</p>
</item>
- <tag><c>c_compiler_used</c></tag>
+ <tag><marker id="system_info_port_count"/><c>port_count</c></tag>
<item>
- <p>Returns a two-tuple describing the C compiler used when
- compiling the runtime system. The first element is an
- atom describing the name of the compiler, or <c>undefined</c>
- if unknown. The second element is a term describing the
- version of the compiler, or <c>undefined</c> if unknown.</p>
+ <p>Returns the number of ports currently existing at the
+ local node. The value is given as an integer. This is
+ the same value as returned by
+ <c>length(erlang:ports())</c>, but more efficient.</p>
</item>
- <tag><c>check_io</c></tag>
+ <tag><marker id="system_info_port_limit"/>
+ <c>port_limit</c></tag>
<item>
- <p>Returns a list containing miscellaneous information
- about the emulators internal I/O checking. Notice that
- the content of the returned list can vary between
- platforms and over time. It is only guaranteed
- that a list is returned.</p>
+ <p>Returns the maximum number of simultaneously existing
+ ports at the local node as an integer. This limit can be
+ configured at startup by using command-line flag
+ <seealso marker="erl#+Q"><c>+Q</c></seealso> in <c>erl(1)</c>.</p>
</item>
- <tag><c>compat_rel</c></tag>
+ <tag><marker id="system_info_process_count"/>
+ <c>process_count</c></tag>
<item>
- <p>Returns the compatibility mode of the local node as
- an integer. The integer returned represents the
- Erlang/OTP release that the current emulator has been
- set to be backward compatible with. The compatibility
- mode can be configured at startup by using command-line flag
- <seealso marker="erts:erl#compat_rel"><c>+R</c></seealso> in
- <c>erl(1)</c>.</p>
+ <p>Returns the number of processes currently existing at the
+ local node. The value is given as an integer. This is
+ the same value as returned by
+ <c>length(processes())</c>, but more efficient.</p>
</item>
- <tag><c>cpu_topology</c></tag>
+ <tag><marker id="system_info_process_limit"/>
+ <c>process_limit</c></tag>
<item>
- <p>See <seealso
- marker="#system_info_cpu_topology_tags">above</seealso>.</p>
+ <p>Returns the maximum number of simultaneously existing
+ processes at the local node. The value is given as an
+ integer. This limit can be configured at startup by using
+ command-line flag <seealso marker="erl#+P"><c>+P</c></seealso>
+ in <c>erl(1)</c>.</p>
</item>
- <tag><c>creation</c></tag>
+ </taglist>
+ </desc>
+ </func>
+
+ <func>
+ <name name="system_info" arity="1" clause_i="26"
+ anchor="system_info_time"/> <!-- end_time -->
+ <name name="system_info" arity="1" clause_i="49"/> <!-- os_monotonic_time_source -->
+ <name name="system_info" arity="1" clause_i="50"/> <!-- os_system_time_source -->
+ <name name="system_info" arity="1" clause_i="62"/> <!-- start_time -->
+ <name name="system_info" arity="1" clause_i="67"/> <!-- time_correction -->
+ <name name="system_info" arity="1" clause_i="68"/> <!-- time_offset -->
+ <name name="system_info" arity="1" clause_i="69"/> <!-- time_warp_mode -->
+ <name name="system_info" arity="1" clause_i="70"/> <!-- tolerant_timeofday -->
+ <fsummary>Information about system time.</fsummary>
+ <desc>
+ <marker id="system_info_time_tags"/>
+ <p>Returns information about the current system
+ (emulator) time as specified by <c><anno>Item</anno></c>:</p>
+ <taglist>
+ <tag><marker id="system_info_end_time"/><c>end_time</c></tag>
<item>
- <p>Returns the creation of the local node as an integer.
- The creation is changed when a node is restarted. The
- creation of a node is stored in process identifiers, port
- identifiers, and references. This makes it (to some
- extent) possible to distinguish between identifiers from
- different incarnations of a node. The valid
- creations are integers in the range 1..3, but this will
- probably change in a future release. If the node is not
- alive, <c>0</c> is returned.</p>
+ <p>The last <seealso marker="#monotonic_time/0">Erlang monotonic
+ time</seealso> in <c>native</c>
+ <seealso marker="#type_time_unit">time unit</seealso> that
+ can be represented internally in the current Erlang runtime system
+ instance. The time between the
+ <seealso marker="#system_info_start_time">start time</seealso> and
+ the end time is at least a quarter of a millennium.</p>
</item>
- <tag><c>debug_compiled</c></tag>
+ <tag><marker id="system_info_os_monotonic_time_source"/>
+ <c>os_monotonic_time_source</c></tag>
<item>
- <p>Returns <c>true</c> if the emulator has been
- debug-compiled, otherwise <c>false</c>.</p>
+ <p>Returns a list containing information about the source of
+ <seealso marker="erts:time_correction#OS_Monotonic_Time">OS
+ monotonic time</seealso> that is used by the runtime system.</p>
+ <p>If <c>[]</c> is returned, no OS monotonic time is
+ available. The list contains two-tuples with <c>Key</c>s
+ as first element, and <c>Value</c>s as second element. The
+ order of these tuples is undefined. The following
+ tuples can be part of the list, but more tuples can be
+ introduced in the future:</p>
+ <taglist>
+ <tag><c>{function, Function}</c></tag>
+ <item><p><c>Function</c> is the name of the function
+ used. This tuple always exists if OS monotonic time is
+ available to the runtime system.</p>
+ </item>
+ <tag><c>{clock_id, ClockId}</c></tag>
+ <item><p>This tuple only exists if <c>Function</c>
+ can be used with different clocks. <c>ClockId</c>
+ corresponds to the clock identifier used when calling
+ <c>Function</c>.</p>
+ </item>
+ <tag><c>{resolution, OsMonotonicTimeResolution}</c></tag>
+ <item><p>Highest possible
+ <seealso marker="time_correction#Time_Resolution">
+ resolution</seealso>
+ of current OS monotonic time source as parts per
+ second. If no resolution information can be retrieved
+ from the OS, <c>OsMonotonicTimeResolution</c> is
+ set to the resolution of the time unit of
+ <c>Function</c>s return value. That is, the actual
+ resolution can be lower than
+ <c>OsMonotonicTimeResolution</c>. Notice that
+ the resolution does not say anything about the
+ <seealso marker="time_correction#Time_Accuracy">
+ accuracy</seealso> or whether the
+ <seealso marker="time_correction#Time_Precision">
+ precision</seealso> aligns with the resolution. You do,
+ however, know that the precision is not better than
+ <c>OsMonotonicTimeResolution</c>.</p>
+ </item>
+ <tag><c>{extended, Extended}</c></tag>
+ <item><p><c>Extended</c> equals <c>yes</c> if
+ the range of time values has been extended;
+ otherwise <c>Extended</c> equals <c>no</c>. The
+ range must be extended if <c>Function</c>
+ returns values that wrap fast. This typically
+ is the case when the return value is a 32-bit value.</p>
+ </item>
+ <tag><c>{parallel, Parallel}</c></tag>
+ <item><p><c>Parallel</c> equals <c>yes</c> if
+ <c>Function</c> is called in parallel from multiple
+ threads. If it is not called in parallel, because
+ calls must be serialized, <c>Parallel</c> equals
+ <c>no</c>.</p>
+ </item>
+ <tag><c>{time, OsMonotonicTime}</c></tag>
+ <item><p><c>OsMonotonicTime</c> equals current OS
+ monotonic time in <c>native</c>
+ <seealso marker="#type_time_unit">time unit</seealso>.</p>
+ </item>
+ </taglist>
</item>
- <tag><c>delayed_node_table_gc</c></tag>
+ <tag><marker id="system_info_os_system_time_source"/>
+ <c>os_system_time_source</c></tag>
<item>
- <marker id="system_info_delayed_node_table_gc"></marker>
- <p>Returns the amount of time in seconds garbage collection
- of an entry in a node table is delayed. This limit can be set
- on startup by passing command-line flag
- <seealso marker="erts:erl#+zdntgc"><c>+zdntgc</c></seealso>
- to <c>erl(1)</c>. For more information, see the documentation of
- the command-line flag.</p>
+ <p>Returns a list containing information about the source of
+ <seealso marker="erts:time_correction#OS_System_Time">OS
+ system time</seealso> that is used by the runtime system.</p>
+ <p>The list contains two-tuples with <c>Key</c>s
+ as first element, and <c>Value</c>s as second element. The
+ order if these tuples is undefined. The following
+ tuples can be part of the list, but more tuples can be
+ introduced in the future:</p>
+ <taglist>
+ <tag><c>{function, Function}</c></tag>
+ <item><p><c>Function</c> is the name of the funcion used.</p>
+ </item>
+ <tag><c>{clock_id, ClockId}</c></tag>
+ <item><p>Exists only if <c>Function</c>
+ can be used with different clocks. <c>ClockId</c>
+ corresponds to the clock identifier used when calling
+ <c>Function</c>.</p>
+ </item>
+ <tag><c>{resolution, OsSystemTimeResolution}</c></tag>
+ <item><p>Highest possible
+ <seealso marker="time_correction#Time_Resolution">
+ resolution</seealso>
+ of current OS system time source as parts per
+ second. If no resolution information can be retrieved
+ from the OS, <c>OsSystemTimeResolution</c> is
+ set to the resolution of the time unit of
+ <c>Function</c>s return value. That is, the actual
+ resolution can be lower than
+ <c>OsSystemTimeResolution</c>. Notice that
+ the resolution does not say anything about the
+ <seealso marker="time_correction#Time_Accuracy">
+ accuracy</seealso> or whether the
+ <seealso marker="time_correction#Time_Precision">
+ precision</seealso> do align with the resolution. You do,
+ however, know that the precision is not better than
+ <c>OsSystemTimeResolution</c>.</p>
+ </item>
+ <tag><c>{parallel, Parallel}</c></tag>
+ <item><p><c>Parallel</c> equals <c>yes</c> if
+ <c>Function</c> is called in parallel from multiple
+ threads. If it is not called in parallel, because
+ calls needs to be serialized, <c>Parallel</c> equals
+ <c>no</c>.</p>
+ </item>
+ <tag><c>{time, OsSystemTime}</c></tag>
+ <item><p><c>OsSystemTime</c> equals current OS
+ system time in <c>native</c>
+ <seealso marker="#type_time_unit">time unit</seealso>.</p>
+ </item>
+ </taglist>
+ </item>
+ <tag><marker id="system_info_start_time"/><c>start_time</c></tag>
+ <item>
+ <p>The <seealso marker="#monotonic_time/0">Erlang monotonic
+ time</seealso> in <c>native</c>
+ <seealso marker="#type_time_unit">time unit</seealso> at the
+ time when current Erlang runtime system instance started.</p>
+ <p>See also <seealso marker="#system_info_end_time">
+ <c>erlang:system_info(end_time)</c></seealso>.</p>
+ </item>
+ <tag><marker id="system_info_time_correction"/>
+ <c>time_correction</c></tag>
+ <item>
+ <p>Returns a boolean value indicating whether
+ <seealso marker="time_correction#Time_Correction">
+ time correction</seealso> is enabled or not.</p>
+ </item>
+ <tag><marker id="system_info_time_offset"/>
+ <c>time_offset</c></tag>
+ <item>
+ <p>Returns the state of the time offset:</p>
+ <taglist>
+ <tag><c>preliminary</c></tag>
+ <item>
+ <p>The time offset is preliminary, and will be changed
+ and finalized later. The preliminary time offset
+ is used during the preliminary phase of the
+ <seealso marker="time_correction#Single_Time_Warp_Mode">
+ single time warp mode</seealso>.</p>
+ </item>
+ <tag><c>final</c></tag>
+ <item>
+ <p>The time offset is final. This either because
+ <seealso marker="time_correction#No_Time_Warp_Mode">
+ no time warp mode</seealso> is used, or because the time
+ offset have been finalized when
+ <seealso marker="time_correction#Single_Time_Warp_Mode">
+ single time warp mode</seealso> is used.</p>
+ </item>
+ <tag><c>volatile</c></tag>
+ <item>
+ <p>The time offset is volatile. That is, it can
+ change at any time. This is because
+ <seealso marker="time_correction#Multi_Time_Warp_Mode">
+ multi-time warp mode</seealso> is used.</p>
+ </item>
+ </taglist>
+ </item>
+ <tag><marker id="system_info_time_warp_mode"/>
+ <c>time_warp_mode</c></tag>
+ <item>
+ <p>Returns a value identifying the
+ <seealso marker="time_correction#Time_Warp_Modes">
+ time warp mode</seealso> that is used:</p>
+ <taglist>
+ <tag><c>no_time_warp</c></tag>
+ <item>The <seealso marker="time_correction#No_Time_Warp_Mode">
+ no time warp mode</seealso> is used.
+ </item>
+ <tag><c>single_time_warp</c></tag>
+ <item>The <seealso marker="time_correction#Single_Time_Warp_Mode">
+ single time warp mode</seealso> is used.
+ </item>
+ <tag><c>multi_time_warp</c></tag>
+ <item>The <seealso marker="time_correction#Multi_Time_Warp_Mode">
+ multi-time warp mode</seealso> is used.
+ </item>
+ </taglist>
</item>
- <tag><c>dirty_cpu_schedulers</c></tag>
+ <tag><marker id="system_info_tolerant_timeofday"/>
+ <c>tolerant_timeofday</c></tag>
+ <item>
+ <p>Returns whether a pre ERTS 7.0 backwards compatible
+ compensation for sudden changes of system time is <c>enabled</c>
+ or <c>disabled</c>. Such compensation is <c>enabled</c> when the
+ <seealso marker="#system_info_time_offset">time offset</seealso>
+ is <c>final</c>, and
+ <seealso marker="#system_info_time_correction">
+ time correction</seealso> is enabled.</p>
+ </item>
+ </taglist>
+ </desc>
+ </func>
+
+ <func>
+ <name name="system_info" arity="1" clause_i="17"
+ anchor="system_info_scheduler"/> <!-- dirty_cpu_schedulers -->
+ <name name="system_info" arity="1" clause_i="18"/> <!-- dirty_cpu_schedulers_online -->
+ <name name="system_info" arity="1" clause_i="19"/> <!-- dirty_io_schedulers -->
+ <name name="system_info" arity="1" clause_i="44"/> <!-- multi_scheduling -->
+ <name name="system_info" arity="1" clause_i="45"/> <!-- multi_scheduling_blockers -->
+ <name name="system_info" arity="1" clause_i="47"/> <!-- normal_multi_scheduling_blockers -->
+ <name name="system_info" arity="1" clause_i="57"/> <!-- scheduler_bind_type -->
+ <name name="system_info" arity="1" clause_i="58"/> <!-- scheduler_bindings -->
+ <name name="system_info" arity="1" clause_i="59"/> <!-- scheduler_id -->
+ <name name="system_info" arity="1" clause_i="60"/> <!-- schedulers -->
+ <name name="system_info" arity="1" clause_i="61"/> <!-- smp_support -->
+ <name name="system_info" arity="1" clause_i="65"/> <!-- threads -->
+ <name name="system_info" arity="1" clause_i="66"/> <!-- thread_pool_size -->
+ <fsummary>Information about system schedulers.</fsummary>
+ <desc>
+ <marker id="system_info_scheduler_tags"/>
+ <p>Returns information about schedulers, scheduling and threads in the
+ current system as specified by <c><anno>Item</anno></c>:</p>
+ <taglist>
+ <tag><marker id="system_info_dirty_cpu_schedulers"/>
+ <c>dirty_cpu_schedulers</c></tag>
<item>
- <marker id="system_info_dirty_cpu_schedulers"></marker>
<p>Returns the number of dirty CPU scheduler threads used by
the emulator. Dirty CPU schedulers execute CPU-bound
native functions, such as NIFs, linked-in driver code,
@@ -7989,9 +8411,9 @@ ok
<c>erlang:system_flag(schedulers_online,
SchedulersOnline)</c></seealso>.</p>
</item>
- <tag><c>dirty_cpu_schedulers_online</c></tag>
+ <tag><marker id="system_info_dirty_cpu_schedulers_online"/>
+ <c>dirty_cpu_schedulers_online</c></tag>
<item>
- <marker id="system_info_dirty_cpu_schedulers_online"></marker>
<p>Returns the number of dirty CPU schedulers online.
The return value satisfies
<c><![CDATA[1 <= DirtyCPUSchedulersOnline <= N]]></c>,
@@ -8013,9 +8435,9 @@ ok
<c>erlang:system_flag(dirty_cpu_schedulers_online,
DirtyCPUSchedulersOnline)</c></seealso>.</p>
</item>
- <tag><c>dirty_io_schedulers</c></tag>
+ <tag><marker id="system_info_dirty_io_schedulers"/>
+ <c>dirty_io_schedulers</c></tag>
<item>
- <marker id="system_info_dirty_io_schedulers"></marker>
<p>Returns the number of dirty I/O schedulers as an integer.
Dirty I/O schedulers execute I/O-bound native functions,
such as NIFs and linked-in driver code, which cannot be
@@ -8032,179 +8454,9 @@ ok
<c>erlang:system_flag(dirty_cpu_schedulers_online,
DirtyCPUSchedulersOnline)</c></seealso>.</p>
</item>
- <tag><c>dist</c></tag>
- <item>
- <p>Returns a binary containing a string of distribution
- information formatted as in Erlang crash dumps. For more
- information, see section <seealso marker="erts:crash_dump">
- How to interpret the Erlang crash dumps</seealso>
- in the User's Guide.</p>
- </item>
- <tag><c>dist_buf_busy_limit</c></tag>
- <item>
- <marker id="system_info_dist_buf_busy_limit"></marker>
- <p>Returns the value of the distribution buffer busy limit
- in bytes. This limit can be set at startup by passing
- command-line flag
- <seealso marker="erts:erl#+zdbbl"><c>+zdbbl</c></seealso>
- to <c>erl(1)</c>.</p>
- </item>
- <tag><c>dist_ctrl</c></tag>
- <item>
- <p>Returns a list of tuples
- <c>{<anno>Node</anno>, <anno>ControllingEntity</anno>}</c>,
- one entry for each connected remote node.
- <c><anno>Node</anno></c> is the node name
- and <c><anno>ControllingEntity</anno></c> is the port or process
- identifier responsible for the communication to that node.
- More specifically, <c><anno>ControllingEntity</anno></c> for
- nodes connected through TCP/IP (the normal case) is the socket
- used in communication with the specific node.</p>
- </item>
- <tag><c>driver_version</c></tag>
- <item>
- <p>Returns a string containing the Erlang driver version
- used by the runtime system. It has the form
- <seealso marker="erts:erl_driver#version_management">
- "&lt;major ver&gt;.&lt;minor ver&gt;"</seealso>.</p>
- </item>
- <tag><c>dynamic_trace</c></tag>
- <item>
- <p>Returns an atom describing the dynamic trace framework
- compiled into the virtual machine. It can be
- <c>dtrace</c>, <c>systemtap</c>, or <c>none</c>. For a
- commercial or standard build, it is always <c>none</c>.
- The other return values indicate a custom configuration
- (for example, <c>./configure --with-dynamic-trace=dtrace</c>).
- For more information about dynamic tracing, see
- <seealso marker="runtime_tools:dyntrace">
- <c>dyntrace(3)</c></seealso> manual page and the
- <c>README.dtrace</c>/<c>README.systemtap</c> files in the
- Erlang source code top directory.</p>
- </item>
- <tag><c>dynamic_trace_probes</c></tag>
+ <tag><marker id="system_info_multi_scheduling"/>
+ <c>multi_scheduling</c></tag>
<item>
- <p>Returns a <c>boolean()</c> indicating if dynamic trace
- probes (<c>dtrace</c> or <c>systemtap</c>) are built into
- the emulator. This can only be <c>true</c> if the virtual
- machine was built for dynamic tracing (that is,
- <c>system_info(dynamic_trace)</c> returns
- <c>dtrace</c> or <c>systemtap</c>).</p>
- </item>
- <tag><marker id="system_info_end_time"/><c>end_time</c></tag>
- <item>
- <p>The last <seealso marker="#monotonic_time/0">Erlang monotonic
- time</seealso> in <c>native</c>
- <seealso marker="#type_time_unit">time unit</seealso> that
- can be represented internally in the current Erlang runtime system
- instance. The time between the
- <seealso marker="#system_info_start_time">start time</seealso> and
- the end time is at least a quarter of a millennium.</p>
- </item>
- <tag><c>elib_malloc</c></tag>
- <item>
- <p>This option will be removed in a future release.
- The return value will always be <c>false</c>, as the
- <c>elib_malloc</c> allocator has been removed.</p>
- </item>
- <tag><c>ets_limit</c></tag>
- <item>
- <p>Returns the maximum number of ETS tables allowed. This
- limit can be increased at startup by passing
- command-line flag
- <seealso marker="erts:erl#+e"><c>+e</c></seealso> to
- <c>erl(1)</c> or by setting environment variable
- <c>ERL_MAX_ETS_TABLES</c> before starting the Erlang
- runtime system.</p>
- </item>
- <tag><c>heap_sizes</c></tag>
- <item>
- <p>Returns a list of integers representing valid heap sizes
- in words. All Erlang heaps are sized from sizes in this
- list.</p>
- </item>
- <tag><c>heap_type</c></tag>
- <item>
- <p>Returns the heap type used by the current emulator. One
- heap type exists:</p>
- <taglist>
- <tag><c>private</c></tag>
- <item>
- Each process has a heap reserved for its use and no
- references between heaps of different processes are
- allowed. Messages passed between processes are copied
- between heaps.
- </item>
- </taglist>
- </item>
- <tag><c>info</c></tag>
- <item>
- <p>Returns a binary containing a string of miscellaneous
- system information formatted as in Erlang crash dumps.
- For more information, see section
- <seealso marker="erts:crash_dump">
- How to interpret the Erlang crash dumps</seealso>
- in the User's Guide.</p>
- </item>
- <tag><c>kernel_poll</c></tag>
- <item>
- <p>Returns <c>true</c> if the emulator uses some kind of
- kernel-poll implementation, otherwise <c>false</c>.</p>
- </item>
- <tag><c>loaded</c></tag>
- <item>
- <p>Returns a binary containing a string of loaded module
- information formatted as in Erlang crash dumps. For more
- information, see section
- <seealso marker="erts:crash_dump">How to interpret the Erlang
- crash dumps</seealso> in the User's Guide.</p>
- </item>
- <tag><c>logical_processors</c></tag>
- <item>
- <marker id="logical_processors"></marker>
- <p>Returns the detected number of logical processors configured
- in the system. The return value is either an integer, or
- the atom <c>unknown</c> if the emulator cannot
- detect the configured logical processors.</p>
- </item>
- <tag><c>logical_processors_available</c></tag>
- <item>
- <marker id="logical_processors_available"></marker>
- <p>Returns the detected number of logical processors available
- to the Erlang runtime system. The return value is either an
- integer, or the atom <c>unknown</c> if the emulator
- cannot detect the available logical processors. The number
- of available logical processors is less than or equal to
- the number of <seealso marker="#logical_processors_online">
- logical processors online</seealso>.</p>
- </item>
- <tag><c>logical_processors_online</c></tag>
- <item>
- <marker id="logical_processors_online"></marker>
- <p>Returns the detected number of logical processors online on
- the system. The return value is either an integer,
- or the atom <c>unknown</c> if the emulator cannot
- detect logical processors online. The number of logical
- processors online is less than or equal to the number of
- <seealso marker="#logical_processors">logical processors
- configured</seealso>.</p>
- </item>
- <tag><c>machine</c></tag>
- <item>
- <p>Returns a string containing the Erlang machine name.</p>
- </item>
- <tag><c>modified_timing_level</c></tag>
- <item>
- <p>Returns the modified timing-level (an integer) if
- modified timing is enabled, otherwise <c>undefined</c>.
- For more information about modified timing, see
- command-line flag
- <seealso marker="erts:erl#+T"><c>+T</c></seealso>
- in <c>erl(1)</c></p>
- </item>
- <tag><c>multi_scheduling</c></tag>
- <item>
- <marker id="system_info_multi_scheduling"></marker>
<p>Returns one of the following:</p>
<taglist>
<tag><c>disabled</c></tag>
@@ -8244,9 +8496,9 @@ ok
and <seealso marker="#system_info_schedulers">
<c>erlang:system_info(schedulers)</c></seealso>.</p>
</item>
- <tag><c>multi_scheduling_blockers</c></tag>
+ <tag><marker id="system_info_multi_scheduling_blockers"/>
+ <c>multi_scheduling_blockers</c></tag>
<item>
- <marker id="system_info_multi_scheduling_blockers"></marker>
<p>Returns a list of <c><anno>Pid</anno></c>s when
multi-scheduling is blocked, otherwise the empty list is
returned. The <c><anno>Pid</anno></c>s in the list
@@ -8264,15 +8516,9 @@ ok
and <seealso marker="#system_info_schedulers">
<c>erlang:system_info(schedulers)</c></seealso>.</p>
</item>
- <tag><c>nif_version</c></tag>
+ <tag><marker id="system_info_normal_multi_scheduling_blockers"/>
+ <c>normal_multi_scheduling_blockers</c></tag>
<item>
- <p>Returns a string containing the version of the Erlang NIF
- interface used by the runtime system. It is on the form
- "&lt;major ver&gt;.&lt;minor ver&gt;".</p>
- </item>
- <tag><c>normal_multi_scheduling_blockers</c></tag>
- <item>
- <marker id="system_info_normal_multi_scheduling_blockers"></marker>
<p>Returns a list of <c><anno>Pid</anno></c>s when
normal multi-scheduling is blocked (that is, all normal schedulers
but one is blocked), otherwise the empty list is returned.
@@ -8290,192 +8536,9 @@ ok
and <seealso marker="#system_info_schedulers">
<c>erlang:system_info(schedulers)</c></seealso>.</p>
</item>
- <tag><marker id="system_info_otp_release"/>
- <c>otp_release</c></tag>
- <item>
- <marker id="system_info_otp_release"></marker>
- <p>Returns a string containing the OTP release number of the
- OTP release that the currently executing ERTS application
- is part of.</p>
- <p>As from Erlang/OTP 17, the OTP release number corresponds to
- the major OTP version number. No
- <c>erlang:system_info()</c> argument gives the exact OTP
- version. This is because the exact OTP version in the general case
- is difficult to determine. For more information, see the
- description of versions in
- <seealso marker="doc/system_principles:versions">
- System principles</seealso> in System Documentation.</p>
- </item>
- <tag><marker id="system_info_os_monotonic_time_source"/>
- <c>os_monotonic_time_source</c></tag>
+ <tag><marker id="system_info_scheduler_bind_type"/>
+ <c>scheduler_bind_type</c></tag>
<item>
- <p>Returns a list containing information about the source of
- <seealso marker="erts:time_correction#OS_Monotonic_Time">OS
- monotonic time</seealso> that is used by the runtime system.</p>
- <p>If <c>[]</c> is returned, no OS monotonic time is
- available. The list contains two-tuples with <c>Key</c>s
- as first element, and <c>Value</c>s as second element. The
- order of these tuples is undefined. The following
- tuples can be part of the list, but more tuples can be
- introduced in the future:</p>
- <taglist>
- <tag><c>{function, Function}</c></tag>
- <item><p><c>Function</c> is the name of the function
- used. This tuple always exists if OS monotonic time is
- available to the runtime system.</p>
- </item>
- <tag><c>{clock_id, ClockId}</c></tag>
- <item><p>This tuple only exists if <c>Function</c>
- can be used with different clocks. <c>ClockId</c>
- corresponds to the clock identifier used when calling
- <c>Function</c>.</p>
- </item>
- <tag><c>{resolution, OsMonotonicTimeResolution}</c></tag>
- <item><p>Highest possible
- <seealso marker="time_correction#Time_Resolution">
- resolution</seealso>
- of current OS monotonic time source as parts per
- second. If no resolution information can be retrieved
- from the OS, <c>OsMonotonicTimeResolution</c> is
- set to the resolution of the time unit of
- <c>Function</c>s return value. That is, the actual
- resolution can be lower than
- <c>OsMonotonicTimeResolution</c>. Notice that
- the resolution does not say anything about the
- <seealso marker="time_correction#Time_Accuracy">
- accuracy</seealso> or whether the
- <seealso marker="time_correction#Time_Precision">
- precision</seealso> aligns with the resolution. You do,
- however, know that the precision is not better than
- <c>OsMonotonicTimeResolution</c>.</p>
- </item>
- <tag><c>{extended, Extended}</c></tag>
- <item><p><c>Extended</c> equals <c>yes</c> if
- the range of time values has been extended;
- otherwise <c>Extended</c> equals <c>no</c>. The
- range must be extended if <c>Function</c>
- returns values that wrap fast. This typically
- is the case when the return value is a 32-bit value.</p>
- </item>
- <tag><c>{parallel, Parallel}</c></tag>
- <item><p><c>Parallel</c> equals <c>yes</c> if
- <c>Function</c> is called in parallel from multiple
- threads. If it is not called in parallel, because
- calls must be serialized, <c>Parallel</c> equals
- <c>no</c>.</p>
- </item>
- <tag><c>{time, OsMonotonicTime}</c></tag>
- <item><p><c>OsMonotonicTime</c> equals current OS
- monotonic time in <c>native</c>
- <seealso marker="#type_time_unit">time unit</seealso>.</p>
- </item>
- </taglist>
- </item>
- <tag><marker id="system_info_os_system_time_source"/>
- <c>os_system_time_source</c></tag>
- <item>
- <p>Returns a list containing information about the source of
- <seealso marker="erts:time_correction#OS_System_Time">OS
- system time</seealso> that is used by the runtime system.</p>
- <p>The list contains two-tuples with <c>Key</c>s
- as first element, and <c>Value</c>s as second element. The
- order if these tuples is undefined. The following
- tuples can be part of the list, but more tuples can be
- introduced in the future:</p>
- <taglist>
- <tag><c>{function, Function}</c></tag>
- <item><p><c>Function</c> is the name of the funcion used.</p>
- </item>
- <tag><c>{clock_id, ClockId}</c></tag>
- <item><p>Exists only if <c>Function</c>
- can be used with different clocks. <c>ClockId</c>
- corresponds to the clock identifier used when calling
- <c>Function</c>.</p>
- </item>
- <tag><c>{resolution, OsSystemTimeResolution}</c></tag>
- <item><p>Highest possible
- <seealso marker="time_correction#Time_Resolution">
- resolution</seealso>
- of current OS system time source as parts per
- second. If no resolution information can be retrieved
- from the OS, <c>OsSystemTimeResolution</c> is
- set to the resolution of the time unit of
- <c>Function</c>s return value. That is, the actual
- resolution can be lower than
- <c>OsSystemTimeResolution</c>. Notice that
- the resolution does not say anything about the
- <seealso marker="time_correction#Time_Accuracy">
- accuracy</seealso> or whether the
- <seealso marker="time_correction#Time_Precision">
- precision</seealso> do align with the resolution. You do,
- however, know that the precision is not better than
- <c>OsSystemTimeResolution</c>.</p>
- </item>
- <tag><c>{parallel, Parallel}</c></tag>
- <item><p><c>Parallel</c> equals <c>yes</c> if
- <c>Function</c> is called in parallel from multiple
- threads. If it is not called in parallel, because
- calls needs to be serialized, <c>Parallel</c> equals
- <c>no</c>.</p>
- </item>
- <tag><c>{time, OsSystemTime}</c></tag>
- <item><p><c>OsSystemTime</c> equals current OS
- system time in <c>native</c>
- <seealso marker="#type_time_unit">time unit</seealso>.</p>
- </item>
- </taglist>
- </item>
- <tag><c>port_parallelism</c></tag>
- <item>
- <marker id="system_info_port_parallelism"></marker>
- <p>Returns the default port parallelism scheduling hint used.
- For more information, see command-line argument
- <seealso marker="erl#+spp"><c>+spp</c></seealso>
- in <c>erl(1)</c>.</p>
- </item>
- <tag><marker id="system_info_port_count"/><c>port_count</c></tag>
- <item>
- <p>Returns the number of ports currently existing at the
- local node. The value is given as an integer. This is
- the same value as returned by
- <c>length(erlang:ports())</c>, but more efficient.</p>
- </item>
- <tag><c>port_limit</c></tag>
- <item>
- <marker id="system_info_port_limit"></marker>
- <p>Returns the maximum number of simultaneously existing
- ports at the local node as an integer. This limit can be
- configured at startup by using command-line flag
- <seealso marker="erl#+Q"><c>+Q</c></seealso> in <c>erl(1)</c>.</p>
- </item>
- <tag><marker id="system_info_process_count"/>
- <c>process_count</c></tag>
- <item>
- <p>Returns the number of processes currently existing at the
- local node. The value is given as an integer. This is
- the same value as returned by
- <c>length(processes())</c>, but more efficient.</p>
- </item>
- <tag><c>process_limit</c></tag>
- <item>
- <marker id="system_info_process_limit"></marker>
- <p>Returns the maximum number of simultaneously existing
- processes at the local node. The value is given as an
- integer. This limit can be configured at startup by using
- command-line flag <seealso marker="erl#+P"><c>+P</c></seealso>
- in <c>erl(1)</c>.</p>
- </item>
- <tag><c>procs</c></tag>
- <item>
- <p>Returns a binary containing a string of process and port
- information formatted as in Erlang crash dumps. For more
- information, see section <seealso marker="erts:crash_dump">
- How to interpret the Erlang crash dumps</seealso>
- in the User's Guide.</p>
- </item>
- <tag><c>scheduler_bind_type</c></tag>
- <item>
- <marker id="system_info_scheduler_bind_type"></marker>
<p>Returns information about how the user has requested
schedulers to be bound or not bound.</p>
<p>Notice that although a user has requested
@@ -8489,9 +8552,9 @@ ok
<seealso marker="#system_info_scheduler_bindings">
<c>erlang:system_info(scheduler_bindings)</c></seealso>.</p>
</item>
- <tag><c>scheduler_bindings</c></tag>
+ <tag><marker id="system_info_scheduler_bindings"/>
+ <c>scheduler_bindings</c></tag>
<item>
- <marker id="system_info_scheduler_bindings"></marker>
<p>Returns information about the currently used scheduler
bindings.</p>
<p>A tuple of a size equal to
@@ -8515,9 +8578,9 @@ ok
<seealso marker="#system_info_schedulers_online">
<c>erlang:system_info(schedulers_online)</c></seealso>.</p>
</item>
- <tag><c>scheduler_id</c></tag>
+ <tag><marker id="system_info_scheduler_id"/>
+ <c>scheduler_id</c></tag>
<item>
- <marker id="system_info_scheduler_id"></marker>
<p>Returns the scheduler ID (<c>SchedulerId</c>) of the
scheduler thread that the calling process is executing
on. <c><anno>SchedulerId</anno></c> is a positive integer,
@@ -8527,9 +8590,9 @@ ok
<seealso marker="#system_info_schedulers">
<c>erlang:system_info(schedulers)</c></seealso>.</p>
</item>
- <tag><c>schedulers</c></tag>
+ <tag><marker id="system_info_schedulers"/>
+ <c>schedulers</c></tag>
<item>
- <marker id="system_info_schedulers"></marker>
<p>Returns the number of scheduler threads used by
the emulator. Scheduler threads online schedules Erlang
processes and Erlang ports, and execute Erlang code
@@ -8556,9 +8619,9 @@ ok
<c>erlang:system_info(multi_scheduling_blockers)</c></seealso>.
</p>
</item>
- <tag><c>schedulers_online</c></tag>
+ <tag><marker id="system_info_schedulers_online"/>
+ <c>schedulers_online</c></tag>
<item>
- <marker id="system_info_schedulers_online"></marker>
<p>Returns the number of schedulers online. The scheduler
identifiers of schedulers online satisfy the relationship
<c><![CDATA[1 <= SchedulerId <=
@@ -8570,34 +8633,18 @@ ok
<c>erlang:system_flag(schedulers_online,
SchedulersOnline)</c></seealso>.</p>
</item>
- <tag><c>smp_support</c></tag>
+ <tag><marker id="system_info_smp_support"/>
+ <c>smp_support</c></tag>
<item>
<p>Returns <c>true</c>.</p>
</item>
- <tag><marker id="system_info_start_time"/><c>start_time</c></tag>
- <item>
- <p>The <seealso marker="#monotonic_time/0">Erlang monotonic
- time</seealso> in <c>native</c>
- <seealso marker="#type_time_unit">time unit</seealso> at the
- time when current Erlang runtime system instance started.</p>
- <p>See also <seealso marker="#system_info_end_time">
- <c>erlang:system_info(end_time)</c></seealso>.</p>
- </item>
- <tag><c>system_version</c></tag>
- <item>
- <p>Returns a string containing version number and
- some important properties, such as the number of schedulers.</p>
- </item>
- <tag><c>system_architecture</c></tag>
- <item>
- <p>Returns a string containing the processor and OS
- architecture the emulator is built for.</p>
- </item>
- <tag><c>threads</c></tag>
+ <tag><marker id="system_info_threads"/>
+ <c>threads</c></tag>
<item>
<p>Returns <c>true</c>.</p>
</item>
- <tag><c>thread_pool_size</c></tag>
+ <tag><marker id="system_info_thread_pool_size"/>
+ <c>thread_pool_size</c></tag>
<item>
<marker id="system_info_thread_pool_size"></marker>
<p>Returns the number of async threads in the async thread
@@ -8606,111 +8653,341 @@ ok
<c>erl_driver:driver_async()</c></seealso>).
The value is given as an integer.</p>
</item>
- <tag><c>time_correction</c></tag>
+ </taglist>
+ </desc>
+ </func>
+
+ <func>
+ <name name="system_info" arity="1" clause_i="14"
+ anchor="system_info_dist"/> <!-- creation -->
+ <name name="system_info" arity="1" clause_i="16"/> <!-- delayed_node_table_gc -->
+ <name name="system_info" arity="1" clause_i="20"/> <!-- dist -->
+ <name name="system_info" arity="1" clause_i="21"/> <!-- dist_buf_busy_limit -->
+ <name name="system_info" arity="1" clause_i="22"/> <!-- dist_ctrl -->
+ <fsummary>Information about erlang distribution.</fsummary>
+ <desc>
+ <marker id="system_info_dist_tags"/>
+ <p>Returns information about Erlang Distribution in the
+ current system as specified by <c><anno>Item</anno></c>:</p>
+ <taglist>
+ <tag><marker id="system_info_creation"/>
+ <c>creation</c></tag>
<item>
- <marker id="system_info_time_correction"></marker>
- <p>Returns a boolean value indicating whether
- <seealso marker="time_correction#Time_Correction">
- time correction</seealso> is enabled or not.</p>
+ <p>Returns the creation of the local node as an integer.
+ The creation is changed when a node is restarted. The
+ creation of a node is stored in process identifiers, port
+ identifiers, and references. This makes it (to some
+ extent) possible to distinguish between identifiers from
+ different incarnations of a node. The valid
+ creations are integers in the range 1..3, but this will
+ probably change in a future release. If the node is not
+ alive, <c>0</c> is returned.</p>
</item>
- <tag><c>time_offset</c></tag>
+ <tag><marker id="system_info_delayed_node_table_gc"/>
+ <c>delayed_node_table_gc</c></tag>
<item>
- <marker id="system_info_time_offset"></marker>
- <p>Returns the state of the time offset:</p>
- <taglist>
- <tag><c>preliminary</c></tag>
- <item>
- <p>The time offset is preliminary, and will be changed
- and finalized later. The preliminary time offset
- is used during the preliminary phase of the
- <seealso marker="time_correction#Single_Time_Warp_Mode">
- single time warp mode</seealso>.</p>
- </item>
- <tag><c>final</c></tag>
- <item>
- <p>The time offset is final. This either because
- <seealso marker="time_correction#No_Time_Warp_Mode">
- no time warp mode</seealso> is used, or because the time
- offset have been finalized when
- <seealso marker="time_correction#Single_Time_Warp_Mode">
- single time warp mode</seealso> is used.</p>
- </item>
- <tag><c>volatile</c></tag>
- <item>
- <p>The time offset is volatile. That is, it can
- change at any time. This is because
- <seealso marker="time_correction#Multi_Time_Warp_Mode">
- multi-time warp mode</seealso> is used.</p>
- </item>
- </taglist>
+ <p>Returns the amount of time in seconds garbage collection
+ of an entry in a node table is delayed. This limit can be set
+ on startup by passing command-line flag
+ <seealso marker="erts:erl#+zdntgc"><c>+zdntgc</c></seealso>
+ to <c>erl(1)</c>. For more information, see the documentation of
+ the command-line flag.</p>
</item>
- <tag><marker id="system_info_time_warp_mode"/>
- <c>time_warp_mode</c></tag>
+ <tag><marker id="system_info_dist"/>
+ <c>dist</c></tag>
<item>
- <p>Returns a value identifying the
- <seealso marker="time_correction#Time_Warp_Modes">
- time warp mode</seealso> that is used:</p>
- <taglist>
- <tag><c>no_time_warp</c></tag>
- <item>The <seealso marker="time_correction#No_Time_Warp_Mode">
- no time warp mode</seealso> is used.
- </item>
- <tag><c>single_time_warp</c></tag>
- <item>The <seealso marker="time_correction#Single_Time_Warp_Mode">
- single time warp mode</seealso> is used.
- </item>
- <tag><c>multi_time_warp</c></tag>
- <item>The <seealso marker="time_correction#Multi_Time_Warp_Mode">
- multi-time warp mode</seealso> is used.
- </item>
- </taglist>
+ <p>Returns a binary containing a string of distribution
+ information formatted as in Erlang crash dumps. For more
+ information, see section <seealso marker="erts:crash_dump">
+ How to interpret the Erlang crash dumps</seealso>
+ in the User's Guide.</p>
</item>
- <tag><c>tolerant_timeofday</c></tag>
+ <tag><marker id="system_info_dist_buf_busy_limit"/>
+ <c>dist_buf_busy_limit</c></tag>
<item>
- <marker id="system_info_tolerant_timeofday"></marker>
- <p>Returns whether a pre ERTS 7.0 backwards compatible
- compensation for sudden changes of system time is <c>enabled</c>
- or <c>disabled</c>. Such compensation is <c>enabled</c> when the
- <seealso marker="#system_info_time_offset">time offset</seealso>
- is <c>final</c>, and
- <seealso marker="#system_info_time_correction">
- time correction</seealso> is enabled.</p>
+ <p>Returns the value of the distribution buffer busy limit
+ in bytes. This limit can be set at startup by passing
+ command-line flag
+ <seealso marker="erts:erl#+zdbbl"><c>+zdbbl</c></seealso>
+ to <c>erl(1)</c>.</p>
+ </item>
+ <tag><marker id="system_info_dist_ctrl"/>
+ <c>dist_ctrl</c></tag>
+ <item>
+ <p>Returns a list of tuples
+ <c>{<anno>Node</anno>, <anno>ControllingEntity</anno>}</c>,
+ one entry for each connected remote node.
+ <c><anno>Node</anno></c> is the node name
+ and <c><anno>ControllingEntity</anno></c> is the port or process
+ identifier responsible for the communication to that node.
+ More specifically, <c><anno>ControllingEntity</anno></c> for
+ nodes connected through TCP/IP (the normal case) is the socket
+ used in communication with the specific node.</p>
+ </item>
+ </taglist>
+ </desc>
+ </func>
+
+ <func>
+ <!-- <name name="system_info" arity="1" clause_i="1"/> allocated_areas -->
+ <!-- <name name="system_info" arity="1" clause_i="2"/> allocated -->
+ <!-- <name name="system_info" arity="1" clause_i="3"/> {allocator, _} -->
+ <!-- <name name="system_info" arity="1" clause_i="4"/> alloc_util_allocators -->
+ <!-- <name name="system_info" arity="1" clause_i="5"/> {allocator_sizes, _} -->
+ <!-- <name name="system_info" arity="1" clause_i="6"/> atom_count -->
+ <!-- <name name="system_info" arity="1" clause_i="7"/> atom_limit -->
+ <name name="system_info" arity="1" clause_i="8"
+ anchor="system_info_misc"/> <!-- build_type -->
+ <name name="system_info" arity="1" clause_i="9"/> <!-- c_compiler_used -->
+ <name name="system_info" arity="1" clause_i="10"/> <!-- check_io -->
+ <name name="system_info" arity="1" clause_i="11"/> <!-- compat_rel -->
+ <!-- <name name="system_info" arity="1" clause_i="12"/> cpu_topology -->
+ <!-- <name name="system_info" arity="1" clause_i="13"/> {cpu_topology, _} -->
+ <!-- <name name="system_info" arity="1" clause_i="14"/> creation -->
+ <name name="system_info" arity="1" clause_i="15"/> <!-- debug_compiled -->
+ <!-- <name name="system_info" arity="1" clause_i="16"/> delayed_node_table_gc -->
+ <!-- <name name="system_info" arity="1" clause_i="17"/> dirty_cpu_schedulers -->
+ <!-- <name name="system_info" arity="1" clause_i="18"/> dirty_cpu_schedulers_online -->
+ <!-- <name name="system_info" arity="1" clause_i="19"/> dirty_io_schedulers -->
+ <!-- <name name="system_info" arity="1" clause_i="20"/> dist -->
+ <!-- <name name="system_info" arity="1" clause_i="21"/> dist_buf_busy_limit -->
+ <!-- <name name="system_info" arity="1" clause_i="22"/> dist_ctrl -->
+ <name name="system_info" arity="1" clause_i="23"/> <!-- driver_version -->
+ <name name="system_info" arity="1" clause_i="24"/> <!-- dynamic_trace -->
+ <name name="system_info" arity="1" clause_i="25"/> <!-- dynamic_trace_probes -->
+ <!-- <name name="system_info" arity="1" clause_i="26"/> end_time -->
+ <!-- <name name="system_info" arity="1" clause_i="27"/> elib_malloc -->
+ <!-- <name name="system_info" arity="1" clause_i="28"/> eager_check_io, removed -->
+ <!-- <name name="system_info" arity="1" clause_i="29"/> ets_limit -->
+ <!-- <name name="system_info" arity="1" clause_i="30"/> fullsweep_after -->
+ <!-- <name name="system_info" arity="1" clause_i="31"/> garbage_collection -->
+ <!-- <name name="system_info" arity="1" clause_i="32"/> heap_sizes -->
+ <!-- <name name="system_info" arity="1" clause_i="33"/> heap_type -->
+ <name name="system_info" arity="1" clause_i="34"/> <!-- info -->
+ <name name="system_info" arity="1" clause_i="35"/> <!-- kernel_poll -->
+ <name name="system_info" arity="1" clause_i="36"/> <!-- loaded -->
+ <!-- <name name="system_info" arity="1" clause_i="37"/> logical_processors -->
+ <name name="system_info" arity="1" clause_i="38"/> <!-- machine -->
+ <!-- <name name="system_info" arity="1" clause_i="39"/> max_heap_size -->
+ <!-- <name name="system_info" arity="1" clause_i="40"/> message_queue_data -->
+ <!-- <name name="system_info" arity="1" clause_i="41"/> min_heap_size -->
+ <!-- <name name="system_info" arity="1" clause_i="42"/> min_bin_vheap_size -->
+ <name name="system_info" arity="1" clause_i="43"/> <!-- modified_timing_level -->
+ <!-- <name name="system_info" arity="1" clause_i="44"/> multi_scheduling -->
+ <!-- <name name="system_info" arity="1" clause_i="45"/> multi_scheduling_blockers -->
+ <name name="system_info" arity="1" clause_i="46"/> <!-- nif_version -->
+ <!-- n<name name="system_info" arity="1" clause_i="47"/> ormal_multi_scheduling_blockers -->
+ <name name="system_info" arity="1" clause_i="48"/> <!-- otp_release -->
+ <!-- <name name="system_info" arity="1" clause_i="49"/> os_monotonic_time_source -->
+ <!-- <name name="system_info" arity="1" clause_i="50"/> os_system_time_source -->
+ <name name="system_info" arity="1" clause_i="51"/> <!-- port_parallelism -->
+ <!-- <name name="system_info" arity="1" clause_i="52"/> port_count -->
+ <!-- <name name="system_info" arity="1" clause_i="53"/> port_limit -->
+ <!-- <name name="system_info" arity="1" clause_i="54"/> process_count -->
+ <!-- <name name="system_info" arity="1" clause_i="55"/> process_limit -->
+ <!-- <name name="system_info" arity="1" clause_i="56"/> procs -->
+ <!-- <name name="system_info" arity="1" clause_i="57"/> scheduler_bind_type -->
+ <!-- <name name="system_info" arity="1" clause_i="58"/> scheduler_bindings -->
+ <!-- <name name="system_info" arity="1" clause_i="59"/> scheduler_id -->
+ <!-- <name name="system_info" arity="1" clause_i="60"/> schedulers -->
+ <!-- <name name="system_info" arity="1" clause_i="61"/> smp_support -->
+ <!-- <name name="system_info" arity="1" clause_i="62"/> start_time -->
+ <name name="system_info" arity="1" clause_i="63"/> <!-- system_version -->
+ <name name="system_info" arity="1" clause_i="64"/> <!-- system_architecture -->
+ <!-- <name name="system_info" arity="1" clause_i="65"/> threads -->
+ <!-- <name name="system_info" arity="1" clause_i="66"/> thread_pool_size -->
+ <!-- <name name="system_info" arity="1" clause_i="67"/> time_correction -->
+ <!-- <name name="system_info" arity="1" clause_i="68"/> time_offset -->
+ <!-- <name name="system_info" arity="1" clause_i="69"/> time_warp_mode -->
+ <!-- <name name="system_info" arity="1" clause_i="70"/> tolerant_timeofday -->
+ <name name="system_info" arity="1" clause_i="71"/> <!-- trace_control_word -->
+ <!-- <name name="system_info" arity="1" clause_i="72"/> update_cpu_info -->
+ <name name="system_info" arity="1" clause_i="73"/> <!-- version -->
+ <name name="system_info" arity="1" clause_i="74"/> <!-- wordsize -->
+ <!-- <name name="system_info" arity="1" clause_i="75"/> overview -->
+ <fsummary>Information about the system.</fsummary>
+ <desc>
+ <marker id="system_info_misc_tags"/>
+ <p>Returns various information about the current system
+ (emulator) as specified by <c><anno>Item</anno></c>:</p>
+ <taglist>
+ <tag><marker id="system_info_build_type"/>
+ <c>build_type</c></tag>
+ <item>
+ <p>Returns an atom describing the build type of the runtime
+ system. This is normally the atom <c>opt</c> for optimized.
+ Other possible return values are <c>debug</c>, <c>purify</c>,
+ <c>quantify</c>, <c>purecov</c>, <c>gcov</c>, <c>valgrind</c>,
+ <c>gprof</c>, and <c>lcnt</c>. Possible return values
+ can be added or removed at any time without prior notice.</p>
+ </item>
+ <tag><marker id="system_info_c_compiler_used"/>
+ <c>c_compiler_used</c></tag>
+ <item>
+ <p>Returns a two-tuple describing the C compiler used when
+ compiling the runtime system. The first element is an
+ atom describing the name of the compiler, or <c>undefined</c>
+ if unknown. The second element is a term describing the
+ version of the compiler, or <c>undefined</c> if unknown.</p>
</item>
- <tag><c>trace_control_word</c></tag>
+ <tag><marker id="system_info_check_io"/>
+ <c>check_io</c></tag>
+ <item>
+ <p>Returns a list containing miscellaneous information
+ about the emulators internal I/O checking. Notice that
+ the content of the returned list can vary between
+ platforms and over time. It is only guaranteed
+ that a list is returned.</p>
+ </item>
+ <tag><marker id="system_info_compat_rel"/>
+ <c>compat_rel</c></tag>
+ <item>
+ <p>Returns the compatibility mode of the local node as
+ an integer. The integer returned represents the
+ Erlang/OTP release that the current emulator has been
+ set to be backward compatible with. The compatibility
+ mode can be configured at startup by using command-line flag
+ <seealso marker="erts:erl#compat_rel"><c>+R</c></seealso> in
+ <c>erl(1)</c>.</p>
+ </item>
+ <tag><marker id="system_info_debug_compiled"/>
+ <c>debug_compiled</c></tag>
+ <item>
+ <p>Returns <c>true</c> if the emulator has been
+ debug-compiled, otherwise <c>false</c>.</p>
+ </item>
+ <tag><marker id="system_info_driver_version"/>
+ <c>driver_version</c></tag>
+ <item>
+ <p>Returns a string containing the Erlang driver version
+ used by the runtime system. It has the form
+ <seealso marker="erts:erl_driver#version_management">
+ "&lt;major ver&gt;.&lt;minor ver&gt;"</seealso>.</p>
+ </item>
+ <tag><marker id="system_info_dynamic_trace"/>
+ <c>dynamic_trace</c></tag>
+ <item>
+ <p>Returns an atom describing the dynamic trace framework
+ compiled into the virtual machine. It can be
+ <c>dtrace</c>, <c>systemtap</c>, or <c>none</c>. For a
+ commercial or standard build, it is always <c>none</c>.
+ The other return values indicate a custom configuration
+ (for example, <c>./configure --with-dynamic-trace=dtrace</c>).
+ For more information about dynamic tracing, see
+ <seealso marker="runtime_tools:dyntrace">
+ <c>dyntrace(3)</c></seealso> manual page and the
+ <c>README.dtrace</c>/<c>README.systemtap</c> files in the
+ Erlang source code top directory.</p>
+ </item>
+ <tag><marker id="system_info_dynamic_trace_probes"/>
+ <c>dynamic_trace_probes</c></tag>
+ <item>
+ <p>Returns a <c>boolean()</c> indicating if dynamic trace
+ probes (<c>dtrace</c> or <c>systemtap</c>) are built into
+ the emulator. This can only be <c>true</c> if the virtual
+ machine was built for dynamic tracing (that is,
+ <c>system_info(dynamic_trace)</c> returns
+ <c>dtrace</c> or <c>systemtap</c>).</p>
+ </item>
+ <tag><marker id="system_info_info"/>
+ <c>info</c></tag>
+ <item>
+ <p>Returns a binary containing a string of miscellaneous
+ system information formatted as in Erlang crash dumps.
+ For more information, see section
+ <seealso marker="erts:crash_dump">
+ How to interpret the Erlang crash dumps</seealso>
+ in the User's Guide.</p>
+ </item>
+ <tag><marker id="system_info_kernel_poll"/>
+ <c>kernel_poll</c></tag>
+ <item>
+ <p>Returns <c>true</c> if the emulator uses some kind of
+ kernel-poll implementation, otherwise <c>false</c>.</p>
+ </item>
+ <tag><marker id="system_info_loaded"/>
+ <c>loaded</c></tag>
+ <item>
+ <p>Returns a binary containing a string of loaded module
+ information formatted as in Erlang crash dumps. For more
+ information, see section
+ <seealso marker="erts:crash_dump">How to interpret the Erlang
+ crash dumps</seealso> in the User's Guide.</p>
+ </item>
+ <tag><marker id="system_info_machine"/>
+ <c>machine</c></tag>
+ <item>
+ <p>Returns a string containing the Erlang machine name.</p>
+ </item>
+ <tag><marker id="system_info_modified_timing_level"/>
+ <c>modified_timing_level</c></tag>
+ <item>
+ <p>Returns the modified timing-level (an integer) if
+ modified timing is enabled, otherwise <c>undefined</c>.
+ For more information about modified timing, see
+ command-line flag
+ <seealso marker="erts:erl#+T"><c>+T</c></seealso>
+ in <c>erl(1)</c></p>
+ </item>
+ <tag><marker id="system_info_nif_version"/>
+ <c>nif_version</c></tag>
+ <item>
+ <p>Returns a string containing the version of the Erlang NIF
+ interface used by the runtime system. It is on the form
+ "&lt;major ver&gt;.&lt;minor ver&gt;".</p>
+ </item>
+ <tag><marker id="system_info_otp_release"/>
+ <c>otp_release</c></tag>
+ <item>
+ <marker id="system_info_otp_release"></marker>
+ <p>Returns a string containing the OTP release number of the
+ OTP release that the currently executing ERTS application
+ is part of.</p>
+ <p>As from Erlang/OTP 17, the OTP release number corresponds to
+ the major OTP version number. No
+ <c>erlang:system_info()</c> argument gives the exact OTP
+ version. This is because the exact OTP version in the general case
+ is difficult to determine. For more information, see the
+ description of versions in
+ <seealso marker="doc/system_principles:versions">
+ System principles</seealso> in System Documentation.</p>
+ </item>
+ <tag><marker id="system_info_port_parallelism"/>
+ <c>port_parallelism</c></tag>
+ <item>
+ <p>Returns the default port parallelism scheduling hint used.
+ For more information, see command-line argument
+ <seealso marker="erl#+spp"><c>+spp</c></seealso>
+ in <c>erl(1)</c>.</p>
+ </item>
+ <tag><marker id="system_info_system_version"/>
+ <c>system_version</c></tag>
+ <item>
+ <p>Returns a string containing version number and
+ some important properties, such as the number of schedulers.</p>
+ </item>
+ <tag><marker id="system_info_system_architecture"/>
+ <c>system_architecture</c></tag>
+ <item>
+ <p>Returns a string containing the processor and OS
+ architecture the emulator is built for.</p>
+ </item>
+ <tag><marker id="system_info_trace_control_word"/>
+ <c>trace_control_word</c></tag>
<item>
<p>Returns the value of the node trace control word. For
more information, see function <c>get_tcw</c> in section
<seealso marker="erts:match_spec#get_tcw">
Match Specifications in Erlang</seealso> in the User's Guide.</p>
</item>
- <tag><c>update_cpu_info</c></tag>
+ <tag><marker id="system_info_version"/>
+ <c>version</c></tag>
<item>
- <marker id="update_cpu_info"></marker>
- <p>The runtime system rereads the CPU information available
- and updates its internally stored information about the
- <seealso marker="#system_info_cpu_topology_detected">detected
- CPU topology</seealso> and the number of logical processors
- <seealso marker="#logical_processors">configured</seealso>,
- <seealso marker="#logical_processors_online">online</seealso>,
- and <seealso marker="#logical_processors_available">
- available</seealso>.</p>
- <p>If the CPU information has changed since the last time
- it was read, the atom <c>changed</c> is returned, otherwise
- the atom <c>unchanged</c>. If the CPU information has changed,
- you probably want to
- <seealso marker="#system_flag_schedulers_online">adjust the
- number of schedulers online</seealso>. You typically want
- to have as many schedulers online as
- <seealso marker="#logical_processors_available">logical
- processors available</seealso>.</p>
- </item>
- <tag><c>version</c></tag>
- <item>
- <marker id="system_info_version"></marker>
<p>Returns a string containing the version number of the
emulator.</p>
</item>
- <tag><c>wordsize</c></tag>
+ <tag><marker id="system_info_wordsize"/>
+ <c>wordsize</c></tag>
<item>
<p>Same as <c>{wordsize, internal}</c>.</p>
</item>
@@ -8732,13 +9009,6 @@ ok
64-bit architecture, 8 is returned.</p>
</item>
</taglist>
- <note>
- <p>Argument <c>scheduler</c> has changed name to
- <c>scheduler_id</c> to avoid mix up with argument
- <c>schedulers</c>. Argument <c>scheduler</c> was
- introduced in ERTS 5.5 and renamed in
- ERTS 5.5.1.</p>
- </note>
</desc>
</func>
diff --git a/erts/doc/src/notes.xml b/erts/doc/src/notes.xml
index 3109da6738..7ef42c2318 100644
--- a/erts/doc/src/notes.xml
+++ b/erts/doc/src/notes.xml
@@ -10964,7 +10964,7 @@
<c>update_cpu_info</c> will make the runtime system
reread and update the internally stored CPU information.
For more information see the documentation of <seealso
- marker="erlang#update_cpu_info">erlang:system_info(update_cpu_info)</seealso>.</p>
+ marker="erlang#system_info_update_cpu_info">erlang:system_info(update_cpu_info)</seealso>.</p>
<p>
The CPU topology is now automatically detected on Windows
systems with less than 33 logical processors. The runtime
diff --git a/erts/emulator/beam/bif.c b/erts/emulator/beam/bif.c
index d68ccc3028..bfd572335f 100644
--- a/erts/emulator/beam/bif.c
+++ b/erts/emulator/beam/bif.c
@@ -1744,7 +1744,6 @@ BIF_RETTYPE process_flag_2(BIF_ALIST_2)
else if (BIF_ARG_1 == am_scheduler) {
ErtsRunQueue *old, *new, *curr;
Sint sched;
- erts_aint32_t state;
if (!is_small(BIF_ARG_2))
goto error;
@@ -1753,23 +1752,23 @@ BIF_RETTYPE process_flag_2(BIF_ALIST_2)
goto error;
if (sched == 0) {
+ old = erts_bind_runq_proc(BIF_P, 0);
new = NULL;
- state = erts_atomic32_read_band_mb(&BIF_P->state,
- ~ERTS_PSFLG_BOUND);
}
else {
+ int bound = !0;
new = erts_schedid2runq(sched);
- erts_atomic_set_nob(&BIF_P->run_queue, (erts_aint_t) new);
- state = erts_atomic32_read_bor_mb(&BIF_P->state,
- ERTS_PSFLG_BOUND);
+ old = erts_set_runq_proc(BIF_P, new, &bound);
+ if (!bound)
+ old = NULL;
}
+ old_value = old ? make_small(old->ix+1) : make_small(0);
+
curr = erts_proc_sched_data(BIF_P)->run_queue;
- old = (ERTS_PSFLG_BOUND & state) ? curr : NULL;
ASSERT(!old || old == curr);
- old_value = old ? make_small(old->ix+1) : make_small(0);
if (new && new != curr)
ERTS_BIF_YIELD_RETURN_X(BIF_P, old_value, am_scheduler);
else
diff --git a/erts/emulator/beam/erl_init.c b/erts/emulator/beam/erl_init.c
index 4846ccd2d3..e8048cfdfc 100644
--- a/erts/emulator/beam/erl_init.c
+++ b/erts/emulator/beam/erl_init.c
@@ -1746,6 +1746,7 @@ erl_start(int argc, char **argv)
}
else if (has_prefix("ecio", sub_param)) {
/* ignore argument, eager check io no longer used */
+ arg = get_arg(sub_param+4, argv[i+1], &i);
}
else if (has_prefix("pp", sub_param)) {
arg = get_arg(sub_param+2, argv[i+1], &i);
diff --git a/erts/emulator/beam/erl_message.c b/erts/emulator/beam/erl_message.c
index abf194cf94..6f7c71ef98 100644
--- a/erts/emulator/beam/erl_message.c
+++ b/erts/emulator/beam/erl_message.c
@@ -616,7 +616,7 @@ erts_try_alloc_message_on_heap(Process *pp,
}
else {
in_message_fragment:
- if (!((*psp) & ERTS_PSFLG_ON_HEAP_MSGQ)) {
+ if ((*psp) & ERTS_PSFLG_OFF_HEAP_MSGQ) {
mp = erts_alloc_message(sz, hpp);
*ohpp = sz == 0 ? NULL : &mp->hfrag.off_heap;
}
@@ -1079,8 +1079,6 @@ erts_change_message_queue_management(Process *c_p, Eterm new_state)
case am_on_heap:
c_p->flags |= F_ON_HEAP_MSGQ;
c_p->flags &= ~F_OFF_HEAP_MSGQ;
- erts_atomic32_read_bor_nob(&c_p->state,
- ERTS_PSFLG_ON_HEAP_MSGQ);
/*
* We are not allowed to clear ERTS_PSFLG_OFF_HEAP_MSGQ
* if a off heap change is ongoing. It will be adjusted
@@ -1106,8 +1104,6 @@ erts_change_message_queue_management(Process *c_p, Eterm new_state)
break;
case am_off_heap:
c_p->flags &= ~F_ON_HEAP_MSGQ;
- erts_atomic32_read_band_nob(&c_p->state,
- ~ERTS_PSFLG_ON_HEAP_MSGQ);
goto change_to_off_heap;
default:
res = THE_NON_VALUE; /* badarg */
diff --git a/erts/emulator/beam/erl_port.h b/erts/emulator/beam/erl_port.h
index 6b90187d60..0d148ee048 100644
--- a/erts/emulator/beam/erl_port.h
+++ b/erts/emulator/beam/erl_port.h
@@ -196,26 +196,52 @@ struct erl_drv_port_data_lock {
Port *prt;
};
+ERTS_GLB_INLINE void erts_init_runq_port(Port *prt, ErtsRunQueue *runq);
+ERTS_GLB_INLINE void erts_set_runq_port(Port *prt, ErtsRunQueue *runq);
+ERTS_GLB_INLINE ErtsRunQueue *erts_get_runq_port(Port *prt);
ERTS_GLB_INLINE ErtsRunQueue *erts_port_runq(Port *prt);
#if ERTS_GLB_INLINE_INCL_FUNC_DEF
+ERTS_GLB_INLINE void
+erts_init_runq_port(Port *prt, ErtsRunQueue *runq)
+{
+ if (!runq)
+ ERTS_INTERNAL_ERROR("Missing run-queue");
+ erts_atomic_init_nob(&prt->run_queue, (erts_aint_t) runq);
+}
+
+ERTS_GLB_INLINE void
+erts_set_runq_port(Port *prt, ErtsRunQueue *runq)
+{
+ if (!runq)
+ ERTS_INTERNAL_ERROR("Missing run-queue");
+ erts_atomic_set_nob(&prt->run_queue, (erts_aint_t) runq);
+}
+
+ERTS_GLB_INLINE ErtsRunQueue *
+erts_get_runq_port(Port *prt)
+{
+ ErtsRunQueue *runq;
+ runq = (ErtsRunQueue *) erts_atomic_read_nob(&prt->run_queue);
+ if (!runq)
+ ERTS_INTERNAL_ERROR("Missing run-queue");
+ return runq;
+}
+
+
ERTS_GLB_INLINE ErtsRunQueue *
erts_port_runq(Port *prt)
{
ErtsRunQueue *rq1, *rq2;
- rq1 = (ErtsRunQueue *) erts_atomic_read_nob(&prt->run_queue);
- if (!rq1)
- return NULL;
+ rq1 = erts_get_runq_port(prt);
while (1) {
erts_runq_lock(rq1);
- rq2 = (ErtsRunQueue *) erts_atomic_read_nob(&prt->run_queue);
+ rq2 = erts_get_runq_port(prt);
if (rq1 == rq2)
return rq1;
erts_runq_unlock(rq1);
rq1 = rq2;
- if (!rq1)
- return NULL;
}
}
diff --git a/erts/emulator/beam/erl_port_task.c b/erts/emulator/beam/erl_port_task.c
index a588477320..4a3671df0c 100644
--- a/erts/emulator/beam/erl_port_task.c
+++ b/erts/emulator/beam/erl_port_task.c
@@ -84,11 +84,10 @@ static void chk_task_queues(Port *pp, ErtsPortTask *execq, int processing_busy_q
#define LTTNG_DRIVER(TRACEPOINT, PP) do {} while(0)
#endif
-#define ERTS_LC_VERIFY_RQ(RQ, PP) \
- do { \
+#define ERTS_LC_VERIFY_RQ(RQ, PP) \
+ do { \
ERTS_LC_ASSERT(erts_lc_runq_is_locked(runq)); \
- ERTS_LC_ASSERT((RQ) == ((ErtsRunQueue *) \
- erts_atomic_read_nob(&(PP)->run_queue))); \
+ ERTS_LC_ASSERT((RQ) == erts_get_runq_port((PP))); \
} while (0)
#define ERTS_PT_STATE_SCHEDULED 0
@@ -1520,19 +1519,15 @@ erts_port_task_schedule(Eterm id,
/* Enqueue port on run-queue */
runq = erts_port_runq(pp);
- if (!runq)
- ERTS_INTERNAL_ERROR("Missing run-queue");
xrunq = erts_check_emigration_need(runq, ERTS_PORT_PRIO_LEVEL);
ERTS_LC_ASSERT(runq != xrunq);
ERTS_LC_VERIFY_RQ(runq, pp);
if (xrunq) {
/* Emigrate port ... */
- erts_atomic_set_nob(&pp->run_queue, (erts_aint_t) xrunq);
+ erts_set_runq_port(pp, xrunq);
erts_runq_unlock(runq);
runq = erts_port_runq(pp);
- if (!runq)
- ERTS_INTERNAL_ERROR("Missing run-queue");
}
enqueue_port(runq, pp);
@@ -1593,8 +1588,6 @@ erts_port_task_free_port(Port *pp)
ASSERT(!(erts_atomic32_read_nob(&pp->state) & ERTS_PORT_SFLGS_DEAD));
runq = erts_port_runq(pp);
- if (!runq)
- ERTS_INTERNAL_ERROR("Missing run-queue");
erts_port_task_sched_lock(&pp->sched);
flags = erts_atomic32_read_bor_relb(&pp->sched.flags,
ERTS_PTS_FLG_EXIT);
@@ -1805,7 +1798,7 @@ erts_port_task_execute(ErtsRunQueue *runq, Port **curr_port_pp)
erts_unblock_fpe(fpe_was_unmasked);
ERTS_MSACC_POP_STATE_M();
- ASSERT(runq == (ErtsRunQueue *) erts_atomic_read_nob(&pp->run_queue));
+ ASSERT(runq == erts_get_runq_port(pp));
active = finalize_exec(pp, &execq, processing_busy_q);
@@ -1831,11 +1824,10 @@ erts_port_task_execute(ErtsRunQueue *runq, Port **curr_port_pp)
}
else {
/* Emigrate port... */
- erts_atomic_set_nob(&pp->run_queue, (erts_aint_t) xrunq);
+ erts_set_runq_port(pp, xrunq);
erts_runq_unlock(runq);
xrunq = erts_port_runq(pp);
- ASSERT(xrunq);
enqueue_port(xrunq, pp);
erts_runq_unlock(xrunq);
erts_notify_inc_runq(xrunq);
@@ -2069,7 +2061,7 @@ void
erts_enqueue_port(ErtsRunQueue *rq, Port *pp)
{
ERTS_LC_ASSERT(erts_lc_runq_is_locked(rq));
- ASSERT(rq == (ErtsRunQueue *) erts_atomic_read_nob(&pp->run_queue));
+ ASSERT(rq == erts_get_runq_port(pp));
ASSERT(erts_atomic32_read_nob(&pp->sched.flags) & ERTS_PTS_FLG_IN_RUNQ);
enqueue_port(rq, pp);
}
@@ -2080,8 +2072,7 @@ erts_dequeue_port(ErtsRunQueue *rq)
Port *pp;
ERTS_LC_ASSERT(erts_lc_runq_is_locked(rq));
pp = pop_port(rq);
- ASSERT(!pp
- || rq == (ErtsRunQueue *) erts_atomic_read_nob(&pp->run_queue));
+ ASSERT(!pp || rq == erts_get_runq_port(pp));
ASSERT(!pp || (erts_atomic32_read_nob(&pp->sched.flags)
& ERTS_PTS_FLG_IN_RUNQ));
return pp;
diff --git a/erts/emulator/beam/erl_process.c b/erts/emulator/beam/erl_process.c
index 3baca6ce79..23fe353495 100644
--- a/erts/emulator/beam/erl_process.c
+++ b/erts/emulator/beam/erl_process.c
@@ -137,36 +137,6 @@ runq_got_work_to_execute(ErtsRunQueue *rq)
return runq_got_work_to_execute_flags(ERTS_RUNQ_FLGS_GET_NOB(rq));
}
-#undef RUNQ_READ_RQ
-#undef RUNQ_SET_RQ
-#define RUNQ_READ_RQ(X) ((ErtsRunQueue *) erts_atomic_read_nob((X)))
-#define RUNQ_SET_RQ(X, RQ) erts_atomic_set_nob((X), (erts_aint_t) (RQ))
-
-#ifdef DEBUG
-# if defined(ARCH_64)
-# define ERTS_DBG_SET_INVALID_RUNQP(RQP, N) \
- (RUNQ_SET_RQ((RQP), (0xdeadbeefdead0003LL | ((N) << 4)))
-# define ERTS_DBG_VERIFY_VALID_RUNQP(RQP) \
-do { \
- ASSERT((RQP) != NULL); \
- ASSERT(((((Uint) (RQP)) & ((Uint) 0x3))) == ((Uint) 0)); \
- ASSERT((((Uint) (RQP)) & ~((Uint) 0xffff)) != ((Uint) 0xdeadbeefdead0000LL));\
-} while (0)
-# else
-# define ERTS_DBG_SET_INVALID_RUNQP(RQP, N) \
- (RUNQ_SET_RQ((RQP), (0xdead0003 | ((N) << 4))))
-# define ERTS_DBG_VERIFY_VALID_RUNQP(RQP) \
-do { \
- ASSERT((RQP) != NULL); \
- ASSERT(((((UWord) (RQP)) & ((UWord) 1))) == ((UWord) 0)); \
- ASSERT((((UWord) (RQP)) & ~((UWord) 0xffff)) != ((UWord) 0xdead0000)); \
-} while (0)
-# endif
-#else
-# define ERTS_DBG_SET_INVALID_RUNQP(RQP, N)
-# define ERTS_DBG_VERIFY_VALID_RUNQP(RQP)
-#endif
-
const Process erts_invalid_process = {{ERTS_INVALID_PID}};
extern BeamInstr beam_apply[];
@@ -3940,21 +3910,16 @@ immigrate(ErtsRunQueue *c_rq, ErtsMigrationPath *mp)
Port *prt;
prt = erts_dequeue_port(rq);
if (prt)
- RUNQ_SET_RQ(&prt->run_queue, c_rq);
+ erts_set_runq_port(prt, c_rq);
erts_runq_unlock(rq);
if (prt) {
- /* port might terminate while we have no lock... */
rq = erts_port_runq(prt);
- if (rq) {
- if (rq != c_rq)
- erts_exit(ERTS_ABORT_EXIT,
- "%s:%d:%s(): Internal error",
- __FILE__, __LINE__, __func__);
- erts_enqueue_port(c_rq, prt);
- if (!iflag)
- return; /* done */
- erts_runq_unlock(c_rq);
- }
+ if (rq != c_rq)
+ ERTS_INTERNAL_ERROR("Unexpected run-queue");
+ erts_enqueue_port(c_rq, prt);
+ if (!iflag)
+ return; /* done */
+ erts_runq_unlock(c_rq);
}
}
else {
@@ -3968,12 +3933,11 @@ immigrate(ErtsRunQueue *c_rq, ErtsMigrationPath *mp)
while (proc) {
erts_aint32_t state;
state = erts_atomic32_read_acqb(&proc->state);
- if (!(ERTS_PSFLG_BOUND & state)
- && (prio == (int) ERTS_PSFLGS_GET_PRQ_PRIO(state))) {
+ if (prio == (int) ERTS_PSFLGS_GET_PRQ_PRIO(state)
+ && erts_try_change_runq_proc(proc, c_rq)) {
ErtsRunQueueInfo *rqi = &rq->procs.prio_info[prio];
unqueue_process(rq, rpq, rqi, prio, prev_proc, proc);
erts_runq_unlock(rq);
- RUNQ_SET_RQ(&proc->run_queue, c_rq);
rq_locked = 0;
erts_runq_lock(c_rq);
@@ -4154,21 +4118,13 @@ evacuate_run_queue(ErtsRunQueue *rq,
while (prt) {
ErtsRunQueue *prt_rq;
prt = erts_dequeue_port(rq);
- RUNQ_SET_RQ(&prt->run_queue, to_rq);
+ erts_set_runq_port(prt, to_rq);
erts_runq_unlock(rq);
- /*
- * The port might terminate while
- * we have no lock on it...
- */
prt_rq = erts_port_runq(prt);
- if (prt_rq) {
- if (prt_rq != to_rq)
- erts_exit(ERTS_ABORT_EXIT,
- "%s:%d:%s() internal error\n",
- __FILE__, __LINE__, __func__);
- erts_enqueue_port(to_rq, prt);
- erts_runq_unlock(to_rq);
- }
+ if (prt_rq != to_rq)
+ ERTS_INTERNAL_ERROR("Unexpected run-queue");
+ erts_enqueue_port(to_rq, prt);
+ erts_runq_unlock(to_rq);
erts_runq_lock(rq);
prt = rq->ports.start;
}
@@ -4179,8 +4135,6 @@ evacuate_run_queue(ErtsRunQueue *rq,
for (prio_q = 0; prio_q < ERTS_NO_PROC_PRIO_QUEUES; prio_q++) {
erts_aint32_t state;
Process *proc;
- int notify = 0;
- to_rq = NULL;
if (!mp->prio[prio_q].runq)
return;
@@ -4191,14 +4145,13 @@ evacuate_run_queue(ErtsRunQueue *rq,
while (proc) {
Process *real_proc;
int prio;
- erts_aint32_t max_qbit, qbit, real_state;
+ erts_aint32_t max_qbit, qbit;
prio = ERTS_PSFLGS_GET_PRQ_PRIO(state);
qbit = ((erts_aint32_t) 1) << prio;
if (!(state & ERTS_PSFLG_PROXY)) {
real_proc = proc;
- real_state = state;
}
else {
real_proc = erts_proc_lookup_raw(proc->common.id);
@@ -4206,7 +4159,6 @@ evacuate_run_queue(ErtsRunQueue *rq,
free_proxy_proc(proc);
goto handle_next_proc;
}
- real_state = erts_atomic32_read_acqb(&real_proc->state);
}
max_qbit = (state >> ERTS_PSFLGS_IN_PRQ_MASK_OFFSET);
@@ -4241,7 +4193,13 @@ evacuate_run_queue(ErtsRunQueue *rq,
goto handle_next_proc;
}
- if (ERTS_PSFLG_BOUND & real_state) {
+ prio = (int) ERTS_PSFLGS_GET_PRQ_PRIO(state);
+ to_rq = mp->prio[prio].runq;
+
+ if (!to_rq)
+ goto handle_next_proc;
+
+ if (!erts_try_change_runq_proc(proc, to_rq)) {
/* Bound processes get stuck here... */
proc->next = NULL;
if (sbpp->last)
@@ -4251,16 +4209,13 @@ evacuate_run_queue(ErtsRunQueue *rq,
sbpp->last = proc;
}
else {
- int prio = (int) ERTS_PSFLGS_GET_PRQ_PRIO(state);
erts_runq_unlock(rq);
- to_rq = mp->prio[prio].runq;
- RUNQ_SET_RQ(&proc->run_queue, to_rq);
-
erts_runq_lock(to_rq);
enqueue_process(to_rq, prio, proc);
erts_runq_unlock(to_rq);
- notify = 1;
+
+ smp_notify_inc_runq(to_rq);
erts_runq_lock(rq);
}
@@ -4268,8 +4223,7 @@ evacuate_run_queue(ErtsRunQueue *rq,
handle_next_proc:
proc = dequeue_process(rq, prio_q, &state);
}
- if (notify)
- smp_notify_inc_runq(to_rq);
+
}
}
@@ -4323,14 +4277,13 @@ try_steal_task_from_victim(ErtsRunQueue *rq, int *rq_lockedp, ErtsRunQueue *vrq,
proc = rpq->first;
while (proc) {
- erts_aint32_t state = erts_atomic32_read_acqb(&proc->state);
- if (!(ERTS_PSFLG_BOUND & state)) {
+ if (erts_try_change_runq_proc(proc, rq)) {
+ erts_aint32_t state = erts_atomic32_read_acqb(&proc->state);
/* Steal process */
int prio = (int) ERTS_PSFLGS_GET_PRQ_PRIO(state);
ErtsRunQueueInfo *rqi = &vrq->procs.prio_info[prio];
unqueue_process(vrq, rpq, rqi, prio, prev_proc, proc);
erts_runq_unlock(vrq);
- RUNQ_SET_RQ(&proc->run_queue, rq);
erts_runq_lock(rq);
*rq_lockedp = 1;
@@ -4355,26 +4308,14 @@ no_procs:
if (vrq->ports.start) {
ErtsRunQueue *prt_rq;
Port *prt = erts_dequeue_port(vrq);
- RUNQ_SET_RQ(&prt->run_queue, rq);
+ erts_set_runq_port(prt, rq);
erts_runq_unlock(vrq);
-
- /*
- * The port might terminate while
- * we have no lock on it...
- */
-
prt_rq = erts_port_runq(prt);
- if (!prt_rq)
- return 0;
- else {
- if (prt_rq != rq)
- erts_exit(ERTS_ABORT_EXIT,
- "%s:%d:%s() internal error\n",
- __FILE__, __LINE__, __func__);
- *rq_lockedp = 1;
- erts_enqueue_port(rq, prt);
- return !0;
- }
+ if (prt_rq != rq)
+ ERTS_INTERNAL_ERROR("Unexpected run-queue");
+ *rq_lockedp = 1;
+ erts_enqueue_port(rq, prt);
+ return !0;
}
erts_runq_unlock(vrq);
@@ -6130,7 +6071,8 @@ make_proxy_proc(Process *prev_proxy, Process *proc, erts_aint32_t prio)
{
erts_aint32_t state;
Process *proxy;
- ErtsRunQueue *rq = RUNQ_READ_RQ(&proc->run_queue);
+ int bound;
+ ErtsRunQueue *rq = erts_get_runq_proc(proc, &bound);
state = (ERTS_PSFLG_PROXY
| ERTS_PSFLG_IN_RUNQ
@@ -6143,7 +6085,7 @@ make_proxy_proc(Process *prev_proxy, Process *proc, erts_aint32_t prio)
proxy = prev_proxy;
ASSERT(erts_atomic32_read_nob(&proxy->state) & ERTS_PSFLG_PROXY);
erts_atomic32_set_nob(&proxy->state, state);
- RUNQ_SET_RQ(&proc->run_queue, rq);
+ (void) erts_set_runq_proc(proc, rq, &bound);
}
else {
proxy = erts_alloc(ERTS_ALC_T_PROC, sizeof(Process));
@@ -6156,8 +6098,7 @@ make_proxy_proc(Process *prev_proxy, Process *proc, erts_aint32_t prio)
}
#endif
erts_atomic32_init_nob(&proxy->state, state);
- erts_atomic_init_nob(&proxy->run_queue,
- erts_atomic_read_nob(&proc->run_queue));
+ erts_init_runq_proc(proc, rq, bound);
}
proxy->common.id = proc->common.id;
@@ -6348,18 +6289,21 @@ select_enqueue_run_queue(int enqueue, int enq_prio, Process *p, erts_aint32_t st
default: {
ErtsRunQueue* runq;
+ int bound;
ASSERT(enqueue == ERTS_ENQUEUE_NORMAL_QUEUE
|| enqueue == -ERTS_ENQUEUE_NORMAL_QUEUE);
- runq = erts_get_runq_proc(p);
+ runq = erts_get_runq_proc(p, &bound);
- if (!(ERTS_PSFLG_BOUND & state)) {
+ if (!bound) {
ErtsRunQueue *new_runq = erts_check_emigration_need(runq, enq_prio);
- if (new_runq) {
- RUNQ_SET_RQ(&p->run_queue, new_runq);
- runq = new_runq;
- }
+ if (new_runq) {
+ if (erts_try_change_runq_proc(p, new_runq))
+ runq = new_runq;
+ else
+ runq = erts_get_runq_proc(p, NULL);
+ }
}
ASSERT(runq);
@@ -11476,6 +11420,7 @@ typedef struct {
Process *proc;
erts_aint32_t state;
ErtsRunQueue *run_queue;
+ int bound;
} ErtsEarlyProcInit;
static void early_init_process_struct(void *varg, Eterm data)
@@ -11486,10 +11431,9 @@ static void early_init_process_struct(void *varg, Eterm data)
proc->common.id = make_internal_pid(data);
erts_atomic32_init_nob(&proc->dirty_state, 0);
proc->dirty_sys_tasks = NULL;
+ erts_init_runq_proc(proc, arg->run_queue, arg->bound);
erts_atomic32_init_relb(&proc->state, arg->state);
- RUNQ_SET_RQ(&proc->run_queue, arg->run_queue);
-
erts_proc_lock_init(proc); /* All locks locked */
}
@@ -11498,7 +11442,7 @@ static void early_init_process_struct(void *varg, Eterm data)
** Allocate process and find out where to place next process.
*/
static Process*
-alloc_process(ErtsRunQueue *rq, erts_aint32_t state)
+alloc_process(ErtsRunQueue *rq, int bound, erts_aint32_t state)
{
ErtsEarlyProcInit init_arg;
Process *p;
@@ -11507,9 +11451,12 @@ alloc_process(ErtsRunQueue *rq, erts_aint32_t state)
if (!p)
return NULL;
+ ASSERT(rq);
+
init_arg.proc = (Process *) p;
- init_arg.run_queue = rq;
init_arg.state = state;
+ init_arg.run_queue = rq;
+ init_arg.bound = bound;
ERTS_CT_ASSERT(offsetof(Process,common) == 0);
@@ -11544,6 +11491,7 @@ erl_create_process(Process* parent, /* Parent of process (default group leader).
Eterm args, /* Arguments for function (must be well-formed list). */
ErlSpawnOpts* so) /* Options for spawn. */
{
+ int bound = 0;
Uint flags = 0;
ErtsRunQueue *rq = NULL;
Process *p;
@@ -11580,7 +11528,7 @@ erl_create_process(Process* parent, /* Parent of process (default group leader).
ASSERT(0 <= ix && ix < erts_no_run_queues);
rq = ERTS_RUNQ_IX(ix);
/* Unsupported feature... */
- state |= ERTS_PSFLG_BOUND;
+ bound = !0;
}
prio = (erts_aint32_t) so->priority;
}
@@ -11593,17 +11541,16 @@ erl_create_process(Process* parent, /* Parent of process (default group leader).
flags |= F_OFF_HEAP_MSGQ;
}
else if (so->flags & SPO_ON_HEAP_MSGQ) {
- state |= ERTS_PSFLG_ON_HEAP_MSGQ;
flags |= F_ON_HEAP_MSGQ;
}
ASSERT((flags & F_ON_HEAP_MSGQ) || (flags & F_OFF_HEAP_MSGQ));
if (!rq)
- rq = erts_get_runq_proc(parent);
+ rq = erts_get_runq_proc(parent, NULL);
- p = alloc_process(rq, state); /* All proc locks are locked by this thread
- on success */
+ p = alloc_process(rq, bound, state); /* All proc locks are locked by this thread
+ on success */
if (!p) {
erts_send_error_to_logger_str(parent->group_leader,
"Too many processes\n");
@@ -11611,11 +11558,6 @@ erl_create_process(Process* parent, /* Parent of process (default group leader).
goto error;
}
- ASSERT((erts_atomic32_read_nob(&p->state)
- & ERTS_PSFLG_ON_HEAP_MSGQ)
- || (erts_atomic32_read_nob(&p->state)
- & ERTS_PSFLG_OFF_HEAP_MSGQ));
-
#ifdef SHCOPY_SPAWN
arg_size = copy_shared_calculate(args, &info);
#else
@@ -11990,7 +11932,7 @@ void erts_init_empty_process(Process *p)
p->pending_exit.bp = NULL;
erts_proc_lock_init(p);
erts_proc_unlock(p, ERTS_PROC_LOCKS_ALL);
- RUNQ_SET_RQ(&p->run_queue, ERTS_RUNQ_IX(0));
+ erts_init_runq_proc(p, ERTS_RUNQ_IX(0), 0);
#if !defined(NO_FPE_SIGNALS) || defined(HIPE)
p->fp_exception = 0;
@@ -12312,7 +12254,7 @@ save_pending_exiter(Process *p, ErtsProcList *plp)
ERTS_LC_ASSERT(ERTS_PROC_LOCK_STATUS & erts_proc_lc_my_proc_locks(p));
- rq = RUNQ_READ_RQ(&p->run_queue);
+ rq = erts_get_runq_proc(p, NULL);
ASSERT(rq && !ERTS_RUNQ_IX_IS_DIRTY(rq->ix));
if (!plp)
diff --git a/erts/emulator/beam/erl_process.h b/erts/emulator/beam/erl_process.h
index 4f200b13ec..8581c6a639 100644
--- a/erts/emulator/beam/erl_process.h
+++ b/erts/emulator/beam/erl_process.h
@@ -244,6 +244,9 @@ extern int erts_dio_sched_thread_suggested_stack_size;
(erts_aint32_t) (MSK), \
(erts_aint32_t) (FLGS)))
+#define ERTS_RUNQ_POINTER_MASK (~((erts_aint_t) 3))
+#define ERTS_RUNQ_BOUND_FLAG ((erts_aint_t) 1)
+
typedef enum {
ERTS_SCHDLR_SSPND_DONE_MSCHED_BLOCKED,
ERTS_SCHDLR_SSPND_DONE_NMSCHED_BLOCKED,
@@ -1168,14 +1171,14 @@ void erts_check_for_holes(Process* p);
#define ERTS_PSFLG_RUNNING ERTS_PSFLG_BIT(9)
#define ERTS_PSFLG_SUSPENDED ERTS_PSFLG_BIT(10)
#define ERTS_PSFLG_GC ERTS_PSFLG_BIT(11)
-#define ERTS_PSFLG_BOUND ERTS_PSFLG_BIT(12)
+/* #define ERTS_PSFLG_ ERTS_PSFLG_BIT(12) */
#define ERTS_PSFLG_TRAP_EXIT ERTS_PSFLG_BIT(13)
#define ERTS_PSFLG_ACTIVE_SYS ERTS_PSFLG_BIT(14)
#define ERTS_PSFLG_RUNNING_SYS ERTS_PSFLG_BIT(15)
#define ERTS_PSFLG_PROXY ERTS_PSFLG_BIT(16)
#define ERTS_PSFLG_DELAYED_SYS ERTS_PSFLG_BIT(17)
#define ERTS_PSFLG_OFF_HEAP_MSGQ ERTS_PSFLG_BIT(18)
-#define ERTS_PSFLG_ON_HEAP_MSGQ ERTS_PSFLG_BIT(19)
+/* #define ERTS_PSFLG_ ERTS_PSFLG_BIT(19) */
#define ERTS_PSFLG_DIRTY_CPU_PROC ERTS_PSFLG_BIT(20)
#define ERTS_PSFLG_DIRTY_IO_PROC ERTS_PSFLG_BIT(21)
#define ERTS_PSFLG_DIRTY_ACTIVE_SYS ERTS_PSFLG_BIT(22)
@@ -2169,7 +2172,12 @@ ERTS_GLB_INLINE int erts_is_scheduler_bound(ErtsSchedulerData *esdp);
ERTS_GLB_INLINE Process *erts_get_current_process(void);
ERTS_GLB_INLINE Eterm erts_get_current_pid(void);
ERTS_GLB_INLINE Uint erts_get_scheduler_id(void);
-ERTS_GLB_INLINE ErtsRunQueue *erts_get_runq_proc(Process *p);
+ERTS_GLB_INLINE void erts_init_runq_proc(Process *p, ErtsRunQueue *rq, int bnd);
+ERTS_GLB_INLINE ErtsRunQueue *erts_set_runq_proc(Process *p, ErtsRunQueue *rq, int *boundp);
+ERTS_GLB_INLINE int erts_try_change_runq_proc(Process *p, ErtsRunQueue *rq);
+ERTS_GLB_INLINE ErtsRunQueue *erts_bind_runq_proc(Process *p, int bind);
+ERTS_GLB_INLINE int erts_proc_runq_is_bound(Process *p);
+ERTS_GLB_INLINE ErtsRunQueue *erts_get_runq_proc(Process *p, int *boundp);
ERTS_GLB_INLINE ErtsRunQueue *erts_get_runq_current(ErtsSchedulerData *esdp);
ERTS_GLB_INLINE void erts_runq_lock(ErtsRunQueue *rq);
ERTS_GLB_INLINE int erts_runq_trylock(ErtsRunQueue *rq);
@@ -2249,11 +2257,144 @@ Uint erts_get_scheduler_id(void)
return esdp ? esdp->no : (Uint) 0;
}
+/**
+ * Init run-queue of process.
+ *
+ * @param p[in,out] Process
+ * @param rq[in] Run-queue that process will be assigned to
+ * @param bnd[in,out] If non-zero binds process to run-queue.
+ */
+
+ERTS_GLB_INLINE void
+erts_init_runq_proc(Process *p, ErtsRunQueue *rq, int bnd)
+{
+ erts_aint_t rqint = (erts_aint_t) rq;
+ if (bnd)
+ rqint |= ERTS_RUNQ_BOUND_FLAG;
+ erts_atomic_init_nob(&p->run_queue, rqint);
+}
+
+/**
+ * Forcibly set run-queue of process.
+ *
+ * @param p[in,out] Process
+ * @param rq[in] Run-queue that process will be assigned to
+ * @param bndp[in,out] Pointer to integer. On input non-zero
+ * value causes the process to be bound to
+ * the run-queue. On output, indicating
+ * wether process previously was bound or
+ * not.
+ * @return Previous run-queue.
+ */
+
+ERTS_GLB_INLINE ErtsRunQueue *
+erts_set_runq_proc(Process *p, ErtsRunQueue *rq, int *bndp)
+{
+ erts_aint_t rqint = (erts_aint_t) rq;
+ ASSERT(bndp);
+ ASSERT(rq);
+ if (*bndp)
+ rqint |= ERTS_RUNQ_BOUND_FLAG;
+ rqint = erts_atomic_xchg_nob(&p->run_queue, rqint);
+ *bndp = (int) (rqint & ERTS_RUNQ_BOUND_FLAG);
+ return (ErtsRunQueue *) (rqint & ERTS_RUNQ_POINTER_MASK);
+}
+
+/**
+ * Try to change run-queue assignment of a process.
+ *
+ * @param p[in,out] Process
+ * @param rq[int] Run-queue that process will be assigned to
+ * @return Non-zero if the run-queue assignment was
+ * successfully changed.
+ */
+
+ERTS_GLB_INLINE int
+erts_try_change_runq_proc(Process *p, ErtsRunQueue *rq)
+{
+ erts_aint_t old_rqint, new_rqint;
+
+ new_rqint = (erts_aint_t) rq;
+ old_rqint = (erts_aint_t) erts_atomic_read_nob(&p->run_queue);
+ while (1) {
+ erts_aint_t act_rqint;
+
+ if (old_rqint & ERTS_RUNQ_BOUND_FLAG)
+ return 0;
+
+ act_rqint = erts_atomic_cmpxchg_nob(&p->run_queue,
+ new_rqint,
+ old_rqint);
+ if (act_rqint == old_rqint)
+ return !0;
+ }
+}
+
+/**
+ *
+ * Bind or unbind process to/from currently used run-queue.
+ *
+ * @param p Process
+ * @param bind Bind if non-zero; otherwise unbind
+ * @return Pointer to previously bound run-queue,
+ * or NULL if previously unbound
+ */
+
+ERTS_GLB_INLINE ErtsRunQueue *
+erts_bind_runq_proc(Process *p, int bind)
+{
+ erts_aint_t rqint;
+ if (bind)
+ rqint = erts_atomic_read_bor_nob(&p->run_queue,
+ ERTS_RUNQ_BOUND_FLAG);
+ else
+ rqint = erts_atomic_read_band_nob(&p->run_queue,
+ ~ERTS_RUNQ_BOUND_FLAG);
+ if (rqint & ERTS_RUNQ_BOUND_FLAG)
+ return (ErtsRunQueue *) (rqint & ERTS_RUNQ_POINTER_MASK);
+ else
+ return NULL;
+}
+
+/**
+ * Determine wether a process is bound to a run-queue or not.
+ *
+ * @return Returns a non-zero value if bound,
+ * and zero of not bound.
+ */
+
+ERTS_GLB_INLINE int
+erts_proc_runq_is_bound(Process *p)
+{
+ erts_aint_t rqint = erts_atomic_read_nob(&p->run_queue);
+ return (int) (rqint & ERTS_RUNQ_BOUND_FLAG);
+}
+
+/**
+ * Set run-queue of process.
+ *
+ * @param p[in,out] Process
+ * @param bndp[out] Pointer to integer. If non-NULL pointer,
+ * the integer will be set to a non-zero
+ * value if the process is bound to the
+ * run-queue.
+ * @return Pointer to the normal run-queue that
+ * the process currently is assigend to.
+ * A process is always assigned to a
+ * normal run-queue.
+ */
+
ERTS_GLB_INLINE ErtsRunQueue *
-erts_get_runq_proc(Process *p)
+erts_get_runq_proc(Process *p, int *bndp)
{
- ASSERT(ERTS_AINT_NULL != erts_atomic_read_nob(&p->run_queue));
- return (ErtsRunQueue *) erts_atomic_read_nob(&p->run_queue);
+ erts_aint_t rqint = erts_atomic_read_nob(&p->run_queue);
+ ErtsRunQueue *rq;
+ if (bndp)
+ *bndp = (int) (rqint & ERTS_RUNQ_BOUND_FLAG);
+ rqint &= ERTS_RUNQ_POINTER_MASK;
+ rq = (ErtsRunQueue *) rqint;
+ ASSERT(rq);
+ return rq;
}
ERTS_GLB_INLINE ErtsRunQueue *
diff --git a/erts/emulator/beam/erl_process_dump.c b/erts/emulator/beam/erl_process_dump.c
index 0d76a4ef53..05e7bcdea2 100644
--- a/erts/emulator/beam/erl_process_dump.c
+++ b/erts/emulator/beam/erl_process_dump.c
@@ -1009,8 +1009,6 @@ erts_dump_extended_process_state(fmtfn_t to, void *to_arg, erts_aint32_t psflg)
erts_print(to, to_arg, "SUSPENDED"); break;
case ERTS_PSFLG_GC:
erts_print(to, to_arg, "GC"); break;
- case ERTS_PSFLG_BOUND:
- erts_print(to, to_arg, "BOUND"); break;
case ERTS_PSFLG_TRAP_EXIT:
erts_print(to, to_arg, "TRAP_EXIT"); break;
case ERTS_PSFLG_ACTIVE_SYS:
@@ -1023,8 +1021,6 @@ erts_dump_extended_process_state(fmtfn_t to, void *to_arg, erts_aint32_t psflg)
erts_print(to, to_arg, "DELAYED_SYS"); break;
case ERTS_PSFLG_OFF_HEAP_MSGQ:
erts_print(to, to_arg, "OFF_HEAP_MSGQ"); break;
- case ERTS_PSFLG_ON_HEAP_MSGQ:
- erts_print(to, to_arg, "ON_HEAP_MSGQ"); break;
case ERTS_PSFLG_DIRTY_CPU_PROC:
erts_print(to, to_arg, "DIRTY_CPU_PROC"); break;
case ERTS_PSFLG_DIRTY_IO_PROC:
diff --git a/erts/emulator/beam/io.c b/erts/emulator/beam/io.c
index 4bb2c0cb01..3e8f6263bb 100644
--- a/erts/emulator/beam/io.c
+++ b/erts/emulator/beam/io.c
@@ -298,7 +298,6 @@ static Port *create_port(char *name,
erts_aint32_t state = ERTS_PORT_SFLG_CONNECTED;
erts_aint32_t x_pts_flgs = 0;
- ErtsRunQueue *runq;
if (!driver_lock) {
/* Align size for mutex following port struct */
port_size = size = ERTS_ALC_DATA_ALIGN_SIZE(sizeof(Port));
@@ -347,11 +346,16 @@ static Port *create_port(char *name,
p += sizeof(erts_mtx_t);
state |= ERTS_PORT_SFLG_PORT_SPECIFIC_LOCK;
}
- if (erts_get_scheduler_data())
- runq = erts_get_runq_current(NULL);
- else
- runq = ERTS_RUNQ_IX(0);
- erts_atomic_set_nob(&prt->run_queue, (erts_aint_t) runq);
+
+ {
+ ErtsRunQueue *runq;
+ ErtsSchedulerData *esdp = erts_get_scheduler_data();
+ if (esdp)
+ runq = erts_get_runq_current(esdp);
+ else
+ runq = ERTS_RUNQ_IX(0);
+ erts_init_runq_port(prt, runq);
+ }
prt->xports = NULL;
diff --git a/erts/emulator/sys/unix/erl_child_setup.c b/erts/emulator/sys/unix/erl_child_setup.c
index 69fc6c2879..57973b10d7 100644
--- a/erts/emulator/sys/unix/erl_child_setup.c
+++ b/erts/emulator/sys/unix/erl_child_setup.c
@@ -437,6 +437,21 @@ main(int argc, char *argv[])
exit(1);
}
+ /* Ignore SIGTERM.
+ Some container environments send SIGTERM to all processes
+ when terminating. We don't want erl_child_setup to terminate
+ in these cases as that will prevent beam from properly
+ cleaning up.
+ */
+ sa.sa_handler = SIG_IGN;
+ sigemptyset(&sa.sa_mask);
+ sa.sa_flags = 0;
+
+ if (sigaction(SIGTERM, &sa, 0) == -1) {
+ perror(NULL);
+ exit(1);
+ }
+
forker_hash_init();
SET_CLOEXEC(uds_fd);
diff --git a/erts/emulator/test/efile_SUITE.erl b/erts/emulator/test/efile_SUITE.erl
index 16d581a567..821381bf0d 100644
--- a/erts/emulator/test/efile_SUITE.erl
+++ b/erts/emulator/test/efile_SUITE.erl
@@ -46,14 +46,14 @@ iter_max_files_1(Config) ->
DataDir = proplists:get_value(data_dir,Config),
TestFile = filename:join(DataDir, "existing_file"),
N = 10,
- %% Run on a different node in order to set the max ports
+ %% Run on a different node in order to make the test more stable.
Dir = filename:dirname(code:which(?MODULE)),
{ok,Node} = test_server:start_node(test_iter_max_files,slave,
- [{args,"+Q 1524 -pa " ++ Dir}]),
+ [{args,"-pa " ++ Dir}]),
L = rpc:call(Node,?MODULE,do_iter_max_files,[N, TestFile]),
test_server:stop_node(Node),
io:format("Number of files opened in each test:~n~w\n", [L]),
- all_equal(L),
+ verify_max_files(L),
Head = hd(L),
if Head >= 2 -> ok;
true -> ct:fail(too_few_files)
@@ -65,12 +65,15 @@ do_iter_max_files(N, Name) when N > 0 ->
do_iter_max_files(_, _) ->
[].
-all_equal([E, E| T]) ->
- all_equal([E| T]);
-all_equal([_]) ->
- ok;
-all_equal([]) ->
- ok.
+%% The attempts shouldn't vary too much; we used to require that they were all
+%% exactly equal, but after we reimplemented the file driver as a NIF we
+%% noticed that the only reason it was stable on Darwin was because the port
+%% limit was hit before ulimit.
+verify_max_files(Attempts) ->
+ N = length(Attempts),
+ Mean = lists:sum(Attempts) / N,
+ Variance = lists:sum([(X - Mean) * (X - Mean) || X <- Attempts]) / N,
+ true = math:sqrt(Variance) =< 1 + (Mean / 1000).
max_files(Name) ->
Fds = open_files(Name),
diff --git a/erts/etc/common/inet_gethost.c b/erts/etc/common/inet_gethost.c
index b746487668..4fc7a93348 100644
--- a/erts/etc/common/inet_gethost.c
+++ b/erts/etc/common/inet_gethost.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 1998-2017. All Rights Reserved.
+ * Copyright Ericsson AB 1998-2018. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -1770,7 +1770,7 @@ static int worker_loop(void)
}
#elif defined(HAVE_GETIPNODEBYNAME) /*#ifdef HAVE_GETADDRINFO */
DEBUGF(5,("Starting getipnodebyname(%s)",data));
- he = getipnodebyname(data, AF_INET6, AI_DEFAULT, &error_num);
+ he = getipnodebyname(data, AF_INET6, 0, &error_num);
if (he) {
free_he = 1;
error_num = 0;
diff --git a/erts/etc/unix/etp-commands.in b/erts/etc/unix/etp-commands.in
index 95e065b156..02ace9126c 100644
--- a/erts/etc/unix/etp-commands.in
+++ b/erts/etc/unix/etp-commands.in
@@ -1693,7 +1693,7 @@ define etp-proc-state-int
printf "dirty-cpu-proc | "
end
if ($arg0 & 0x2000000)
- printf "on-heap-msgq | "
+ printf "GARBAGE<0x2000000> | "
end
if ($arg0 & 0x1000000)
printf "off-heap-msgq | "
@@ -1717,7 +1717,7 @@ define etp-proc-state-int
printf "trapping-exit | "
end
if ($arg0 & 0x40000)
- printf "bound | "
+ printf "GARBAGE<0x40000> | "
end
if ($arg0 & 0x20000)
printf "garbage-collecting | "
diff --git a/erts/preloaded/src/erlang.erl b/erts/preloaded/src/erlang.erl
index d352e11751..370ecdc3f6 100644
--- a/erts/preloaded/src/erlang.erl
+++ b/erts/preloaded/src/erlang.erl
@@ -2563,10 +2563,10 @@ tuple_to_list(_Tuple) ->
Settings :: [{Subsystem :: atom(),
[{Parameter :: atom(),
Value :: term()}]}];
- (alloc_util_allocators) -> [Alloc] when
- Alloc :: atom();
({allocator, Alloc}) -> [_] when %% More or less anything
Alloc :: atom();
+ (alloc_util_allocators) -> [Alloc] when
+ Alloc :: atom();
({allocator_sizes, Alloc}) -> [_] when %% More or less anything
Alloc :: atom();
(atom_count) -> pos_integer();
@@ -2593,6 +2593,7 @@ tuple_to_list(_Tuple) ->
(driver_version) -> string();
(dynamic_trace) -> none | dtrace | systemtap;
(dynamic_trace_probes) -> boolean();
+ (end_time) -> non_neg_integer();
(elib_malloc) -> false;
(eager_check_io) -> boolean();
(ets_limit) -> pos_integer();
@@ -2620,6 +2621,7 @@ tuple_to_list(_Tuple) ->
(otp_release) -> string();
(os_monotonic_time_source) -> [{atom(),term()}];
(os_system_time_source) -> [{atom(),term()}];
+ (port_parallelism) -> boolean();
(port_count) -> non_neg_integer();
(port_limit) -> pos_integer();
(process_count) -> pos_integer();
@@ -2649,7 +2651,8 @@ tuple_to_list(_Tuple) ->
(trace_control_word) -> non_neg_integer();
(update_cpu_info) -> changed | unchanged;
(version) -> string();
- (wordsize | {wordsize, internal} | {wordsize, external}) -> 4 | 8.
+ (wordsize | {wordsize, internal} | {wordsize, external}) -> 4 | 8;
+ (overview) -> boolean().
system_info(_Item) ->
erlang:nif_error(undefined).
diff --git a/lib/asn1/src/asn1ct_gen_per.erl b/lib/asn1/src/asn1ct_gen_per.erl
index 82e9326294..c09b0f47d1 100644
--- a/lib/asn1/src/asn1ct_gen_per.erl
+++ b/lib/asn1/src/asn1ct_gen_per.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2017. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -47,14 +47,20 @@ dialyzer_suppressions(#gen{erule=per,aligned=Aligned}) ->
false -> uper;
true -> per
end,
- case asn1ct_func:is_used({Mod,complete,1}) of
+ suppress({Mod,complete,1}),
+ suppress({per_common,to_bitstring,2}),
+ emit([" ok.",nl]).
+
+suppress({M,F,A}=MFA) ->
+ case asn1ct_func:is_used(MFA) of
false ->
ok;
true ->
- emit([" _ = complete(Arg),",nl])
- end,
- emit([" ok.",nl]).
-
+ Args =
+ [lists:concat(["element(",I,", Arg)"])
+ || I <- lists:seq(1, A)],
+ emit([" ",{call,M,F,Args},com,nl])
+ end.
gen_encode(Erules,Type) when is_record(Type,typedef) ->
gen_encode_user(Erules,Type).
diff --git a/lib/compiler/src/beam_block.erl b/lib/compiler/src/beam_block.erl
index 47a2be8ab5..8cd271e1dc 100644
--- a/lib/compiler/src/beam_block.erl
+++ b/lib/compiler/src/beam_block.erl
@@ -363,10 +363,18 @@ opt_tuple_element_1([{set,[D],[S],move}|Is0], I0, {_,S}, Acc) ->
case eliminate_use_of_from_reg(Is0, S, D) of
no ->
no;
- {yes,Is} ->
+ {yes,Is1} ->
{set,[S],Ss,Op} = I0,
I = {set,[D],Ss,Op},
- {yes,reverse(Acc, [I|Is])}
+ case opt_move_rev(S, Acc, [I|Is1]) of
+ not_possible ->
+ %% Not safe because the move of the
+ %% get_tuple_element instruction would cause the
+ %% result of a previous instruction to be ignored.
+ no;
+ {_,Is} ->
+ {yes,Is}
+ end
end;
opt_tuple_element_1([{set,Ds,Ss,_}=I|Is], MovedI, {S,D}=Regs, Acc) ->
case member(S, Ds) orelse member(D, Ss) of
diff --git a/lib/compiler/src/beam_type.erl b/lib/compiler/src/beam_type.erl
index b83ed17b55..28f36db399 100644
--- a/lib/compiler/src/beam_type.erl
+++ b/lib/compiler/src/beam_type.erl
@@ -17,14 +17,15 @@
%%
%% %CopyrightEnd%
%%
-%% Purpose : Type-based optimisations.
+%% Purpose: Type-based optimisations. See the comment for verified_type/1
+%% the very end of this file for a description of the types in the
+%% type database.
-module(beam_type).
-export([module/2]).
--import(lists, [filter/2,foldl/3,keyfind/3,member/2,
- reverse/1,reverse/2,sort/1]).
+-import(lists, [foldl/3,member/2,reverse/1,reverse/2,sort/1]).
-define(UNICODE_INT, {integer,{0,16#10FFFF}}).
@@ -93,22 +94,28 @@ simplify_basic([I0|Is], Ts0, Acc) ->
simplify_basic([], Ts, Acc) ->
{reverse(Acc),Ts}.
+%% simplify_instr(Instruction, Ts) -> [Instruction].
+
+%% Simplify a simple instruction using type information. Return an
+%% empty list if the instruction should be removed, or a list with
+%% the original or modified instruction.
+
simplify_instr({set,[D],[{integer,Index},Reg],{bif,element,_}}=I, Ts) ->
case max_tuple_size(Reg, Ts) of
Sz when 0 < Index, Index =< Sz ->
[{set,[D],[Reg],{get_tuple_element,Index-1}}];
_ -> [I]
end;
-simplify_instr({test,is_atom,_,[R]}=I, Ts) ->
- case tdb_find(R, Ts) of
- boolean -> [];
- _ -> [I]
- end;
-simplify_instr({test,is_integer,_,[R]}=I, Ts) ->
+simplify_instr({test,Test,Fail,[R]}=I, Ts) ->
case tdb_find(R, Ts) of
- integer -> [];
- {integer,_} -> [];
- _ -> [I]
+ any ->
+ [I];
+ Type ->
+ case will_succeed(Test, Type) of
+ yes -> [];
+ no -> [{jump,Fail}];
+ maybe -> [I]
+ end
end;
simplify_instr({set,[D],[TupleReg],{get_tuple_element,0}}=I, Ts) ->
case tdb_find(TupleReg, Ts) of
@@ -117,31 +124,17 @@ simplify_instr({set,[D],[TupleReg],{get_tuple_element,0}}=I, Ts) ->
_ ->
[I]
end;
-simplify_instr({test,is_tuple,_,[R]}=I, Ts) ->
- case tdb_find(R, Ts) of
- {tuple,_,_,_} -> [];
- _ -> [I]
- end;
simplify_instr({test,test_arity,_,[R,Arity]}=I, Ts) ->
case tdb_find(R, Ts) of
{tuple,exact_size,Arity,_} -> [];
_ -> [I]
end;
-simplify_instr({test,is_map,_,[R]}=I, Ts) ->
- case tdb_find(R, Ts) of
- map -> [];
- _ -> [I]
- end;
-simplify_instr({test,is_nonempty_list,_,[R]}=I, Ts) ->
- case tdb_find(R, Ts) of
- nonempty_list -> [];
- _ -> [I]
- end;
-simplify_instr({test,is_eq_exact,Fail,[R,{atom,_}=Atom]}=I, Ts) ->
+simplify_instr({test,is_eq_exact,Fail,[R,{atom,A}=Atom]}=I, Ts) ->
case tdb_find(R, Ts) of
{atom,_}=Atom -> [];
- {atom,_} -> [{jump,Fail}];
- _ -> [I]
+ boolean when is_boolean(A) -> [I];
+ any -> [I];
+ _ -> [{jump,Fail}]
end;
simplify_instr({test,is_record,_,[R,{atom,_}=Tag,{integer,Arity}]}=I, Ts) ->
case tdb_find(R, Ts) of
@@ -162,16 +155,6 @@ simplify_instr({test,bs_test_unit,_,[Src,Unit]}=I, Ts) ->
{binary,U} when U rem Unit =:= 0 -> [];
_ -> [I]
end;
-simplify_instr({test,is_binary,_,[Src]}=I, Ts) ->
- case tdb_find(Src, Ts) of
- {binary,U} when U rem 8 =:= 0 -> [];
- _ -> [I]
- end;
-simplify_instr({test,is_bitstr,_,[Src]}=I, Ts) ->
- case tdb_find(Src, Ts) of
- {binary,_} -> [];
- _ -> [I]
- end;
simplify_instr(I, _) -> [I].
simplify_select_val_int({select,select_val,R,_,L0}=I, {Min,Max}) ->
@@ -200,6 +183,53 @@ eq_ranges([H], H, H) -> true;
eq_ranges([H|T], H, Max) -> eq_ranges(T, H+1, Max);
eq_ranges(_, _, _) -> false.
+%% will_succeed(TestOperation, Type) -> yes|no|maybe.
+%% Test whether TestOperation applied to an argument of type Type
+%% will succeed. Return yes, no, or maybe.
+%%
+%% Type is a type as described in the comment for verified_type/1 at
+%% the very end of this file, but it will *never* be 'any'.
+
+will_succeed(is_atom, Type) ->
+ case Type of
+ {atom,_} -> yes;
+ boolean -> yes;
+ _ -> no
+ end;
+will_succeed(is_binary, Type) ->
+ case Type of
+ {binary,U} when U rem 8 =:= 0 -> yes;
+ {binary,_} -> maybe;
+ _ -> no
+ end;
+will_succeed(is_bitstr, Type) ->
+ case Type of
+ {binary,_} -> yes;
+ _ -> no
+ end;
+will_succeed(is_integer, Type) ->
+ case Type of
+ integer -> yes;
+ {integer,_} -> yes;
+ _ -> no
+ end;
+will_succeed(is_map, Type) ->
+ case Type of
+ map -> yes;
+ _ -> no
+ end;
+will_succeed(is_nonempty_list, Type) ->
+ case Type of
+ nonempty_list -> yes;
+ _ -> no
+ end;
+will_succeed(is_tuple, Type) ->
+ case Type of
+ {tuple,_,_,_} -> yes;
+ _ -> no
+ end;
+will_succeed(_, _) -> maybe.
+
%% simplify_float([Instruction], TypeDatabase) ->
%% {[Instruction],TypeDatabase'} | not_possible
%% Simplify floating point operations in blocks.
@@ -229,7 +259,7 @@ simplify_float_1([{set,[D0],[A0],{alloc,_,{gc_bif,'-',{f,0}}}}=I|Is]=Is0,
{D,Rs} = find_dest(D0, Rs1),
Areg = fetch_reg(A, Rs),
Acc = [{set,[D],[Areg],{bif,fnegate,{f,0}}}|clearerror(Acc1)],
- Ts = tdb_update([{D0,float}], Ts0),
+ Ts = tdb_store(D0, float, Ts0),
simplify_float_1(Is, Ts, Rs, Acc);
_Other ->
Ts = update(I, Ts0),
@@ -252,7 +282,7 @@ simplify_float_1([{set,[D0],[A0,B0],{alloc,_,{gc_bif,Op0,{f,0}}}}=I|Is]=Is0,
Areg = fetch_reg(A, Rs),
Breg = fetch_reg(B, Rs),
Acc = [{set,[D],[Areg,Breg],{bif,Op,{f,0}}}|clearerror(Acc2)],
- Ts = tdb_update([{D0,float}], Ts0),
+ Ts = tdb_store(D0, float, Ts0),
simplify_float_1(Is, Ts, Rs, Acc)
end;
simplify_float_1([{set,_,_,{try_catch,_,_}}=I|Is]=Is0, _Ts, Rs0, Acc0) ->
@@ -425,104 +455,100 @@ update({'%anno',_}, Ts) ->
Ts;
update({set,[D],[S],move}, Ts) ->
tdb_copy(S, D, Ts);
-update({set,[D],[{integer,I},Reg],{bif,element,_}}, Ts0) ->
- tdb_update([{Reg,{tuple,min_size,I,[]}},{D,kill}], Ts0);
-update({set,[D],[_Index,Reg],{bif,element,_}}, Ts0) ->
- tdb_update([{Reg,{tuple,min_size,0,[]}},{D,kill}], Ts0);
-update({set,[D],Args,{bif,N,_}}, Ts0) ->
+update({set,[D],[Index,Reg],{bif,element,_}}, Ts0) ->
+ MinSize = case Index of
+ {integer,I} -> I;
+ _ -> 0
+ end,
+ Ts = tdb_meet(Reg, {tuple,min_size,MinSize,[]}, Ts0),
+ tdb_store(D, any, Ts);
+update({set,[D],Args,{bif,N,_}}, Ts) ->
Ar = length(Args),
BoolOp = erl_internal:new_type_test(N, Ar) orelse
erl_internal:comp_op(N, Ar) orelse
erl_internal:bool_op(N, Ar),
- case BoolOp of
- true ->
- tdb_update([{D,boolean}], Ts0);
- false ->
- tdb_update([{D,kill}], Ts0)
+ Type = case BoolOp of
+ true -> boolean;
+ false -> unary_op_type(N)
+ end,
+ tdb_store(D, Type, Ts);
+update({set,[D],[S],{get_tuple_element,0}}, Ts0) ->
+ if
+ D =:= S ->
+ tdb_store(D, any, Ts0);
+ true ->
+ Ts = tdb_store(D, {tuple_element,S,0}, Ts0),
+ tdb_store(S, {tuple,min_size,1,[]}, Ts)
end;
-update({set,[D],[S],{get_tuple_element,0}}, Ts) ->
- tdb_update([{D,{tuple_element,S,0}}], Ts);
update({set,[D],[S],{alloc,_,{gc_bif,float,{f,0}}}}, Ts0) ->
%% Make sure we reject non-numeric literal argument.
case possibly_numeric(S) of
- true -> tdb_update([{D,float}], Ts0);
- false -> Ts0
+ true -> tdb_store(D, float, Ts0);
+ false -> Ts0
end;
update({set,[D],[S1,S2],{alloc,_,{gc_bif,'band',{f,0}}}}, Ts) ->
- case keyfind(integer, 1, [S1,S2]) of
- {integer,N} ->
- update_band(N, D, Ts);
- false ->
- tdb_update([{D,integer}], Ts)
- end;
-update({set,[D],[S1,S2],{alloc,_,{gc_bif,'/',{f,0}}}}, Ts0) ->
+ Type = band_type(S1, S2, Ts),
+ tdb_store(D, Type, Ts);
+update({set,[D],[S1,S2],{alloc,_,{gc_bif,'/',{f,0}}}}, Ts) ->
%% Make sure we reject non-numeric literals.
case possibly_numeric(S1) andalso possibly_numeric(S2) of
- true -> tdb_update([{D,float}], Ts0);
- false -> Ts0
+ true -> tdb_store(D, float, Ts);
+ false -> Ts
end;
update({set,[D],[S1,S2],{alloc,_,{gc_bif,Op,{f,0}}}}, Ts0) ->
case op_type(Op) of
integer ->
- tdb_update([{D,integer}], Ts0);
- {float,_} ->
- case {tdb_find(S1, Ts0),tdb_find(S2, Ts0)} of
- {float,_} -> tdb_update([{D,float}], Ts0);
- {_,float} -> tdb_update([{D,float}], Ts0);
- {_,_} -> tdb_update([{D,kill}], Ts0)
- end;
- unknown ->
- tdb_update([{D,kill}], Ts0)
- end;
-update({set,[],_Src,_Op}, Ts0) -> Ts0;
-update({set,[D],_Src,_Op}, Ts0) ->
- tdb_update([{D,kill}], Ts0);
+ tdb_store(D, integer, Ts0);
+ {float,_} ->
+ case {tdb_find(S1, Ts0),tdb_find(S2, Ts0)} of
+ {float,_} -> tdb_store(D, float, Ts0);
+ {_,float} -> tdb_store(D, float, Ts0);
+ {_,_} -> tdb_store(D, any, Ts0)
+ end;
+ Type ->
+ tdb_store(D, Type, Ts0)
+ end;
+update({set,[D],[_],{alloc,_,{gc_bif,Op,{f,0}}}}, Ts) ->
+ tdb_store(D, unary_op_type(Op), Ts);
+update({set,[],_Src,_Op}, Ts) ->
+ Ts;
+update({set,[D],_Src,_Op}, Ts) ->
+ tdb_store(D, any, Ts);
update({kill,D}, Ts) ->
- tdb_update([{D,kill}], Ts);
+ tdb_store(D, any, Ts);
%% Instructions outside of blocks.
-update({test,is_float,_Fail,[Src]}, Ts0) ->
- tdb_update([{Src,float}], Ts0);
-update({test,test_arity,_Fail,[Src,Arity]}, Ts0) ->
- tdb_update([{Src,{tuple,exact_size,Arity,[]}}], Ts0);
-update({test,is_map,_Fail,[Src]}, Ts0) ->
- tdb_update([{Src,map}], Ts0);
+update({test,test_arity,_Fail,[Src,Arity]}, Ts) ->
+ tdb_meet(Src, {tuple,exact_size,Arity,[]}, Ts);
update({get_map_elements,_,Src,{list,Elems0}}, Ts0) ->
+ Ts1 = tdb_meet(Src, map, Ts0),
{_Ss,Ds} = beam_utils:split_even(Elems0),
- Elems = [{Dst,kill} || Dst <- Ds],
- tdb_update([{Src,map}|Elems], Ts0);
-update({test,is_nonempty_list,_Fail,[Src]}, Ts0) ->
- tdb_update([{Src,nonempty_list}], Ts0);
-update({test,is_eq_exact,_,[Reg,{atom,_}=Atom]}, Ts) ->
- case tdb_find(Reg, Ts) of
- error ->
- Ts;
- {tuple_element,TupleReg,0} ->
- tdb_update([{TupleReg,{tuple,min_size,1,[Atom]}}], Ts);
- _ ->
- Ts
- end;
+ foldl(fun(Dst, A) -> tdb_store(Dst, any, A) end, Ts1, Ds);
+update({test,is_eq_exact,_,[Reg,{atom,_}=Atom]}, Ts0) ->
+ Ts = case tdb_find_source_tuple(Reg, Ts0) of
+ {source_tuple,TupleReg} ->
+ tdb_meet(TupleReg, {tuple,min_size,1,[Atom]}, Ts0);
+ none ->
+ Ts0
+ end,
+ tdb_meet(Reg, Atom, Ts);
update({test,is_record,_Fail,[Src,Tag,{integer,Arity}]}, Ts) ->
- tdb_update([{Src,{tuple,exact_size,Arity,[Tag]}}], Ts);
+ tdb_meet(Src, {tuple,exact_size,Arity,[Tag]}, Ts);
%% Binaries and binary matching.
-update({test,is_binary,_Fail,[Src]}, Ts0) ->
- tdb_update([{Src,{binary,8}}], Ts0);
-update({test,is_bitstr,_Fail,[Src]}, Ts0) ->
- tdb_update([{Src,{binary,1}}], Ts0);
update({test,bs_get_integer2,_,_,Args,Dst}, Ts) ->
- tdb_update([{Dst,get_bs_integer_type(Args)}], Ts);
+ tdb_store(Dst, get_bs_integer_type(Args), Ts);
update({test,bs_get_utf8,_,_,_,Dst}, Ts) ->
- tdb_update([{Dst,?UNICODE_INT}], Ts);
+ tdb_store(Dst, ?UNICODE_INT, Ts);
update({test,bs_get_utf16,_,_,_,Dst}, Ts) ->
- tdb_update([{Dst,?UNICODE_INT}], Ts);
+ tdb_store(Dst, ?UNICODE_INT, Ts);
update({test,bs_get_utf32,_,_,_,Dst}, Ts) ->
- tdb_update([{Dst,?UNICODE_INT}], Ts);
+ tdb_store(Dst, ?UNICODE_INT, Ts);
update({bs_init,_,{bs_init2,_,_},_,_,Dst}, Ts) ->
- tdb_update([{Dst,{binary,8}}], Ts);
+ tdb_store(Dst, {binary,8}, Ts);
update({bs_init,_,_,_,_,Dst}, Ts) ->
- tdb_update([{Dst,{binary,1}}], Ts);
+ tdb_store(Dst, {binary,1}, Ts);
update({bs_put,_,_,_}, Ts) ->
Ts;
update({bs_save2,_,_}, Ts) ->
@@ -530,21 +556,31 @@ update({bs_save2,_,_}, Ts) ->
update({bs_restore2,_,_}, Ts) ->
Ts;
update({bs_context_to_binary,Dst}, Ts) ->
- tdb_update([{Dst,kill}], Ts);
-update({test,bs_start_match2,_,_,[Src,_],Dst}, Ts) ->
- Type = case tdb_find(Src, Ts) of
- {binary,_}=Type0 -> Type0;
- _ -> {binary,1}
- end,
- tdb_update([{Dst,Type}], Ts);
+ tdb_store(Dst, {binary,1}, Ts);
+update({test,bs_start_match2,_,_,[Src,_],Dst}, Ts0) ->
+ Ts = tdb_meet(Src, {binary,1}, Ts0),
+ tdb_copy(Src, Dst, Ts);
update({test,bs_get_binary2,_,_,[_,_,Unit,_],Dst}, Ts) ->
true = is_integer(Unit), %Assertion.
- tdb_update([{Dst,{binary,Unit}}], Ts);
+ tdb_store(Dst, {binary,Unit}, Ts);
update({test,bs_get_float2,_,_,_,Dst}, Ts) ->
- tdb_update([{Dst,float}], Ts);
+ tdb_store(Dst, float, Ts);
update({test,bs_test_unit,_,[Src,Unit]}, Ts) ->
- tdb_update([{Src,{binary,Unit}}], Ts);
-
+ tdb_meet(Src, {binary,Unit}, Ts);
+
+%% Other test instructions
+update({test,Test,_Fail,[Src]}, Ts) ->
+ Type = case Test of
+ is_binary -> {binary,8};
+ is_bitstr -> {binary,1};
+ is_boolean -> boolean;
+ is_float -> float;
+ is_integer -> integer;
+ is_map -> map;
+ is_nonempty_list -> nonempty_list;
+ _ -> any
+ end,
+ tdb_meet(Src, Type, Ts);
update({test,_Test,_Fail,_Other}, Ts) ->
Ts;
@@ -552,7 +588,7 @@ update({test,_Test,_Fail,_Other}, Ts) ->
update({call_ext,Ar,{extfunc,math,Math,Ar}}, Ts) ->
case is_math_bif(Math, Ar) of
- true -> tdb_update([{{x,0},float}], Ts);
+ true -> tdb_store({x,0}, float, Ts);
false -> tdb_kill_xregs(Ts)
end;
update({call_ext,3,{extfunc,erlang,setelement,3}}, Ts0) ->
@@ -569,7 +605,7 @@ update({call_ext,3,{extfunc,erlang,setelement,3}}, Ts0) ->
%% first element of the tuple.
{tuple,SzKind,Sz,[]}
end,
- tdb_update([{{x,0},T}], Ts);
+ tdb_store({x,0}, T, Ts);
_ ->
Ts
end;
@@ -585,20 +621,27 @@ update({'%',_}, Ts) -> Ts;
%% The instruction is unknown. Kill all information.
update(_I, _Ts) -> tdb_new().
-update_band(N, Reg, Ts) ->
- Type = update_band_1(N, 0),
- tdb_update([{Reg,Type}], Ts).
+band_type({integer,Int}, Other, Ts) ->
+ band_type_1(Int, Other, Ts);
+band_type(Other, {integer,Int}, Ts) ->
+ band_type_1(Int, Other, Ts);
+band_type(_, _, _) -> integer.
+
+band_type_1(Int, OtherSrc, Ts) ->
+ Type = band_type_2(Int, 0),
+ OtherType = tdb_find(OtherSrc, Ts),
+ meet(Type, OtherType).
-update_band_1(N, Bits) when Bits < 64 ->
+band_type_2(N, Bits) when Bits < 64 ->
case 1 bsl Bits of
P when P =:= N + 1 ->
{integer,{0,N}};
P when P > N + 1 ->
integer;
_ ->
- update_band_1(N, Bits+1)
+ band_type_2(N, Bits+1)
end;
-update_band_1(_, _) ->
+band_type_2(_, _) ->
%% Negative or large positive number. Give up.
integer.
@@ -722,7 +765,15 @@ op_type('bxor') -> integer;
op_type('bsl') -> integer;
op_type('bsr') -> integer;
op_type('div') -> integer;
-op_type(_) -> unknown.
+op_type(_) -> any.
+
+unary_op_type(bit_size) -> integer;
+unary_op_type(byte_size) -> integer;
+unary_op_type(length) -> integer;
+unary_op_type(map_size) -> integer;
+unary_op_type(size) -> integer;
+unary_op_type(tuple_size) -> integer;
+unary_op_type(_) -> any.
flush(Rs, [{set,[_],[_,_,_],{bif,is_record,_}}|_]=Is0, Acc0) ->
Acc = flush_all(Rs, Is0, Acc0),
@@ -805,41 +856,39 @@ checkerror_1([], OrigIs) -> OrigIs.
checkerror_2(OrigIs) -> [{set,[],[],fcheckerror}|OrigIs].
-%%% Routines for maintaining a type database. The type database
+%%% Routines for maintaining a type database. The type database
%%% associates type information with registers.
%%%
-%%% {tuple,min_size,Size,First} means that the corresponding register contains
-%%% a tuple with *at least* Size elements (conversely, exact_size means that it
-%%% contains a tuple with *exactly* Size elements). An tuple with unknown size
-%%% is represented as {tuple,min_size,0,[]}. First is either [] (meaning that
-%%% the tuple's first element is unknown) or [FirstElement] (the contents of
-%%% the first element).
-%%%
-%%% 'float' means that the register contains a float.
-%%%
-%%% 'integer' or {integer,{Min,Max}} that the register contains an
-%%% integer.
-%%%
-%%% {binary,Unit} means that the register contains a binary/bitstring aligned
-%%% to unit Unit.
+%%% See the comment for verified_type/1 at the end of module for
+%%% a description of the possible types.
%% tdb_new() -> EmptyDataBase
%% Creates a new, empty type database.
tdb_new() -> [].
-%% tdb_find(Register, Db) -> Information|error
+%% tdb_find(Register, Db) -> Type
%% Returns type information or the atom error if there is no type
%% information available for Register.
+%%
+%% See the comment for verified_type/1 at the end of module for
+%% a description of the possible types.
-tdb_find({x,_}=K, Ts) -> tdb_find_1(K, Ts);
-tdb_find({y,_}=K, Ts) -> tdb_find_1(K, Ts);
-tdb_find(_, _) -> error.
+tdb_find(Reg, Ts) ->
+ case tdb_find_raw(Reg, Ts) of
+ {tuple_element,_,_} -> any;
+ Type -> Type
+ end.
-tdb_find_1(K, Ts) ->
- case orddict:find(K, Ts) of
- {ok,Val} -> Val;
- error -> error
+%% tdb_find_source_tuple(Register, Ts) -> {source_tuple,Register} | 'none'.
+%% Find the tuple whose first element was fetched to the register Register.
+
+tdb_find_source_tuple(Reg, Ts) ->
+ case tdb_find_raw(Reg, Ts) of
+ {tuple_element,Src,0} ->
+ {source_tuple,Src};
+ _ ->
+ none
end.
%% tdb_copy(Source, Dest, Db) -> Db'
@@ -847,9 +896,9 @@ tdb_find_1(K, Ts) ->
%% as the Source.
tdb_copy({Tag,_}=S, D, Ts) when Tag =:= x; Tag =:= y ->
- case tdb_find(S, Ts) of
- error -> orddict:erase(D, Ts);
- Type -> orddict:store(D, Type, Ts)
+ case tdb_find_raw(S, Ts) of
+ any -> orddict:erase(D, Ts);
+ Type -> orddict:store(D, Type, Ts)
end;
tdb_copy(Literal, D, Ts) ->
Type = case Literal of
@@ -861,14 +910,89 @@ tdb_copy(Literal, D, Ts) ->
{literal,Tuple} when tuple_size(Tuple) >= 1 ->
Lit = tag_literal(element(1, Tuple)),
{tuple,exact_size,tuple_size(Tuple),[Lit]};
- _ -> term
+ _ -> any
end,
- if
- Type =:= term ->
- orddict:erase(D, Ts);
- true ->
- verify_type(Type),
- orddict:store(D, Type, Ts)
+ tdb_store(D, verified_type(Type), Ts).
+
+%% tdb_store(Register, Type, Ts0) -> Ts.
+%% Store a new type for register Register. Return the update type
+%% database. Use this function when a new value is assigned to
+%% a register.
+%%
+%% See the comment for verified_type/1 at the end of module for
+%% a description of the possible types.
+
+tdb_store(Reg, any, Ts) ->
+ erase(Reg, Ts);
+tdb_store(Reg, Type, Ts) ->
+ store(Reg, verified_type(Type), Ts).
+
+store(Key, New, [{K,_}|_]=Dict) when Key < K ->
+ [{Key,New}|Dict];
+store(Key, New, [{K,Val}=E|Dict]) when Key > K ->
+ case Val of
+ {tuple_element,Key,_} -> store(Key, New, Dict);
+ _ -> [E|store(Key, New, Dict)]
+ end;
+store(Key, New, [{_K,Old}|Dict]) -> %Key == K
+ case Old of
+ {tuple,_,_,_} ->
+ [{Key,New}|erase_tuple_element(Key, Dict)];
+ _ ->
+ [{Key,New}|Dict]
+ end;
+store(Key, New, []) -> [{Key,New}].
+
+erase(Key, [{K,_}=E|Dict]) when Key < K ->
+ [E|Dict];
+erase(Key, [{K,Val}=E|Dict]) when Key > K ->
+ case Val of
+ {tuple_element,Key,_} -> erase(Key, Dict);
+ _ -> [E|erase(Key, Dict)]
+ end;
+erase(Key, [{_K,Val}|Dict]) -> %Key == K
+ case Val of
+ {tuple,_,_,_} -> erase_tuple_element(Key, Dict);
+ _ -> Dict
+ end;
+erase(_, []) -> [].
+
+erase_tuple_element(Key, [{_,{tuple_element,Key,_}}|Dict]) ->
+ erase_tuple_element(Key, Dict);
+erase_tuple_element(Key, [E|Dict]) ->
+ [E|erase_tuple_element(Key, Dict)];
+erase_tuple_element(_Key, []) -> [].
+
+%% tdb_meet(Register, Type, Ts0) -> Ts.
+%% Update information of a register that is used as the source for an
+%% instruction. The type Type will be combined using the meet operation
+%% with the previous type information for the register, resulting in
+%% narrower (more specific) type.
+%%
+%% For example, if the previous type is {tuple,min_size,2,[]} and the
+%% the new type is {tuple,exact_size,5,[]}, the meet of the types will
+%% be {tuple,exact_size,5,[]}.
+%%
+%% See the comment for verified_type/1 at the end of module for
+%% a description of the possible types.
+
+tdb_meet(Reg, NewType, Ts) ->
+ Update = fun(Type0) -> meet(Type0, NewType) end,
+ orddict:update(Reg, Update, NewType, Ts).
+
+%%%
+%%% Here follows internal helper functions for accessing and
+%%% updating the type database.
+%%%
+
+tdb_find_raw({x,_}=K, Ts) -> tdb_find_raw_1(K, Ts);
+tdb_find_raw({y,_}=K, Ts) -> tdb_find_raw_1(K, Ts);
+tdb_find_raw(_, _) -> any.
+
+tdb_find_raw_1(K, Ts) ->
+ case orddict:find(K, Ts) of
+ {ok,Val} -> Val;
+ error -> any
end.
tag_literal(A) when is_atom(A) -> {atom,A};
@@ -877,45 +1001,6 @@ tag_literal(I) when is_integer(I) -> {integer,I};
tag_literal([]) -> nil;
tag_literal(Lit) -> {literal,Lit}.
-%% tdb_update([UpdateOp], Db) -> NewDb
-%% UpdateOp = {Register,kill}|{Register,NewInfo}
-%% Updates a type database. If a 'kill' operation is given, the type
-%% information for that register will be removed from the database.
-%% A kill operation takes precedence over other operations for the same
-%% register (i.e. [{{x,0},kill},{{x,0},{tuple,min_size,5,[]}}] means that the
-%% the existing type information, if any, will be discarded, and the
-%% the '{tuple,min_size,5,[]}' information ignored.
-%%
-%% If NewInfo information is given and there exists information about
-%% the register, the old and new type information will be merged.
-%% For instance, {tuple,min_size,5,_} and {tuple,min_size,10,_} will be merged
-%% to produce {tuple,min_size,10,_}.
-
-tdb_update(Uis0, Ts0) ->
- Uis1 = filter(fun ({{x,_},_Op}) -> true;
- ({{y,_},_Op}) -> true;
- (_) -> false
- end, Uis0),
- tdb_update1(lists:sort(Uis1), Ts0).
-
-tdb_update1([{Key,kill}|Ops], [{K,_Old}|_]=Db) when Key < K ->
- tdb_update1(remove_key(Key, Ops), Db);
-tdb_update1([{Key,Type}=New|Ops], [{K,_Old}|_]=Db) when Key < K ->
- verify_type(Type),
- [New|tdb_update1(Ops, Db)];
-tdb_update1([{Key,kill}|Ops], [{Key,_}|Db]) ->
- tdb_update1(remove_key(Key, Ops), Db);
-tdb_update1([{Key,NewInfo}|Ops], [{Key,OldInfo}|Db]) ->
- [{Key,merge_type_info(NewInfo, OldInfo)}|tdb_update1(Ops, Db)];
-tdb_update1([{_,_}|_]=Ops, [Old|Db]) ->
- [Old|tdb_update1(Ops, Db)];
-tdb_update1([{Key,kill}|Ops], []) ->
- tdb_update1(remove_key(Key, Ops), []);
-tdb_update1([{_,Type}=New|Ops], []) ->
- verify_type(Type),
- [New|tdb_update1(Ops, [])];
-tdb_update1([], Db) -> Db.
-
%% tdb_kill_xregs(Db) -> NewDb
%% Kill all information about x registers. Also kill all tuple_element
%% dependencies from y registers to x registers.
@@ -924,44 +1009,106 @@ tdb_kill_xregs([{{x,_},_Type}|Db]) -> tdb_kill_xregs(Db);
tdb_kill_xregs([{{y,_},{tuple_element,{x,_},_}}|Db]) -> tdb_kill_xregs(Db);
tdb_kill_xregs([Any|Db]) -> [Any|tdb_kill_xregs(Db)];
tdb_kill_xregs([]) -> [].
-
-remove_key(Key, [{Key,_Op}|Ops]) -> remove_key(Key, Ops);
-remove_key(_, Ops) -> Ops.
-merge_type_info(I, I) -> I;
-merge_type_info({tuple,min_size,Sz1,Same}, {tuple,min_size,Sz2,Same}=Max) when Sz1 < Sz2 ->
+%% meet(Type1, Type2) -> Type
+%% Returns the "meet" of Type1 and Type2. The meet is a narrower
+%% type than Type1 and Type2. For example:
+%%
+%% meet(integer, {integer,{0,3}}) -> {integer,{0,3}}
+%%
+%% The meet for two different types result in 'none', which is
+%% the bottom element for our type lattice:
+%%
+%% meet(integer, map) -> none
+
+meet(T, T) ->
+ T;
+meet({integer,_}=T, integer) ->
+ T;
+meet(integer, {integer,_}=T) ->
+ T;
+meet({integer,{Min1,Max1}}, {integer,{Min2,Max2}}) ->
+ {integer,{max(Min1, Min2),min(Max1, Max2)}};
+meet({tuple,min_size,Sz1,Same}, {tuple,min_size,Sz2,Same}=Max) when Sz1 < Sz2 ->
Max;
-merge_type_info({tuple,min_size,Sz1,Same}=Max, {tuple,min_size,Sz2,Same}) when Sz1 > Sz2 ->
+meet({tuple,min_size,Sz1,Same}=Max, {tuple,min_size,Sz2,Same}) when Sz1 > Sz2 ->
Max;
-merge_type_info({tuple,exact_size,_,Same}=Exact, {tuple,_,_,Same}) ->
+meet({tuple,exact_size,_,Same}=Exact, {tuple,_,_,Same}) ->
Exact;
-merge_type_info({tuple,_,_,Same},{tuple,exact_size,_,Same}=Exact) ->
+meet({tuple,_,_,Same},{tuple,exact_size,_,Same}=Exact) ->
Exact;
-merge_type_info({tuple,SzKind1,Sz1,[]}, {tuple,_SzKind2,_Sz2,First}=Tuple2) ->
- merge_type_info({tuple,SzKind1,Sz1,First}, Tuple2);
-merge_type_info({tuple,_SzKind1,_Sz1,First}=Tuple1, {tuple,SzKind2,Sz2,_}) ->
- merge_type_info(Tuple1, {tuple,SzKind2,Sz2,First});
-merge_type_info(integer, {integer,_}) ->
- integer;
-merge_type_info({integer,_}, integer) ->
- integer;
-merge_type_info({integer,{Min1,Max1}}, {integer,{Min2,Max2}}) ->
- {integer,{max(Min1, Min2),min(Max1, Max2)}};
-merge_type_info({binary,U1}, {binary,U2}) ->
+meet({tuple,SzKind1,Sz1,[]}, {tuple,_SzKind2,_Sz2,First}=Tuple2) ->
+ meet({tuple,SzKind1,Sz1,First}, Tuple2);
+meet({tuple,_SzKind1,_Sz1,First}=Tuple1, {tuple,SzKind2,Sz2,_}) ->
+ meet(Tuple1, {tuple,SzKind2,Sz2,First});
+meet({binary,U1}, {binary,U2}) ->
{binary,max(U1, U2)};
-merge_type_info(NewType, _) ->
- verify_type(NewType),
- NewType.
-
-verify_type({atom,_}) -> ok;
-verify_type({binary,U}) when is_integer(U) -> ok;
-verify_type(boolean) -> ok;
-verify_type(integer) -> ok;
-verify_type({integer,{Min,Max}})
- when is_integer(Min), is_integer(Max) -> ok;
-verify_type(map) -> ok;
-verify_type(nonempty_list) -> ok;
-verify_type({tuple,_,Sz,[]}) when is_integer(Sz) -> ok;
-verify_type({tuple,_,Sz,[_]}) when is_integer(Sz) -> ok;
-verify_type({tuple_element,_,_}) -> ok;
-verify_type(float) -> ok.
+meet(T1, T2) ->
+ case is_any(T1) of
+ true ->
+ verified_type(T2);
+ false ->
+ case is_any(T2) of
+ true ->
+ verified_type(T1);
+ false ->
+ none %The bottom element.
+ end
+ end.
+
+is_any(any) -> true;
+is_any({tuple_element,_,_}) -> true;
+is_any(_) -> false.
+
+%% verified_type(Type) -> Type
+%% Returns the passed in type if it is one of the defined types.
+%% Crashes if there is anything wrong with the type.
+%%
+%% Here are all possible types:
+%%
+%% any Any Erlang term (top element for the type lattice).
+%%
+%% {atom,Atom} The specific atom Atom.
+%% {binary,Unit} Binary/bitstring aligned to unit Unit.
+%% boolean 'true' | 'false'
+%% float Floating point number.
+%% integer Integer.
+%% {integer,{Min,Max}} Integer in the inclusive range Min through Max.
+%% map Map.
+%% nonempty_list Nonempty list.
+%% {tuple,_,_,_} Tuple (see below).
+%%
+%% none No type (bottom element for the type lattice).
+%%
+%% {tuple,min_size,Size,First} means that the corresponding register
+%% contains a tuple with *at least* Size elements (conversely,
+%% {tuple,exact_size,Size,First} means that it contains a tuple with
+%% *exactly* Size elements). An tuple with unknown size is
+%% represented as {tuple,min_size,0,[]}. First is either [] (meaning
+%% that the tuple's first element is unknown) or [FirstElement] (the
+%% contents of the first element).
+%%
+%% There is also a pseudo-type called {tuple_element,_,_}:
+%%
+%% {tuple_element,SrcTuple,ElementNumber}
+%%
+%% that does not provide any information about the type of the
+%% register itself, but provides a link back to the source tuple that
+%% the register got its value from.
+%%
+%% Note that {tuple_element,_,_} will *never* be returned by tdb_find/2.
+%% Use tdb_find_source_tuple/2 to locate the source tuple for a register.
+
+verified_type(any=T) -> T;
+verified_type({atom,_}=T) -> T;
+verified_type({binary,U}=T) when is_integer(U) -> T;
+verified_type(boolean=T) -> T;
+verified_type(integer=T) -> T;
+verified_type({integer,{Min,Max}}=T)
+ when is_integer(Min), is_integer(Max) -> T;
+verified_type(map=T) -> T;
+verified_type(nonempty_list=T) -> T;
+verified_type({tuple,_,Sz,[]}=T) when is_integer(Sz) -> T;
+verified_type({tuple,_,Sz,[_]}=T) when is_integer(Sz) -> T;
+verified_type({tuple_element,_,_}=T) -> T;
+verified_type(float=T) -> T.
diff --git a/lib/compiler/test/beam_type_SUITE.erl b/lib/compiler/test/beam_type_SUITE.erl
index e33df809ff..541075af2a 100644
--- a/lib/compiler/test/beam_type_SUITE.erl
+++ b/lib/compiler/test/beam_type_SUITE.erl
@@ -122,7 +122,7 @@ do_integers_5(X0, Y0) ->
3 -> three
end.
-coverage(_Config) ->
+coverage(Config) ->
{'EXIT',{badarith,_}} = (catch id(1) bsl 0.5),
{'EXIT',{badarith,_}} = (catch id(2.0) bsl 2),
{'EXIT',{badarith,_}} = (catch a + 0.5),
@@ -133,6 +133,29 @@ coverage(_Config) ->
id(id(42) band 387439739874298734983787934283479243879),
id(-1 band id(13)),
+ error = if
+ is_map(Config), is_integer(Config) -> ok;
+ true -> error
+ end,
+ error = if
+ is_map(Config), is_atom(Config) -> ok;
+ true -> error
+ end,
+ error = if
+ is_map(Config), is_tuple(Config) -> ok;
+ true -> error
+ end,
+ error = if
+ is_integer(Config), is_bitstring(Config) -> ok;
+ true -> error
+ end,
+
+ ok = case Config of
+ <<_>> when is_binary(Config) ->
+ impossible;
+ [_|_] ->
+ ok
+ end,
ok.
booleans(_Config) ->
diff --git a/lib/crypto/test/engine_SUITE.erl b/lib/crypto/test/engine_SUITE.erl
index f206f967c7..f410542f72 100644
--- a/lib/crypto/test/engine_SUITE.erl
+++ b/lib/crypto/test/engine_SUITE.erl
@@ -72,7 +72,12 @@ groups() ->
init_per_suite(Config) ->
try crypto:start() of
ok ->
- Config;
+ case crypto:info_lib() of
+ [{_,_, <<"OpenSSL 1.0.1s-freebsd 1 Mar 2016">>}] ->
+ {skip, "Problem with engine on OpenSSL 1.0.1s-freebsd"};
+ _ ->
+ Config
+ end;
{error,{already_started,crypto}} ->
Config
catch _:_ ->
diff --git a/lib/diameter/doc/src/diameter.xml b/lib/diameter/doc/src/diameter.xml
index 6b84b22eb5..6bc7d147c0 100644
--- a/lib/diameter/doc/src/diameter.xml
+++ b/lib/diameter/doc/src/diameter.xml
@@ -1865,8 +1865,8 @@ An example return value with for a client service with Origin-Host
{raddr,{127,0,0,1}},
{rport,3868},
{reuseaddr,true}]}]},
- {watchdog,{&lt;0.66.0>,{1346,171491,996448},okay}},
- {peer,{&lt;0.67.0>,{1346,171491,999906}}},
+ {watchdog,{&lt;0.66.0>,-576460736368485571,okay}},
+ {peer,{&lt;0.67.0>,-576460736357885808}},
{apps,[{0,common}]},
{caps,[{origin_host,{"client.example.com","server.example.com"}},
{origin_realm,{"example.com","example.com"}},
@@ -1946,8 +1946,8 @@ connection might look as follows.</p>
{transport_config,[{reuseaddr,true},
{ip,{127,0,0,1}},
{port,3868}]}]},
- {accept,[[{watchdog,{&lt;0.56.0>,{1346,171481,226895},okay}},
- {peer,{&lt;0.58.0>,{1346,171491,999511}}},
+ {accept,[[{watchdog,{&lt;0.56.0>,-576460739249514012,okay}},
+ {peer,{&lt;0.58.0>,-576460638229179167}},
{apps,[{0,common}]},
{caps,[{origin_host,{"server.example.com","client.example.com"}},
{origin_realm,{"example.com","example.com"}},
@@ -1976,7 +1976,7 @@ connection might look as follows.</p>
{send_max,148},
{send_avg,87},
{send_pend,0}]}]}],
- [{watchdog,{&lt;0.72.0>,{1346,171491,998404},initial}}]]},
+ [{watchdog,{&lt;0.72.0>,-576460638229717546,initial}}]]},
{statistics,[{{{0,280,0},recv},7},
{{{0,280,1},send},7},
{{{0,280,0},recv,{'Result-Code',2001}},7},
@@ -2024,8 +2024,8 @@ A return value for the server above might look as follows.</p>
{transport_config,[{reuseaddr,true},
{ip,{127,0,0,1}},
{port,3868}]}]},
- {watchdog,{&lt;0.56.0>,{1346,171481,226895},okay}},
- {peer,{&lt;0.58.0>,{1346,171491,999511}}},
+ {watchdog,{&lt;0.56.0>,-576460739249514012,okay}},
+ {peer,{&lt;0.58.0>,-576460638229179167}},
{apps,[{0,common}]},
{caps,[{origin_host,{"server.example.com","client.example.com"}},
{origin_realm,{"example.com","example.com"}},
diff --git a/lib/diameter/src/base/diameter_reg.erl b/lib/diameter/src/base/diameter_reg.erl
index 5b7cfab31a..c1762a07e3 100644
--- a/lib/diameter/src/base/diameter_reg.erl
+++ b/lib/diameter/src/base/diameter_reg.erl
@@ -246,8 +246,11 @@ handle_call({add, Uniq, Key}, {Pid, _}, S) ->
handle_call({remove, Key}, {Pid, _}, S) ->
Rec = {Key, Pid},
- ets:delete_object(?TABLE, Rec),
- {reply, true, notify(remove, Rec, S)};
+ {reply, true, try
+ notify(remove, Rec, S)
+ after
+ ets:delete_object(?TABLE, Rec)
+ end};
handle_call({wait, Pat}, {Pid, _} = From, S) ->
NS = add_monitor(Pid, S),
@@ -370,10 +373,12 @@ send({_,_} = From, add, Rec) ->
down(Pid, #state{monitors = Ps} = S) ->
Recs = match('_', Pid),
- ets:match_delete(?TABLE, {'_', Pid}),
- lists:foldl(fun(R,NS) -> notify(remove, R, NS) end,
- flush(Pid, S#state{monitors = sets:del_element(Pid, Ps)}),
- Recs).
+ Acc0 = flush(Pid, S#state{monitors = sets:del_element(Pid, Ps)}),
+ try
+ lists:foldl(fun(R,NS) -> notify(remove, R, NS) end, Acc0, Recs)
+ after
+ ets:match_delete(?TABLE, {'_', Pid})
+ end.
%% flush/3
diff --git a/lib/diameter/src/base/diameter_service.erl b/lib/diameter/src/base/diameter_service.erl
index 31dd92f878..cbe66ef27a 100644
--- a/lib/diameter/src/base/diameter_service.erl
+++ b/lib/diameter/src/base/diameter_service.erl
@@ -151,7 +151,7 @@
apps :: match([{0..16#FFFFFFFF, diameter:app_alias()}] %% {Id, Alias}
| [diameter:app_alias()]), %% remote
caps :: match(#diameter_caps{}),
- started = diameter_lib:now(), %% at process start or sharing
+ started = diameter_lib:now(), %% at connection_up
watchdog :: match(pid() %% key into watchdogT
| undefined)}). %% undefined if remote
@@ -554,15 +554,25 @@ terminate(Reason, #state{service_name = Name, local = {PeerT, _, _}} = S) ->
%% wait for watchdog state changes to take care of if. That this
%% takes place after deleting the state entry ensures that the
%% resulting failover by request processes accomplishes nothing.
- ets:foldl(fun(#peer{pid = TPid}, _) ->
- diameter_traffic:peer_down(TPid)
- end,
- ok,
- PeerT),
+ ets:foldl(fun peer_down/2, ok, PeerT),
shutdown == Reason %% application shutdown
andalso shutdown(application, S).
+%% peer_down/1
+%%
+%% Entries with watchdog state SUSPECT are already down: ignore the
+%% expected failure. This assumes the current implementation, but
+%% double the number of lookups (in the typical case) could be the
+%% greater evil if there are many peer connections.
+
+peer_down(#peer{pid = TPid}, _) ->
+ try
+ diameter_traffic:peer_down(TPid)
+ catch
+ error: {badmatch, []} -> ok
+ end.
+
%% ---------------------------------------------------------------------------
%% # code_change/3
%% ---------------------------------------------------------------------------
diff --git a/lib/diameter/src/diameter.appup.src b/lib/diameter/src/diameter.appup.src
index 7da59f8b25..05a8c9378e 100644
--- a/lib/diameter/src/diameter.appup.src
+++ b/lib/diameter/src/diameter.appup.src
@@ -2,7 +2,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2010-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2010-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -54,10 +54,10 @@
{"1.12.1", [{restart_application, diameter}]}, %% 19.1
{"1.12.2", [{restart_application, diameter}]}, %% 19.3
{"2.0", [{restart_application, diameter}]}, %% 20.0
- {"2.1", [{load_module, diameter_gen}, %% 20.1
- {update, diameter_reg, {advanced, "2.1"}}]},
- {"2.1.1", [{load_module, diameter_gen}]}, %% 20.1.2
- {"2.1.2", []} %% 20.1.3
+ {"2.1", [{restart_application, diameter}]}, %% 20.1
+ {"2.1.1", [{restart_application, diameter}]}, %% 20.1.2
+ {"2.1.2", [{restart_application, diameter}]}, %% 20.1.3
+ {"2.1.3", [{restart_application, diameter}]} %% 20.2
],
[
{"0.9", [{restart_application, diameter}]},
@@ -94,7 +94,8 @@
{"1.12.2", [{restart_application, diameter}]},
{"2.0", [{restart_application, diameter}]},
{"2.1", [{restart_application, diameter}]},
- {"2.1.1", [{load_module, diameter_gen}]},
- {"2.1.2", []}
+ {"2.1.1", [{restart_application, diameter}]},
+ {"2.1.2", [{restart_application, diameter}]},
+ {"2.1.3", [{restart_application, diameter}]}
]
}.
diff --git a/lib/diameter/vsn.mk b/lib/diameter/vsn.mk
index 0c852d75cd..b0fb4ada28 100644
--- a/lib/diameter/vsn.mk
+++ b/lib/diameter/vsn.mk
@@ -1,6 +1,6 @@
# %CopyrightBegin%
#
-# Copyright Ericsson AB 2010-2017. All Rights Reserved.
+# Copyright Ericsson AB 2010-2018. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -17,5 +17,5 @@
# %CopyrightEnd%
APPLICATION = diameter
-DIAMETER_VSN = 2.1.3
+DIAMETER_VSN = 2.1.4
APP_VSN = $(APPLICATION)-$(DIAMETER_VSN)$(PRE_VSN)
diff --git a/lib/inets/doc/src/http_client.xml b/lib/inets/doc/src/http_client.xml
index 212958f17f..15e383ec77 100644
--- a/lib/inets/doc/src/http_client.xml
+++ b/lib/inets/doc/src/http_client.xml
@@ -97,27 +97,32 @@
7 > {ok, {{NewVersion, 200, NewReasonPhrase}, NewHeaders, NewBody}} =
httpc:request(get, {"http://www.erlang.org", [{"connection", "close"}]},
[], []).</code>
-
+ <p>This sends an HTTP request over a unix domain socket (experimental):</p>
+ <code type="erl">
+ 8 > httpc:set_options([{ipfamily, local},
+ {unix_socket,"/tmp/unix_socket/consul_http.sock"}]).
+ 9 > {ok, {{NewVersion, 200, NewReasonPhrase}, NewHeaders, NewBody}} =
+ httpc:request(put, {"http:///v1/kv/foo", [], [], "hello"}, [], []).</code>
<p>Start an HTTP client profile:</p>
<code><![CDATA[
- 8 > {ok, Pid} = inets:start(httpc, [{profile, foo}]).
+ 10 > {ok, Pid} = inets:start(httpc, [{profile, foo}]).
{ok, <0.45.0>}
]]></code>
<p>The new profile has no proxy settings, so the connection is refused:</p>
<code type="erl">
- 9 > httpc:request("http://www.erlang.org", foo).
+ 11 > httpc:request("http://www.erlang.org", foo).
{error, econnrefused}</code>
<p>Stop the HTTP client profile:</p>
<code type="erl">
- 10 > inets:stop(httpc, foo).
+ 12 > inets:stop(httpc, foo).
ok</code>
<p>Alternative way to stop the HTTP client profile:</p>
<code type="erl">
- 10 > inets:stop(httpc, Pid).
+ 13 > inets:stop(httpc, Pid).
ok</code>
</section>
diff --git a/lib/inets/doc/src/http_uri.xml b/lib/inets/doc/src/http_uri.xml
index 20c042c202..f57214a7ce 100644
--- a/lib/inets/doc/src/http_uri.xml
+++ b/lib/inets/doc/src/http_uri.xml
@@ -45,7 +45,6 @@
this module:</p>
<p><c>boolean() = true | false</c></p>
<p><c>string()</c> = list of ASCII characters</p>
- <p><c>unicode_binary()</c> = binary() with characters encoded in the UTF-8 coding standard</p>
</section>
@@ -54,22 +53,22 @@
<p>Type definitions that are related to URI:</p>
<taglist>
- <tag><c>uri() = string() | unicode:unicode_binary()</c></tag>
+ <tag><c>uri() = string() | binary()</c></tag>
<item><p>Syntax according to the URI definition in RFC 3986,
for example, "http://www.erlang.org/"</p></item>
- <tag><c>user_info() = string() | unicode:unicode_binary()</c></tag>
+ <tag><c>user_info() = string() | binary()</c></tag>
<item><p></p></item>
<tag><c>scheme() = atom()</c></tag>
<item><p>Example: http, https</p></item>
- <tag><c>host() = string() | unicode:unicode_binary()</c></tag>
+ <tag><c>host() = string() | binary()</c></tag>
<item><p></p></item>
- <tag><c>port() = pos_integer()</c></tag>
+ <tag><c>port() = inet:port_number()</c></tag>
<item><p></p></item>
- <tag><c>path() = string() | unicode:unicode_binary()</c></tag>
+ <tag><c>path() = string() | binary()</c></tag>
<item><p>Represents a file path or directory path</p></item>
- <tag><c>query() = string() | unicode:unicode_binary()</c></tag>
+ <tag><c>query() = string() | binary()</c></tag>
<item><p></p></item>
- <tag><c>fragment() = string() | unicode:unicode_binary()</c></tag>
+ <tag><c>fragment() = string() | binary()</c></tag>
<item><p></p></item>
</taglist>
@@ -84,7 +83,7 @@
<fsummary>Decodes a hexadecimal encoded URI.</fsummary>
<type>
- <v>HexEncodedURI = string() | unicode:unicode_binary() - A possibly hexadecimal encoded URI</v>
+ <v>HexEncodedURI = string() | binary() - A possibly hexadecimal encoded URI</v>
<v>URI = uri()</v>
</type>
@@ -99,7 +98,7 @@
<fsummary>Encodes a hexadecimal encoded URI.</fsummary>
<type>
<v>URI = uri()</v>
- <v>HexEncodedURI = string() | unicode:unicode_binary() - Hexadecimal encoded URI</v>
+ <v>HexEncodedURI = string() | binary() - Hexadecimal encoded URI</v>
</type>
<desc>
@@ -119,12 +118,13 @@
<v>Option = {ipv6_host_with_brackets, boolean()} |
{scheme_defaults, scheme_defaults()} |
{fragment, boolean()} |
- {scheme_validation_fun, fun()}]</v>
+ {scheme_validation_fun, fun()}</v>
<v>Result = {Scheme, UserInfo, Host, Port, Path, Query} |
{Scheme, UserInfo, Host, Port, Path, Query, Fragment}</v>
+ <v>Scheme = scheme()</v>
<v>UserInfo = user_info()</v>
<v>Host = host()</v>
- <v>Port = pos_integer()</v>
+ <v>Port = inet:port_number()</v>
<v>Path = path()</v>
<v>Query = query()</v>
<v>Fragment = fragment()</v>
@@ -146,13 +146,20 @@
<p>Scheme validation fun is to be defined as follows:</p>
<code>
-fun(SchemeStr :: string() | unicode:unicode_binary()) ->
+fun(SchemeStr :: string() | binary()) ->
valid | {error, Reason :: term()}.
</code>
<p>It is called before scheme string gets converted into scheme atom and
thus possible atom leak could be prevented</p>
+ <warning>
+ <p>The scheme portion of the URI gets converted into atom,
+ meaning that atom leak may occur. Specifying a scheme
+ validation fun is recommended unless the URI is already
+ sanitized.</p>
+ </warning>
+
<marker id="encode"></marker>
</desc>
</func>
@@ -162,7 +169,7 @@ fun(SchemeStr :: string() | unicode:unicode_binary()) ->
<fsummary>A list of the scheme and their default ports.</fsummary>
<type>
<v>SchemeDefaults = [{scheme(), default_scheme_port_number()}] </v>
- <v>default_scheme_port_number() = pos_integer()</v>
+ <v>default_scheme_port_number() = inet:port_number()</v>
</type>
<desc>
<p>Provides a list of the scheme and their default
diff --git a/lib/inets/doc/src/httpc.xml b/lib/inets/doc/src/httpc.xml
index 58714328c5..14662f257c 100644
--- a/lib/inets/doc/src/httpc.xml
+++ b/lib/inets/doc/src/httpc.xml
@@ -210,7 +210,8 @@
ip |
port |
socket_opts |
- verbose</v>
+ verbose |
+ unix_socket</v>
<v>Profile = profile() | pid()</v>
<d>When started <c>stand_alone</c> only the pid can used.</d>
<v>Values = [{option_item(), term()}]</v>
@@ -297,8 +298,8 @@
{full_result, boolean()} |
{headers_as_is, boolean() |
{socket_opts, socket_opts()} |
- {receiver, receiver()},
- {ipv6_host_with_brackets, boolean()}}</v>
+ {receiver, receiver()} |
+ {ipv6_host_with_brackets, boolean()}</v>
<v>stream_to() = none | self | {self, once} | filename()</v>
<v>socket_opts() = [socket_opt()]</v>
<v>receiver() = pid() | function()/1 | {Module, Function, Args}</v>
@@ -533,7 +534,8 @@
<v>| {ip, IpAddress}</v>
<v>| {port, Port}</v>
<v>| {socket_opts, socket_opts()}</v>
- <v>| {verbose, VerboseMode}</v>
+ <v>| {verbose, VerboseMode}</v>
+ <v>| {unix_socket, UnixSocket}</v>
<v>Proxy = {Hostname, Port}</v>
<v>Hostname = string()</v>
<d>Example: "localhost" or "foo.bar.se"</d>
@@ -576,7 +578,7 @@
If option <c>verify</c> is used, function <c>store_cookies/2</c>
has to be called for the cookies to be saved.
Default is <c>disabled</c>.</d>
- <v>IpFamily = inet | inet6 </v>
+ <v>IpFamily = inet | inet6 | local</v>
<d>Default is <c>inet</c>.</d>
<v>IpAddress = ip_address()</v>
<d>If the host has several network interfaces, this option specifies
@@ -601,6 +603,12 @@
It is a debug feature.</d>
<v>Profile = profile() | pid()</v>
<d>When started <c>stand_alone</c> only the pid can be used.</d>
+ <v>UnixSocket = path()</v>
+ <d>
+ Experimental option for sending HTTP requests over a unix domain socket. The value
+ of <c>unix_socket</c> shall be the full path to a unix domain socket file with read/write
+ permissions for the erlang process. Default is <c>undefined</c>.
+ </d>
</type>
<desc>
<p>Sets options to be used for subsequent requests.</p>
diff --git a/lib/inets/src/http_client/httpc.erl b/lib/inets/src/http_client/httpc.erl
index 821eb7f02f..a73503a5ce 100644
--- a/lib/inets/src/http_client/httpc.erl
+++ b/lib/inets/src/http_client/httpc.erl
@@ -171,6 +171,7 @@ request(Method,
HTTPOptions, Options, Profile)
when (Method =:= options) orelse
(Method =:= get) orelse
+ (Method =:= put) orelse
(Method =:= head) orelse
(Method =:= delete) orelse
(Method =:= trace) andalso
@@ -531,6 +532,7 @@ handle_request(Method, Url,
Stream = proplists:get_value(stream, Options),
Receiver = proplists:get_value(receiver, Options),
SocketOpts = proplists:get_value(socket_opts, Options),
+ UnixSocket = proplists:get_value(unix_socket, Options),
BracketedHost = proplists:get_value(ipv6_host_with_brackets,
Options),
@@ -558,6 +560,7 @@ handle_request(Method, Url,
headers_as_is = headers_as_is(Headers0, Options),
socket_opts = SocketOpts,
started = Started,
+ unix_socket = UnixSocket,
ipv6_host_with_brackets = BracketedHost},
case httpc_manager:request(Request, profile_name(Profile)) of
{ok, RequestId} ->
@@ -823,7 +826,7 @@ request_options_defaults() ->
error
end,
- VerifyBrackets = VerifyBoolean,
+ VerifyBrackets = VerifyBoolean,
[
{sync, true, VerifySync},
@@ -894,11 +897,36 @@ request_options_sanity_check(Opts) ->
end,
ok.
-validate_options(Options) ->
- (catch validate_options(Options, [])).
-
-validate_options([], ValidateOptions) ->
- {ok, lists:reverse(ValidateOptions)};
+validate_ipfamily_unix_socket(Options0) ->
+ IpFamily = proplists:get_value(ipfamily, Options0, inet),
+ UnixSocket = proplists:get_value(unix_socket, Options0, undefined),
+ Options1 = proplists:delete(ipfamily, Options0),
+ Options2 = proplists:delete(ipfamily, Options1),
+ validate_ipfamily_unix_socket(IpFamily, UnixSocket, Options2,
+ [{ipfamily, IpFamily}, {unix_socket, UnixSocket}]).
+%%
+validate_ipfamily_unix_socket(local, undefined, _Options, _Acc) ->
+ bad_option(unix_socket, undefined);
+validate_ipfamily_unix_socket(IpFamily, UnixSocket, _Options, _Acc)
+ when IpFamily =/= local, UnixSocket =/= undefined ->
+ bad_option(ipfamily, IpFamily);
+validate_ipfamily_unix_socket(IpFamily, UnixSocket, Options, Acc) ->
+ validate_ipfamily(IpFamily),
+ validate_unix_socket(UnixSocket),
+ {Options, Acc}.
+
+
+validate_options(Options0) ->
+ try
+ {Options, Acc} = validate_ipfamily_unix_socket(Options0),
+ validate_options(Options, Acc)
+ catch
+ error:Reason ->
+ {error, Reason}
+ end.
+%%
+validate_options([], ValidOptions) ->
+ {ok, lists:reverse(ValidOptions)};
validate_options([{proxy, Proxy} = Opt| Tail], Acc) ->
validate_proxy(Proxy),
@@ -958,6 +986,10 @@ validate_options([{verbose, Value} = Opt| Tail], Acc) ->
validate_verbose(Value),
validate_options(Tail, [Opt | Acc]);
+validate_options([{unix_socket, Value} = Opt| Tail], Acc) ->
+ validate_unix_socket(Value),
+ validate_options(Tail, [Opt | Acc]);
+
validate_options([{_, _} = Opt| _], _Acc) ->
{error, {not_an_option, Opt}}.
@@ -1026,7 +1058,8 @@ validate_ipv6(BadValue) ->
bad_option(ipv6, BadValue).
validate_ipfamily(Value)
- when (Value =:= inet) orelse (Value =:= inet6) orelse (Value =:= inet6fb4) ->
+ when (Value =:= inet) orelse (Value =:= inet6) orelse
+ (Value =:= inet6fb4) orelse (Value =:= local) ->
Value;
validate_ipfamily(BadValue) ->
bad_option(ipfamily, BadValue).
@@ -1056,6 +1089,15 @@ validate_verbose(Value)
validate_verbose(BadValue) ->
bad_option(verbose, BadValue).
+validate_unix_socket(Value)
+ when (Value =:= undefined) ->
+ Value;
+validate_unix_socket(Value)
+ when is_list(Value) andalso length(Value) > 0 ->
+ Value;
+validate_unix_socket(BadValue) ->
+ bad_option(unix_socket, BadValue).
+
bad_option(Option, BadValue) ->
throw({error, {bad_option, Option, BadValue}}).
diff --git a/lib/inets/src/http_client/httpc_handler.erl b/lib/inets/src/http_client/httpc_handler.erl
index e398b4f0aa..9b09832eb8 100644
--- a/lib/inets/src/http_client/httpc_handler.erl
+++ b/lib/inets/src/http_client/httpc_handler.erl
@@ -754,6 +754,7 @@ connect(SocketType, ToAddress,
#options{ipfamily = IpFamily,
ip = FromAddress,
port = FromPort,
+ unix_socket = UnixSocket,
socket_opts = Opts0}, Timeout) ->
Opts1 =
case FromPort of
@@ -789,6 +790,16 @@ connect(SocketType, ToAddress,
OK ->
OK
end;
+ local ->
+ Opts3 = [IpFamily | Opts2],
+ SocketAddr = {local, UnixSocket},
+ case http_transport:connect(SocketType, {SocketAddr, 0}, Opts3, Timeout) of
+ {error, Reason} ->
+ {error, {failed_connect, [{to_address, SocketAddr},
+ {IpFamily, Opts3, Reason}]}};
+ Else ->
+ Else
+ end;
_ ->
Opts3 = [IpFamily | Opts2],
case http_transport:connect(SocketType, ToAddress, Opts3, Timeout) of
@@ -800,9 +811,23 @@ connect(SocketType, ToAddress,
end
end.
-connect_and_send_first_request(Address, Request, #state{options = Options} = State) ->
+handle_unix_socket_options(#request{unix_socket = UnixSocket}, Options)
+ when UnixSocket =:= undefined ->
+ Options;
+
+handle_unix_socket_options(#request{unix_socket = UnixSocket},
+ Options = #options{ipfamily = IpFamily}) ->
+ case IpFamily of
+ local ->
+ Options#options{unix_socket = UnixSocket};
+ Else ->
+ error({badarg, [{ipfamily, Else}, {unix_socket, UnixSocket}]})
+ end.
+
+connect_and_send_first_request(Address, Request, #state{options = Options0} = State) ->
SocketType = socket_type(Request),
ConnTimeout = (Request#request.settings)#http_options.connect_timeout,
+ Options = handle_unix_socket_options(Request, Options0),
case connect(SocketType, Address, Options, ConnTimeout) of
{ok, Socket} ->
ClientClose =
@@ -841,9 +866,10 @@ connect_and_send_first_request(Address, Request, #state{options = Options} = Sta
{ok, State#state{request = Request}}
end.
-connect_and_send_upgrade_request(Address, Request, #state{options = Options} = State) ->
+connect_and_send_upgrade_request(Address, Request, #state{options = Options0} = State) ->
ConnTimeout = (Request#request.settings)#http_options.connect_timeout,
SocketType = ip_comm,
+ Options = handle_unix_socket_options(Request, Options0),
case connect(SocketType, Address, Options, ConnTimeout) of
{ok, Socket} ->
SessionType = httpc_manager:session_type(Options),
diff --git a/lib/inets/src/http_client/httpc_internal.hrl b/lib/inets/src/http_client/httpc_internal.hrl
index 5f8c70f28d..c5fe439722 100644
--- a/lib/inets/src/http_client/httpc_internal.hrl
+++ b/lib/inets/src/http_client/httpc_internal.hrl
@@ -83,10 +83,11 @@
max_sessions = ?HTTP_MAX_TCP_SESSIONS,
cookies = disabled, % enabled | disabled | verify
verbose = false, % boolean(),
- ipfamily = inet, % inet | inet6 | inet6fb4
+ ipfamily = inet, % inet | inet6 | inet6fb4 | local
ip = default, % specify local interface
port = default, % specify local port
- socket_opts = [] % other socket options
+ socket_opts = [], % other socket options
+ unix_socket = undefined % Local unix socket
}
).
-type options() :: #options{}.
@@ -115,6 +116,7 @@
% request
timer :: undefined | reference(),
socket_opts, % undefined | [socket_option()]
+ unix_socket, % undefined | string()
ipv6_host_with_brackets % boolean()
}
).
diff --git a/lib/inets/src/http_client/httpc_manager.erl b/lib/inets/src/http_client/httpc_manager.erl
index ffdf1603b3..7b8d7875de 100644
--- a/lib/inets/src/http_client/httpc_manager.erl
+++ b/lib/inets/src/http_client/httpc_manager.erl
@@ -553,7 +553,8 @@ handle_cast({set_options, Options}, State = #state{options = OldOptions}) ->
ip = get_ip(Options, OldOptions),
port = get_port(Options, OldOptions),
verbose = get_verbose(Options, OldOptions),
- socket_opts = get_socket_opts(Options, OldOptions)
+ socket_opts = get_socket_opts(Options, OldOptions),
+ unix_socket = get_unix_socket_opts(Options, OldOptions)
},
case {OldOptions#options.verbose, NewOptions#options.verbose} of
{Same, Same} ->
@@ -963,7 +964,10 @@ get_option(ip, #options{ip = IP}) ->
get_option(port, #options{port = Port}) ->
Port;
get_option(socket_opts, #options{socket_opts = SocketOpts}) ->
- SocketOpts.
+ SocketOpts;
+get_option(unix_socket, #options{unix_socket = UnixSocket}) ->
+ UnixSocket.
+
get_proxy(Opts, #options{proxy = Default}) ->
proplists:get_value(proxy, Opts, Default).
@@ -1016,6 +1020,8 @@ get_verbose(Opts, #options{verbose = Default}) ->
get_socket_opts(Opts, #options{socket_opts = Default}) ->
proplists:get_value(socket_opts, Opts, Default).
+get_unix_socket_opts(Opts, #options{unix_socket = Default}) ->
+ proplists:get_value(unix_socket, Opts, Default).
handle_verbose(debug) ->
dbg:p(self(), [call]),
diff --git a/lib/inets/src/http_lib/http_uri.erl b/lib/inets/src/http_lib/http_uri.erl
index 7f1ca02014..d02913121c 100644
--- a/lib/inets/src/http_lib/http_uri.erl
+++ b/lib/inets/src/http_lib/http_uri.erl
@@ -61,19 +61,35 @@
scheme_defaults/0,
encode/1, decode/1]).
--export_type([scheme/0, default_scheme_port_number/0]).
+-export_type([uri/0,
+ user_info/0,
+ scheme/0, default_scheme_port_number/0,
+ host/0,
+ path/0,
+ query/0,
+ fragment/0]).
+-type uri() :: string() | binary().
+-type user_info() :: string() | binary().
+-type scheme() :: atom().
+-type host() :: string() | binary().
+-type path() :: string() | binary().
+-type query() :: string() | binary().
+-type fragment() :: string() | binary().
+-type port_number() :: inet:port_number().
+-type default_scheme_port_number() :: port_number().
+-type hex_uri() :: string() | binary(). %% Hexadecimal encoded URI.
+-type maybe_hex_uri() :: string() | binary(). %% A possibly hexadecimal encoded URI.
+
+-type scheme_defaults() :: [{scheme(), default_scheme_port_number()}].
+-type scheme_validation_fun() :: fun((SchemeStr :: string() | binary()) ->
+ valid | {error, Reason :: term()}).
%%%=========================================================================
%%% API
%%%=========================================================================
--type scheme() :: atom().
--type default_scheme_port_number() :: pos_integer().
-
--spec scheme_defaults() ->
- [{scheme(), default_scheme_port_number()}].
-
+-spec scheme_defaults() -> scheme_defaults().
scheme_defaults() ->
[{http, 80},
{https, 443},
@@ -82,9 +98,20 @@ scheme_defaults() ->
{sftp, 22},
{tftp, 69}].
+-type parse_result() ::
+ {scheme(), user_info(), host(), port_number(), path(), query()} |
+ {scheme(), user_info(), host(), port_number(), path(), query(),
+ fragment()}.
+
+-spec parse(uri()) -> {ok, parse_result()} | {error, term()}.
parse(AbsURI) ->
parse(AbsURI, []).
+-spec parse(uri(), [Option]) -> {ok, parse_result()} | {error, term()} when
+ Option :: {ipv6_host_with_brackets, boolean()} |
+ {scheme_defaults, scheme_defaults()} |
+ {fragment, boolean()} |
+ {scheme_validation_fun, scheme_validation_fun() | none}.
parse(AbsURI, Opts) ->
case parse_scheme(AbsURI, Opts) of
{error, Reason} ->
@@ -105,6 +132,7 @@ reserved() ->
$#, $[, $], $<, $>, $\", ${, $}, $|, %"
$\\, $', $^, $%, $ ]).
+-spec encode(uri()) -> hex_uri().
encode(URI) when is_list(URI) ->
Reserved = reserved(),
lists:append([uri_encode(Char, Reserved) || Char <- URI]);
@@ -112,6 +140,7 @@ encode(URI) when is_binary(URI) ->
Reserved = reserved(),
<< <<(uri_encode_binary(Char, Reserved))/binary>> || <<Char>> <= URI >>.
+-spec decode(maybe_hex_uri()) -> uri().
decode(String) when is_list(String) ->
do_decode(String);
decode(String) when is_binary(String) ->
diff --git a/lib/inets/src/inets_app/inets.appup.src b/lib/inets/src/inets_app/inets.appup.src
index e24a4a8694..a86413147c 100644
--- a/lib/inets/src/inets_app/inets.appup.src
+++ b/lib/inets/src/inets_app/inets.appup.src
@@ -18,14 +18,10 @@
%% %CopyrightEnd%
{"%VSN%",
[
- {<<"6.4.5">>, [{load_module, httpc_handler,
- soft_purge, soft_purge, []}]},
{<<"6\\..*">>,[{restart_application, inets}]},
{<<"5\\..*">>,[{restart_application, inets}]}
],
[
- {<<"6.4.5">>, [{load_module, httpc_handler,
- soft_purge, soft_purge, []}]},
{<<"6\\..*">>,[{restart_application, inets}]},
{<<"5\\..*">>,[{restart_application, inets}]}
]
diff --git a/lib/inets/test/http_test_lib.erl b/lib/inets/test/http_test_lib.erl
index 38e9e4976e..4e119cce04 100644
--- a/lib/inets/test/http_test_lib.erl
+++ b/lib/inets/test/http_test_lib.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2015-2015. All Rights Reserved.
+%% Copyright Ericsson AB 2015-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -55,6 +55,25 @@ dummy_server_init(Caller, ip_comm, Inet, Extra) ->
]]},
[], ContentCb, Conf, ListenSocket);
+dummy_server_init(Caller, unix_socket, Inet, Extra) ->
+ ContentCb = proplists:get_value(content_cb, Extra),
+ UnixSocket = proplists:get_value(unix_socket, Extra),
+ SocketAddr = {local, UnixSocket},
+ BaseOpts = [binary, {packet, 0}, {reuseaddr,true}, {active, false}, {nodelay, true},
+ {ifaddr, SocketAddr}],
+ Conf = proplists:get_value(conf, Extra),
+ {ok, ListenSocket} = gen_tcp:listen(0, [Inet | BaseOpts]),
+ {ok, Port} = inet:port(ListenSocket),
+ Caller ! {port, Port},
+ dummy_ipcomm_server_loop({httpd_request, parse, [[{max_uri, ?HTTP_MAX_URI_SIZE},
+ {max_header, ?HTTP_MAX_HEADER_SIZE},
+ {max_version,?HTTP_MAX_VERSION_STRING},
+ {max_method, ?HTTP_MAX_METHOD_STRING},
+ {max_content_length, ?HTTP_MAX_CONTENT_LENGTH},
+ {customize, httpd_custom}
+ ]]},
+ [], ContentCb, Conf, ListenSocket);
+
dummy_server_init(Caller, ssl, Inet, Extra) ->
ContentCb = proplists:get_value(content_cb, Extra),
SSLOptions = proplists:get_value(ssl, Extra),
diff --git a/lib/inets/test/httpc_SUITE.erl b/lib/inets/test/httpc_SUITE.erl
index 4bb449408f..38705372c9 100644
--- a/lib/inets/test/httpc_SUITE.erl
+++ b/lib/inets/test/httpc_SUITE.erl
@@ -37,6 +37,10 @@
-define(TLS_URL_START, "https://").
-define(NOT_IN_USE_PORT, 8997).
+%% Using hardcoded file path to keep it below 107 charaters
+%% (maximum length supported by erlang)
+-define(UNIX_SOCKET, "/tmp/inets_httpc_SUITE.sock").
+
-record(sslsocket, {fd = nil, pid = nil}).
%%--------------------------------------------------------------------
%% Common Test interface functions -----------------------------------
@@ -51,6 +55,7 @@ all() ->
{group, http},
{group, sim_http},
{group, http_internal},
+ {group, http_unix_socket},
{group, https},
{group, sim_https},
{group, misc}
@@ -64,6 +69,7 @@ groups() ->
%% will fail.
{sim_http, [], only_simulated() ++ [process_leak_on_keepalive]},
{http_internal, [], real_requests_esi()},
+ {http_unix_socket, [], simulated_unix_socket()},
{https, [], real_requests()},
{sim_https, [], only_simulated()},
{misc, [], misc()}
@@ -102,6 +108,9 @@ real_requests()->
real_requests_esi() ->
[slow_connection].
+simulated_unix_socket() ->
+ [unix_domain_socket].
+
only_simulated() ->
[
cookie,
@@ -187,15 +196,29 @@ init_per_group(Group, Config0) when Group =:= sim_https; Group =:= https->
_:_ ->
{skip, "Crypto did not start"}
end;
-
+init_per_group(http_unix_socket = Group, Config0) ->
+ case os:type() of
+ {win32,_} ->
+ {skip, "Unix Domain Sockets are not supported on Windows"};
+ _ ->
+ file:delete(?UNIX_SOCKET),
+ start_apps(Group),
+ Config = proplists:delete(port, Config0),
+ Port = server_start(Group, server_config(Group, Config)),
+ [{port, Port} | Config]
+ end;
init_per_group(Group, Config0) ->
start_apps(Group),
Config = proplists:delete(port, Config0),
Port = server_start(Group, server_config(Group, Config)),
[{port, Port} | Config].
+end_per_group(http_unix_socket,_Config) ->
+ file:delete(?UNIX_SOCKET),
+ ok;
end_per_group(_, _Config) ->
ok.
+
do_init_per_group(Group, Config0) ->
Config = proplists:delete(port, Config0),
Port = server_start(Group, server_config(Group, Config)),
@@ -1268,6 +1291,21 @@ slow_connection(Config) when is_list(Config) ->
%% in httpc_handler.
{ok, _} = httpc:request(post, Request, [], []).
+%%-------------------------------------------------------------------------
+unix_domain_socket() ->
+ [{"doc, Test HTTP requests over unix domain sockets"}].
+unix_domain_socket(Config) when is_list(Config) ->
+
+ URL = "http:///v1/kv/foo",
+
+ {ok,[{unix_socket,?UNIX_SOCKET}]} =
+ httpc:get_options([unix_socket]),
+ {ok, {{_,200,_}, [_ | _], _}}
+ = httpc:request(put, {URL, [], [], ""}, [], []),
+ {ok, {{_,200,_}, [_ | _], _}}
+ = httpc:request(get, {URL, []}, [], []).
+
+
%%--------------------------------------------------------------------
%% Internal Functions ------------------------------------------------
@@ -1383,19 +1421,28 @@ group_name(Config) ->
server_start(sim_http, _) ->
Inet = inet_version(),
- ok = httpc:set_options([{ipfamily, Inet}]),
+ ok = httpc:set_options([{ipfamily, Inet},{unix_socket, undefined}]),
{_Pid, Port} = http_test_lib:dummy_server(ip_comm, Inet, [{content_cb, ?MODULE}]),
Port;
server_start(sim_https, SslConfig) ->
Inet = inet_version(),
- ok = httpc:set_options([{ipfamily, Inet}]),
+ ok = httpc:set_options([{ipfamily, Inet},{unix_socket, undefined}]),
{_Pid, Port} = http_test_lib:dummy_server(ssl, Inet, [{ssl, SslConfig}, {content_cb, ?MODULE}]),
Port;
+server_start(http_unix_socket, Config) ->
+ Inet = local,
+ Socket = proplists:get_value(unix_socket, Config),
+ ok = httpc:set_options([{ipfamily, Inet},{unix_socket, Socket}]),
+ {_Pid, Port} = http_test_lib:dummy_server(unix_socket, Inet, [{content_cb, ?MODULE},
+ {unix_socket, Socket}]),
+ Port;
+
server_start(_, HttpdConfig) ->
{ok, Pid} = inets:start(httpd, HttpdConfig),
Serv = inets:services_info(),
+ ok = httpc:set_options([{ipfamily, inet_version()},{unix_socket, undefined}]),
{value, {_, _, Info}} = lists:keysearch(Pid, 2, Serv),
proplists:get_value(port, Info).
@@ -1425,6 +1472,10 @@ server_config(https, Config) ->
[{socket_type, {essl, ssl_config(Config)}} | server_config(http, Config)];
server_config(sim_https, Config) ->
ssl_config(Config);
+server_config(http_unix_socket, _Config) ->
+ Socket = ?UNIX_SOCKET,
+ [{unix_socket, Socket}];
+
server_config(_, _) ->
[].
@@ -2169,6 +2220,19 @@ handle_uri(_,"/delay_close.html",_,_,Socket,_) ->
handle_uri("HEAD",_,_,_,_,_) ->
"HTTP/1.1 200 ok\r\n" ++
"Content-Length:0\r\n\r\n";
+handle_uri("PUT","/v1/kv/foo",_,_,_,_) ->
+ "HTTP/1.1 200 OK\r\n" ++
+ "Date: Tue, 20 Feb 2018 14:39:08 GMT\r\n" ++
+ "Content-Length: 5\r\n\r\n" ++
+ "Content-Type: application/json\r\n\r\n" ++
+ "true\n";
+handle_uri("GET","/v1/kv/foo",_,_,_,_) ->
+ "HTTP/1.1 200 OK\r\n" ++
+ "Date: Tue, 20 Feb 2018 14:39:08 GMT\r\n" ++
+ "Content-Length: 24\r\n" ++
+ "Content-Type: application/json\r\n\r\n" ++
+ "[{\"Value\": \"aGVsbG8=\"}]\n";
+
handle_uri(_,_,_,_,_,DefaultResponse) ->
DefaultResponse.
diff --git a/lib/inets/vsn.mk b/lib/inets/vsn.mk
index dccdbfa94a..1fad9afe33 100644
--- a/lib/inets/vsn.mk
+++ b/lib/inets/vsn.mk
@@ -19,6 +19,6 @@
# %CopyrightEnd%
APPLICATION = inets
-INETS_VSN = 6.4.6
+INETS_VSN = 6.5
PRE_VSN =
APP_VSN = "$(APPLICATION)-$(INETS_VSN)$(PRE_VSN)"
diff --git a/lib/kernel/doc/src/inet.xml b/lib/kernel/doc/src/inet.xml
index abb045b744..9552332948 100644
--- a/lib/kernel/doc/src/inet.xml
+++ b/lib/kernel/doc/src/inet.xml
@@ -4,7 +4,7 @@
<erlref>
<header>
<copyright>
- <year>1997</year><year>2017</year>
+ <year>1997</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -277,9 +277,7 @@ fe80::204:acff:fe17:bf38
<p>Returns a <c>hostent</c> record for the host with the specified
hostname.</p>
<p>If resolver option <c>inet6</c> is <c>true</c>,
- an IPv6 address is looked up. If that fails,
- the IPv4 address is looked up and returned on
- IPv6-mapped IPv4 format.</p>
+ an IPv6 address is looked up.</p>
</desc>
</func>
@@ -582,6 +580,19 @@ get_tcpi_sacked(Sock) ->
</func>
<func>
+ <name name="ipv4_mapped_ipv6_address" arity="1" />
+ <fsummary>Convert to and from IPv4-mapped IPv6 address.</fsummary>
+ <desc>
+ <p>
+ Convert an IPv4 address to an IPv4-mapped IPv6 address
+ or the reverse. When converting from an IPv6 address
+ all but the 2 low words are ignored so this function also
+ works on some other types of addresses than IPv4-mapped.
+ </p>
+ </desc>
+ </func>
+
+ <func>
<name name="parse_strict_address" arity="1" />
<fsummary>Parse an IPv4 or IPv6 address strict.</fsummary>
<desc>
diff --git a/lib/kernel/doc/src/inet_res.xml b/lib/kernel/doc/src/inet_res.xml
index 3454e3c6f9..351d86a93a 100644
--- a/lib/kernel/doc/src/inet_res.xml
+++ b/lib/kernel/doc/src/inet_res.xml
@@ -4,7 +4,7 @@
<erlref>
<header>
<copyright>
- <year>2009</year><year>2015</year>
+ <year>2009</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -230,9 +230,7 @@ inet_dns:record_type(_) -> undefined.</pre>
<seealso marker="#getbyname/2"><c>getbyname/2,3</c></seealso>.
</p>
<p>If resolver option <c>inet6</c> is <c>true</c>,
- an IPv6 address is looked up. If that fails,
- the IPv4 address is looked up and returned on
- IPv6-mapped IPv4 format.</p>
+ an IPv6 address is looked up.</p>
</desc>
</func>
diff --git a/lib/kernel/doc/src/rpc.xml b/lib/kernel/doc/src/rpc.xml
index adec2d9520..fab616e630 100644
--- a/lib/kernel/doc/src/rpc.xml
+++ b/lib/kernel/doc/src/rpc.xml
@@ -4,7 +4,7 @@
<erlref>
<header>
<copyright>
- <year>1996</year><year>2016</year>
+ <year>1996</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -217,7 +217,7 @@
<list type="bulleted">
<item>A list of the nodes that do not exist</item>
<item>A list of the nodes where the server does not exist</item>
- <item>A list of the nodes where the server terminatd before sending
+ <item>A list of the nodes where the server terminated before sending
any reply.</item>
</list>
</desc>
@@ -268,8 +268,9 @@
on the specified nodes and collects the answers. It returns
<c>{<anno>ResL</anno>, <anno>BadNodes</anno>}</c>, where
<c><anno>BadNodes</anno></c> is a list
- of the nodes that terminated or timed out during computation,
- and <c><anno>ResL</anno></c> is a list of the return values.
+ of the nodes that do not exist,
+ and <c><anno>ResL</anno></c> is a list of the return values,
+ or <c>{badrpc, <anno>Reason</anno>}</c> for failing calls.
<c><anno>Timeout</anno></c> is a time (integer) in milliseconds, or
<c>infinity</c>.</p>
<p>The following example is useful when new object code is to
@@ -347,7 +348,7 @@
<func>
<name name="pmap" arity="3"/>
- <fsummary>Parallell evaluation of mapping a function over a
+ <fsummary>Parallel evaluation of mapping a function over a
list.</fsummary>
<desc>
<p>Evaluates <c>apply(<anno>Module</anno>, <anno>Function</anno>,
diff --git a/lib/kernel/src/inet.erl b/lib/kernel/src/inet.erl
index fe91b0d33e..4bad523dff 100644
--- a/lib/kernel/src/inet.erl
+++ b/lib/kernel/src/inet.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2017. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -34,7 +34,8 @@
ip/1, stats/0, options/0,
pushf/3, popf/1, close/1, gethostname/0, gethostname/1,
parse_ipv4_address/1, parse_ipv6_address/1, parse_ipv4strict_address/1,
- parse_ipv6strict_address/1, parse_address/1, parse_strict_address/1, ntoa/1]).
+ parse_ipv6strict_address/1, parse_address/1, parse_strict_address/1,
+ ntoa/1, ipv4_mapped_ipv6_address/1]).
-export([connect_options/2, listen_options/2, udp_options/2, sctp_options/2]).
-export([udp_module/1, tcp_module/1, tcp_module/2, sctp_module/1]).
@@ -675,6 +676,14 @@ parse_address(Addr) ->
parse_strict_address(Addr) ->
inet_parse:strict_address(Addr).
+-spec ipv4_mapped_ipv6_address(ip_address()) -> ip_address().
+ipv4_mapped_ipv6_address({D1,D2,D3,D4})
+ when (D1 bor D2 bor D3 bor D4) < 256 ->
+ {0,0,0,0,0,16#ffff,(D1 bsl 8) bor D2,(D3 bsl 8) bor D4};
+ipv4_mapped_ipv6_address({D1,D2,D3,D4,D5,D6,D7,D8})
+ when (D1 bor D2 bor D3 bor D4 bor D5 bor D6 bor D7 bor D8) < 65536 ->
+ {D7 bsr 8,D7 band 255,D8 bsr 8,D8 band 255}.
+
%% Return a list of available options
options() ->
[
@@ -1244,9 +1253,7 @@ gethostbyname_string(Name, Type)
inet ->
inet_parse:ipv4_address(Name);
inet6 ->
- %% XXX should we really translate IPv4 addresses here
- %% even if we do not know if this host can do IPv6?
- inet_parse:ipv6_address(Name)
+ inet_parse:ipv6strict_address(Name)
end of
{ok,IP} ->
{ok,make_hostent(Name, [IP], [], Type)};
diff --git a/lib/kernel/src/inet_hosts.erl b/lib/kernel/src/inet_hosts.erl
index 0bdf00ac30..fc653bf0d3 100644
--- a/lib/kernel/src/inet_hosts.erl
+++ b/lib/kernel/src/inet_hosts.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -72,9 +72,6 @@ gethostbyname(Name, Type, Byname, Byaddr) ->
gethostbyaddr({A,B,C,D}=IP) when ?ip(A,B,C,D) ->
gethostbyaddr(IP, inet);
-%% ipv4 only ipv6 address
-gethostbyaddr({0,0,0,0,0,16#ffff=F,G,H}) when ?ip6(0,0,0,0,0,F,G,H) ->
- gethostbyaddr({G bsr 8, G band 255, H bsr 8, H band 255});
gethostbyaddr({A,B,C,D,E,F,G,H}=IP) when ?ip6(A,B,C,D,E,F,G,H) ->
gethostbyaddr(IP, inet6);
gethostbyaddr(Addr) when is_list(Addr) ->
diff --git a/lib/kernel/src/inet_res.erl b/lib/kernel/src/inet_res.erl
index 49aa5f8bda..6454802b04 100644
--- a/lib/kernel/src/inet_res.erl
+++ b/lib/kernel/src/inet_res.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -349,9 +349,6 @@ gethostbyaddr_tm({A,B,C,D} = IP, Timer) when ?ip(A,B,C,D) ->
{ok, HEnt} -> {ok, HEnt};
_ -> res_gethostbyaddr(dn_in_addr_arpa(A,B,C,D), IP, Timer)
end;
-%% ipv4 only ipv6 address
-gethostbyaddr_tm({0,0,0,0,0,16#ffff,G,H},Timer) when is_integer(G+H) ->
- gethostbyaddr_tm({G div 256, G rem 256, H div 256, H rem 256},Timer);
gethostbyaddr_tm({A,B,C,D,E,F,G,H} = IP, Timer) when ?ip6(A,B,C,D,E,F,G,H) ->
inet_db:res_update_conf(),
case inet_db:gethostbyaddr(IP) of
@@ -431,28 +428,7 @@ gethostbyname(Name,Family,Timeout) ->
gethostbyname_tm(Name,inet,Timer) ->
getbyname_tm(Name,?S_A,Timer);
gethostbyname_tm(Name,inet6,Timer) ->
- case getbyname_tm(Name,?S_AAAA,Timer) of
- {ok,HEnt} -> {ok,HEnt};
- {error,nxdomain} ->
- case getbyname_tm(Name, ?S_A,Timer) of
- {ok, HEnt} ->
- %% rewrite to a ipv4 only ipv6 address
- {ok,
- HEnt#hostent {
- h_addrtype = inet6,
- h_length = 16,
- h_addr_list =
- lists:map(
- fun({A,B,C,D}) ->
- {0,0,0,0,0,16#ffff,A*256+B,C*256+D}
- end, HEnt#hostent.h_addr_list)
- }};
- Error ->
- Error
- end;
- Error ->
- Error
- end;
+ getbyname_tm(Name,?S_AAAA,Timer);
gethostbyname_tm(_Name, _Family, _Timer) ->
{error, einval}.
diff --git a/lib/kernel/src/rpc.erl b/lib/kernel/src/rpc.erl
index 0e0b7dffa3..b04aa9030b 100644
--- a/lib/kernel/src/rpc.erl
+++ b/lib/kernel/src/rpc.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2017. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -498,7 +498,7 @@ start_monitor(Node, Name) ->
Module :: module(),
Function :: atom(),
Args :: [term()],
- ResL :: [term()],
+ ResL :: [Res :: term() | {'badrpc', Reason :: term()}],
BadNodes :: [node()].
multicall(M, F, A) ->
@@ -509,14 +509,14 @@ multicall(M, F, A) ->
Module :: module(),
Function :: atom(),
Args :: [term()],
- ResL :: [term()],
+ ResL :: [Res :: term() | {'badrpc', Reason :: term()}],
BadNodes :: [node()];
(Module, Function, Args, Timeout) -> {ResL, BadNodes} when
Module :: module(),
Function :: atom(),
Args :: [term()],
Timeout :: timeout(),
- ResL :: [term()],
+ ResL :: [Res :: term() | {'badrpc', Reason :: term()}],
BadNodes :: [node()].
multicall(Nodes, M, F, A) when is_list(Nodes) ->
@@ -531,7 +531,7 @@ multicall(M, F, A, Timeout) ->
Function :: atom(),
Args :: [term()],
Timeout :: timeout(),
- ResL :: [term()],
+ ResL :: [Res :: term() | {'badrpc', Reason :: term()}],
BadNodes :: [node()].
multicall(Nodes, M, F, A, infinity)
diff --git a/lib/kernel/test/inet_SUITE.erl b/lib/kernel/test/inet_SUITE.erl
index ba0d075ef2..2e5f8c7d2c 100644
--- a/lib/kernel/test/inet_SUITE.erl
+++ b/lib/kernel/test/inet_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2017. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -40,7 +40,8 @@
lookup_bad_search_option/1,
getif/1,
getif_ifr_name_overflow/1,getservbyname_overflow/1, getifaddrs/1,
- parse_strict_address/1, simple_netns/1, simple_netns_open/1,
+ parse_strict_address/1, ipv4_mapped_ipv6_address/1,
+ simple_netns/1, simple_netns_open/1,
simple_bind_to_device/1, simple_bind_to_device_open/1]).
-export([get_hosts/1, get_ipv6_hosts/1, parse_hosts/1, parse_address/1,
@@ -667,6 +668,26 @@ parse_strict_address(Config) when is_list(Config) ->
{ok, {3089,3106,23603,50240,0,0,119,136}} =
inet:parse_strict_address("c11:0c22:5c33:c440::077:0088").
+ipv4_mapped_ipv6_address(Config) when is_list(Config) ->
+ {D1,D2,D3,D4} = IPv4Address =
+ {rand:uniform(256) - 1,
+ rand:uniform(256) - 1,
+ rand:uniform(256) - 1,
+ rand:uniform(256) - 1},
+ E7 = (D1 bsl 8) bor D2,
+ E8 = (D3 bsl 8) bor D4,
+ io:format("IPv4Address: ~p.~n", [IPv4Address]),
+ {0,0,0,0,0,65535,E7,E8} = inet:ipv4_mapped_ipv6_address(IPv4Address),
+ IPv6Address =
+ {rand:uniform(65536) - 1,
+ rand:uniform(65536) - 1,
+ rand:uniform(65536) - 1,
+ rand:uniform(65536) - 1,
+ rand:uniform(65536) - 1,
+ rand:uniform(65536) - 1, E7, E8},
+ IPv4Address = inet:ipv4_mapped_ipv6_address(IPv6Address),
+ ok.
+
t_gethostnative(Config) when is_list(Config) ->
%% this will result in 26 bytes sent which causes problem in Windows
%% if the port-program has not assured stdin to be read in BINARY mode
diff --git a/lib/sasl/doc/src/release_handler.xml b/lib/sasl/doc/src/release_handler.xml
index 8f073807fb..975188f489 100644
--- a/lib/sasl/doc/src/release_handler.xml
+++ b/lib/sasl/doc/src/release_handler.xml
@@ -61,6 +61,7 @@
<list type="bulleted">
<item>A release upgrade file, <c>relup</c></item>
<item>A system configuration file, <c>sys.config</c></item>
+ <item>A system configuration source file, <c>sys.config.src</c></item>
</list>
<p>The <c>relup</c> file contains instructions for how to upgrade
to, or downgrade from, this version of the release.</p>
@@ -819,4 +820,3 @@ release_handler:set_unpacked(RelFile, [{myapp,"1.0","/home/user"},...]).
<seealso marker="systools"><c>systools(3)</c></seealso></p>
</section>
</erlref>
-
diff --git a/lib/sasl/doc/src/systools.xml b/lib/sasl/doc/src/systools.xml
index e7c3c499da..4842c732b1 100644
--- a/lib/sasl/doc/src/systools.xml
+++ b/lib/sasl/doc/src/systools.xml
@@ -349,10 +349,11 @@ myapp-1/ebin/myapp.app
the release version as specified in <c>Name.rel</c>.</p>
<p><c>releases/RelVsn</c> contains the boot script
<c>Name.boot</c> renamed to <c>start.boot</c> and, if found,
- the files <c>relup</c> and <c>sys.config</c>. These files
+ the files <c>relup</c> and <c>sys.config</c> or <c>sys.config.src</c>. These files
are searched for in the same directory as <c>Name.rel</c>,
in the current working directory, and in any directories
- specified using option <c>path</c>.</p>
+ specified using option <c>path</c>. In the case of <c>sys.config</c>
+ it is not included if <c>sys.config.src</c> is found.</p>
<p>If the release package is to contain a new Erlang runtime
system, the <c>bin</c> directory of the specified runtime
system <c>{erts,Dir}</c> is copied to <c>erts-ErtsVsn/bin</c>.</p>
@@ -397,4 +398,3 @@ myapp-1/ebin/myapp.app
<seealso marker="script"><c>script(4)</c></seealso></p>
</section>
</erlref>
-
diff --git a/lib/sasl/src/systools_make.erl b/lib/sasl/src/systools_make.erl
index 9d960b7361..fa3182cc08 100644
--- a/lib/sasl/src/systools_make.erl
+++ b/lib/sasl/src/systools_make.erl
@@ -310,6 +310,7 @@ add_apply_upgrade(Script,Args) ->
%% RelVsn/start.boot
%% relup
%% sys.config
+%% sys.config.src
%% erts-EVsn[/bin]
%%-----------------------------------------------------------------
@@ -1552,6 +1553,7 @@ create_kernel_procs(Appls) ->
%% RelVsn/start.boot
%% relup
%% sys.config
+%% sys.config.src
%% erts-EVsn[/bin]
%%
%% The VariableN.tar.gz files can also be stored as own files not
@@ -1707,14 +1709,18 @@ add_system_files(Tar, RelName, Release, Path1) ->
add_to_tar(Tar, Relup, filename:join(RelVsnDir, "relup"))
end,
- case lookup_file("sys.config", Path) of
- false ->
- ignore;
- Sys ->
- check_sys_config(Sys),
- add_to_tar(Tar, Sys, filename:join(RelVsnDir, "sys.config"))
+ case lookup_file("sys.config.src", Path) of
+ false ->
+ case lookup_file("sys.config", Path) of
+ false ->
+ ignore;
+ Sys ->
+ check_sys_config(Sys),
+ add_to_tar(Tar, Sys, filename:join(RelVsnDir, "sys.config"))
+ end;
+ SysSrc ->
+ add_to_tar(Tar, SysSrc, filename:join(RelVsnDir, "sys.config.src"))
end,
-
ok.
lookup_file(Name, [Dir|Path]) ->
diff --git a/lib/sasl/test/systools_SUITE.erl b/lib/sasl/test/systools_SUITE.erl
index 07748d975f..c8b2f31120 100644
--- a/lib/sasl/test/systools_SUITE.erl
+++ b/lib/sasl/test/systools_SUITE.erl
@@ -67,7 +67,7 @@ groups() ->
otp_3065_circular_dependenies, included_and_used_sort_script]},
{tar, [],
[tar_options, normal_tar, no_mod_vsn_tar, system_files_tar,
- invalid_system_files_tar, variable_tar,
+ system_src_file_tar, invalid_system_files_tar, variable_tar,
src_tests_tar, var_tar, exref_tar, link_tar, no_sasl_tar,
otp_9507_path_ebin]},
{relup, [],
@@ -945,12 +945,47 @@ system_files_tar(Config) ->
ok.
+
system_files_tar(cleanup,Config) ->
Dir = ?privdir,
file:delete(filename:join(Dir,"sys.config")),
file:delete(filename:join(Dir,"relup")),
ok.
+%% make_tar: Check that sys.config.src and not sys.config is included
+system_src_file_tar(Config) ->
+ {ok, OldDir} = file:get_cwd(),
+
+ {LatestDir, LatestName} = create_script(latest,Config),
+
+ DataDir = filename:absname(?copydir),
+ LibDir = fname([DataDir, d_normal, lib]),
+ P = [fname([LibDir, 'db-2.1', ebin]),
+ fname([LibDir, 'fe-3.1', ebin])],
+
+ ok = file:set_cwd(LatestDir),
+
+ %% Add dummy sys.config and sys.config.src
+ ok = file:write_file("sys.config.src","[${SOMETHING}].\n"),
+ ok = file:write_file("sys.config","[].\n"),
+
+ {ok, _, _} = systools:make_script(LatestName, [silent, {path, P}]),
+ ok = systools:make_tar(LatestName, [{path, P}]),
+ ok = check_tar(fname(["releases","LATEST","sys.config.src"]), LatestName),
+ {error, _} = check_tar(fname(["releases","LATEST","sys.config"]), LatestName),
+ {ok, _, _} = systools:make_tar(LatestName, [{path, P}, silent]),
+ ok = check_tar(fname(["releases","LATEST","sys.config.src"]), LatestName),
+ {error, _} = check_tar(fname(["releases","LATEST","sys.config"]), LatestName),
+
+ ok = file:set_cwd(OldDir),
+
+ ok.
+
+system_src_file_tar(cleanup,Config) ->
+ Dir = ?privdir,
+ file:delete(filename:join(Dir,"sys.config")),
+ file:delete(filename:join(Dir,"sys.config.src")),
+ ok.
%% make_tar: Check that make_tar fails if relup or sys.config exist
%% but do not have valid content
diff --git a/lib/ssh/doc/src/notes.xml b/lib/ssh/doc/src/notes.xml
index df2e04c92a..f5cb3ec254 100644
--- a/lib/ssh/doc/src/notes.xml
+++ b/lib/ssh/doc/src/notes.xml
@@ -95,7 +95,6 @@
</list>
</section>
-
<section><title>Improvements and New Features</title>
<list>
<item>
@@ -125,7 +124,6 @@
</section>
<section><title>Ssh 4.6.2</title>
-
<section><title>Fixed Bugs and Malfunctions</title>
<list>
<item>
@@ -421,6 +419,24 @@
</section>
+<section><title>Ssh 4.4.2.1</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Trailing white space was removed at end of the
+ hello-string. This caused interoperability problems with
+ some other ssh-implementations (e.g OpenSSH 7.3p1 on
+ Solaris 11)</p>
+ <p>
+ Own Id: OTP-14763 Aux Id: ERIERL-74 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>Ssh 4.4.2</title>
<section><title>Fixed Bugs and Malfunctions</title>
@@ -791,6 +807,93 @@
</section>
+<section><title>Ssh 4.2.2.5</title>
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p>
+ Default exec is disabled when a user-defined shell is
+ enabled.</p>
+ <p>
+ Own Id: OTP-14881</p>
+ </item>
+ </list>
+ </section>
+</section>
+
+
+<section><title>Ssh 4.2.2.4</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Trailing white space was removed at end of the
+ hello-string. This caused interoperability problems with
+ some other ssh-implementations (e.g OpenSSH 7.3p1 on
+ Solaris 11)</p>
+ <p>
+ Own Id: OTP-14763 Aux Id: ERIERL-74 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Ssh 4.2.2.3</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ The key exchange algorithm
+ diffie-hellman-group-exchange-sha* has a server-option
+ <c>{dh_gex_limits,{Min,Max}}</c>. There was a hostkey
+ signature validation error on the client side if the
+ option was used and the <c>Min</c> or the <c>Max</c>
+ differed from the corresponding values obtained from the
+ client.</p>
+ <p>
+ This bug is now corrected.</p>
+ <p>
+ Own Id: OTP-14166</p>
+ </item>
+ </list>
+ </section>
+
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p>
+ Key exchange algorithms
+ diffie-hellman-group-exchange-sha* optimized, up to a
+ factor of 11 for the slowest ( = biggest and safest) one.</p>
+ <p>
+ Own Id: OTP-14169 Aux Id: seq-13261 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Ssh 4.2.2.2</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Upgrade of an established client connection could crash
+ because the ssh client supervisors children had wrong
+ type. This is fixed now.</p>
+ <p>
+ Own Id: OTP-13782 Aux Id: seq13158 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>Ssh 4.2.2.1</title>
<section><title>Fixed Bugs and Malfunctions</title>
diff --git a/lib/ssh/src/ssh.erl b/lib/ssh/src/ssh.erl
index 032d87bdad..25d537c624 100644
--- a/lib/ssh/src/ssh.erl
+++ b/lib/ssh/src/ssh.erl
@@ -184,7 +184,6 @@ channel_info(ConnectionRef, ChannelId, Options) ->
daemon(Port) ->
daemon(Port, []).
-
daemon(Socket, UserOptions) when is_port(Socket) ->
try
#{} = Options = ssh_options:handle_options(server, UserOptions),
@@ -267,8 +266,6 @@ daemon(Host0, Port0, UserOptions0) when 0 =< Port0, Port0 =< 65535,
daemon(_, _, _) ->
{error, badarg}.
-
-
%%--------------------------------------------------------------------
-spec daemon_info(daemon_ref()) -> ok_error( [{atom(), term()}] ).
diff --git a/lib/ssh/src/ssh_connection_handler.erl b/lib/ssh/src/ssh_connection_handler.erl
index c8ac3a9c04..e11d3adee4 100644
--- a/lib/ssh/src/ssh_connection_handler.erl
+++ b/lib/ssh/src/ssh_connection_handler.erl
@@ -1174,17 +1174,25 @@ handle_event({call,_}, _, StateName, _) when not ?CONNECTED(StateName) ->
handle_event({call,From}, {request, ChannelPid, ChannelId, Type, Data, Timeout}, StateName, D0)
when ?CONNECTED(StateName) ->
- D = handle_request(ChannelPid, ChannelId, Type, Data, true, From, D0),
- %% Note reply to channel will happen later when reply is recived from peer on the socket
- start_channel_request_timer(ChannelId, From, Timeout),
- {keep_state, cache_request_idle_timer_check(D)};
+ case handle_request(ChannelPid, ChannelId, Type, Data, true, From, D0) of
+ {error,Error} ->
+ {keep_state, D0, {reply,From,{error,Error}}};
+ D ->
+ %% Note reply to channel will happen later when reply is recived from peer on the socket
+ start_channel_request_timer(ChannelId, From, Timeout),
+ {keep_state, cache_request_idle_timer_check(D)}
+ end;
handle_event({call,From}, {request, ChannelId, Type, Data, Timeout}, StateName, D0)
when ?CONNECTED(StateName) ->
- D = handle_request(ChannelId, Type, Data, true, From, D0),
- %% Note reply to channel will happen later when reply is recived from peer on the socket
- start_channel_request_timer(ChannelId, From, Timeout),
- {keep_state, cache_request_idle_timer_check(D)};
+ case handle_request(ChannelId, Type, Data, true, From, D0) of
+ {error,Error} ->
+ {keep_state, D0, {reply,From,{error,Error}}};
+ D ->
+ %% Note reply to channel will happen later when reply is recived from peer on the socket
+ start_channel_request_timer(ChannelId, From, Timeout),
+ {keep_state, cache_request_idle_timer_check(D)}
+ end;
handle_event({call,From}, {data, ChannelId, Type, Data, Timeout}, StateName, D0)
when ?CONNECTED(StateName) ->
@@ -1773,21 +1781,31 @@ is_usable_user_pubkey(A, Ssh) ->
%%%----------------------------------------------------------------
handle_request(ChannelPid, ChannelId, Type, Data, WantReply, From, D) ->
case ssh_channel:cache_lookup(cache(D), ChannelId) of
- #channel{remote_id = Id} = Channel ->
+ #channel{remote_id = Id,
+ sent_close = false} = Channel ->
update_sys(cache(D), Channel, Type, ChannelPid),
send_msg(ssh_connection:channel_request_msg(Id, Type, WantReply, Data),
add_request(WantReply, ChannelId, From, D));
- undefined ->
- D
+
+ _ when WantReply==true ->
+ {error,closed};
+
+ _ ->
+ D
end.
handle_request(ChannelId, Type, Data, WantReply, From, D) ->
case ssh_channel:cache_lookup(cache(D), ChannelId) of
- #channel{remote_id = Id} ->
+ #channel{remote_id = Id,
+ sent_close = false} ->
send_msg(ssh_connection:channel_request_msg(Id, Type, WantReply, Data),
add_request(WantReply, ChannelId, From, D));
- undefined ->
- D
+
+ _ when WantReply==true ->
+ {error,closed};
+
+ _ ->
+ D
end.
%%%----------------------------------------------------------------
diff --git a/lib/ssh/test/ssh_connection_SUITE.erl b/lib/ssh/test/ssh_connection_SUITE.erl
index b818a7f45d..9587c0c251 100644
--- a/lib/ssh/test/ssh_connection_SUITE.erl
+++ b/lib/ssh/test/ssh_connection_SUITE.erl
@@ -897,11 +897,22 @@ start_subsystem_on_closed_channel(Config) ->
{user_interaction, false},
{user_dir, UserDir}]),
- {ok, ChannelId} = ssh_connection:session_channel(ConnectionRef, infinity),
- ok = ssh_connection:close(ConnectionRef, ChannelId),
+ {ok, ChannelId1} = ssh_connection:session_channel(ConnectionRef, infinity),
+ ok = ssh_connection:close(ConnectionRef, ChannelId1),
+ {error, closed} = ssh_connection:ptty_alloc(ConnectionRef, ChannelId1, []),
+ {error, closed} = ssh_connection:subsystem(ConnectionRef, ChannelId1, "echo_n", 5000),
+ {error, closed} = ssh_connection:exec(ConnectionRef, ChannelId1, "testing1.\n", 5000),
+ {error, closed} = ssh_connection:send(ConnectionRef, ChannelId1, "exit().\n", 5000),
- {error, closed} = ssh_connection:subsystem(ConnectionRef, ChannelId, "echo_n", infinity),
+ %% Test that there could be a gap between close and an operation (Bugfix OTP-14939):
+ {ok, ChannelId2} = ssh_connection:session_channel(ConnectionRef, infinity),
+ ok = ssh_connection:close(ConnectionRef, ChannelId2),
+ timer:sleep(2000),
+ {error, closed} = ssh_connection:ptty_alloc(ConnectionRef, ChannelId2, []),
+ {error, closed} = ssh_connection:subsystem(ConnectionRef, ChannelId2, "echo_n", 5000),
+ {error, closed} = ssh_connection:exec(ConnectionRef, ChannelId2, "testing1.\n", 5000),
+ {error, closed} = ssh_connection:send(ConnectionRef, ChannelId2, "exit().\n", 5000),
ssh:close(ConnectionRef),
ssh:stop_daemon(Pid).
diff --git a/lib/ssh/vsn.mk b/lib/ssh/vsn.mk
index 6aaa22a6b4..480e955ec4 100644
--- a/lib/ssh/vsn.mk
+++ b/lib/ssh/vsn.mk
@@ -1,5 +1,4 @@
#-*-makefile-*- ; force emacs to enter makefile-mode
SSH_VSN = 4.6.5
-
APP_VSN = "ssh-$(SSH_VSN)"
diff --git a/lib/ssl/doc/src/ssl.xml b/lib/ssl/doc/src/ssl.xml
index 4f72114ae9..7267083e32 100644
--- a/lib/ssl/doc/src/ssl.xml
+++ b/lib/ssl/doc/src/ssl.xml
@@ -264,8 +264,9 @@
<item><p>Specifies if to reject renegotiation attempt that does
not live up to
<url href="http://www.ietf.org/rfc/rfc5746.txt">RFC 5746</url>.
- By default <c>secure_renegotiate</c> is set to <c>false</c>,
- that is, secure renegotiation is used if possible,
+ By default <c>secure_renegotiate</c> is set to <c>true</c>,
+ that is, secure renegotiation is enforced. If set to <c>false</c> secure renegotiation
+ will still be used if possible,
but it falls back to insecure renegotiation if the peer
does not support
<url href="http://www.ietf.org/rfc/rfc5746.txt">RFC 5746</url>.</p>
diff --git a/lib/ssl/src/ssl.erl b/lib/ssl/src/ssl.erl
index 0b035d31be..82f62b51b9 100644
--- a/lib/ssl/src/ssl.erl
+++ b/lib/ssl/src/ssl.erl
@@ -843,7 +843,7 @@ handle_options(Opts0, Role, Host) ->
%% Server side option
reuse_session = handle_option(reuse_session, Opts, ReuseSessionFun),
reuse_sessions = handle_option(reuse_sessions, Opts, true),
- secure_renegotiate = handle_option(secure_renegotiate, Opts, false),
+ secure_renegotiate = handle_option(secure_renegotiate, Opts, true),
client_renegotiation = handle_option(client_renegotiation, Opts,
default_option_role(server, true, Role),
server, Role),
diff --git a/lib/ssl/src/ssl_cipher.erl b/lib/ssl/src/ssl_cipher.erl
index 1d645e5782..a83ce42455 100644
--- a/lib/ssl/src/ssl_cipher.erl
+++ b/lib/ssl/src/ssl_cipher.erl
@@ -96,7 +96,7 @@ security_parameters(Version, CipherSuite, SecParams) ->
expanded_key_material_length = expanded_key_material(Cipher),
key_material_length = key_material(Cipher),
iv_size = iv_size(Cipher),
- mac_algorithm = hash_algorithm(Hash),
+ mac_algorithm = mac_algorithm(Hash),
prf_algorithm = prf_algorithm(PrfHashAlg, Version),
hash_size = hash_size(Hash)}.
@@ -2531,6 +2531,11 @@ prf_algorithm(default_prf, {3, _}) ->
prf_algorithm(Algo, _) ->
hash_algorithm(Algo).
+mac_algorithm(aead) ->
+ aead;
+mac_algorithm(Algo) ->
+ hash_algorithm(Algo).
+
hash_algorithm(null) -> ?NULL;
hash_algorithm(md5) -> ?MD5;
hash_algorithm(sha) -> ?SHA; %% Only sha always refers to "SHA-1"
@@ -2561,6 +2566,10 @@ sign_algorithm(Other) when is_integer(Other) andalso ((Other >= 224) and (Other
hash_size(null) ->
0;
+%% The AEAD MAC hash size is not used in the context
+%% of calculating the master secret. See RFC 5246 Section 6.2.3.3.
+hash_size(aead) ->
+ 0;
hash_size(md5) ->
16;
hash_size(sha) ->
diff --git a/lib/ssl/src/ssl_handshake.erl b/lib/ssl/src/ssl_handshake.erl
index 0c55af9174..09160e2f9c 100644
--- a/lib/ssl/src/ssl_handshake.erl
+++ b/lib/ssl/src/ssl_handshake.erl
@@ -774,9 +774,8 @@ decode_suites('3_bytes', Dec) ->
%%====================================================================
available_suites(UserSuites, Version) ->
- lists:filtermap(fun(Suite) ->
- lists:member(Suite, ssl_cipher:all_suites(Version))
- end, UserSuites).
+ VersionSuites = ssl_cipher:all_suites(Version) ++ ssl_cipher:anonymous_suites(Version),
+ lists:filtermap(fun(Suite) -> lists:member(Suite, VersionSuites) end, UserSuites).
available_suites(ServerCert, UserSuites, Version, undefined, Curve) ->
ssl_cipher:filter(ServerCert, available_suites(UserSuites, Version))
@@ -1056,7 +1055,9 @@ select_curve(undefined, _, _) ->
%%
%% Description: Handles signature_algorithms hello extension (server)
%%--------------------------------------------------------------------
-select_hashsign(_, undefined, _, _, _Version) ->
+select_hashsign(_, _, KeyExAlgo, _, _Version) when KeyExAlgo == dh_anon;
+ KeyExAlgo == ecdh_anon;
+ KeyExAlgo == srp_anon ->
{null, anon};
%% The signature_algorithms extension was introduced with TLS 1.2. Ignore it if we have
%% negotiated a lower version.
diff --git a/lib/ssl/test/ssl_basic_SUITE.erl b/lib/ssl/test/ssl_basic_SUITE.erl
index 2781203557..05979d3cfd 100644
--- a/lib/ssl/test/ssl_basic_SUITE.erl
+++ b/lib/ssl/test/ssl_basic_SUITE.erl
@@ -194,6 +194,7 @@ renegotiate_tests() ->
[client_renegotiate,
server_renegotiate,
client_secure_renegotiate,
+ client_secure_renegotiate_fallback,
client_renegotiate_reused_session,
server_renegotiate_reused_session,
client_no_wrap_sequence_number,
@@ -2898,6 +2899,36 @@ client_secure_renegotiate(Config) when is_list(Config) ->
ssl_test_lib:close(Server),
ssl_test_lib:close(Client).
+%%--------------------------------------------------------------------
+client_secure_renegotiate_fallback() ->
+ [{doc,"Test that we can set secure_renegotiate to false that is "
+ "fallback option, we however do not have a insecure server to test against!"}].
+client_secure_renegotiate_fallback(Config) when is_list(Config) ->
+ ServerOpts = ssl_test_lib:ssl_options(server_opts, Config),
+ ClientOpts = ssl_test_lib:ssl_options(client_opts, Config),
+
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+
+ Data = "From erlang to erlang",
+
+ Server =
+ ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {mfa, {?MODULE, erlang_ssl_receive, [Data]}},
+ {options, [{secure_renegotiate, false} | ServerOpts]}]),
+ Port = ssl_test_lib:inet_port(Server),
+
+ Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {mfa, {?MODULE,
+ renegotiate, [Data]}},
+ {options, [{reuse_sessions, false},
+ {secure_renegotiate, false}| ClientOpts]}]),
+
+ ssl_test_lib:check_result(Client, ok, Server, ok),
+ ssl_test_lib:close(Server),
+ ssl_test_lib:close(Client).
%%--------------------------------------------------------------------
server_renegotiate() ->
diff --git a/lib/ssl/test/ssl_engine_SUITE.erl b/lib/ssl/test/ssl_engine_SUITE.erl
index bc221d35fd..71891356e8 100644
--- a/lib/ssl/test/ssl_engine_SUITE.erl
+++ b/lib/ssl/test/ssl_engine_SUITE.erl
@@ -39,23 +39,28 @@ init_per_suite(Config) ->
catch crypto:stop(),
try crypto:start() of
ok ->
- ssl_test_lib:clean_start(),
- case crypto:get_test_engine() of
- {ok, EngineName} ->
- try crypto:engine_load(<<"dynamic">>,
- [{<<"SO_PATH">>, EngineName},
- <<"LOAD">>],
- []) of
- {ok, Engine} ->
- [{engine, Engine} |Config];
- {error, Reason} ->
- ct:pal("Reason ~p", [Reason]),
- {skip, "No dynamic engine support"}
- catch error:notsup ->
- {skip, "No engine support in OpenSSL"}
- end;
- {error, notexist} ->
- {skip, "Test engine not found"}
+ case crypto:info_lib() of
+ [{_,_, <<"OpenSSL 1.0.1s-freebsd 1 Mar 2016">>}] ->
+ {skip, "Problem with engine on OpenSSL 1.0.1s-freebsd"};
+ _ ->
+ ssl_test_lib:clean_start(),
+ case crypto:get_test_engine() of
+ {ok, EngineName} ->
+ try crypto:engine_load(<<"dynamic">>,
+ [{<<"SO_PATH">>, EngineName},
+ <<"LOAD">>],
+ []) of
+ {ok, Engine} ->
+ [{engine, Engine} |Config];
+ {error, Reason} ->
+ ct:pal("Reason ~p", [Reason]),
+ {skip, "No dynamic engine support"}
+ catch error:notsup ->
+ {skip, "No engine support in OpenSSL"}
+ end;
+ {error, notexist} ->
+ {skip, "Test engine not found"}
+ end
end
catch _:_ ->
{skip, "Crypto did not start"}
diff --git a/lib/ssl/test/ssl_to_openssl_SUITE.erl b/lib/ssl/test/ssl_to_openssl_SUITE.erl
index f091c8786e..dcdea6beb5 100644
--- a/lib/ssl/test/ssl_to_openssl_SUITE.erl
+++ b/lib/ssl/test/ssl_to_openssl_SUITE.erl
@@ -70,6 +70,9 @@ all_versions_tests() ->
erlang_server_openssl_client,
erlang_client_openssl_server_dsa_cert,
erlang_server_openssl_client_dsa_cert,
+ erlang_client_openssl_server_anon,
+ erlang_server_openssl_client_anon,
+ erlang_server_openssl_client_anon_with_cert,
erlang_server_openssl_client_reuse_session,
erlang_client_openssl_server_renegotiate,
erlang_client_openssl_server_nowrap_seqnum,
@@ -89,6 +92,9 @@ dtls_all_versions_tests() ->
erlang_server_openssl_client,
erlang_client_openssl_server_dsa_cert,
erlang_server_openssl_client_dsa_cert,
+ erlang_client_openssl_server_anon,
+ erlang_server_openssl_client_anon,
+ erlang_server_openssl_client_anon_with_cert,
erlang_server_openssl_client_reuse_session,
erlang_client_openssl_server_renegotiate,
erlang_client_openssl_server_nowrap_seqnum,
@@ -550,7 +556,121 @@ erlang_server_openssl_client_dsa_cert(Config) when is_list(Config) ->
ssl_test_lib:close_port(OpenSslPort),
process_flag(trap_exit, false).
-%%--------------------------------------------------------------------
+%%--------------------------------------------------------------------
+erlang_client_openssl_server_anon() ->
+ [{doc,"Test erlang client with openssl server, anonymous"}].
+erlang_client_openssl_server_anon(Config) when is_list(Config) ->
+ process_flag(trap_exit, true),
+ %% OpenSSL expects a certificate and key, even if the cipher spec
+ %% is restructed to aNULL, so we use 'server_rsa_opts' here
+ ServerOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config),
+ ClientOpts = ssl_test_lib:ssl_options(client_anon_opts, Config),
+ VersionTuple = ssl_test_lib:protocol_version(Config, tuple),
+ Ciphers = ssl_test_lib:anonymous_suites(VersionTuple),
+
+ {ClientNode, _, Hostname} = ssl_test_lib:run_where(Config),
+
+ Data = "From openssl to erlang",
+
+ Port = ssl_test_lib:inet_port(node()),
+ CertFile = proplists:get_value(certfile, ServerOpts),
+ KeyFile = proplists:get_value(keyfile, ServerOpts),
+ Version = ssl_test_lib:protocol_version(Config),
+ Exe = "openssl",
+ Args = ["s_server", "-accept", integer_to_list(Port),
+ ssl_test_lib:version_flag(Version),
+ "-cert", CertFile, "-key", KeyFile,
+ "-cipher", "aNULL", "-msg"],
+
+ OpensslPort = ssl_test_lib:portable_open_port(Exe, Args),
+
+ ssl_test_lib:wait_for_openssl_server(Port, proplists:get_value(protocol, Config)),
+
+ Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {mfa, {?MODULE,
+ erlang_ssl_receive, [Data]}},
+ {options, [{ciphers, Ciphers} | ClientOpts]}]),
+
+ true = port_command(OpensslPort, Data),
+
+ ssl_test_lib:check_result(Client, ok),
+
+ %% Clean close down! Server needs to be closed first !!
+ ssl_test_lib:close_port(OpensslPort),
+ ssl_test_lib:close(Client),
+ process_flag(trap_exit, false),
+ ok.
+%%--------------------------------------------------------------------
+erlang_server_openssl_client_anon() ->
+ [{doc,"Test erlang server with openssl client, anonymous"}].
+erlang_server_openssl_client_anon(Config) when is_list(Config) ->
+ process_flag(trap_exit, true),
+ ServerOpts = ssl_test_lib:ssl_options(server_anon_opts, Config),
+ VersionTuple = ssl_test_lib:protocol_version(Config, tuple),
+ Ciphers = ssl_test_lib:anonymous_suites(VersionTuple),
+
+ {_, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+
+ Data = "From openssl to erlang",
+
+ Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {mfa, {?MODULE, erlang_ssl_receive, [Data]}},
+ {options, [{ciphers, Ciphers} | ServerOpts]}]),
+ Port = ssl_test_lib:inet_port(Server),
+ Version = ssl_test_lib:protocol_version(Config),
+ Exe = "openssl",
+ Args = ["s_client", "-connect", hostname_format(Hostname) ++ ":" ++ integer_to_list(Port),
+ ssl_test_lib:version_flag(Version),
+ "-cipher", "aNULL", "-msg"],
+
+ OpenSslPort = ssl_test_lib:portable_open_port(Exe, Args),
+ true = port_command(OpenSslPort, Data),
+
+ ssl_test_lib:check_result(Server, ok),
+
+ %% Clean close down! Server needs to be closed first !!
+ ssl_test_lib:close(Server),
+ ssl_test_lib:close_port(OpenSslPort),
+ process_flag(trap_exit, false).
+
+ %%--------------------------------------------------------------------
+ erlang_server_openssl_client_anon_with_cert() ->
+ [{doc,"Test erlang server with openssl client, anonymous (with cert)"}].
+ erlang_server_openssl_client_anon_with_cert(Config) when is_list(Config) ->
+ process_flag(trap_exit, true),
+ ServerOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config),
+ VersionTuple = ssl_test_lib:protocol_version(Config, tuple),
+ Ciphers = ssl_test_lib:anonymous_suites(VersionTuple),
+
+ {_, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+
+ Data = "From openssl to erlang",
+
+ Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {mfa, {?MODULE, erlang_ssl_receive, [Data]}},
+ {options, [{ciphers, Ciphers} | ServerOpts]}]),
+ Port = ssl_test_lib:inet_port(Server),
+ Version = ssl_test_lib:protocol_version(Config),
+ Exe = "openssl",
+ Args = ["s_client", "-connect", hostname_format(Hostname) ++ ":" ++ integer_to_list(Port),
+ ssl_test_lib:version_flag(Version),
+ "-cipher", "aNULL", "-msg"],
+
+ OpenSslPort = ssl_test_lib:portable_open_port(Exe, Args),
+ true = port_command(OpenSslPort, Data),
+
+ ssl_test_lib:check_result(Server, ok),
+
+ %% Clean close down! Server needs to be closed first !!
+ ssl_test_lib:close(Server),
+ ssl_test_lib:close_port(OpenSslPort),
+ process_flag(trap_exit, false).
+
+%%--------------------------------------------------------------------
erlang_server_openssl_client_reuse_session() ->
[{doc, "Test erlang server with openssl client that reconnects with the"
diff --git a/lib/stdlib/doc/src/erl_tar.xml b/lib/stdlib/doc/src/erl_tar.xml
index caf8f4a96d..14c543ee2b 100644
--- a/lib/stdlib/doc/src/erl_tar.xml
+++ b/lib/stdlib/doc/src/erl_tar.xml
@@ -417,7 +417,7 @@
<v>Reason = term()</v>
</type>
<desc>
- <p>Cconverts an error reason term to a human-readable error message
+ <p>Converts an error reason term to a human-readable error message
string.</p>
</desc>
</func>
diff --git a/otp_versions.table b/otp_versions.table
index 7161ca98fc..b976962c1e 100644
--- a/otp_versions.table
+++ b/otp_versions.table
@@ -52,6 +52,7 @@ OTP-19.0.3 : inets-6.3.2 kernel-5.0.1 ssl-8.0.1 # asn1-4.0.3 common_test-1.12.2
OTP-19.0.2 : compiler-7.0.1 erts-8.0.2 stdlib-3.0.1 # asn1-4.0.3 common_test-1.12.2 cosEvent-2.2.1 cosEventDomain-1.2.1 cosFileTransfer-1.2.1 cosNotification-1.2.2 cosProperty-1.2.1 cosTime-1.2.2 cosTransactions-1.3.2 crypto-3.7 debugger-4.2 dialyzer-3.0.1 diameter-1.12 edoc-0.7.19 eldap-1.2.2 erl_docgen-0.5 erl_interface-3.9 et-1.6 eunit-2.3 gs-1.6.1 hipe-3.15.1 ic-4.4.1 inets-6.3.1 jinterface-1.7 kernel-5.0 megaco-3.18.1 mnesia-4.14 observer-2.2.1 odbc-2.11.2 orber-3.8.2 os_mon-2.4.1 otp_mibs-1.1.1 parsetools-2.1.2 percept-0.9 public_key-1.2 reltool-0.7.1 runtime_tools-1.10 sasl-3.0 snmp-5.2.3 ssh-4.3.1 ssl-8.0 syntax_tools-2.0 tools-2.8.5 typer-0.9.11 wx-1.7 xmerl-1.3.11 :
OTP-19.0.1 : dialyzer-3.0.1 erts-8.0.1 inets-6.3.1 observer-2.2.1 ssh-4.3.1 tools-2.8.5 # asn1-4.0.3 common_test-1.12.2 compiler-7.0 cosEvent-2.2.1 cosEventDomain-1.2.1 cosFileTransfer-1.2.1 cosNotification-1.2.2 cosProperty-1.2.1 cosTime-1.2.2 cosTransactions-1.3.2 crypto-3.7 debugger-4.2 diameter-1.12 edoc-0.7.19 eldap-1.2.2 erl_docgen-0.5 erl_interface-3.9 et-1.6 eunit-2.3 gs-1.6.1 hipe-3.15.1 ic-4.4.1 jinterface-1.7 kernel-5.0 megaco-3.18.1 mnesia-4.14 odbc-2.11.2 orber-3.8.2 os_mon-2.4.1 otp_mibs-1.1.1 parsetools-2.1.2 percept-0.9 public_key-1.2 reltool-0.7.1 runtime_tools-1.10 sasl-3.0 snmp-5.2.3 ssl-8.0 stdlib-3.0 syntax_tools-2.0 typer-0.9.11 wx-1.7 xmerl-1.3.11 :
OTP-19.0 : asn1-4.0.3 common_test-1.12.2 compiler-7.0 cosEvent-2.2.1 cosEventDomain-1.2.1 cosFileTransfer-1.2.1 cosNotification-1.2.2 cosProperty-1.2.1 cosTime-1.2.2 cosTransactions-1.3.2 crypto-3.7 debugger-4.2 dialyzer-3.0 diameter-1.12 edoc-0.7.19 eldap-1.2.2 erl_docgen-0.5 erl_interface-3.9 erts-8.0 et-1.6 eunit-2.3 gs-1.6.1 hipe-3.15.1 ic-4.4.1 inets-6.3 jinterface-1.7 kernel-5.0 megaco-3.18.1 mnesia-4.14 observer-2.2 odbc-2.11.2 orber-3.8.2 os_mon-2.4.1 otp_mibs-1.1.1 parsetools-2.1.2 percept-0.9 public_key-1.2 reltool-0.7.1 runtime_tools-1.10 sasl-3.0 snmp-5.2.3 ssh-4.3 ssl-8.0 stdlib-3.0 syntax_tools-2.0 tools-2.8.4 typer-0.9.11 wx-1.7 xmerl-1.3.11 # :
+OTP-18.3.4.8 : ssh-4.2.2.5 # asn1-4.0.2 common_test-1.12.1.1 compiler-6.0.3.1 cosEvent-2.2 cosEventDomain-1.2 cosFileTransfer-1.2 cosNotification-1.2.1 cosProperty-1.2 cosTime-1.2.1 cosTransactions-1.3.1 crypto-3.6.3.1 debugger-4.1.2 dialyzer-2.9 diameter-1.11.2 edoc-0.7.18 eldap-1.2.1.1 erl_docgen-0.4.2 erl_interface-3.8.2 erts-7.3.1.4 et-1.5.1 eunit-2.2.13 gs-1.6 hipe-3.15 ic-4.4 inets-6.2.4.1 jinterface-1.6.1 kernel-4.2 megaco-3.18 mnesia-4.13.4 observer-2.1.2 odbc-2.11.1 orber-3.8.1 os_mon-2.4 ose-1.1 otp_mibs-1.1 parsetools-2.1.1 percept-0.8.11 public_key-1.1.1 reltool-0.7 runtime_tools-1.9.3 sasl-2.7 snmp-5.2.2 ssl-7.3.3.2 stdlib-2.8 syntax_tools-1.7 test_server-3.10 tools-2.8.3 typer-0.9.10 webtool-0.9.1 wx-1.6.1 xmerl-1.3.10 :
OTP-18.3.4.7 : ssl-7.3.3.2 # asn1-4.0.2 common_test-1.12.1.1 compiler-6.0.3.1 cosEvent-2.2 cosEventDomain-1.2 cosFileTransfer-1.2 cosNotification-1.2.1 cosProperty-1.2 cosTime-1.2.1 cosTransactions-1.3.1 crypto-3.6.3.1 debugger-4.1.2 dialyzer-2.9 diameter-1.11.2 edoc-0.7.18 eldap-1.2.1.1 erl_docgen-0.4.2 erl_interface-3.8.2 erts-7.3.1.4 et-1.5.1 eunit-2.2.13 gs-1.6 hipe-3.15 ic-4.4 inets-6.2.4.1 jinterface-1.6.1 kernel-4.2 megaco-3.18 mnesia-4.13.4 observer-2.1.2 odbc-2.11.1 orber-3.8.1 os_mon-2.4 ose-1.1 otp_mibs-1.1 parsetools-2.1.1 percept-0.8.11 public_key-1.1.1 reltool-0.7 runtime_tools-1.9.3 sasl-2.7 snmp-5.2.2 ssh-4.2.2.4 stdlib-2.8 syntax_tools-1.7 test_server-3.10 tools-2.8.3 typer-0.9.10 webtool-0.9.1 wx-1.6.1 xmerl-1.3.10 :
OTP-18.3.4.6 : compiler-6.0.3.1 eldap-1.2.1.1 erts-7.3.1.4 ssh-4.2.2.4 # asn1-4.0.2 common_test-1.12.1.1 cosEvent-2.2 cosEventDomain-1.2 cosFileTransfer-1.2 cosNotification-1.2.1 cosProperty-1.2 cosTime-1.2.1 cosTransactions-1.3.1 crypto-3.6.3.1 debugger-4.1.2 dialyzer-2.9 diameter-1.11.2 edoc-0.7.18 erl_docgen-0.4.2 erl_interface-3.8.2 et-1.5.1 eunit-2.2.13 gs-1.6 hipe-3.15 ic-4.4 inets-6.2.4.1 jinterface-1.6.1 kernel-4.2 megaco-3.18 mnesia-4.13.4 observer-2.1.2 odbc-2.11.1 orber-3.8.1 os_mon-2.4 ose-1.1 otp_mibs-1.1 parsetools-2.1.1 percept-0.8.11 public_key-1.1.1 reltool-0.7 runtime_tools-1.9.3 sasl-2.7 snmp-5.2.2 ssl-7.3.3.1 stdlib-2.8 syntax_tools-1.7 test_server-3.10 tools-2.8.3 typer-0.9.10 webtool-0.9.1 wx-1.6.1 xmerl-1.3.10 :
OTP-18.3.4.5 : crypto-3.6.3.1 erts-7.3.1.3 inets-6.2.4.1 ssh-4.2.2.3 # asn1-4.0.2 common_test-1.12.1.1 compiler-6.0.3 cosEvent-2.2 cosEventDomain-1.2 cosFileTransfer-1.2 cosNotification-1.2.1 cosProperty-1.2 cosTime-1.2.1 cosTransactions-1.3.1 debugger-4.1.2 dialyzer-2.9 diameter-1.11.2 edoc-0.7.18 eldap-1.2.1 erl_docgen-0.4.2 erl_interface-3.8.2 et-1.5.1 eunit-2.2.13 gs-1.6 hipe-3.15 ic-4.4 jinterface-1.6.1 kernel-4.2 megaco-3.18 mnesia-4.13.4 observer-2.1.2 odbc-2.11.1 orber-3.8.1 os_mon-2.4 ose-1.1 otp_mibs-1.1 parsetools-2.1.1 percept-0.8.11 public_key-1.1.1 reltool-0.7 runtime_tools-1.9.3 sasl-2.7 snmp-5.2.2 ssl-7.3.3.1 stdlib-2.8 syntax_tools-1.7 test_server-3.10 tools-2.8.3 typer-0.9.10 webtool-0.9.1 wx-1.6.1 xmerl-1.3.10 :
diff --git a/system/doc/design_principles/release_structure.xml b/system/doc/design_principles/release_structure.xml
index a0ab21c43f..8e62ba845f 100644
--- a/system/doc/design_principles/release_structure.xml
+++ b/system/doc/design_principles/release_structure.xml
@@ -208,8 +208,8 @@ releases/ch_rel-1.rel</pre>
is therefore now instead duplicated in the tar file so no manual
copying is necessary.</p>
<p>If a <c>relup</c> file and/or a system configuration file called
- <c>sys.config</c> is found, these files are also included in
- the release package. See
+ <c>sys.config</c>, or a <c>sys.config.src</c>, is found, these files
+ are also included in the release package. See
<seealso marker="release_handling#req">Release Handling</seealso>.</p>
<p>Options can be set to make the release package include source
code and the ERTS binary as well.</p>
@@ -240,7 +240,7 @@ $ROOT/lib/App1-AVsn1/ebin
<item><c>erts-EVsn/bin</c> - Erlang runtime system executables</item>
<item><c>releases/Vsn</c> - <c>.rel</c> file and boot script
<c>start.boot</c>; if present in the release package, <c>relup</c>
- and/or <c>sys.config</c></item>
+ and/or <c>sys.config</c> or <c>sys.config.src</c></item>
<item><c>bin</c> - Top-level Erlang runtime system executables</item>
</list>
<p>Applications are not required to be located under directory
diff --git a/system/doc/system_principles/create_target.xmlsrc b/system/doc/system_principles/create_target.xmlsrc
index f9b27ffc35..dc6cbbe980 100644
--- a/system/doc/system_principles/create_target.xmlsrc
+++ b/system/doc/system_principles/create_target.xmlsrc
@@ -263,6 +263,14 @@ os> <input>/usr/local/erl-target/bin/erl -boot /usr/local/erl-target/releases/FI
current directory create not only the file <c>mysystem.rel</c>,
but also file <c>sys.config</c>, the latter file is tacitly
put in the appropriate directory.</p>
+ <p>However, it can also be convenient to replace variables in
+ within a <c>sys.config</c> on the target after unpacking but
+ before running the release. If you have a <c>sys.config.src</c>
+ it will be included and is not required to be a valid Erlang term
+ file like <c>sys.config</c>. Before running the release you must
+ have a valid <c>sys.config</c> in the same directory, so using
+ <c>sys.config.src</c> requires having some tool to populate what is
+ needed and write <c>sys.config</c> to disk before booting the release.</p>
</section>
<section>