diff options
207 files changed, 3374 insertions, 1532 deletions
diff --git a/.gitignore b/.gitignore index cbf7881ae7..234d21c7df 100644 --- a/.gitignore +++ b/.gitignore @@ -94,8 +94,6 @@ lib/os_mon/priv/obj/win32/ lib/runtime_tools/c_src/win32/ lib/runtime_tools/priv/lib/ lib/runtime_tools/priv/obj/ -lib/runtime_tools/doc/src/DTRACE.xml -lib/runtime_tools/doc/src/SYSTEMTAP.xml lib/tools/bin/win32/ lib/tools/c_src/win32/ lib/tools/obj/win32/ @@ -178,7 +176,7 @@ JAVADOC-GENERATED /lib/*/doc/man[0-9]/*.[0-9] /lib/*/doc/pdf/*.fo /lib/*/doc/pdf/*.pdf - +/lib/*/doc/xml/*.xml /lib/configure /lib/config.log @@ -206,6 +204,7 @@ JAVADOC-GENERATED /lib/erl_interface/src/auxdir/config.guess /lib/erl_interface/src/auxdir/config.sub /lib/erl_interface/src/auxdir/install-sh +/lib/erl_interface/config.h.in /lib/megaco/aclocal.m4 /lib/odbc/aclocal.m4 /lib/common_test/test_server/config.guess @@ -232,15 +231,12 @@ JAVADOC-GENERATED # asn1 -/lib/asn1/doc/src/asn1_spec.xml /lib/asn1/test/asn1_SUITE.erl /lib/asn1/test/asn1_bin_SUITE.erl /lib/asn1/test/asn1_bin_v2_SUITE.erl # common_test -/lib/common_test/doc/src/ct_property_test.xml -/lib/common_test/doc/src/ct_slave.xml /lib/common_test/priv/install.sh # compiler @@ -274,15 +270,13 @@ JAVADOC-GENERATED /erts/doc/html/*.eix /erts/doc/pdf/*.fo /erts/doc/pdf/*.pdf +/erts/doc/xml/*.xml /erts/doc/man[0-9]/*.[0-9] /erts/doc/CONF_INFO # et /lib/et/doc/html/*.png -/lib/et/doc/src/et_desc.xml -/lib/et/doc/src/et_examples.xml -/lib/et/doc/src/et_tutorial.xml # gs @@ -366,27 +360,15 @@ JAVADOC-GENERATED /lib/snmp/priv/mibs/[A-Z]*.bin /lib/snmp/test/snmp_test_data/[A-Z]*.bin /lib/snmp/test/snmp_test_data/[A-Z]*.hrl +/lib/snmp/doc/intex.html # system /system/doc/pdf /system/doc/html +/system/doc/xml /system/doc/top/PR.template /system/doc/top/erlresolvelinks.js -/system/doc/programming_examples/funs.xml -/system/doc/system_principles/create_target.xml -/system/doc/tutorial/c_port.xml -/system/doc/tutorial/c_portdriver.xml -/system/doc/tutorial/cnode.xml -/system/doc/tutorial/erl_interface.xml -/system/doc/tutorial/example.xml -/system/doc/tutorial/nif.xml -/system/doc/html/installation_guide -/system/doc/installation_guide/INSTALL.xml -/system/doc/installation_guide/INSTALL-CROSS.xml -/system/doc/installation_guide/INSTALL-WIN32.xml -/system/doc/installation_guide/OTP-PATCH-APPLY.xml -/system/doc/installation_guide/MARKDOWN.xml # test_server @@ -406,7 +388,7 @@ JAVADOC-GENERATED /lib/wx/api_gen/*_generated /lib/wx/wx-*.ez /lib/wx/CONF_INFO -/lib/wx/doc/src/wx*.xml +/lib/wx/doc/src/ref_man.xml /lib/wx/priv/wxe_driver.* /lib/wx/priv/erl_gl.* @@ -416,4 +398,3 @@ JAVADOC-GENERATED /lib/xmerl/src/xmerl_b64Bin.erl /lib/xmerl/src/xmerl_xpath_parse.erl /lib/xmerl/test/xmerl_test.erl -/lib/erl_interface/config.h.in diff --git a/bootstrap/bin/no_dot_erlang.boot b/bootstrap/bin/no_dot_erlang.boot Binary files differindex 010993cc67..e425b58f12 100644 --- a/bootstrap/bin/no_dot_erlang.boot +++ b/bootstrap/bin/no_dot_erlang.boot diff --git a/bootstrap/bin/start.boot b/bootstrap/bin/start.boot Binary files differindex 010993cc67..e425b58f12 100644 --- a/bootstrap/bin/start.boot +++ b/bootstrap/bin/start.boot diff --git a/bootstrap/bin/start_clean.boot b/bootstrap/bin/start_clean.boot Binary files differindex 010993cc67..e425b58f12 100644 --- a/bootstrap/bin/start_clean.boot +++ b/bootstrap/bin/start_clean.boot diff --git a/bootstrap/lib/compiler/ebin/beam_a.beam b/bootstrap/lib/compiler/ebin/beam_a.beam Binary files differindex 72f044da26..248c6dc0e4 100644 --- a/bootstrap/lib/compiler/ebin/beam_a.beam +++ b/bootstrap/lib/compiler/ebin/beam_a.beam diff --git a/bootstrap/lib/compiler/ebin/beam_asm.beam b/bootstrap/lib/compiler/ebin/beam_asm.beam Binary files differindex cca4e97485..c0db0d1ac4 100644 --- a/bootstrap/lib/compiler/ebin/beam_asm.beam +++ b/bootstrap/lib/compiler/ebin/beam_asm.beam diff --git a/bootstrap/lib/compiler/ebin/beam_block.beam b/bootstrap/lib/compiler/ebin/beam_block.beam Binary files differindex 18f5dc6967..dc941da6ae 100644 --- a/bootstrap/lib/compiler/ebin/beam_block.beam +++ b/bootstrap/lib/compiler/ebin/beam_block.beam diff --git a/bootstrap/lib/compiler/ebin/beam_bs.beam b/bootstrap/lib/compiler/ebin/beam_bs.beam Binary files differindex 1361b0b08d..1fc68940ac 100644 --- a/bootstrap/lib/compiler/ebin/beam_bs.beam +++ b/bootstrap/lib/compiler/ebin/beam_bs.beam diff --git a/bootstrap/lib/compiler/ebin/beam_clean.beam b/bootstrap/lib/compiler/ebin/beam_clean.beam Binary files differindex ab18a32fa8..bc49326e74 100644 --- a/bootstrap/lib/compiler/ebin/beam_clean.beam +++ b/bootstrap/lib/compiler/ebin/beam_clean.beam diff --git a/bootstrap/lib/compiler/ebin/beam_dead.beam b/bootstrap/lib/compiler/ebin/beam_dead.beam Binary files differindex 33ee4dea87..af2f76c6ee 100644 --- a/bootstrap/lib/compiler/ebin/beam_dead.beam +++ b/bootstrap/lib/compiler/ebin/beam_dead.beam diff --git a/bootstrap/lib/compiler/ebin/beam_dict.beam b/bootstrap/lib/compiler/ebin/beam_dict.beam Binary files differindex 2e9c7d0f00..1e2068b5cb 100644 --- a/bootstrap/lib/compiler/ebin/beam_dict.beam +++ b/bootstrap/lib/compiler/ebin/beam_dict.beam diff --git a/bootstrap/lib/compiler/ebin/beam_disasm.beam b/bootstrap/lib/compiler/ebin/beam_disasm.beam Binary files differindex 5983f341f5..5e3585ada7 100644 --- a/bootstrap/lib/compiler/ebin/beam_disasm.beam +++ b/bootstrap/lib/compiler/ebin/beam_disasm.beam diff --git a/bootstrap/lib/compiler/ebin/beam_flatten.beam b/bootstrap/lib/compiler/ebin/beam_flatten.beam Binary files differindex 8758e98a71..e039f3c12b 100644 --- a/bootstrap/lib/compiler/ebin/beam_flatten.beam +++ b/bootstrap/lib/compiler/ebin/beam_flatten.beam diff --git a/bootstrap/lib/compiler/ebin/beam_jump.beam b/bootstrap/lib/compiler/ebin/beam_jump.beam Binary files differindex 5551ba9f90..e13be6fb24 100644 --- a/bootstrap/lib/compiler/ebin/beam_jump.beam +++ b/bootstrap/lib/compiler/ebin/beam_jump.beam diff --git a/bootstrap/lib/compiler/ebin/beam_peep.beam b/bootstrap/lib/compiler/ebin/beam_peep.beam Binary files differindex d2b10e030b..67d1f808b6 100644 --- a/bootstrap/lib/compiler/ebin/beam_peep.beam +++ b/bootstrap/lib/compiler/ebin/beam_peep.beam diff --git a/bootstrap/lib/compiler/ebin/beam_receive.beam b/bootstrap/lib/compiler/ebin/beam_receive.beam Binary files differindex 8d16d7d39d..909e5403d1 100644 --- a/bootstrap/lib/compiler/ebin/beam_receive.beam +++ b/bootstrap/lib/compiler/ebin/beam_receive.beam diff --git a/bootstrap/lib/compiler/ebin/beam_record.beam b/bootstrap/lib/compiler/ebin/beam_record.beam Binary files differindex 55cac5310d..188bd82412 100644 --- a/bootstrap/lib/compiler/ebin/beam_record.beam +++ b/bootstrap/lib/compiler/ebin/beam_record.beam diff --git a/bootstrap/lib/compiler/ebin/beam_split.beam b/bootstrap/lib/compiler/ebin/beam_split.beam Binary files differindex 8165aab002..476dd53ee6 100644 --- a/bootstrap/lib/compiler/ebin/beam_split.beam +++ b/bootstrap/lib/compiler/ebin/beam_split.beam diff --git a/bootstrap/lib/compiler/ebin/beam_type.beam b/bootstrap/lib/compiler/ebin/beam_type.beam Binary files differindex 0c8341a6c9..dab30b21eb 100644 --- a/bootstrap/lib/compiler/ebin/beam_type.beam +++ b/bootstrap/lib/compiler/ebin/beam_type.beam diff --git a/bootstrap/lib/compiler/ebin/beam_utils.beam b/bootstrap/lib/compiler/ebin/beam_utils.beam Binary files differindex 1e9c30d00a..eff13429dd 100644 --- a/bootstrap/lib/compiler/ebin/beam_utils.beam +++ b/bootstrap/lib/compiler/ebin/beam_utils.beam diff --git a/bootstrap/lib/compiler/ebin/beam_validator.beam b/bootstrap/lib/compiler/ebin/beam_validator.beam Binary files differindex 25f8772409..58f69e1c1d 100644 --- a/bootstrap/lib/compiler/ebin/beam_validator.beam +++ b/bootstrap/lib/compiler/ebin/beam_validator.beam diff --git a/bootstrap/lib/compiler/ebin/cerl.beam b/bootstrap/lib/compiler/ebin/cerl.beam Binary files differindex 61515da20a..97e0c72b15 100644 --- a/bootstrap/lib/compiler/ebin/cerl.beam +++ b/bootstrap/lib/compiler/ebin/cerl.beam diff --git a/bootstrap/lib/compiler/ebin/cerl_inline.beam b/bootstrap/lib/compiler/ebin/cerl_inline.beam Binary files differindex 36888f6363..6b365ce68f 100644 --- a/bootstrap/lib/compiler/ebin/cerl_inline.beam +++ b/bootstrap/lib/compiler/ebin/cerl_inline.beam diff --git a/bootstrap/lib/compiler/ebin/cerl_trees.beam b/bootstrap/lib/compiler/ebin/cerl_trees.beam Binary files differindex 3deb60c450..4304437799 100644 --- a/bootstrap/lib/compiler/ebin/cerl_trees.beam +++ b/bootstrap/lib/compiler/ebin/cerl_trees.beam diff --git a/bootstrap/lib/compiler/ebin/compile.beam b/bootstrap/lib/compiler/ebin/compile.beam Binary files differindex 82d601c128..99a6c5d7f0 100644 --- a/bootstrap/lib/compiler/ebin/compile.beam +++ b/bootstrap/lib/compiler/ebin/compile.beam diff --git a/bootstrap/lib/compiler/ebin/compiler.app b/bootstrap/lib/compiler/ebin/compiler.app index 286b48ec23..1506292674 100644 --- a/bootstrap/lib/compiler/ebin/compiler.app +++ b/bootstrap/lib/compiler/ebin/compiler.app @@ -19,7 +19,7 @@ {application, compiler, [{description, "ERTS CXC 138 10"}, - {vsn, "7.1.4"}, + {vsn, "7.1.5"}, {modules, [ beam_a, beam_asm, diff --git a/bootstrap/lib/compiler/ebin/core_lint.beam b/bootstrap/lib/compiler/ebin/core_lint.beam Binary files differindex f3b420121a..41c6083337 100644 --- a/bootstrap/lib/compiler/ebin/core_lint.beam +++ b/bootstrap/lib/compiler/ebin/core_lint.beam diff --git a/bootstrap/lib/compiler/ebin/core_parse.beam b/bootstrap/lib/compiler/ebin/core_parse.beam Binary files differindex cd4a22c6d8..618668e92e 100644 --- a/bootstrap/lib/compiler/ebin/core_parse.beam +++ b/bootstrap/lib/compiler/ebin/core_parse.beam diff --git a/bootstrap/lib/compiler/ebin/core_pp.beam b/bootstrap/lib/compiler/ebin/core_pp.beam Binary files differindex 59503a2933..f382d4d606 100644 --- a/bootstrap/lib/compiler/ebin/core_pp.beam +++ b/bootstrap/lib/compiler/ebin/core_pp.beam diff --git a/bootstrap/lib/compiler/ebin/erl_bifs.beam b/bootstrap/lib/compiler/ebin/erl_bifs.beam Binary files differindex 060c6571af..19be744e9d 100644 --- a/bootstrap/lib/compiler/ebin/erl_bifs.beam +++ b/bootstrap/lib/compiler/ebin/erl_bifs.beam diff --git a/bootstrap/lib/compiler/ebin/sys_core_bsm.beam b/bootstrap/lib/compiler/ebin/sys_core_bsm.beam Binary files differindex 451b2ff3b5..d14579410c 100644 --- a/bootstrap/lib/compiler/ebin/sys_core_bsm.beam +++ b/bootstrap/lib/compiler/ebin/sys_core_bsm.beam diff --git a/bootstrap/lib/compiler/ebin/sys_core_fold.beam b/bootstrap/lib/compiler/ebin/sys_core_fold.beam Binary files differindex 62e56d92b0..f54ff65ff9 100644 --- a/bootstrap/lib/compiler/ebin/sys_core_fold.beam +++ b/bootstrap/lib/compiler/ebin/sys_core_fold.beam diff --git a/bootstrap/lib/compiler/ebin/sys_core_inline.beam b/bootstrap/lib/compiler/ebin/sys_core_inline.beam Binary files differindex 40f6ebf167..b4cdba519a 100644 --- a/bootstrap/lib/compiler/ebin/sys_core_inline.beam +++ b/bootstrap/lib/compiler/ebin/sys_core_inline.beam diff --git a/bootstrap/lib/compiler/ebin/sys_pre_attributes.beam b/bootstrap/lib/compiler/ebin/sys_pre_attributes.beam Binary files differindex 91a29c5266..d96bc1913a 100644 --- a/bootstrap/lib/compiler/ebin/sys_pre_attributes.beam +++ b/bootstrap/lib/compiler/ebin/sys_pre_attributes.beam diff --git a/bootstrap/lib/compiler/ebin/v3_codegen.beam b/bootstrap/lib/compiler/ebin/v3_codegen.beam Binary files differindex bf1bcaafd2..6640d1199f 100644 --- a/bootstrap/lib/compiler/ebin/v3_codegen.beam +++ b/bootstrap/lib/compiler/ebin/v3_codegen.beam diff --git a/bootstrap/lib/compiler/ebin/v3_core.beam b/bootstrap/lib/compiler/ebin/v3_core.beam Binary files differindex b4672b1315..162105c0bf 100644 --- a/bootstrap/lib/compiler/ebin/v3_core.beam +++ b/bootstrap/lib/compiler/ebin/v3_core.beam diff --git a/bootstrap/lib/compiler/ebin/v3_kernel.beam b/bootstrap/lib/compiler/ebin/v3_kernel.beam Binary files differindex 082bd6b75d..7a155ec05c 100644 --- a/bootstrap/lib/compiler/ebin/v3_kernel.beam +++ b/bootstrap/lib/compiler/ebin/v3_kernel.beam diff --git a/bootstrap/lib/compiler/ebin/v3_kernel_pp.beam b/bootstrap/lib/compiler/ebin/v3_kernel_pp.beam Binary files differindex fb780c2a43..4aef1389be 100644 --- a/bootstrap/lib/compiler/ebin/v3_kernel_pp.beam +++ b/bootstrap/lib/compiler/ebin/v3_kernel_pp.beam diff --git a/bootstrap/lib/kernel/ebin/application_controller.beam b/bootstrap/lib/kernel/ebin/application_controller.beam Binary files differindex 5e63aa4e8a..e060d2bd9a 100644 --- a/bootstrap/lib/kernel/ebin/application_controller.beam +++ b/bootstrap/lib/kernel/ebin/application_controller.beam diff --git a/bootstrap/lib/kernel/ebin/application_master.beam b/bootstrap/lib/kernel/ebin/application_master.beam Binary files differindex 4bafc43619..55adf9849c 100644 --- a/bootstrap/lib/kernel/ebin/application_master.beam +++ b/bootstrap/lib/kernel/ebin/application_master.beam diff --git a/bootstrap/lib/kernel/ebin/code.beam b/bootstrap/lib/kernel/ebin/code.beam Binary files differindex 102ac41ac2..669efdc50f 100644 --- a/bootstrap/lib/kernel/ebin/code.beam +++ b/bootstrap/lib/kernel/ebin/code.beam diff --git a/bootstrap/lib/kernel/ebin/code_server.beam b/bootstrap/lib/kernel/ebin/code_server.beam Binary files differindex 922c5e6308..c42c641c17 100644 --- a/bootstrap/lib/kernel/ebin/code_server.beam +++ b/bootstrap/lib/kernel/ebin/code_server.beam diff --git a/bootstrap/lib/kernel/ebin/disk_log.beam b/bootstrap/lib/kernel/ebin/disk_log.beam Binary files differindex 76264b975b..19880724ba 100644 --- a/bootstrap/lib/kernel/ebin/disk_log.beam +++ b/bootstrap/lib/kernel/ebin/disk_log.beam diff --git a/bootstrap/lib/kernel/ebin/disk_log_1.beam b/bootstrap/lib/kernel/ebin/disk_log_1.beam Binary files differindex 05c002ba67..10c7275240 100644 --- a/bootstrap/lib/kernel/ebin/disk_log_1.beam +++ b/bootstrap/lib/kernel/ebin/disk_log_1.beam diff --git a/bootstrap/lib/kernel/ebin/disk_log_server.beam b/bootstrap/lib/kernel/ebin/disk_log_server.beam Binary files differindex f3ca0687dd..0f0418a911 100644 --- a/bootstrap/lib/kernel/ebin/disk_log_server.beam +++ b/bootstrap/lib/kernel/ebin/disk_log_server.beam diff --git a/bootstrap/lib/kernel/ebin/dist_ac.beam b/bootstrap/lib/kernel/ebin/dist_ac.beam Binary files differindex 7419ba7c27..517fa7dfdb 100644 --- a/bootstrap/lib/kernel/ebin/dist_ac.beam +++ b/bootstrap/lib/kernel/ebin/dist_ac.beam diff --git a/bootstrap/lib/kernel/ebin/dist_util.beam b/bootstrap/lib/kernel/ebin/dist_util.beam Binary files differindex 3a4d230a7f..1a18fd98b5 100644 --- a/bootstrap/lib/kernel/ebin/dist_util.beam +++ b/bootstrap/lib/kernel/ebin/dist_util.beam diff --git a/bootstrap/lib/kernel/ebin/erl_boot_server.beam b/bootstrap/lib/kernel/ebin/erl_boot_server.beam Binary files differindex d921ffabd9..6559fc04c1 100644 --- a/bootstrap/lib/kernel/ebin/erl_boot_server.beam +++ b/bootstrap/lib/kernel/ebin/erl_boot_server.beam diff --git a/bootstrap/lib/kernel/ebin/erl_ddll.beam b/bootstrap/lib/kernel/ebin/erl_ddll.beam Binary files differindex b672c39f5d..baec5883a9 100644 --- a/bootstrap/lib/kernel/ebin/erl_ddll.beam +++ b/bootstrap/lib/kernel/ebin/erl_ddll.beam diff --git a/bootstrap/lib/kernel/ebin/file.beam b/bootstrap/lib/kernel/ebin/file.beam Binary files differindex df612743bd..07a4f410e1 100644 --- a/bootstrap/lib/kernel/ebin/file.beam +++ b/bootstrap/lib/kernel/ebin/file.beam diff --git a/bootstrap/lib/kernel/ebin/file_io_server.beam b/bootstrap/lib/kernel/ebin/file_io_server.beam Binary files differindex d37ed85781..e889d294b8 100644 --- a/bootstrap/lib/kernel/ebin/file_io_server.beam +++ b/bootstrap/lib/kernel/ebin/file_io_server.beam diff --git a/bootstrap/lib/kernel/ebin/global.beam b/bootstrap/lib/kernel/ebin/global.beam Binary files differindex 8b057dff1a..e138217d25 100644 --- a/bootstrap/lib/kernel/ebin/global.beam +++ b/bootstrap/lib/kernel/ebin/global.beam diff --git a/bootstrap/lib/kernel/ebin/group.beam b/bootstrap/lib/kernel/ebin/group.beam Binary files differindex 43c35f0a3a..03abd10d20 100644 --- a/bootstrap/lib/kernel/ebin/group.beam +++ b/bootstrap/lib/kernel/ebin/group.beam diff --git a/bootstrap/lib/kernel/ebin/hipe_unified_loader.beam b/bootstrap/lib/kernel/ebin/hipe_unified_loader.beam Binary files differindex 16841cc417..989fceaa2c 100644 --- a/bootstrap/lib/kernel/ebin/hipe_unified_loader.beam +++ b/bootstrap/lib/kernel/ebin/hipe_unified_loader.beam diff --git a/bootstrap/lib/kernel/ebin/inet.beam b/bootstrap/lib/kernel/ebin/inet.beam Binary files differindex c1f7d2e8b0..fd855be69b 100644 --- a/bootstrap/lib/kernel/ebin/inet.beam +++ b/bootstrap/lib/kernel/ebin/inet.beam diff --git a/bootstrap/lib/kernel/ebin/inet_db.beam b/bootstrap/lib/kernel/ebin/inet_db.beam Binary files differindex e86ce51920..315d1126aa 100644 --- a/bootstrap/lib/kernel/ebin/inet_db.beam +++ b/bootstrap/lib/kernel/ebin/inet_db.beam diff --git a/bootstrap/lib/kernel/ebin/inet_dns.beam b/bootstrap/lib/kernel/ebin/inet_dns.beam Binary files differindex c437ed85d7..7b04a63303 100644 --- a/bootstrap/lib/kernel/ebin/inet_dns.beam +++ b/bootstrap/lib/kernel/ebin/inet_dns.beam diff --git a/bootstrap/lib/kernel/ebin/inet_gethost_native.beam b/bootstrap/lib/kernel/ebin/inet_gethost_native.beam Binary files differindex ccd9f21cd4..610d9a2205 100644 --- a/bootstrap/lib/kernel/ebin/inet_gethost_native.beam +++ b/bootstrap/lib/kernel/ebin/inet_gethost_native.beam diff --git a/bootstrap/lib/kernel/ebin/inet_hosts.beam b/bootstrap/lib/kernel/ebin/inet_hosts.beam Binary files differindex 601a6704ee..63fadee640 100644 --- a/bootstrap/lib/kernel/ebin/inet_hosts.beam +++ b/bootstrap/lib/kernel/ebin/inet_hosts.beam diff --git a/bootstrap/lib/kernel/ebin/inet_res.beam b/bootstrap/lib/kernel/ebin/inet_res.beam Binary files differindex 8c18d0d1ad..463f90fae8 100644 --- a/bootstrap/lib/kernel/ebin/inet_res.beam +++ b/bootstrap/lib/kernel/ebin/inet_res.beam diff --git a/bootstrap/lib/kernel/ebin/inet_tcp_dist.beam b/bootstrap/lib/kernel/ebin/inet_tcp_dist.beam Binary files differindex 2aa0a7270a..9a7e36791e 100644 --- a/bootstrap/lib/kernel/ebin/inet_tcp_dist.beam +++ b/bootstrap/lib/kernel/ebin/inet_tcp_dist.beam diff --git a/bootstrap/lib/kernel/ebin/kernel.app b/bootstrap/lib/kernel/ebin/kernel.app index d027eb6bcb..2e09684f73 100644 --- a/bootstrap/lib/kernel/ebin/kernel.app +++ b/bootstrap/lib/kernel/ebin/kernel.app @@ -22,7 +22,7 @@ {application, kernel, [ {description, "ERTS CXC 138 10"}, - {vsn, "5.4.2"}, + {vsn, "5.4.3"}, {modules, [application, application_controller, application_master, diff --git a/bootstrap/lib/kernel/ebin/net_kernel.beam b/bootstrap/lib/kernel/ebin/net_kernel.beam Binary files differindex 0355024eb4..6509d4429c 100644 --- a/bootstrap/lib/kernel/ebin/net_kernel.beam +++ b/bootstrap/lib/kernel/ebin/net_kernel.beam diff --git a/bootstrap/lib/kernel/ebin/pg2.beam b/bootstrap/lib/kernel/ebin/pg2.beam Binary files differindex 4661129bc9..a106700e44 100644 --- a/bootstrap/lib/kernel/ebin/pg2.beam +++ b/bootstrap/lib/kernel/ebin/pg2.beam diff --git a/bootstrap/lib/kernel/ebin/ram_file.beam b/bootstrap/lib/kernel/ebin/ram_file.beam Binary files differindex d426a75ed9..658240ef1e 100644 --- a/bootstrap/lib/kernel/ebin/ram_file.beam +++ b/bootstrap/lib/kernel/ebin/ram_file.beam diff --git a/bootstrap/lib/kernel/ebin/raw_file_io_compressed.beam b/bootstrap/lib/kernel/ebin/raw_file_io_compressed.beam Binary files differindex caa3d9ac6b..6f07a3c5c3 100644 --- a/bootstrap/lib/kernel/ebin/raw_file_io_compressed.beam +++ b/bootstrap/lib/kernel/ebin/raw_file_io_compressed.beam diff --git a/bootstrap/lib/kernel/ebin/raw_file_io_delayed.beam b/bootstrap/lib/kernel/ebin/raw_file_io_delayed.beam Binary files differindex dcda821d8e..2c20a06fd1 100644 --- a/bootstrap/lib/kernel/ebin/raw_file_io_delayed.beam +++ b/bootstrap/lib/kernel/ebin/raw_file_io_delayed.beam diff --git a/bootstrap/lib/kernel/ebin/raw_file_io_list.beam b/bootstrap/lib/kernel/ebin/raw_file_io_list.beam Binary files differindex 85deafd35a..4c69c890cd 100644 --- a/bootstrap/lib/kernel/ebin/raw_file_io_list.beam +++ b/bootstrap/lib/kernel/ebin/raw_file_io_list.beam diff --git a/bootstrap/lib/kernel/ebin/rpc.beam b/bootstrap/lib/kernel/ebin/rpc.beam Binary files differindex e4ed087628..7a1c9e0b31 100644 --- a/bootstrap/lib/kernel/ebin/rpc.beam +++ b/bootstrap/lib/kernel/ebin/rpc.beam diff --git a/bootstrap/lib/kernel/ebin/standard_error.beam b/bootstrap/lib/kernel/ebin/standard_error.beam Binary files differindex 8c598615f8..c01106ef11 100644 --- a/bootstrap/lib/kernel/ebin/standard_error.beam +++ b/bootstrap/lib/kernel/ebin/standard_error.beam diff --git a/bootstrap/lib/kernel/ebin/user.beam b/bootstrap/lib/kernel/ebin/user.beam Binary files differindex e57d6896bd..4cbf2174a2 100644 --- a/bootstrap/lib/kernel/ebin/user.beam +++ b/bootstrap/lib/kernel/ebin/user.beam diff --git a/bootstrap/lib/kernel/include/dist.hrl b/bootstrap/lib/kernel/include/dist.hrl index db4a5eaebc..6baaa35d72 100644 --- a/bootstrap/lib/kernel/include/dist.hrl +++ b/bootstrap/lib/kernel/include/dist.hrl @@ -41,32 +41,7 @@ -define(DFLAG_MAP_TAG, 16#20000). -define(DFLAG_BIG_CREATION, 16#40000). -define(DFLAG_SEND_SENDER, 16#80000). - -%% DFLAGs that require strict ordering or:ed together... --define(DFLAGS_STRICT_ORDER_DELIVERY, - ?DFLAG_DIST_HDR_ATOM_CACHE). - +-define(DFLAG_BIG_SEQTRACE_LABELS, 16#100000). %% Also update dflag2str() in ../src/dist_util.erl %% when adding flags... - --define(DFLAGS_ALL, - (?DFLAG_PUBLISHED - bor ?DFLAG_ATOM_CACHE - bor ?DFLAG_EXTENDED_REFERENCES - bor ?DFLAG_DIST_MONITOR - bor ?DFLAG_FUN_TAGS - bor ?DFLAG_DIST_MONITOR_NAME - bor ?DFLAG_HIDDEN_ATOM_CACHE - bor ?DFLAG_NEW_FUN_TAGS - bor ?DFLAG_EXTENDED_PIDS_PORTS - bor ?DFLAG_EXPORT_PTR_TAG - bor ?DFLAG_BIT_BINARIES - bor ?DFLAG_NEW_FLOATS - bor ?DFLAG_UNICODE_IO - bor ?DFLAG_DIST_HDR_ATOM_CACHE - bor ?DFLAG_SMALL_ATOM_TAGS - bor ?DFLAG_UTF8_ATOMS - bor ?DFLAG_MAP_TAG - bor ?DFLAG_BIG_CREATION - bor ?DFLAG_SEND_SENDER)). diff --git a/bootstrap/lib/stdlib/ebin/array.beam b/bootstrap/lib/stdlib/ebin/array.beam Binary files differindex 1dd8846725..e352b65951 100644 --- a/bootstrap/lib/stdlib/ebin/array.beam +++ b/bootstrap/lib/stdlib/ebin/array.beam diff --git a/bootstrap/lib/stdlib/ebin/beam_lib.beam b/bootstrap/lib/stdlib/ebin/beam_lib.beam Binary files differindex 7ffab34254..b17a9b1947 100644 --- a/bootstrap/lib/stdlib/ebin/beam_lib.beam +++ b/bootstrap/lib/stdlib/ebin/beam_lib.beam diff --git a/bootstrap/lib/stdlib/ebin/c.beam b/bootstrap/lib/stdlib/ebin/c.beam Binary files differindex b3f62c467d..6c8d14bac1 100644 --- a/bootstrap/lib/stdlib/ebin/c.beam +++ b/bootstrap/lib/stdlib/ebin/c.beam diff --git a/bootstrap/lib/stdlib/ebin/dets.beam b/bootstrap/lib/stdlib/ebin/dets.beam Binary files differindex 9384a4379f..0c45d5fa71 100644 --- a/bootstrap/lib/stdlib/ebin/dets.beam +++ b/bootstrap/lib/stdlib/ebin/dets.beam diff --git a/bootstrap/lib/stdlib/ebin/dets_utils.beam b/bootstrap/lib/stdlib/ebin/dets_utils.beam Binary files differindex 265facaa57..6f00fd917b 100644 --- a/bootstrap/lib/stdlib/ebin/dets_utils.beam +++ b/bootstrap/lib/stdlib/ebin/dets_utils.beam diff --git a/bootstrap/lib/stdlib/ebin/dets_v9.beam b/bootstrap/lib/stdlib/ebin/dets_v9.beam Binary files differindex f53f9fcf85..e97d806a8f 100644 --- a/bootstrap/lib/stdlib/ebin/dets_v9.beam +++ b/bootstrap/lib/stdlib/ebin/dets_v9.beam diff --git a/bootstrap/lib/stdlib/ebin/digraph.beam b/bootstrap/lib/stdlib/ebin/digraph.beam Binary files differindex c51ecf54fc..1faf374588 100644 --- a/bootstrap/lib/stdlib/ebin/digraph.beam +++ b/bootstrap/lib/stdlib/ebin/digraph.beam diff --git a/bootstrap/lib/stdlib/ebin/digraph_utils.beam b/bootstrap/lib/stdlib/ebin/digraph_utils.beam Binary files differindex 6b0158ce48..fa41a7af26 100644 --- a/bootstrap/lib/stdlib/ebin/digraph_utils.beam +++ b/bootstrap/lib/stdlib/ebin/digraph_utils.beam diff --git a/bootstrap/lib/stdlib/ebin/epp.beam b/bootstrap/lib/stdlib/ebin/epp.beam Binary files differindex 58e29d0c3b..9695be2c1a 100644 --- a/bootstrap/lib/stdlib/ebin/epp.beam +++ b/bootstrap/lib/stdlib/ebin/epp.beam diff --git a/bootstrap/lib/stdlib/ebin/erl_eval.beam b/bootstrap/lib/stdlib/ebin/erl_eval.beam Binary files differindex eb913d070d..f3fc64ee32 100644 --- a/bootstrap/lib/stdlib/ebin/erl_eval.beam +++ b/bootstrap/lib/stdlib/ebin/erl_eval.beam diff --git a/bootstrap/lib/stdlib/ebin/erl_expand_records.beam b/bootstrap/lib/stdlib/ebin/erl_expand_records.beam Binary files differindex 1869788f7b..a4bfe3d411 100644 --- a/bootstrap/lib/stdlib/ebin/erl_expand_records.beam +++ b/bootstrap/lib/stdlib/ebin/erl_expand_records.beam diff --git a/bootstrap/lib/stdlib/ebin/erl_lint.beam b/bootstrap/lib/stdlib/ebin/erl_lint.beam Binary files differindex b8350e8975..64caedd3ac 100644 --- a/bootstrap/lib/stdlib/ebin/erl_lint.beam +++ b/bootstrap/lib/stdlib/ebin/erl_lint.beam diff --git a/bootstrap/lib/stdlib/ebin/erl_parse.beam b/bootstrap/lib/stdlib/ebin/erl_parse.beam Binary files differindex bfc5843912..86876cda96 100644 --- a/bootstrap/lib/stdlib/ebin/erl_parse.beam +++ b/bootstrap/lib/stdlib/ebin/erl_parse.beam diff --git a/bootstrap/lib/stdlib/ebin/erl_posix_msg.beam b/bootstrap/lib/stdlib/ebin/erl_posix_msg.beam Binary files differindex 825051d134..a5d30afed2 100644 --- a/bootstrap/lib/stdlib/ebin/erl_posix_msg.beam +++ b/bootstrap/lib/stdlib/ebin/erl_posix_msg.beam diff --git a/bootstrap/lib/stdlib/ebin/erl_pp.beam b/bootstrap/lib/stdlib/ebin/erl_pp.beam Binary files differindex ca3d18a5db..f645aea910 100644 --- a/bootstrap/lib/stdlib/ebin/erl_pp.beam +++ b/bootstrap/lib/stdlib/ebin/erl_pp.beam diff --git a/bootstrap/lib/stdlib/ebin/erl_scan.beam b/bootstrap/lib/stdlib/ebin/erl_scan.beam Binary files differindex 4bc9f7cbc3..0f516803e3 100644 --- a/bootstrap/lib/stdlib/ebin/erl_scan.beam +++ b/bootstrap/lib/stdlib/ebin/erl_scan.beam diff --git a/bootstrap/lib/stdlib/ebin/erl_tar.beam b/bootstrap/lib/stdlib/ebin/erl_tar.beam Binary files differindex ba7382f874..b72e4ebf6a 100644 --- a/bootstrap/lib/stdlib/ebin/erl_tar.beam +++ b/bootstrap/lib/stdlib/ebin/erl_tar.beam diff --git a/bootstrap/lib/stdlib/ebin/error_logger_tty_h.beam b/bootstrap/lib/stdlib/ebin/error_logger_tty_h.beam Binary files differindex d504f97f9f..a6e46e72b4 100644 --- a/bootstrap/lib/stdlib/ebin/error_logger_tty_h.beam +++ b/bootstrap/lib/stdlib/ebin/error_logger_tty_h.beam diff --git a/bootstrap/lib/stdlib/ebin/escript.beam b/bootstrap/lib/stdlib/ebin/escript.beam Binary files differindex 5ae2752a6d..79ed0a3876 100644 --- a/bootstrap/lib/stdlib/ebin/escript.beam +++ b/bootstrap/lib/stdlib/ebin/escript.beam diff --git a/bootstrap/lib/stdlib/ebin/ets.beam b/bootstrap/lib/stdlib/ebin/ets.beam Binary files differindex f2a649e0d1..3d103b1624 100644 --- a/bootstrap/lib/stdlib/ebin/ets.beam +++ b/bootstrap/lib/stdlib/ebin/ets.beam diff --git a/bootstrap/lib/stdlib/ebin/file_sorter.beam b/bootstrap/lib/stdlib/ebin/file_sorter.beam Binary files differindex 8a9e501e1b..3808a2da30 100644 --- a/bootstrap/lib/stdlib/ebin/file_sorter.beam +++ b/bootstrap/lib/stdlib/ebin/file_sorter.beam diff --git a/bootstrap/lib/stdlib/ebin/filelib.beam b/bootstrap/lib/stdlib/ebin/filelib.beam Binary files differindex 7fc4d0b06a..d1ec5357fc 100644 --- a/bootstrap/lib/stdlib/ebin/filelib.beam +++ b/bootstrap/lib/stdlib/ebin/filelib.beam diff --git a/bootstrap/lib/stdlib/ebin/gb_sets.beam b/bootstrap/lib/stdlib/ebin/gb_sets.beam Binary files differindex 4b524f17a3..43ba8674b7 100644 --- a/bootstrap/lib/stdlib/ebin/gb_sets.beam +++ b/bootstrap/lib/stdlib/ebin/gb_sets.beam diff --git a/bootstrap/lib/stdlib/ebin/gb_trees.beam b/bootstrap/lib/stdlib/ebin/gb_trees.beam Binary files differindex e62ee69cec..4476889671 100644 --- a/bootstrap/lib/stdlib/ebin/gb_trees.beam +++ b/bootstrap/lib/stdlib/ebin/gb_trees.beam diff --git a/bootstrap/lib/stdlib/ebin/gen.beam b/bootstrap/lib/stdlib/ebin/gen.beam Binary files differindex 0c36dfe05a..b0e38024c5 100644 --- a/bootstrap/lib/stdlib/ebin/gen.beam +++ b/bootstrap/lib/stdlib/ebin/gen.beam diff --git a/bootstrap/lib/stdlib/ebin/gen_event.beam b/bootstrap/lib/stdlib/ebin/gen_event.beam Binary files differindex 21806df360..4973a8eee9 100644 --- a/bootstrap/lib/stdlib/ebin/gen_event.beam +++ b/bootstrap/lib/stdlib/ebin/gen_event.beam diff --git a/bootstrap/lib/stdlib/ebin/gen_fsm.beam b/bootstrap/lib/stdlib/ebin/gen_fsm.beam Binary files differindex fccfecd7d8..5db1d6b014 100644 --- a/bootstrap/lib/stdlib/ebin/gen_fsm.beam +++ b/bootstrap/lib/stdlib/ebin/gen_fsm.beam diff --git a/bootstrap/lib/stdlib/ebin/gen_server.beam b/bootstrap/lib/stdlib/ebin/gen_server.beam Binary files differindex 3f2d31465f..cce5da1bfb 100644 --- a/bootstrap/lib/stdlib/ebin/gen_server.beam +++ b/bootstrap/lib/stdlib/ebin/gen_server.beam diff --git a/bootstrap/lib/stdlib/ebin/gen_statem.beam b/bootstrap/lib/stdlib/ebin/gen_statem.beam Binary files differindex c79b4a16f9..9750faf6f0 100644 --- a/bootstrap/lib/stdlib/ebin/gen_statem.beam +++ b/bootstrap/lib/stdlib/ebin/gen_statem.beam diff --git a/bootstrap/lib/stdlib/ebin/io_lib.beam b/bootstrap/lib/stdlib/ebin/io_lib.beam Binary files differindex adb2ac56b0..f2992f1ef5 100644 --- a/bootstrap/lib/stdlib/ebin/io_lib.beam +++ b/bootstrap/lib/stdlib/ebin/io_lib.beam diff --git a/bootstrap/lib/stdlib/ebin/io_lib_format.beam b/bootstrap/lib/stdlib/ebin/io_lib_format.beam Binary files differindex 713f6236aa..584d2130f4 100644 --- a/bootstrap/lib/stdlib/ebin/io_lib_format.beam +++ b/bootstrap/lib/stdlib/ebin/io_lib_format.beam diff --git a/bootstrap/lib/stdlib/ebin/io_lib_fread.beam b/bootstrap/lib/stdlib/ebin/io_lib_fread.beam Binary files differindex 2eebe1c85d..b33a6bbd72 100644 --- a/bootstrap/lib/stdlib/ebin/io_lib_fread.beam +++ b/bootstrap/lib/stdlib/ebin/io_lib_fread.beam diff --git a/bootstrap/lib/stdlib/ebin/io_lib_pretty.beam b/bootstrap/lib/stdlib/ebin/io_lib_pretty.beam Binary files differindex bf9e95e6be..1bc755ce36 100644 --- a/bootstrap/lib/stdlib/ebin/io_lib_pretty.beam +++ b/bootstrap/lib/stdlib/ebin/io_lib_pretty.beam diff --git a/bootstrap/lib/stdlib/ebin/lib.beam b/bootstrap/lib/stdlib/ebin/lib.beam Binary files differindex 7d342a59a9..2cc777b388 100644 --- a/bootstrap/lib/stdlib/ebin/lib.beam +++ b/bootstrap/lib/stdlib/ebin/lib.beam diff --git a/bootstrap/lib/stdlib/ebin/lists.beam b/bootstrap/lib/stdlib/ebin/lists.beam Binary files differindex bfcebe04a4..a711637e0c 100644 --- a/bootstrap/lib/stdlib/ebin/lists.beam +++ b/bootstrap/lib/stdlib/ebin/lists.beam diff --git a/bootstrap/lib/stdlib/ebin/ms_transform.beam b/bootstrap/lib/stdlib/ebin/ms_transform.beam Binary files differindex 8228a076ba..62b1b83eaf 100644 --- a/bootstrap/lib/stdlib/ebin/ms_transform.beam +++ b/bootstrap/lib/stdlib/ebin/ms_transform.beam diff --git a/bootstrap/lib/stdlib/ebin/ordsets.beam b/bootstrap/lib/stdlib/ebin/ordsets.beam Binary files differindex b966590d8d..eac57f960a 100644 --- a/bootstrap/lib/stdlib/ebin/ordsets.beam +++ b/bootstrap/lib/stdlib/ebin/ordsets.beam diff --git a/bootstrap/lib/stdlib/ebin/otp_internal.beam b/bootstrap/lib/stdlib/ebin/otp_internal.beam Binary files differindex 166574e0f6..5532192e13 100644 --- a/bootstrap/lib/stdlib/ebin/otp_internal.beam +++ b/bootstrap/lib/stdlib/ebin/otp_internal.beam diff --git a/bootstrap/lib/stdlib/ebin/proc_lib.beam b/bootstrap/lib/stdlib/ebin/proc_lib.beam Binary files differindex 6689783d5d..7b6c20a0b0 100644 --- a/bootstrap/lib/stdlib/ebin/proc_lib.beam +++ b/bootstrap/lib/stdlib/ebin/proc_lib.beam diff --git a/bootstrap/lib/stdlib/ebin/proplists.beam b/bootstrap/lib/stdlib/ebin/proplists.beam Binary files differindex a9768d2929..cb2e3ddb11 100644 --- a/bootstrap/lib/stdlib/ebin/proplists.beam +++ b/bootstrap/lib/stdlib/ebin/proplists.beam diff --git a/bootstrap/lib/stdlib/ebin/qlc.beam b/bootstrap/lib/stdlib/ebin/qlc.beam Binary files differindex 6c2895ac79..523f93a848 100644 --- a/bootstrap/lib/stdlib/ebin/qlc.beam +++ b/bootstrap/lib/stdlib/ebin/qlc.beam diff --git a/bootstrap/lib/stdlib/ebin/qlc_pt.beam b/bootstrap/lib/stdlib/ebin/qlc_pt.beam Binary files differindex d40c197029..4153598cc7 100644 --- a/bootstrap/lib/stdlib/ebin/qlc_pt.beam +++ b/bootstrap/lib/stdlib/ebin/qlc_pt.beam diff --git a/bootstrap/lib/stdlib/ebin/rand.beam b/bootstrap/lib/stdlib/ebin/rand.beam Binary files differindex 6574df6c6f..55f8db7445 100644 --- a/bootstrap/lib/stdlib/ebin/rand.beam +++ b/bootstrap/lib/stdlib/ebin/rand.beam diff --git a/bootstrap/lib/stdlib/ebin/re.beam b/bootstrap/lib/stdlib/ebin/re.beam Binary files differindex 784cf2fe7a..4334fa8dc4 100644 --- a/bootstrap/lib/stdlib/ebin/re.beam +++ b/bootstrap/lib/stdlib/ebin/re.beam diff --git a/bootstrap/lib/stdlib/ebin/sets.beam b/bootstrap/lib/stdlib/ebin/sets.beam Binary files differindex 3f90d78b8f..c1b7414741 100644 --- a/bootstrap/lib/stdlib/ebin/sets.beam +++ b/bootstrap/lib/stdlib/ebin/sets.beam diff --git a/bootstrap/lib/stdlib/ebin/shell.beam b/bootstrap/lib/stdlib/ebin/shell.beam Binary files differindex e2dfa3c636..8c8c1f5821 100644 --- a/bootstrap/lib/stdlib/ebin/shell.beam +++ b/bootstrap/lib/stdlib/ebin/shell.beam diff --git a/bootstrap/lib/stdlib/ebin/sofs.beam b/bootstrap/lib/stdlib/ebin/sofs.beam Binary files differindex bfefd0c3a9..4a127561e8 100644 --- a/bootstrap/lib/stdlib/ebin/sofs.beam +++ b/bootstrap/lib/stdlib/ebin/sofs.beam diff --git a/bootstrap/lib/stdlib/ebin/stdlib.app b/bootstrap/lib/stdlib/ebin/stdlib.app index d542c669f8..c24ca46516 100644 --- a/bootstrap/lib/stdlib/ebin/stdlib.app +++ b/bootstrap/lib/stdlib/ebin/stdlib.app @@ -20,7 +20,7 @@ %% {application, stdlib, [{description, "ERTS CXC 138 10"}, - {vsn, "3.4.3"}, + {vsn, "3.4.5"}, {modules, [array, base64, beam_lib, diff --git a/bootstrap/lib/stdlib/ebin/string.beam b/bootstrap/lib/stdlib/ebin/string.beam Binary files differindex feeeec6a84..39ec49672a 100644 --- a/bootstrap/lib/stdlib/ebin/string.beam +++ b/bootstrap/lib/stdlib/ebin/string.beam diff --git a/bootstrap/lib/stdlib/ebin/supervisor.beam b/bootstrap/lib/stdlib/ebin/supervisor.beam Binary files differindex 61e8fca92c..37c6e31aab 100644 --- a/bootstrap/lib/stdlib/ebin/supervisor.beam +++ b/bootstrap/lib/stdlib/ebin/supervisor.beam diff --git a/bootstrap/lib/stdlib/ebin/supervisor_bridge.beam b/bootstrap/lib/stdlib/ebin/supervisor_bridge.beam Binary files differindex 800c167237..dbd598ab13 100644 --- a/bootstrap/lib/stdlib/ebin/supervisor_bridge.beam +++ b/bootstrap/lib/stdlib/ebin/supervisor_bridge.beam diff --git a/bootstrap/lib/stdlib/ebin/sys.beam b/bootstrap/lib/stdlib/ebin/sys.beam Binary files differindex 0cec9f4be8..ec94d7df70 100644 --- a/bootstrap/lib/stdlib/ebin/sys.beam +++ b/bootstrap/lib/stdlib/ebin/sys.beam diff --git a/bootstrap/lib/stdlib/ebin/unicode_util.beam b/bootstrap/lib/stdlib/ebin/unicode_util.beam Binary files differindex ab18c78028..7ff215178f 100644 --- a/bootstrap/lib/stdlib/ebin/unicode_util.beam +++ b/bootstrap/lib/stdlib/ebin/unicode_util.beam diff --git a/bootstrap/lib/stdlib/ebin/uri_string.beam b/bootstrap/lib/stdlib/ebin/uri_string.beam Binary files differindex 95b7a2e6ae..e14164a823 100644 --- a/bootstrap/lib/stdlib/ebin/uri_string.beam +++ b/bootstrap/lib/stdlib/ebin/uri_string.beam diff --git a/bootstrap/lib/stdlib/ebin/zip.beam b/bootstrap/lib/stdlib/ebin/zip.beam Binary files differindex 3e19c83090..ef7ea86791 100644 --- a/bootstrap/lib/stdlib/ebin/zip.beam +++ b/bootstrap/lib/stdlib/ebin/zip.beam diff --git a/erts/doc/src/Makefile b/erts/doc/src/Makefile index c4f1baf89e..5fa8b0673a 100644 --- a/erts/doc/src/Makefile +++ b/erts/doc/src/Makefile @@ -155,7 +155,7 @@ clean: rm -f errs core *~ $(SPECDIR)/specs_%.xml: - escript $(SPECS_EXTRACTOR) $(SPECS_FLAGS) \ + $(gen_verbose)escript $(SPECS_EXTRACTOR) $(SPECS_FLAGS) \ -o$(dir $@) -module $(patsubst $(SPECDIR)/specs_%.xml,%,$@) # ---------------------------------------------------- diff --git a/erts/doc/src/erl_nif.xml b/erts/doc/src/erl_nif.xml index cabc07d020..8a9ae58e99 100644 --- a/erts/doc/src/erl_nif.xml +++ b/erts/doc/src/erl_nif.xml @@ -1292,7 +1292,7 @@ typedef struct { ErlNifIOVec *iovec = NULL; size_t max_elements = 128; ERL_NIF_TERM tail; -if (!enif_inspect_iovec(NULL, max_elements, term, &tail, iovec)) +if (!enif_inspect_iovec(NULL, max_elements, term, &tail, &iovec)) return 0; // Do things with the iovec diff --git a/erts/doc/src/erlang.xml b/erts/doc/src/erlang.xml index c086928bb3..d4d4dd7f31 100644 --- a/erts/doc/src/erlang.xml +++ b/erts/doc/src/erlang.xml @@ -53,14 +53,14 @@ <datatypes> <datatype> - <name>ext_binary()</name> + <name name="ext_binary"/> <desc> <p>A binary data object, structured according to the Erlang external term format.</p> </desc> </datatype> <datatype> - <name>iovec()</name> + <name name="iovec"/> <desc> <p>A list of binaries. This datatype is useful to use together with <seealso marker="erl_nif#enif_inspect_iovec"> @@ -204,10 +204,6 @@ <name name="abs" arity="1" clause_i="1"/> <name name="abs" arity="1" clause_i="2"/> <fsummary>Arithmetical absolute value.</fsummary> - <type> - <v>Float = float()</v> - <v>Int = integer()</v> - </type> <desc> <p>Returns an integer or float that is the arithmetical absolute value of <c><anno>Float</anno></c> or diff --git a/erts/emulator/beam/beam_emu.c b/erts/emulator/beam/beam_emu.c index fb87be3f17..ee287243a4 100644 --- a/erts/emulator/beam/beam_emu.c +++ b/erts/emulator/beam/beam_emu.c @@ -2420,8 +2420,7 @@ erts_hibernate(Process* c_p, Eterm* reg) * shrink the heap. */ erts_proc_lock(c_p, ERTS_PROC_LOCK_MSGQ|ERTS_PROC_LOCK_STATUS); - erts_proc_sig_fetch(c_p); - if (!c_p->sig_qs.len) { + if (!erts_proc_sig_fetch(c_p)) { erts_proc_unlock(c_p, ERTS_PROC_LOCK_MSGQ|ERTS_PROC_LOCK_STATUS); c_p->fvalue = NIL; PROCESS_MAIN_CHK_LOCKS(c_p); @@ -2429,8 +2428,7 @@ erts_hibernate(Process* c_p, Eterm* reg) ERTS_VERIFY_UNUSED_TEMP_ALLOC(c_p); PROCESS_MAIN_CHK_LOCKS(c_p); erts_proc_lock(c_p, ERTS_PROC_LOCK_MSGQ|ERTS_PROC_LOCK_STATUS); - erts_proc_sig_fetch(c_p); - if (!c_p->sig_qs.len) + if (!erts_proc_sig_fetch(c_p)) erts_atomic32_read_band_relb(&c_p->state, ~ERTS_PSFLG_ACTIVE); ASSERT(!ERTS_PROC_IS_EXITING(c_p)); } diff --git a/erts/emulator/beam/bif.c b/erts/emulator/beam/bif.c index 232597c5b6..017faffa48 100644 --- a/erts/emulator/beam/bif.c +++ b/erts/emulator/beam/bif.c @@ -4147,7 +4147,8 @@ BIF_RETTYPE erts_internal_group_leader_2(BIF_ALIST_2) rp = BIF_P; else { rp = erts_try_lock_sig_free_proc(BIF_ARG_2, - ERTS_PROC_LOCK_MAIN); + ERTS_PROC_LOCK_MAIN, + NULL); if (!rp) BIF_RET(am_badarg); if (rp == ERTS_PROC_LOCK_BUSY) diff --git a/erts/emulator/beam/bif.h b/erts/emulator/beam/bif.h index a33421d762..a47339253e 100644 --- a/erts/emulator/beam/bif.h +++ b/erts/emulator/beam/bif.h @@ -425,6 +425,12 @@ do { \ BIF_TRAP3((TRP), (P), (A0), (A1), (A2)); \ } while (0) +#define ERTS_BIF_PREP_EXITED(RET, PROC) \ +do { \ + KILL_CATCHES((PROC)); \ + ERTS_BIF_PREP_ERROR((RET), (PROC), EXTAG_EXIT); \ +} while (0) + #define ERTS_BIF_EXITED(PROC) \ do { \ KILL_CATCHES((PROC)); \ diff --git a/erts/emulator/beam/binary.c b/erts/emulator/beam/binary.c index 95d324d2c1..d53f75c279 100644 --- a/erts/emulator/beam/binary.c +++ b/erts/emulator/beam/binary.c @@ -113,6 +113,40 @@ new_binary(Process *p, byte *buf, Uint len) return build_proc_bin(&MSO(p), HAlloc(p, PROC_BIN_SIZE), bptr); } +Eterm +erts_heap_factory_new_binary(ErtsHeapFactory *hfact, byte *buf, Uint len, + Uint reserve_size) +{ + Eterm *hp; + Binary* bptr; + + if (len <= ERL_ONHEAP_BIN_LIMIT) { + ErlHeapBin* hb; + hp = erts_produce_heap(hfact, heap_bin_size(len), reserve_size); + hb = (ErlHeapBin *) hp; + hb->thing_word = header_heap_bin(len); + hb->size = len; + if (buf != NULL) { + sys_memcpy(hb->data, buf, len); + } + return make_binary(hb); + } + + /* + * Allocate the binary struct itself. + */ + bptr = erts_bin_nrml_alloc(len); + if (buf != NULL) { + sys_memcpy(bptr->orig_bytes, buf, len); + } + + hp = erts_produce_heap(hfact, PROC_BIN_SIZE, reserve_size); + + return build_proc_bin(hfact->off_heap, hp, bptr); +} + + + /* * When heap binary is not desired... */ diff --git a/erts/emulator/beam/break.c b/erts/emulator/beam/break.c index 4dabac3512..ba8cc5e2ba 100644 --- a/erts/emulator/beam/break.c +++ b/erts/emulator/beam/break.c @@ -204,6 +204,7 @@ print_process_info(fmtfn_t to, void *to_arg, Process *p) { int garbing = 0; int running = 0; + Sint len; struct saved_calls *scb; erts_aint32_t state; @@ -252,9 +253,9 @@ print_process_info(fmtfn_t to, void *to_arg, Process *p) erts_print(to, to_arg, "Spawned by: %T\n", p->parent); erts_proc_lock(p, ERTS_PROC_LOCK_MSGQ); - erts_proc_sig_fetch(p); + len = erts_proc_sig_fetch(p); erts_proc_unlock(p, ERTS_PROC_LOCK_MSGQ); - erts_print(to, to_arg, "Message queue length: %d\n", p->sig_qs.len); + erts_print(to, to_arg, "Message queue length: %d\n", len); /* display the message queue only if there is anything in it */ if (!ERTS_IS_CRASH_DUMPING && p->sig_qs.first != NULL && !garbing) { diff --git a/erts/emulator/beam/erl_bif_info.c b/erts/emulator/beam/erl_bif_info.c index bdca93428e..d443e12409 100644 --- a/erts/emulator/beam/erl_bif_info.c +++ b/erts/emulator/beam/erl_bif_info.c @@ -155,8 +155,10 @@ static Eterm os_type_tuple; static Eterm os_version_tuple; static Eterm -current_function(Process* p, Process* rp, Eterm** hpp, int full_info); -static Eterm current_stacktrace(Process* p, Process* rp, Eterm** hpp); +current_function(Process* p, ErtsHeapFactory *hfact, Process* rp, + int full_info, Uint reserve_size, int flags); +static Eterm current_stacktrace(ErtsHeapFactory *hfact, Process* rp, + Uint reserve_size); static Eterm bld_bin_list(Uint **hpp, Uint *szp, ErlOffHeap* oh) @@ -693,119 +695,222 @@ collect_one_suspend_monitor(ErtsMonitor *mon, void *vsmicp) * process_info/[1,2] */ -#define ERTS_PI_FAIL_TYPE_BADARG 0 -#define ERTS_PI_FAIL_TYPE_YIELD 1 -#define ERTS_PI_FAIL_TYPE_EXITED 2 - -static ERTS_INLINE ErtsProcLocks -pi_locks(Eterm info) -{ - switch (info) { - case am_priority: - case am_status: - return 0; - case am_suspended: - return ERTS_PROC_LOCK_STATUS; - case am_messages: - case am_message_queue_len: - case am_total_heap_size: - return ERTS_PROC_LOCK_MAIN|ERTS_PROC_LOCK_MSGQ; - default: - return ERTS_PROC_LOCK_MAIN; - } -} - /* * All valid process_info arguments. */ -static Eterm pi_args[] = { - am_registered_name, - am_current_function, - am_initial_call, - am_status, - am_messages, - am_message_queue_len, - am_links, - am_monitors, - am_monitored_by, - am_dictionary, - am_trap_exit, - am_error_handler, - am_heap_size, - am_stack_size, - am_memory, - am_garbage_collection, - am_group_leader, - am_reductions, - am_priority, - am_trace, - am_binary, - am_sequential_trace_token, - am_catchlevel, - am_backtrace, - am_last_calls, - am_total_heap_size, - am_suspending, - am_min_heap_size, - am_min_bin_vheap_size, - am_max_heap_size, - am_current_location, - am_current_stacktrace, - am_message_queue_data, - am_garbage_collection_info, - am_magic_ref + +#define ERTS_PI_IX_REGISTERED_NAME 0 +#define ERTS_PI_IX_CURRENT_FUNCTION 1 +#define ERTS_PI_IX_INITIAL_CALL 2 +#define ERTS_PI_IX_STATUS 3 +#define ERTS_PI_IX_MESSAGES 4 +#define ERTS_PI_IX_MESSAGE_QUEUE_LEN 5 +#define ERTS_PI_IX_LINKS 6 +#define ERTS_PI_IX_MONITORS 7 +#define ERTS_PI_IX_MONITORED_BY 8 +#define ERTS_PI_IX_DICTIONARY 9 +#define ERTS_PI_IX_TRAP_EXIT 10 +#define ERTS_PI_IX_ERROR_HANDLER 11 +#define ERTS_PI_IX_HEAP_SIZE 12 +#define ERTS_PI_IX_STACK_SIZE 13 +#define ERTS_PI_IX_MEMORY 14 +#define ERTS_PI_IX_GARBAGE_COLLECTION 15 +#define ERTS_PI_IX_GROUP_LEADER 16 +#define ERTS_PI_IX_REDUCTIONS 17 +#define ERTS_PI_IX_PRIORITY 18 +#define ERTS_PI_IX_TRACE 19 +#define ERTS_PI_IX_BINARY 20 +#define ERTS_PI_IX_SEQUENTIAL_TRACE_TOKEN 21 +#define ERTS_PI_IX_CATCHLEVEL 22 +#define ERTS_PI_IX_BACKTRACE 23 +#define ERTS_PI_IX_LAST_CALLS 24 +#define ERTS_PI_IX_TOTAL_HEAP_SIZE 25 +#define ERTS_PI_IX_SUSPENDING 26 +#define ERTS_PI_IX_MIN_HEAP_SIZE 27 +#define ERTS_PI_IX_MIN_BIN_VHEAP_SIZE 28 +#define ERTS_PI_IX_MAX_HEAP_SIZE 29 +#define ERTS_PI_IX_CURRENT_LOCATION 30 +#define ERTS_PI_IX_CURRENT_STACKTRACE 31 +#define ERTS_PI_IX_MESSAGE_QUEUE_DATA 32 +#define ERTS_PI_IX_GARBAGE_COLLECTION_INFO 33 +#define ERTS_PI_IX_MAGIC_REF 34 +#define ERTS_PI_IX_FULLSWEEP_AFTER 35 + +#define ERTS_PI_FLAG_SINGELTON (1 << 0) +#define ERTS_PI_FLAG_ALWAYS_WRAP (1 << 1) +#define ERTS_PI_FLAG_WANT_MSGS (1 << 2) +#define ERTS_PI_FLAG_NEED_MSGQ_LEN (1 << 3) +#define ERTS_PI_FLAG_FORCE_SIG_SEND (1 << 4) +#define ERTS_PI_FLAG_REQUEST_FOR_OTHER (1 << 5) + +#define ERTS_PI_UNRESERVE(RS, SZ) \ + (ASSERT((RS) >= (SZ)), (RS) -= (SZ)) + + +typedef struct { + Eterm name; + Uint reserve_size; + int flags; + ErtsProcLocks locks; +} ErtsProcessInfoArgs; + +static ErtsProcessInfoArgs pi_args[] = { + {am_registered_name, 0, 0, ERTS_PROC_LOCK_MAIN}, + {am_current_function, 4, 0, ERTS_PROC_LOCK_MAIN}, + {am_initial_call, 4, 0, ERTS_PROC_LOCK_MAIN}, + {am_status, 0, 0, 0}, + {am_messages, 0, ERTS_PI_FLAG_WANT_MSGS|ERTS_PI_FLAG_NEED_MSGQ_LEN|ERTS_PI_FLAG_FORCE_SIG_SEND, ERTS_PROC_LOCK_MAIN}, + {am_message_queue_len, 0, ERTS_PI_FLAG_NEED_MSGQ_LEN, ERTS_PROC_LOCK_MAIN}, + {am_links, 0, ERTS_PI_FLAG_FORCE_SIG_SEND, ERTS_PROC_LOCK_MAIN}, + {am_monitors, 0, ERTS_PI_FLAG_FORCE_SIG_SEND, ERTS_PROC_LOCK_MAIN}, + {am_monitored_by, 0, ERTS_PI_FLAG_FORCE_SIG_SEND, ERTS_PROC_LOCK_MAIN}, + {am_dictionary, 0, ERTS_PI_FLAG_FORCE_SIG_SEND, ERTS_PROC_LOCK_MAIN}, + {am_trap_exit, 0, 0, ERTS_PROC_LOCK_MAIN}, + {am_error_handler, 0, 0, ERTS_PROC_LOCK_MAIN}, + {am_heap_size, 0, 0, ERTS_PROC_LOCK_MAIN}, + {am_stack_size, 0, 0, ERTS_PROC_LOCK_MAIN}, + {am_memory, 0, ERTS_PI_FLAG_NEED_MSGQ_LEN|ERTS_PI_FLAG_FORCE_SIG_SEND, ERTS_PROC_LOCK_MAIN}, + {am_garbage_collection, 3+2 + 3+2 + 3+2 + 3+2 + 3+2 + ERTS_MAX_HEAP_SIZE_MAP_SZ, 0, ERTS_PROC_LOCK_MAIN}, + {am_group_leader, 0, 0, ERTS_PROC_LOCK_MAIN}, + {am_reductions, 0, 0, ERTS_PROC_LOCK_MAIN}, + {am_priority, 0, 0, 0}, + {am_trace, 0, 0, ERTS_PROC_LOCK_MAIN}, + {am_binary, 0, ERTS_PI_FLAG_FORCE_SIG_SEND, ERTS_PROC_LOCK_MAIN}, + {am_sequential_trace_token, 0, 0, ERTS_PROC_LOCK_MAIN}, + {am_catchlevel, 0, 0, ERTS_PROC_LOCK_MAIN}, + {am_backtrace, 0, 0, ERTS_PROC_LOCK_MAIN}, + {am_last_calls, 0, 0, ERTS_PROC_LOCK_MAIN}, + {am_total_heap_size, 0, ERTS_PI_FLAG_NEED_MSGQ_LEN|ERTS_PI_FLAG_FORCE_SIG_SEND, ERTS_PROC_LOCK_MAIN}, + {am_suspending, 0, ERTS_PI_FLAG_FORCE_SIG_SEND, 0}, + {am_min_heap_size, 0, 0, ERTS_PROC_LOCK_MAIN}, + {am_min_bin_vheap_size, 0, 0, ERTS_PROC_LOCK_MAIN}, + {am_max_heap_size, 0, 0, ERTS_PROC_LOCK_MAIN}, + {am_current_location, 0, 0, ERTS_PROC_LOCK_MAIN}, + {am_current_stacktrace, 0, 0, ERTS_PROC_LOCK_MAIN}, + {am_message_queue_data, 0, 0, ERTS_PROC_LOCK_MAIN}, + {am_garbage_collection_info, ERTS_PROCESS_GC_INFO_MAX_SIZE, 0, ERTS_PROC_LOCK_MAIN}, + {am_magic_ref, 0, ERTS_PI_FLAG_FORCE_SIG_SEND, ERTS_PROC_LOCK_MAIN}, + {am_fullsweep_after, 0, 0, ERTS_PROC_LOCK_MAIN} }; -#define ERTS_PI_ARGS ((int) (sizeof(pi_args)/sizeof(Eterm))) +#define ERTS_PI_ARGS ((int) (sizeof(pi_args)/sizeof(pi_args[0]))) + +#ifdef DEBUG +# define ERTS_PI_DEF_ARR_SZ 2 +#else +# define ERTS_PI_DEF_ARR_SZ ERTS_PI_ARGS +#endif static ERTS_INLINE Eterm pi_ix2arg(int ix) { if (ix < 0 || ERTS_PI_ARGS <= ix) return am_undefined; - return pi_args[ix]; + return pi_args[ix].name; +} + +static ERTS_INLINE int +pi_ix2flags(int ix) +{ + if (ix < 0 || ERTS_PI_ARGS <= ix) + return 0; + return pi_args[ix].flags; +} + +static ERTS_INLINE Uint +pi_ix2rsz(int ix) +{ + if (ix < 0 || ERTS_PI_ARGS <= ix) + return 0; + return pi_args[ix].reserve_size; +} + +static ERTS_INLINE ErtsProcLocks +pi_ix2locks(int ix) +{ + if (ix < 0 || ERTS_PI_ARGS <= ix) + return 0; + return pi_args[ix].locks; } static ERTS_INLINE int pi_arg2ix(Eterm arg) { switch (arg) { - case am_registered_name: return 0; - case am_current_function: return 1; - case am_initial_call: return 2; - case am_status: return 3; - case am_messages: return 4; - case am_message_queue_len: return 5; - case am_links: return 6; - case am_monitors: return 7; - case am_monitored_by: return 8; - case am_dictionary: return 9; - case am_trap_exit: return 10; - case am_error_handler: return 11; - case am_heap_size: return 12; - case am_stack_size: return 13; - case am_memory: return 14; - case am_garbage_collection: return 15; - case am_group_leader: return 16; - case am_reductions: return 17; - case am_priority: return 18; - case am_trace: return 19; - case am_binary: return 20; - case am_sequential_trace_token: return 21; - case am_catchlevel: return 22; - case am_backtrace: return 23; - case am_last_calls: return 24; - case am_total_heap_size: return 25; - case am_suspending: return 26; - case am_min_heap_size: return 27; - case am_min_bin_vheap_size: return 28; - case am_max_heap_size: return 29; - case am_current_location: return 30; - case am_current_stacktrace: return 31; - case am_message_queue_data: return 32; - case am_garbage_collection_info: return 33; - case am_magic_ref: return 34; - default: return -1; + case am_registered_name: + return ERTS_PI_IX_REGISTERED_NAME; + case am_current_function: + return ERTS_PI_IX_CURRENT_FUNCTION; + case am_initial_call: + return ERTS_PI_IX_INITIAL_CALL; + case am_status: + return ERTS_PI_IX_STATUS; + case am_messages: + return ERTS_PI_IX_MESSAGES; + case am_message_queue_len: + return ERTS_PI_IX_MESSAGE_QUEUE_LEN; + case am_links: + return ERTS_PI_IX_LINKS; + case am_monitors: + return ERTS_PI_IX_MONITORS; + case am_monitored_by: + return ERTS_PI_IX_MONITORED_BY; + case am_dictionary: + return ERTS_PI_IX_DICTIONARY; + case am_trap_exit: + return ERTS_PI_IX_TRAP_EXIT; + case am_error_handler: + return ERTS_PI_IX_ERROR_HANDLER; + case am_heap_size: + return ERTS_PI_IX_HEAP_SIZE; + case am_stack_size: + return ERTS_PI_IX_STACK_SIZE; + case am_memory: + return ERTS_PI_IX_MEMORY; + case am_garbage_collection: + return ERTS_PI_IX_GARBAGE_COLLECTION; + case am_group_leader: + return ERTS_PI_IX_GROUP_LEADER; + case am_reductions: + return ERTS_PI_IX_REDUCTIONS; + case am_priority: + return ERTS_PI_IX_PRIORITY; + case am_trace: + return ERTS_PI_IX_TRACE; + case am_binary: + return ERTS_PI_IX_BINARY; + case am_sequential_trace_token: + return ERTS_PI_IX_SEQUENTIAL_TRACE_TOKEN; + case am_catchlevel: + return ERTS_PI_IX_CATCHLEVEL; + case am_backtrace: + return ERTS_PI_IX_BACKTRACE; + case am_last_calls: + return ERTS_PI_IX_LAST_CALLS; + case am_total_heap_size: + return ERTS_PI_IX_TOTAL_HEAP_SIZE; + case am_suspending: + return ERTS_PI_IX_SUSPENDING; + case am_min_heap_size: + return ERTS_PI_IX_MIN_HEAP_SIZE; + case am_min_bin_vheap_size: + return ERTS_PI_IX_MIN_BIN_VHEAP_SIZE; + case am_max_heap_size: + return ERTS_PI_IX_MAX_HEAP_SIZE; + case am_current_location: + return ERTS_PI_IX_CURRENT_LOCATION; + case am_current_stacktrace: + return ERTS_PI_IX_CURRENT_STACKTRACE; + case am_message_queue_data: + return ERTS_PI_IX_MESSAGE_QUEUE_DATA; + case am_garbage_collection_info: + return ERTS_PI_IX_GARBAGE_COLLECTION_INFO; + case am_magic_ref: + return ERTS_PI_IX_MAGIC_REF; + case am_fullsweep_after: + return ERTS_PI_IX_FULLSWEEP_AFTER; + default: + return -1; } } @@ -858,186 +963,41 @@ process_info_init(void) } -static ERTS_INLINE Process * -pi_lookup_proc(Process *c_p, Eterm pid, ErtsProcLocks *locks) -{ - /* - * If the main lock is needed, we use erts_pid2proc_not_running() - * instead of erts_pid2proc() for two reasons: - * * Current function of pid and possibly other information will - * have been updated so that process_info() is consistent with an - * info-request/info-response signal model. - * * We avoid blocking the whole scheduler executing the - * process that is calling process_info() for a long time - * which will happen if pid is currently running. - * The caller of process_info() may have to yield if pid - * is currently running. - */ - - if ((*locks) & ERTS_PROC_LOCK_MAIN) { - erts_aint32_t state; - int local_only, done; - Process *rp; - ErtsProcLocks more_locks; - - rp = erts_pid2proc_not_running(c_p, ERTS_PROC_LOCK_MAIN, - pid, ERTS_PROC_LOCK_MAIN); - - if (!rp || rp == ERTS_PROC_LOCK_BUSY) - return rp; - - if ((*locks) & ERTS_PROC_LOCK_MSGQ) { - /* - * Move in queue into private queue and - * release msgq lock, enabling others to - * send messages to the process while it - * is being inspected... - */ - erts_proc_lock(rp, ERTS_PROC_LOCK_MSGQ); - erts_proc_sig_fetch(rp); - erts_proc_unlock(rp, ERTS_PROC_LOCK_MSGQ); - (*locks) &= ~ERTS_PROC_LOCK_MSGQ; - } - - /* - * Handle all signals received up to this point - * in order to preserve signal order. - * - * FIX ME: Should be done yielding... - */ - local_only = 0; - do { - int r = CONTEXT_REDS; - done = erts_proc_sig_handle_incoming(rp, &state, &r, - CONTEXT_REDS, - local_only); - local_only = !0; - BUMP_REDS(c_p, r); - } while (!done && !(state & ERTS_PSFLG_EXITING)); - - if (state & ERTS_PSFLG_EXITING) { - if (rp != c_p) - erts_proc_unlock(rp, ERTS_PROC_LOCK_MAIN); - return NULL; - } - more_locks = (*locks) & ~ERTS_PROC_LOCK_MAIN; - if (more_locks) - erts_proc_lock(rp, more_locks); - return rp; - } - - ASSERT(!((*locks) & ERTS_PROC_LOCK_MSGQ)); - - if (*locks) - return erts_pid2proc(c_p, ERTS_PROC_LOCK_MAIN, - pid, *locks); - - return erts_proc_lookup(pid); -} - - - - - static BIF_RETTYPE -process_info_aux(Process *BIF_P, +process_info_aux(Process *c_p, + ErtsHeapFactory *hfact, Process *rp, ErtsProcLocks rp_locks, - Eterm rpid, - Eterm item, - int always_wrap, - int *reds); - -#define ERTS_PI_RES_ELEM_IX_BUF_INC 1024 -#define ERTS_PI_DEF_RES_ELEM_IX_BUF_SZ ERTS_PI_ARGS + int item_ix, + int flags, + Uint *reserve_sizep, + Uint *reds); -static Eterm -process_info_list(Process *c_p, Eterm pid, Eterm list, int always_wrap, - int *fail_type) +Eterm +erts_process_info(Process *c_p, + ErtsHeapFactory *hfact, + Process *rp, + ErtsProcLocks rp_locks, + int *item_ix, + int item_ix_len, + int flags, + Uint reserve_size, + Uint *reds) { - int want_messages = 0; - int def_res_elem_ix_buf[ERTS_PI_DEF_RES_ELEM_IX_BUF_SZ]; - int *res_elem_ix = &def_res_elem_ix_buf[0]; - int res_elem_ix_ix = -1; - int res_elem_ix_sz = ERTS_PI_DEF_RES_ELEM_IX_BUF_SZ; + Eterm res; Eterm part_res[ERTS_PI_ARGS]; - Eterm res, arg; - Uint *hp, *hp_end; - ErtsProcLocks locks = (ErtsProcLocks) 0; - int res_len, ix; - Process *rp = NULL; - int reds = 0; + int item_ix_ix, ix; - *fail_type = ERTS_PI_FAIL_TYPE_BADARG; + if (ERTS_PI_FLAG_SINGELTON & flags) { + ASSERT(item_ix_len == 1); + res = process_info_aux(c_p, hfact, rp, rp_locks, item_ix[0], + flags, &reserve_size, reds); + return res; + } for (ix = 0; ix < ERTS_PI_ARGS; ix++) part_res[ix] = THE_NON_VALUE; - ASSERT(is_list(list)); - - while (is_list(list)) { - Eterm* consp = list_val(list); - - arg = CAR(consp); - ix = pi_arg2ix(arg); - if (ix < 0) { - res = THE_NON_VALUE; - goto done; - } - if (arg == am_messages) - want_messages = 1; - locks |= pi_locks(arg); - res_elem_ix_ix++; - if (res_elem_ix_ix >= res_elem_ix_sz) { - if (res_elem_ix != &def_res_elem_ix_buf[0]) - res_elem_ix = - erts_realloc(ERTS_ALC_T_TMP, - res_elem_ix, - sizeof(int)*(res_elem_ix_sz - += ERTS_PI_RES_ELEM_IX_BUF_INC)); - else { - int new_res_elem_ix_sz = ERTS_PI_RES_ELEM_IX_BUF_INC; - int *new_res_elem_ix = erts_alloc(ERTS_ALC_T_TMP, - sizeof(int)*new_res_elem_ix_sz); - sys_memcpy((void *) new_res_elem_ix, - (void *) res_elem_ix, - sizeof(int)*res_elem_ix_sz); - res_elem_ix = new_res_elem_ix; - res_elem_ix_sz = new_res_elem_ix_sz; - } - } - res_elem_ix[res_elem_ix_ix] = ix; - list = CDR(consp); - } - if (is_not_nil(list)) { - res = THE_NON_VALUE; - goto done; - } - - res_len = res_elem_ix_ix+1; - - ASSERT(res_len > 0); - - rp = pi_lookup_proc(c_p, pid, &locks); - if (!rp) { - if (c_p->common.id != pid) - res = am_undefined; - else { - *fail_type = ERTS_PI_FAIL_TYPE_EXITED; - res = THE_NON_VALUE; - } - goto done; - } - else if (rp == ERTS_PROC_LOCK_BUSY) { - rp = NULL; - res = THE_NON_VALUE; - *fail_type = ERTS_PI_FAIL_TYPE_YIELD; - goto done; - } - - if (c_p == rp) - locks |= ERTS_PROC_LOCK_MAIN; - /* * We always handle 'messages' first if it should be part * of the result. This since if both 'messages' and @@ -1045,35 +1005,31 @@ process_info_list(Process *c_p, Eterm pid, Eterm list, int always_wrap, * change the result of 'message_queue_len' (in case * the queue contain bad distribution messages). */ - if (want_messages) { + if (flags & ERTS_PI_FLAG_WANT_MSGS) { ix = pi_arg2ix(am_messages); ASSERT(part_res[ix] == THE_NON_VALUE); - res = process_info_aux(c_p, rp, locks, pid, am_messages, - always_wrap, &reds); + res = process_info_aux(c_p, hfact, rp, rp_locks, ix, + flags, &reserve_size, reds); ASSERT(res != am_undefined); ASSERT(res != THE_NON_VALUE); part_res[ix] = res; } - for (; res_elem_ix_ix >= 0; res_elem_ix_ix--) { - ix = res_elem_ix[res_elem_ix_ix]; + for (item_ix_ix = item_ix_len - 1; item_ix_ix >= 0; item_ix_ix--) { + ix = item_ix[item_ix_ix]; if (part_res[ix] == THE_NON_VALUE) { - arg = pi_ix2arg(ix); - res = process_info_aux(c_p, rp, locks, pid, arg, - always_wrap, &reds); - if (res == am_undefined) - goto done; + res = process_info_aux(c_p, hfact, rp, rp_locks, ix, + flags, &reserve_size, reds); + ASSERT(res != am_undefined); ASSERT(res != THE_NON_VALUE); part_res[ix] = res; } } - hp = HAlloc(c_p, res_len*2); - hp_end = hp + res_len*2; res = NIL; - for (res_elem_ix_ix = res_len - 1; res_elem_ix_ix >= 0; res_elem_ix_ix--) { - ix = res_elem_ix[res_elem_ix_ix]; + for (item_ix_ix = item_ix_len - 1; item_ix_ix >= 0; item_ix_ix--) { + ix = item_ix[item_ix_ix]; ASSERT(part_res[ix] != THE_NON_VALUE); /* * If we should ignore the value of registered_name, @@ -1081,155 +1037,310 @@ process_info_list(Process *c_p, Eterm pid, Eterm list, int always_wrap, * beginning of process_info_aux(). */ if (is_nil(part_res[ix])) { - ASSERT(!always_wrap); + ASSERT(!(flags & ERTS_PI_FLAG_ALWAYS_WRAP)); ASSERT(pi_ix2arg(ix) == am_registered_name); } else { + Eterm *hp; + ERTS_PI_UNRESERVE(reserve_size, 2); + hp = erts_produce_heap(hfact, 2, reserve_size); res = CONS(hp, part_res[ix], res); - hp += 2; } } - if (!always_wrap) { - HRelease(c_p, hp_end, hp); - } + return res; +} - done: +static void +pi_setup_grow(int **arr, int *def_arr, Uint *sz, int ix); - if (c_p == rp) - locks &= ~ERTS_PROC_LOCK_MAIN; - if (locks && rp) - erts_proc_unlock(rp, locks); +static BIF_RETTYPE +process_info_bif(Process *c_p, Eterm pid, Eterm opt, int always_wrap, int pi2) +{ + ErtsHeapFactory hfact; + int def_arr[ERTS_PI_DEF_ARR_SZ]; + int *item_ix = &def_arr[0]; + Process *rp = NULL; + erts_aint32_t state; + BIF_RETTYPE ret; + Uint reds = 0; + ErtsProcLocks locks = 0; + int flags; + Uint reserve_size; + int len; + Eterm res; - if (res_elem_ix != &def_res_elem_ix_buf[0]) - erts_free(ERTS_ALC_T_TMP, res_elem_ix); + ERTS_CT_ASSERT(ERTS_PI_DEF_ARR_SZ > 0); - BUMP_REDS(c_p, reds); + if (c_p->common.id == pid) { + int local_only = c_p->flags & F_LOCAL_SIGS_ONLY; + int sreds = ERTS_BIF_REDS_LEFT(c_p); + int sres; - return res; -} + if (!local_only) { + erts_proc_lock(c_p, ERTS_PROC_LOCK_MSGQ); + erts_proc_sig_fetch(c_p); + erts_proc_unlock(c_p, ERTS_PROC_LOCK_MSGQ); + } -BIF_RETTYPE process_info_1(BIF_ALIST_1) -{ - Eterm res; - int fail_type; + sres = erts_proc_sig_handle_incoming(c_p, &state, &sreds, sreds, !0); + if (state & ERTS_PSFLG_EXITING) { + c_p->flags &= ~F_LOCAL_SIGS_ONLY; + goto exited; + } + if (!sres) { + /* + * More signals to handle; need to yield and continue. + * Prevent fetching of more signals by setting + * local-sigs-only flag. + */ + c_p->flags |= F_LOCAL_SIGS_ONLY; + goto yield; + } - if (is_external_pid(BIF_ARG_1) - && external_pid_dist_entry(BIF_ARG_1) == erts_this_dist_entry) - BIF_RET(am_undefined); - - if (is_not_internal_pid(BIF_ARG_1)) { - BIF_ERROR(BIF_P, BADARG); - } - - res = process_info_list(BIF_P, BIF_ARG_1, pi_1_keys_list, 0, &fail_type); - if (is_non_value(res)) { - switch (fail_type) { - case ERTS_PI_FAIL_TYPE_BADARG: - BIF_ERROR(BIF_P, BADARG); - case ERTS_PI_FAIL_TYPE_YIELD: - ERTS_BIF_YIELD1(bif_export[BIF_process_info_1], BIF_P, BIF_ARG_1); - case ERTS_PI_FAIL_TYPE_EXITED: - ERTS_BIF_EXITED(BIF_P); - default: - erts_exit(ERTS_ABORT_EXIT, "%s:%d: Internal error", __FILE__, __LINE__); - } + c_p->flags &= ~F_LOCAL_SIGS_ONLY; } - ASSERT(!(BIF_P->flags & F_P2PNR_RESCHED)); - BIF_RET(res); -} + if (is_atom(opt)) { + int ix = pi_arg2ix(opt); + item_ix[0] = ix; + len = 1; + locks = pi_ix2locks(ix); + reserve_size = 3 + pi_ix2rsz(ix); + flags = ERTS_PI_FLAG_SINGELTON; + flags |= pi_ix2flags(ix); + if (ix < 0) + goto badarg; + } + else { + Eterm list = opt; + Uint size = ERTS_PI_DEF_ARR_SZ; + len = 0; + reserve_size = 0; + locks = 0; + flags = 0; -BIF_RETTYPE process_info_2(BIF_ALIST_2) -{ - Eterm res; - Process *rp; - Eterm pid = BIF_ARG_1; - ErtsProcLocks info_locks; - int fail_type, reds = 0; + while (is_list(list)) { + Eterm *consp = list_val(list); + Eterm arg = CAR(consp); + int ix = pi_arg2ix(arg); + if (ix < 0) + goto badarg; + + if (len >= size) + pi_setup_grow(&item_ix, def_arr, &size, len); + + item_ix[len++] = ix; + + locks |= pi_ix2locks(ix); + flags |= pi_ix2flags(ix); + reserve_size += pi_ix2rsz(ix); + reserve_size += 3; /* 2-tuple */ + reserve_size += 2; /* cons */ + + list = CDR(consp); + } + + if (is_not_nil(list)) + goto badarg; + } - if (is_external_pid(pid) - && external_pid_dist_entry(pid) == erts_this_dist_entry) - BIF_RET(am_undefined); - if (is_not_internal_pid(pid)) { - BIF_ERROR(BIF_P, BADARG); + if (is_external_pid(pid) + && external_pid_dist_entry(pid) == erts_this_dist_entry) + goto undefined; + goto badarg; } - if (is_nil(BIF_ARG_2)) - BIF_RET(NIL); + if (always_wrap) + flags |= ERTS_PI_FLAG_ALWAYS_WRAP; - if (is_list(BIF_ARG_2)) { - res = process_info_list(BIF_P, BIF_ARG_1, BIF_ARG_2, 1, &fail_type); - if (is_non_value(res)) { - switch (fail_type) { - case ERTS_PI_FAIL_TYPE_BADARG: - BIF_ERROR(BIF_P, BADARG); - case ERTS_PI_FAIL_TYPE_YIELD: - ERTS_BIF_YIELD2(bif_export[BIF_process_info_2], BIF_P, - BIF_ARG_1, BIF_ARG_2); - case ERTS_PI_FAIL_TYPE_EXITED: - ERTS_BIF_EXITED(BIF_P); - default: - erts_exit(ERTS_ABORT_EXIT, "%s:%d: Internal error", - __FILE__, __LINE__); - } - } - ASSERT(!(BIF_P->flags & F_P2PNR_RESCHED)); - BIF_RET(res); + if (c_p->common.id == pid) { + rp = c_p; + if (locks & ~ERTS_PROC_LOCK_MAIN) + erts_proc_lock(c_p, locks & ~ERTS_PROC_LOCK_MAIN); + locks |= ERTS_PROC_LOCK_MAIN; + } + else { + if (flags & ERTS_PI_FLAG_FORCE_SIG_SEND) + goto send_signal; + rp = erts_try_lock_sig_free_proc(pid, locks, &state); + if (!rp) + goto undefined; + if (rp == ERTS_PROC_LOCK_BUSY) { + rp = NULL; + goto send_signal; + } + if (state & ERTS_PSFLG_EXITING) { + if (locks) + erts_proc_unlock(rp, locks); + locks = 0; + /* wait for it to terminate properly... */ + goto send_signal; + } + if (flags & ERTS_PI_FLAG_NEED_MSGQ_LEN) { + ASSERT(locks & ERTS_PROC_LOCK_MAIN); + erts_proc_lock(rp, ERTS_PROC_LOCK_MSGQ); + erts_proc_sig_fetch(rp); + if (c_p->sig_qs.cont) { + erts_proc_unlock(rp, locks|ERTS_PROC_LOCK_MSGQ); + locks = 0; + goto send_signal; + } + erts_proc_unlock(rp, ERTS_PROC_LOCK_MSGQ); + } } - if (pi_arg2ix(BIF_ARG_2) < 0) - BIF_ERROR(BIF_P, BADARG); + erts_factory_proc_init(&hfact, c_p); - info_locks = pi_locks(BIF_ARG_2); + res = erts_process_info(c_p, &hfact, rp, locks, item_ix, len, + flags, reserve_size, &reds); - rp = pi_lookup_proc(BIF_P, pid, &info_locks); - if (!rp) { - if (BIF_P->common.id == pid) - ERTS_BIF_EXITED(BIF_P); - BIF_RET(am_undefined); + erts_factory_close(&hfact); + + if (reds > INT_MAX/2) + reds = INT_MAX/2; + BUMP_REDS(c_p, (int) reds); + + state = erts_atomic32_read_acqb(&rp->state); + if (state & (ERTS_PSFLG_EXITING|ERTS_PSFLG_FREE)) { + if (state & ERTS_PSFLG_FREE) { + ASSERT(!locks); + goto undefined; + } + if (locks) + erts_proc_unlock(rp, locks); + locks = 0; + /* wait for it to terminate properly... */ + goto send_signal; } - else if (rp == ERTS_PROC_LOCK_BUSY) - ERTS_BIF_YIELD2(bif_export[BIF_process_info_2], BIF_P, - BIF_ARG_1, BIF_ARG_2); - if (BIF_P == rp) - info_locks |= ERTS_PROC_LOCK_MAIN; + ERTS_BIF_PREP_RET(ret, res); + +done: - res = process_info_aux(BIF_P, rp, info_locks, pid, BIF_ARG_2, - 0, &reds); + if (c_p == rp) + locks &= ~ERTS_PROC_LOCK_MAIN; - BUMP_REDS(BIF_P, reds); + if (locks && rp) + erts_proc_unlock(rp, locks); - if (BIF_P == rp) - info_locks &= ~ERTS_PROC_LOCK_MAIN; - if (rp && info_locks) - erts_proc_unlock(rp, info_locks); + if (item_ix != def_arr) + erts_free(ERTS_ALC_T_TMP, item_ix); - ASSERT(!(BIF_P->flags & F_P2PNR_RESCHED)); - BIF_RET(res); + return ret; + +badarg: + ERTS_BIF_PREP_ERROR(ret, c_p, BADARG); + goto done; + +undefined: + ERTS_BIF_PREP_RET(ret, am_undefined); + goto done; + +exited: + ERTS_BIF_PREP_EXITED(ret, c_p); + goto done; + +yield: + if (pi2) + ERTS_BIF_PREP_YIELD2(ret, bif_export[BIF_process_info_2], c_p, pid, opt); + else + ERTS_BIF_PREP_YIELD1(ret, bif_export[BIF_process_info_1], c_p, pid); + goto done; + +send_signal: { + Eterm ref = erts_make_ref(c_p); + int enqueued, need_msgq_len; + flags |= ERTS_PI_FLAG_REQUEST_FOR_OTHER; + need_msgq_len = (flags & ERTS_PI_FLAG_NEED_MSGQ_LEN); + /* + * Set receive mark so we wont have to scan the whole + * message queue for the result. Note caller unconditionally + * has to enter a receive only matching messages containing + * 'ref', or restore save pointer. + */ + ERTS_RECV_MARK_SAVE(c_p); + ERTS_RECV_MARK_SET(c_p); + enqueued = erts_proc_sig_send_process_info_request(c_p, pid, item_ix, + len, need_msgq_len, + flags, reserve_size, + ref); + if (!enqueued) { + /* Restore save pointer... */ + JOIN_MESSAGE(c_p); + goto undefined; + } + ERTS_BIF_PREP_TRAP1(ret, erts_await_result, c_p, ref); + goto done; + } +} + +static void +pi_setup_grow(int **arr, int *def_arr, Uint *sz, int ix) +{ + *sz = (ix+1) + ERTS_PI_DEF_ARR_SZ; + if (*arr != def_arr) + *arr = erts_realloc(ERTS_ALC_T_TMP, *arr, (*sz)*sizeof(int)); + else { + int *new_arr = erts_alloc(ERTS_ALC_T_TMP, (*sz)*sizeof(int)); + sys_memcpy((void *) new_arr, (void *) def_arr, + sizeof(int)*ERTS_PI_DEF_ARR_SZ); + *arr = new_arr; + } +} + + +BIF_RETTYPE process_info_2(BIF_ALIST_2) +{ + return process_info_bif(BIF_P, BIF_ARG_1, BIF_ARG_2, !is_atom(BIF_ARG_2), !0); +} + +BIF_RETTYPE process_info_1(BIF_ALIST_1) +{ + return process_info_bif(BIF_P, BIF_ARG_1, pi_1_keys_list, 0, 0); } Eterm -process_info_aux(Process *BIF_P, +process_info_aux(Process *c_p, + ErtsHeapFactory *hfact, Process *rp, ErtsProcLocks rp_locks, - Eterm rpid, - Eterm item, - int always_wrap, - int *reds) + int item_ix, + int flags, + Uint *reserve_sizep, + Uint *reds) { Eterm *hp; Eterm res = NIL; + Uint reserved; + Uint reserve_size = *reserve_sizep; + +#ifdef ERTS_ENABLE_LOCK_CHECK + ErtsProcLocks locks = erts_proc_lc_my_proc_locks(rp); + + switch (item_ix) { + case ERTS_PI_IX_STATUS: + case ERTS_PI_IX_PRIORITY: + case ERTS_PI_IX_SUSPENDING: + ERTS_LC_ASSERT((locks & ~ERTS_PROC_LOCK_MAIN) == 0); + break; + default: + ERTS_LC_ASSERT(locks == ERTS_PROC_LOCK_MAIN); + break; + } +#endif + + reserved = pi_ix2rsz(item_ix); + ERTS_PI_UNRESERVE(reserve_size, reserved); (*reds)++; ASSERT(rp); /* - * Q: Why this always_wrap argument? + * Q: Why this ERTS_PI_FLAG_ALWAYS_WRAP flag? * * A: registered_name is strange. If process has no registered name, * process_info(Pid, registered_name) returns [], and @@ -1241,41 +1352,39 @@ process_info_aux(Process *BIF_P, * registered_name behaves as it should, i.e. a * {registered_name, []} will appear in the resulting list. * - * If always_wrap != 0, process_info_aux() always wrap the result - * in a key two tuple. + * If ERTS_PI_FLAG_ALWAYS_WRAP is set, process_info_aux() always + * wrap the result in a key two tuple. */ - switch (item) { + switch (item_ix) { - case am_registered_name: - if (rp->common.u.alive.reg) { - hp = HAlloc(BIF_P, 3); + case ERTS_PI_IX_REGISTERED_NAME: + if (rp->common.u.alive.reg) res = rp->common.u.alive.reg->name; - } else { - if (always_wrap) { - hp = HAlloc(BIF_P, 3); + else { + if (flags & ERTS_PI_FLAG_ALWAYS_WRAP) res = NIL; - } - else { + else return NIL; - } } break; - case am_current_function: - res = current_function(BIF_P, rp, &hp, 0); + case ERTS_PI_IX_CURRENT_FUNCTION: + res = current_function(c_p, hfact, rp, 0, + reserve_size, flags); break; - case am_current_location: - res = current_function(BIF_P, rp, &hp, 1); + case ERTS_PI_IX_CURRENT_LOCATION: + res = current_function(c_p, hfact, rp, 1, + reserve_size, flags); break; - case am_current_stacktrace: - res = current_stacktrace(BIF_P, rp, &hp); + case ERTS_PI_IX_CURRENT_STACKTRACE: + res = current_stacktrace(hfact, rp, reserve_size); break; - case am_initial_call: - hp = HAlloc(BIF_P, 3+4); + case ERTS_PI_IX_INITIAL_CALL: + hp = erts_produce_heap(hfact, 4, reserve_size); res = TUPLE3(hp, rp->u.initial.module, rp->u.initial.function, @@ -1283,24 +1392,37 @@ process_info_aux(Process *BIF_P, hp += 4; break; - case am_status: - res = erts_process_state2status(erts_atomic32_read_nob(&rp->state)); - if (res == am_exiting || res == am_free) - return am_undefined; - hp = HAlloc(BIF_P, 3); + case ERTS_PI_IX_STATUS: { + erts_aint32_t state = erts_atomic32_read_nob(&rp->state); + res = erts_process_state2status(state); + if (res == am_running && (state & ERTS_PSFLG_RUNNING_SYS)) { + ASSERT(c_p == rp); + ASSERT(flags & ERTS_PI_FLAG_REQUEST_FOR_OTHER); + if (!(state & (ERTS_PSFLG_SYS_TASKS + | ERTS_PSFLG_ACTIVE + | ERTS_PSFLG_SIG_Q + | ERTS_PSFLG_SIG_IN_Q))) { + /* + * We are servicing a process-info request from + * another process. If that other process could + * have inspected our state itself, we would have + * been in the 'waiting' state. + */ + res = am_waiting; + } + } break; + } - case am_messages: { - - if (rp->sig_qs.len == 0 || ERTS_TRACE_FLAGS(rp) & F_SENSITIVE) { - hp = HAlloc(BIF_P, 3); - } else { + case ERTS_PI_IX_MESSAGES: { + ASSERT(flags & ERTS_PI_FLAG_NEED_MSGQ_LEN); + if (rp->sig_qs.len == 0 || (ERTS_TRACE_FLAGS(rp) & F_SENSITIVE)) + res = NIL; + else { + int info_on_self = !(flags & ERTS_PI_FLAG_REQUEST_FOR_OTHER); ErtsMessageInfo *mip; - Sint i; + Sint i, len; Uint heap_need; -#ifdef DEBUG - Eterm *hp_end; -#endif mip = erts_alloc(ERTS_ALC_T_TMP, rp->sig_qs.len*sizeof(ErtsMessageInfo)); @@ -1310,46 +1432,52 @@ process_info_aux(Process *BIF_P, * erts_proc_sig_prep_msgq_for_inspection() since it removes * corrupt distribution messages. */ - heap_need = erts_proc_sig_prep_msgq_for_inspection(BIF_P, rp, - rp_locks, mip); - heap_need += 3; /* top 2-tuple */ - heap_need += rp->sig_qs.len*2; /* Cons cells */ + heap_need = erts_proc_sig_prep_msgq_for_inspection(c_p, rp, + rp_locks, + info_on_self, + mip); + len = rp->sig_qs.len; - hp = HAlloc(BIF_P, heap_need); /* heap_need is exact */ -#ifdef DEBUG - hp_end = hp + heap_need; -#endif + heap_need += len*2; /* Cons cells */ + + reserve_size += heap_need; /* Build list of messages... */ - for (i = rp->sig_qs.len - 1, res = NIL; i >= 0; i--) { + for (i = len - 1, res = NIL; i >= 0; i--) { Eterm msg = ERL_MESSAGE_TERM(mip[i].msgp); Uint sz = mip[i].size; + ERTS_PI_UNRESERVE(reserve_size, sz+2); + hp = erts_produce_heap(hfact, sz+2, reserve_size); + if (sz != 0) - msg = copy_struct(msg, sz, &hp, &BIF_P->off_heap); + msg = copy_struct(msg, sz, &hp, hfact->off_heap); res = CONS(hp, msg, res); hp += 2; } - ASSERT(hp_end == hp + 3); - - if (rp->sig_qs.len > CONTEXT_REDS*4) - *reds += CONTEXT_REDS*4; - else - *reds += rp->sig_qs.len / 4; + *reds += (Uint) len / 4; erts_free(ERTS_ALC_T_TMP, mip); } break; } - case am_message_queue_len: - hp = HAlloc(BIF_P, 3); - res = make_small(rp->sig_qs.len); + case ERTS_PI_IX_MESSAGE_QUEUE_LEN: { + Sint len = rp->sig_qs.len; + ASSERT(flags & ERTS_PI_FLAG_NEED_MSGQ_LEN); + ASSERT(len >= 0); + if (len <= MAX_SMALL) + res = make_small(len); + else { + hp = erts_produce_heap(hfact, BIG_UINT_HEAP_SIZE, reserve_size); + res = uint_to_big((Uint) len, hp); + } break; + } - case am_links: { + case ERTS_PI_IX_LINKS: { MonitorInfoCollection mic; int i; Eterm item; @@ -1358,24 +1486,24 @@ process_info_aux(Process *BIF_P, erts_link_tree_foreach(ERTS_P_LINKS(rp), collect_one_link, (void *) &mic); - hp = HAlloc(BIF_P, 3 + mic.sz); + reserve_size += mic.sz; res = NIL; for (i = 0; i < mic.mi_i; i++) { - item = STORE_NC(&hp, &MSO(BIF_P), mic.mi[i].entity.term); + Eterm item_src = mic.mi[i].entity.term; + Uint sz = NC_HEAP_SIZE(item_src) + 2; + ERTS_PI_UNRESERVE(reserve_size, sz); + hp = erts_produce_heap(hfact, sz, reserve_size); + item = STORE_NC(&hp, hfact->off_heap, item_src); res = CONS(hp, item, res); - hp += 2; } - if (mic.mi_i > CONTEXT_REDS*4) - *reds += CONTEXT_REDS*4; - else - *reds += mic.mi_i / 4; + *reds += (Uint) mic.mi_i / 4; DESTROY_MONITOR_INFOS(mic); break; } - case am_monitors: { + case ERTS_PI_IX_MONITORS: { MonitorInfoCollection mic; int i; @@ -1384,7 +1512,7 @@ process_info_aux(Process *BIF_P, collect_one_origin_monitor, (void *) &mic); - hp = HAlloc(BIF_P, 3 + mic.sz); + reserve_size += mic.sz; res = NIL; for (i = 0; i < mic.mi_i; i++) { if (mic.mi[i].named) { @@ -1399,23 +1527,30 @@ process_info_aux(Process *BIF_P, || is_port(mic.mi[i].pid) || is_atom(mic.mi[i].pid)); + ERTS_PI_UNRESERVE(reserve_size, 3+3+2); + hp = erts_produce_heap(hfact, 3+3+2, reserve_size); + t1 = TUPLE2(hp, mic.mi[i].entity.term, mic.mi[i].node); hp += 3; t2 = TUPLE2(hp, m_type, t1); hp += 3; res = CONS(hp, t2, res); - hp += 2; } else { /* Build {process|port|time_offset, Pid|clock_service} and cons it. */ Eterm t; Eterm pid; Eterm m_type; + Eterm pid_src = mic.mi[i].entity.term; + Uint sz = is_atom(pid_src) ? 0 : NC_HEAP_SIZE(pid_src); + sz += 3 + 2; - if (is_atom(mic.mi[i].entity.term)) - pid = mic.mi[i].entity.term; - else - pid = STORE_NC(&hp, &MSO(BIF_P), mic.mi[i].entity.term); + ERTS_PI_UNRESERVE(reserve_size, sz); + hp = erts_produce_heap(hfact, sz, reserve_size); + + pid = (is_atom(pid_src) + ? pid_src + : STORE_NC(&hp, hfact->off_heap, pid_src)); switch (mic.mi[i].type) { case ERTS_MON_TYPE_PORT: @@ -1435,20 +1570,16 @@ process_info_aux(Process *BIF_P, t = TUPLE2(hp, m_type, pid); hp += 3; res = CONS(hp, t, res); - hp += 2; } } - if (mic.mi_i > CONTEXT_REDS*4) - *reds += CONTEXT_REDS*4; - else - *reds += mic.mi_i / 4; + *reds += (Uint) mic.mi_i / 4; DESTROY_MONITOR_INFOS(mic); break; } - case am_monitored_by: { + case ERTS_PI_IX_MONITORED_BY: { MonitorInfoCollection mic; int i; Eterm item; @@ -1461,59 +1592,71 @@ process_info_aux(Process *BIF_P, collect_one_target_monitor, (void *) &mic); - hp = HAlloc(BIF_P, 3 + mic.sz); + reserve_size += mic.sz; res = NIL; for (i = 0; i < mic.mi_i; ++i) { + Uint sz = 2; + + if (mic.mi[i].type == ERTS_MON_TYPE_RESOURCE) + sz += erts_resource_ref_size(mic.mi[i].entity.resource); + else + sz += NC_HEAP_SIZE(mic.mi[i].entity.term); + + ERTS_PI_UNRESERVE(reserve_size, sz); + hp = erts_produce_heap(hfact, sz, reserve_size); + if (mic.mi[i].type == ERTS_MON_TYPE_RESOURCE) item = erts_bld_resource_ref(&hp, - &MSO(BIF_P), + hfact->off_heap, mic.mi[i].entity.resource); else item = STORE_NC(&hp, - &MSO(BIF_P), + hfact->off_heap, mic.mi[i].entity.term); res = CONS(hp, item, res); - hp += 2; } - if (mic.mi_i > CONTEXT_REDS*4) - *reds += CONTEXT_REDS*4; - else - *reds += mic.mi_i / 4; + *reds += (Uint) mic.mi_i / 4; DESTROY_MONITOR_INFOS(mic); break; } - case am_suspending: { + case ERTS_PI_IX_SUSPENDING: { ErtsSuspendMonitorInfoCollection smic; int i; Eterm item; -#ifdef DEBUG - Eterm *hp_end; -#endif + + erts_proc_lock(rp, ERTS_PROC_LOCK_STATUS); ERTS_INIT_SUSPEND_MONITOR_INFOS(smic, - BIF_P, - (BIF_P == rp + c_p, + (c_p == rp ? ERTS_PROC_LOCK_MAIN : 0) | ERTS_PROC_LOCK_STATUS); erts_monitor_tree_foreach(rp->suspend_monitors, &collect_one_suspend_monitor, &smic); - hp = HAlloc(BIF_P, 3 + smic.sz); -#ifdef DEBUG - hp_end = hp + smic.sz; -#endif - + + reserve_size += smic.sz; + res = NIL; for (i = 0; i < smic.smi_i; i++) { Sint a = (Sint) smic.smi[i]->active; /* quiet compiler warnings */ Sint p = (Sint) smic.smi[i]->pending; /* on 64-bit machines... */ Eterm active; Eterm pending; + Uint sz = 4 + 2; + if (!IS_SSMALL(a)) + sz += BIG_UINT_HEAP_SIZE; + if (!IS_SSMALL(p)) + sz += BIG_UINT_HEAP_SIZE; + + ERTS_PI_UNRESERVE(reserve_size, sz); + hp = erts_produce_heap(hfact, sz, reserve_size); + if (IS_SSMALL(a)) active = make_small(a); else { @@ -1529,95 +1672,83 @@ process_info_aux(Process *BIF_P, item = TUPLE3(hp, smic.smi[i]->mon.other.item, active, pending); hp += 4; res = CONS(hp, item, res); - hp += 2; } - if (smic.smi_i > CONTEXT_REDS*4) - *reds += CONTEXT_REDS*4; - else - *reds += smic.smi_i / 4; + erts_proc_unlock(rp, ERTS_PROC_LOCK_STATUS); + + *reds += (Uint) smic.smi_i / 4; ERTS_DESTROY_SUSPEND_MONITOR_INFOS(smic); - ASSERT(hp == hp_end); break; } - case am_dictionary: + case ERTS_PI_IX_DICTIONARY: if (!rp->dictionary || (ERTS_TRACE_FLAGS(rp) & F_SENSITIVE)) { res = NIL; } else { Uint num = rp->dictionary->numElements; - res = erts_dictionary_copy(BIF_P, rp->dictionary); - if (num > CONTEXT_REDS*4) - *reds += CONTEXT_REDS*4; - else - *reds += (int) num / 4; + res = erts_dictionary_copy(hfact, rp->dictionary, reserve_size); + *reds += (Uint) num / 4; } - hp = HAlloc(BIF_P, 3); + break; - case am_trap_exit: { - hp = HAlloc(BIF_P, 3); - if (rp->flags & F_TRAP_EXIT) - res = am_true; - else - res = am_false; + case ERTS_PI_IX_TRAP_EXIT: + res = (rp->flags & F_TRAP_EXIT) ? am_true : am_false; break; - } - case am_error_handler: - hp = HAlloc(BIF_P, 3); - res = erts_proc_get_error_handler(BIF_P); + case ERTS_PI_IX_ERROR_HANDLER: + res = erts_proc_get_error_handler(rp); break; - case am_heap_size: { - Uint hsz = 3; + case ERTS_PI_IX_HEAP_SIZE: { + Uint hsz = 0; (void) erts_bld_uint(NULL, &hsz, HEAP_SIZE(rp)); - hp = HAlloc(BIF_P, hsz); + hp = erts_produce_heap(hfact, hsz, reserve_size); res = erts_bld_uint(&hp, NULL, HEAP_SIZE(rp)); break; } - case am_fullsweep_after: { - Uint hsz = 3; + case ERTS_PI_IX_FULLSWEEP_AFTER: { + Uint hsz = 0; (void) erts_bld_uint(NULL, &hsz, MAX_GEN_GCS(rp)); - hp = HAlloc(BIF_P, hsz); + hp = erts_produce_heap(hfact, hsz, reserve_size); res = erts_bld_uint(&hp, NULL, MAX_GEN_GCS(rp)); break; } - case am_min_heap_size: { - Uint hsz = 3; + case ERTS_PI_IX_MIN_HEAP_SIZE: { + Uint hsz = 0; (void) erts_bld_uint(NULL, &hsz, MIN_HEAP_SIZE(rp)); - hp = HAlloc(BIF_P, hsz); + hp = erts_produce_heap(hfact, hsz, reserve_size); res = erts_bld_uint(&hp, NULL, MIN_HEAP_SIZE(rp)); break; } - case am_min_bin_vheap_size: { - Uint hsz = 3; + case ERTS_PI_IX_MIN_BIN_VHEAP_SIZE: { + Uint hsz = 0; (void) erts_bld_uint(NULL, &hsz, MIN_VHEAP_SIZE(rp)); - hp = HAlloc(BIF_P, hsz); + hp = erts_produce_heap(hfact, hsz, reserve_size); res = erts_bld_uint(&hp, NULL, MIN_VHEAP_SIZE(rp)); break; } - case am_max_heap_size: { - Uint hsz = 3; + case ERTS_PI_IX_MAX_HEAP_SIZE: { + Uint hsz = 0; (void) erts_max_heap_size_map(MAX_HEAP_SIZE_GET(rp), MAX_HEAP_SIZE_FLAGS_GET(rp), NULL, &hsz); - hp = HAlloc(BIF_P, hsz); + hp = erts_produce_heap(hfact, hsz, reserve_size); res = erts_max_heap_size_map(MAX_HEAP_SIZE_GET(rp), MAX_HEAP_SIZE_FLAGS_GET(rp), &hp, NULL); break; } - case am_total_heap_size: { + case ERTS_PI_IX_TOTAL_HEAP_SIZE: { Uint total_heap_size; - Uint hsz = 3; + Uint hsz = 0; total_heap_size = rp->heap_sz; if (rp->old_hend && rp->old_heap) @@ -1626,58 +1757,52 @@ process_info_aux(Process *BIF_P, total_heap_size += rp->mbuf_sz; if (rp->flags & F_ON_HEAP_MSGQ) { - ERTS_FOREACH_SIG_PRIVQS( - rp, mp, - { - if (ERTS_SIG_IS_MSG(mp) && mp->data.attached) - total_heap_size += erts_msg_attached_data_size(mp); - }); - - if (rp->sig_qs.len > CONTEXT_REDS*4) - *reds += CONTEXT_REDS*4; - else - *reds += rp->sig_qs.len / 4; + ErtsMessage *mp; + ASSERT(flags & ERTS_PI_FLAG_NEED_MSGQ_LEN); + for (mp = rp->sig_qs.first; mp; mp = mp->next) { + ASSERT(ERTS_SIG_IS_MSG(mp)); + if (mp->data.attached) + total_heap_size += erts_msg_attached_data_size(mp); + } + *reds += (Uint) rp->sig_qs.len / 4; } (void) erts_bld_uint(NULL, &hsz, total_heap_size); - hp = HAlloc(BIF_P, hsz); + hp = erts_produce_heap(hfact, hsz, reserve_size); res = erts_bld_uint(&hp, NULL, total_heap_size); break; } - case am_stack_size: { + case ERTS_PI_IX_STACK_SIZE: { Uint stack_size = STACK_START(rp) - rp->stop; - Uint hsz = 3; + Uint hsz = 0; (void) erts_bld_uint(NULL, &hsz, stack_size); - hp = HAlloc(BIF_P, hsz); + hp = erts_produce_heap(hfact, hsz, reserve_size); res = erts_bld_uint(&hp, NULL, stack_size); break; } - case am_memory: { /* Memory consumed in bytes */ - Uint hsz = 3; + case ERTS_PI_IX_MEMORY: { /* Memory consumed in bytes */ + Uint hsz = 0; Uint size = erts_process_memory(rp, 0); (void) erts_bld_uint(NULL, &hsz, size); - hp = HAlloc(BIF_P, hsz); + hp = erts_produce_heap(hfact, hsz, reserve_size); res = erts_bld_uint(&hp, NULL, size); - if (rp->sig_qs.len > CONTEXT_REDS*4) - *reds += CONTEXT_REDS*4; - else - *reds += rp->sig_qs.len / 4; + ASSERT(flags & ERTS_PI_FLAG_NEED_MSGQ_LEN); + *reds += (Uint) rp->sig_qs.len / 4; break; } - case am_garbage_collection: { + case ERTS_PI_IX_GARBAGE_COLLECTION: { DECL_AM(minor_gcs); Eterm t; Uint map_sz = 0; erts_max_heap_size_map(MAX_HEAP_SIZE_GET(rp), MAX_HEAP_SIZE_FLAGS_GET(rp), NULL, &map_sz); - hp = HAlloc(BIF_P, 3+2 + 3+2 + 3+2 + 3+2 + 3+2 + map_sz + 3); - /* last "3" is for outside tuple */ + hp = erts_produce_heap(hfact, 3+2 + 3+2 + 3+2 + 3+2 + 3+2 + map_sz, reserve_size); t = TUPLE2(hp, AM_minor_gcs, make_small(GEN_GCS(rp))); hp += 3; res = CONS(hp, t, NIL); hp += 2; @@ -1696,93 +1821,76 @@ process_info_aux(Process *BIF_P, break; } - case am_garbage_collection_info: { + case ERTS_PI_IX_GARBAGE_COLLECTION_INFO: { Uint sz = 0, actual_sz = 0; - if (rp == BIF_P) { - sz += ERTS_PROCESS_GC_INFO_MAX_SIZE; - } else { - erts_process_gc_info(rp, &sz, NULL, 0, 0); - sz += 3; - } + erts_process_gc_info(rp, &sz, NULL, 0, 0); - hp = HAlloc(BIF_P, sz); + hp = erts_produce_heap(hfact, sz, reserve_size); res = erts_process_gc_info(rp, &actual_sz, &hp, 0, 0); - /* We may have some extra space, fill with 0 tuples */ - if (actual_sz <= sz - 3) { - for (; actual_sz < sz - 3; hp++, actual_sz++) - hp[0] = make_arityval(0); - } else { - for (; actual_sz < sz; hp++, actual_sz++) - hp[0] = make_arityval(0); - hp = HAlloc(BIF_P, 3); - } - break; } - case am_group_leader: { + case ERTS_PI_IX_GROUP_LEADER: { int sz = NC_HEAP_SIZE(rp->group_leader); - hp = HAlloc(BIF_P, 3 + sz); - res = STORE_NC(&hp, &MSO(BIF_P), rp->group_leader); + hp = erts_produce_heap(hfact, sz, reserve_size); + res = STORE_NC(&hp, hfact->off_heap, rp->group_leader); break; } - case am_reductions: { - Uint reds = rp->reds + erts_current_reductions(BIF_P, rp); - Uint hsz = 3; + case ERTS_PI_IX_REDUCTIONS: { + Uint reds = rp->reds + erts_current_reductions(c_p, rp); + Uint hsz = 0; (void) erts_bld_uint(NULL, &hsz, reds); - hp = HAlloc(BIF_P, hsz); + hp = erts_produce_heap(hfact, hsz, reserve_size); res = erts_bld_uint(&hp, NULL, reds); break; } - case am_priority: { + case ERTS_PI_IX_PRIORITY: { erts_aint32_t state = erts_atomic32_read_nob(&rp->state); if (ERTS_PSFLG_EXITING & state) return am_undefined; - hp = HAlloc(BIF_P, 3); res = erts_get_process_priority(state); break; } - case am_trace: - hp = HAlloc(BIF_P, 3); + case ERTS_PI_IX_TRACE: res = make_small(ERTS_TRACE_FLAGS(rp) & TRACEE_FLAGS); break; - case am_binary: { - Uint sz = 3; + case ERTS_PI_IX_BINARY: { + Uint sz = 0; (void) bld_bin_list(NULL, &sz, &MSO(rp)); - hp = HAlloc(BIF_P, sz); + hp = erts_produce_heap(hfact, sz, reserve_size); res = bld_bin_list(&hp, NULL, &MSO(rp)); break; } - case am_sequential_trace_token: - res = copy_object(rp->seq_trace_token, BIF_P); - hp = HAlloc(BIF_P, 3); + case ERTS_PI_IX_SEQUENTIAL_TRACE_TOKEN: { + Uint sz = size_object(rp->seq_trace_token); + hp = erts_produce_heap(hfact, sz, reserve_size); + res = copy_struct(rp->seq_trace_token, sz, &hp, hfact->off_heap); break; + } - case am_catchlevel: - hp = HAlloc(BIF_P, 3); - res = make_small(catchlevel(BIF_P)); + case ERTS_PI_IX_CATCHLEVEL: + res = make_small(catchlevel(rp)); break; - case am_backtrace: { + case ERTS_PI_IX_BACKTRACE: { erts_dsprintf_buf_t *dsbufp = erts_create_tmp_dsbuf(0); erts_stack_dump(ERTS_PRINT_DSBUF, (void *) dsbufp, rp); - res = new_binary(BIF_P, (byte *) dsbufp->str, dsbufp->str_len); + res = erts_heap_factory_new_binary(hfact, (byte *) dsbufp->str, + dsbufp->str_len, reserve_size); erts_destroy_tmp_dsbuf(dsbufp); - hp = HAlloc(BIF_P, 3); break; } - case am_last_calls: { + case ERTS_PI_IX_LAST_CALLS: { struct saved_calls *scb = ERTS_PROC_GET_SAVED_CALLS_BUF(rp); if (!scb) { - hp = HAlloc(BIF_P, 3); res = am_false; } else { /* @@ -1790,23 +1898,34 @@ process_info_aux(Process *BIF_P, * Might be less than that, if there are sends, receives or timeouts, * so we must do a HRelease() to avoid creating holes. */ - Uint needed = scb->n*(2+4) + 3; - Eterm* limit; + Sint needed = scb->n*(2+4); Eterm term, list; int i, j; + Export *exp; + + reserve_size += needed; - hp = HAlloc(BIF_P, needed); - limit = hp + needed; list = NIL; for (i = 0; i < scb->n; i++) { + Uint sz; j = scb->cur - i - 1; if (j < 0) j += scb->len; - if (scb->ct[j] == &exp_send) + + sz = 2; + exp = scb->ct[j]; + if (exp != &exp_send && exp != &exp_receive && exp != &exp_timeout) + sz += 4; + + needed -= sz; + ERTS_PI_UNRESERVE(reserve_size, sz); + hp = erts_produce_heap(hfact, sz, reserve_size); + + if (exp == &exp_send) term = am_send; - else if (scb->ct[j] == &exp_receive) + else if (exp == &exp_receive) term = am_receive; - else if (scb->ct[j] == &exp_timeout) + else if (exp == &exp_timeout) term = am_timeout; else { term = TUPLE3(hp, @@ -1816,18 +1935,18 @@ process_info_aux(Process *BIF_P, hp += 4; } list = CONS(hp, term, list); - hp += 2; } + + ASSERT(needed >= 0); + if (needed > 0) + reserve_size -= needed; + res = list; - res = TUPLE2(hp, item, res); - hp += 3; - HRelease(BIF_P,limit,hp); - return res; } break; } - case am_message_queue_data: + case ERTS_PI_IX_MESSAGE_QUEUE_DATA: switch (rp->flags & (F_OFF_HEAP_MSGQ|F_ON_HEAP_MSGQ)) { case F_OFF_HEAP_MSGQ: res = am_off_heap; @@ -1840,16 +1959,15 @@ process_info_aux(Process *BIF_P, ERTS_INTERNAL_ERROR("Inconsistent message queue management state"); break; } - hp = HAlloc(BIF_P, 3); break; - case am_magic_ref: { - Uint sz = 3; + case ERTS_PI_IX_MAGIC_REF: { + Uint sz = 0; (void) bld_magic_ref_bin_list(NULL, &sz, &MSO(rp)); - hp = HAlloc(BIF_P, sz); + hp = erts_produce_heap(hfact, sz, 0); res = bld_magic_ref_bin_list(&hp, NULL, &MSO(rp)); - *reds += 10; + *reds += (Uint) 10; break; } @@ -1858,12 +1976,17 @@ process_info_aux(Process *BIF_P, } - return TUPLE2(hp, item, res); + ERTS_PI_UNRESERVE(reserve_size, 3); + *reserve_sizep = reserve_size; + hp = erts_produce_heap(hfact, 3, reserve_size); + + return TUPLE2(hp, pi_ix2arg(item_ix), res); } #undef MI_INC static Eterm -current_function(Process* BIF_P, Process* rp, Eterm** hpp, int full_info) +current_function(Process *c_p, ErtsHeapFactory *hfact, Process* rp, + int full_info, Uint reserve_size, int flags) { Eterm* hp; Eterm res; @@ -1880,7 +2003,7 @@ current_function(Process* BIF_P, Process* rp, Eterm** hpp, int full_info) } } - if (BIF_P == rp) { + if (c_p == rp && !(flags & ERTS_PI_FLAG_REQUEST_FOR_OTHER)) { FunctionInfo fi2; /* @@ -1900,24 +2023,22 @@ current_function(Process* BIF_P, Process* rp, Eterm** hpp, int full_info) * Return the result. */ if (rp->current == NULL) { - hp = HAlloc(BIF_P, 3); res = am_undefined; } else if (full_info) { - hp = HAlloc(BIF_P, 3+fi.needed); - hp = erts_build_mfa_item(&fi, hp, am_true, &res); + hp = erts_produce_heap(hfact, fi.needed, reserve_size); + erts_build_mfa_item(&fi, hp, am_true, &res); } else { - hp = HAlloc(BIF_P, 3+4); + hp = erts_produce_heap(hfact, 4, reserve_size); res = TUPLE3(hp, rp->current->module, rp->current->function, make_small(rp->current->arity)); - hp += 4; } - *hpp = hp; return res; } static Eterm -current_stacktrace(Process* p, Process* rp, Eterm** hpp) +current_stacktrace(ErtsHeapFactory *hfact, Process* rp, + Uint reserve_size) { Uint sz; struct StackTrace* s; @@ -1926,7 +2047,7 @@ current_stacktrace(Process* p, Process* rp, Eterm** hpp) FunctionInfo* stkp; Uint heap_size; int i; - Eterm* hp = *hpp; + Eterm* hp; Eterm mfa; Eterm res = NIL; @@ -1956,17 +2077,23 @@ current_stacktrace(Process* p, Process* rp, Eterm** hpp) } } - hp = HAlloc(p, heap_size); + reserve_size += heap_size; + + /* + * We intentionally produce heap in small chunks + * (for more info see process_info_aux()). + */ while (stkp > stk) { stkp--; + sz = stkp->needed + 2; + ERTS_PI_UNRESERVE(reserve_size, sz); + hp = erts_produce_heap(hfact, sz, reserve_size); hp = erts_build_mfa_item(stkp, hp, am_true, &mfa); res = CONS(hp, mfa, res); - hp += 2; } erts_free(ERTS_ALC_T_TMP, stk); erts_free(ERTS_ALC_T_TMP, s); - *hpp = hp; return res; } @@ -3838,7 +3965,7 @@ BIF_RETTYPE erts_debug_get_internal_state_1(BIF_ALIST_1) Eterm res = NIL; Uint *hp = HAlloc(BIF_P, 2*ERTS_PI_ARGS); for (i = ERTS_PI_ARGS-1; i >= 0; i--) { - res = CONS(hp, pi_args[i], res); + res = CONS(hp, pi_args[i].name, res); hp += 2; } BIF_RET(res); diff --git a/erts/emulator/beam/erl_gc.c b/erts/emulator/beam/erl_gc.c index 5da8e3eda5..ea87cd7f50 100644 --- a/erts/emulator/beam/erl_gc.c +++ b/erts/emulator/beam/erl_gc.c @@ -61,7 +61,7 @@ # define ERTS_GC_ASSERT(B) ((void) 1) #endif -#if defined(DEBUG) && 0 +#if defined(DEBUG) && 1 # define HARDDEBUG 1 #endif @@ -222,6 +222,24 @@ ERTS_SCHED_PREF_QUICK_ALLOC_IMPL(gcireq, ErtsGCInfoReq, 5, ERTS_ALC_T_GC_INFO_REQ) + +static ERTS_INLINE void +ensure_sigq_roots_available(Process *p) +{ + ERTS_LC_ASSERT(ERTS_PROC_LOCK_MAIN == erts_proc_lc_my_proc_locks(p)); + switch (p->flags & (F_OFF_HEAP_MSGQ|F_OFF_HEAP_MSGQ_CHNG)) { + case F_OFF_HEAP_MSGQ_CHNG: + case 0: + erts_proc_lock(p, ERTS_PROC_LOCK_MSGQ); + erts_proc_sig_fetch(p); + erts_proc_unlock(p, ERTS_PROC_LOCK_MSGQ); + break; + default: + break; + } +} + + /* * Initialize GC global data. */ @@ -425,6 +443,8 @@ erts_gc_after_bif_call_lhf(Process* p, ErlHeapFragment *live_hf_end, live_hf_end = ERTS_INVALID_HFRAG_PTR; } + ensure_sigq_roots_available(p); + if (is_non_value(result)) { if (p->freason == TRAP) { #ifdef HIPE @@ -642,7 +662,7 @@ check_for_possibly_long_gc(Process *p, Uint ygen_usage) sz = ygen_usage; sz += p->hend - p->stop; if (p->flags & F_ON_HEAP_MSGQ) - sz += p->sig_qs.len; + sz += erts_proc_sig_privqs_len(p); if (major) sz += p->old_htop - p->old_heap; @@ -868,8 +888,11 @@ do_major_collection: int erts_garbage_collect_nobump(Process* p, int need, Eterm* objv, int nobj, int fcalls) { - int reds = garbage_collect(p, ERTS_INVALID_HFRAG_PTR, need, objv, nobj, fcalls, 0); - int reds_left = ERTS_REDS_LEFT(p, fcalls); + int reds; + int reds_left; + ensure_sigq_roots_available(p); + reds = garbage_collect(p, ERTS_INVALID_HFRAG_PTR, need, objv, nobj, fcalls, 0); + reds_left = ERTS_REDS_LEFT(p, fcalls); if (reds > reds_left) reds = reds_left; ASSERT(CONTEXT_REDS - (reds_left - reds) >= erts_proc_sched_data(p)->virtual_reds); @@ -879,7 +902,9 @@ erts_garbage_collect_nobump(Process* p, int need, Eterm* objv, int nobj, int fca void erts_garbage_collect(Process* p, int need, Eterm* objv, int nobj) { - int reds = garbage_collect(p, ERTS_INVALID_HFRAG_PTR, need, objv, nobj, p->fcalls, 0); + int reds; + ensure_sigq_roots_available(p); + reds = garbage_collect(p, ERTS_INVALID_HFRAG_PTR, need, objv, nobj, p->fcalls, 0); BUMP_REDS(p, reds); ASSERT(CONTEXT_REDS - ERTS_BIF_REDS_LEFT(p) >= erts_proc_sched_data(p)->virtual_reds); @@ -1105,6 +1130,8 @@ erts_garbage_collect_literals(Process* p, Eterm* literals, * First an ordinary major collection... */ + ensure_sigq_roots_available(p); + p->flags |= F_NEED_FULLSWEEP; if (ERTS_SCHEDULER_IS_DIRTY(erts_proc_sched_data(p))) @@ -2541,14 +2568,17 @@ setup_rootset(Process *p, Eterm *objv, int nobj, Rootset *rootset) break; case F_OFF_HEAP_MSGQ_CHNG: case 0: { + Sint len; /* * We do not have off heap message queue enabled, i.e. we - * need to add message queue to rootset... + * need to add signal queues to rootset... */ + len = erts_proc_sig_privqs_len(p); + /* Ensure large enough rootset... */ - if (n + p->sig_qs.len > rootset->size) { - Uint new_size = n + p->sig_qs.len; + if (n + len > rootset->size) { + Uint new_size = n + len; ERTS_GC_ASSERT(roots == rootset->def); roots = erts_alloc(ERTS_ALC_T_ROOTSET, new_size*sizeof(Roots)); @@ -3448,7 +3478,7 @@ erts_max_heap_size_map(Sint max_heap_size, Uint max_heap_flags, Eterm **hpp, Uint *sz) { if (!hpp) { - *sz += (2*3 + 1 + MAP_HEADER_FLATMAP_SZ); + *sz += ERTS_MAX_HEAP_SIZE_MAP_SZ; return THE_NON_VALUE; } else { Eterm *hp = *hpp; diff --git a/erts/emulator/beam/erl_gc.h b/erts/emulator/beam/erl_gc.h index 63d03cdf8b..b9b1ed728c 100644 --- a/erts/emulator/beam/erl_gc.h +++ b/erts/emulator/beam/erl_gc.h @@ -154,6 +154,8 @@ typedef struct { Uint64 garbage_cols; } ErtsGCInfo; +#define ERTS_MAX_HEAP_SIZE_MAP_SZ (2*3 + 1 + MAP_HEADER_FLATMAP_SZ) + #define ERTS_PROCESS_GC_INFO_MAX_TERMS (11) /* number of elements in process_gc_info*/ #define ERTS_PROCESS_GC_INFO_MAX_SIZE \ (ERTS_PROCESS_GC_INFO_MAX_TERMS * (2/*cons*/ + 3/*2-tuple*/ + BIG_UINT_HEAP_SIZE)) diff --git a/erts/emulator/beam/erl_message.c b/erts/emulator/beam/erl_message.c index 51b7865c0b..34bd11d87c 100644 --- a/erts/emulator/beam/erl_message.c +++ b/erts/emulator/beam/erl_message.c @@ -264,11 +264,6 @@ erts_queue_dist_message(Process *rcvr, Eterm from) { ErtsMessage* mp; -#ifdef USE_VM_PROBES - Sint tok_label = 0; - Sint tok_lastcnt = 0; - Sint tok_serial = 0; -#endif erts_aint_t state; ERTS_LC_ASSERT(rcvr_locks == erts_proc_lc_my_proc_locks(rcvr)); @@ -309,25 +304,6 @@ erts_queue_dist_message(Process *rcvr, } else { -#ifdef USE_VM_PROBES - if (DTRACE_ENABLED(message_queued)) { - DTRACE_CHARBUF(receiver_name, DTRACE_TERM_BUF_SIZE); - - dtrace_proc_str(rcvr, receiver_name); - if (have_seqtrace(token)) { - tok_label = SEQ_TRACE_T_DTRACE_LABEL(token); - tok_lastcnt = signed_val(SEQ_TRACE_T_LASTCNT(token)); - tok_serial = signed_val(SEQ_TRACE_T_SERIAL(token)); - } - /* - * TODO: We don't know the real size of the external message here. - * -1 will appear to a D script as 4294967295. - */ - DTRACE6(message_queued, receiver_name, -1, rcvr->sig_qs.len + 1, - tok_label, tok_lastcnt, tok_serial); - } -#endif - LINK_MESSAGE(rcvr, mp, &mp->next, 1); if (!(rcvr_locks & ERTS_PROC_LOCK_MSGQ)) @@ -346,7 +322,6 @@ queue_messages(Process* receiver, ErtsMessage** last, Uint len) { - Sint res; int locked_msgq = 0; erts_aint32_t state; @@ -394,31 +369,14 @@ queue_messages(Process* receiver, return 0; } - res = receiver->sig_qs.len; - if (receiver_locks & ERTS_PROC_LOCK_MAIN) { - /* - * We move 'in queue' to 'private queue' and place - * message at the end of 'private queue' in order - * to ensure that the 'in queue' doesn't contain - * references into the heap. By ensuring this, - * we don't need to include the 'in queue' in - * the root set when garbage collecting. - */ - res += receiver->sig_inq.len; - erts_proc_sig_fetch(receiver); - LINK_MESSAGE_PRIVQ(receiver, first, last, len); - } - else - { - LINK_MESSAGE(receiver, first, last, len); - } + LINK_MESSAGE(receiver, first, last, len); if (locked_msgq) { erts_proc_unlock(receiver, ERTS_PROC_LOCK_MSGQ); } erts_proc_notify_new_message(receiver, receiver_locks); - return res; + return 0; } static Sint @@ -870,7 +828,7 @@ erts_move_messages_off_heap(Process *c_p) * it... */ - reds += c_p->sig_qs.len / 10; + reds += erts_proc_sig_privqs_len(c_p) / 10; ASSERT(erts_atomic32_read_nob(&c_p->state) & ERTS_PSFLG_OFF_HEAP_MSGQ); @@ -1361,32 +1319,18 @@ void erts_factory_dummy_init(ErtsHeapFactory* factory) factory->mode = FACTORY_CLOSED; } -static void reserve_heap(ErtsHeapFactory*, Uint need, Uint xtra); - -Eterm* erts_produce_heap(ErtsHeapFactory* factory, Uint need, Uint xtra) -{ - Eterm* res; - - ASSERT((unsigned int)factory->mode > (unsigned int)FACTORY_CLOSED); - if (factory->hp + need > factory->hp_end) { - reserve_heap(factory, need, xtra); - } - res = factory->hp; - factory->hp += need; - return res; -} - Eterm* erts_reserve_heap(ErtsHeapFactory* factory, Uint need) { ASSERT((unsigned int)factory->mode > (unsigned int)FACTORY_CLOSED); if (factory->hp + need > factory->hp_end) { - reserve_heap(factory, need, 200); + erts_reserve_heap__(factory, need, 200); } return factory->hp; } -static void reserve_heap(ErtsHeapFactory* factory, Uint need, Uint xtra) +void erts_reserve_heap__(ErtsHeapFactory* factory, Uint need, Uint xtra) { + /* internal... */ ErlHeapFragment* bp; switch (factory->mode) { @@ -1396,7 +1340,9 @@ static void reserve_heap(ErtsHeapFactory* factory, Uint need, Uint xtra) factory->hp_end = factory->hp + need; return; - case FACTORY_MESSAGE: + case FACTORY_MESSAGE: { + int replace_oh; + int replace_msg_hfrag; if (!factory->heap_frags) { ASSERT(factory->message->data.attached == ERTS_MSG_COMBINED_HFRAG); bp = &factory->message->hfrag; @@ -1408,25 +1354,45 @@ static void reserve_heap(ErtsHeapFactory* factory, Uint need, Uint xtra) bp = factory->heap_frags; } + replace_oh = 0; + replace_msg_hfrag = 0; + if (bp) { - ASSERT(factory->hp > bp->mem); + ASSERT(factory->hp >= bp->mem); ASSERT(factory->hp <= factory->hp_end); ASSERT(factory->hp_end == bp->mem + bp->alloc_size); bp->used_size = factory->hp - bp->mem; + if (!bp->used_size && factory->heap_frags) { + factory->heap_frags = bp->next; + bp->next = NULL; + ASSERT(!bp->off_heap.first); + if (factory->off_heap == &bp->off_heap) + replace_oh = !0; + if (factory->message && factory->message->data.heap_frag == bp) + replace_msg_hfrag = !0; + free_message_buffer(bp); + } } bp = (ErlHeapFragment*) ERTS_HEAP_ALLOC(factory->alloc_type, ERTS_HEAP_FRAG_SIZE(need+xtra)); bp->next = factory->heap_frags; factory->heap_frags = bp; bp->alloc_size = need + xtra; - bp->used_size = need; + bp->used_size = need + xtra; bp->off_heap.first = NULL; bp->off_heap.overhead = 0; - + if (replace_oh) { + factory->off_heap = &bp->off_heap; + factory->off_heap_saved.first = factory->off_heap->first; + factory->off_heap_saved.overhead = factory->off_heap->overhead; + } + if (replace_msg_hfrag) + factory->message->data.heap_frag = bp; factory->hp = bp->mem; factory->hp_end = bp->mem + bp->alloc_size; return; + } case FACTORY_STATIC: case FACTORY_CLOSED: @@ -1509,9 +1475,11 @@ void erts_factory_trim_and_close(ErtsHeapFactory* factory, if (bp->next == NULL) { Uint used_sz = factory->hp - bp->mem; ASSERT(used_sz <= bp->alloc_size); - if (used_sz > 0) - bp = erts_resize_message_buffer(bp, used_sz, - brefs, brefs_size); + if (used_sz > 0) { + if (used_sz != bp->alloc_size) + bp = erts_resize_message_buffer(bp, used_sz, + brefs, brefs_size); + } else { free_message_buffer(bp); bp = NULL; diff --git a/erts/emulator/beam/erl_message.h b/erts/emulator/beam/erl_message.h index f56a252aef..ee87297ba4 100644 --- a/erts/emulator/beam/erl_message.h +++ b/erts/emulator/beam/erl_message.h @@ -89,12 +89,33 @@ void erts_factory_static_init(ErtsHeapFactory*, Eterm* hp, Uint size, ErlOffHeap void erts_factory_tmp_init(ErtsHeapFactory*, Eterm* hp, Uint size, Uint32 atype); void erts_factory_dummy_init(ErtsHeapFactory*); -Eterm* erts_produce_heap(ErtsHeapFactory*, Uint need, Uint xtra); +ERTS_GLB_INLINE Eterm* erts_produce_heap(ErtsHeapFactory*, Uint need, Uint xtra); + Eterm* erts_reserve_heap(ErtsHeapFactory*, Uint need); void erts_factory_close(ErtsHeapFactory*); void erts_factory_trim_and_close(ErtsHeapFactory*,Eterm *brefs, Uint brefs_size); void erts_factory_undo(ErtsHeapFactory*); +void erts_reserve_heap__(ErtsHeapFactory*, Uint need, Uint xtra); /* internal */ + +#if ERTS_GLB_INLINE_INCL_FUNC_DEF + +ERTS_GLB_INLINE Eterm * +erts_produce_heap(ErtsHeapFactory* factory, Uint need, Uint xtra) +{ + Eterm* res; + + ASSERT((unsigned int)factory->mode > (unsigned int)FACTORY_CLOSED); + if (factory->hp + need > factory->hp_end) { + erts_reserve_heap__(factory, need, xtra); + } + res = factory->hp; + factory->hp += need; + return res; +} + +#endif /* ERTS_GLB_INLINE_INCL_FUNC_DEF */ + #ifdef CHECK_FOR_HOLES # define ERTS_FACTORY_HOLE_CHECK(f) do { \ /*if ((f)->p) erts_check_for_holes((f)->p);*/ \ @@ -215,6 +236,48 @@ typedef struct { #define ERL_MESSAGE_BUF_SZ 500 typedef struct { + /* + * ** The signal queues private to a process. ** + * + * These are: + * - an inner queue which only consists of + * message signals + * - a middle queue which contains a mixture + * of message and non-message signals + * + * When the process isn't processing signals in + * erts_proc_sig_handle_incoming(): + * - the message queue corresponds to the inner + * queue. Messages in the middle queue (and + * in the outer queue) are in transit and + * have NOT been received yet! + * + * When the process is processing signals in + * erts_proc_sig_handle_incoming(): + * - the message queue corresponds to the inner + * queue plus the head of the middle queue up + * to the signal currently being processed. + * Any messages further back in the middle queue + * (and in the outer queue) are still in transit + * and have NOT been received yet! + * + * In the general case the 'len' field of this + * structure does NOT correspond to the message + * queue length. When the process is inspected + * via process info it does however correspond + * to the message queue length, but this is a + * special case! + * + * When no process-info request is in transit to + * the process the 'len' field corresponds to + * the total amount of messages in inner and + * middle queues (which does NOT correspond to + * the message queue length). When process-info + * requests are in transit to the process, the + * usage of the 'len' field changes and is used + * as an offset which even might be negative. + */ + /* inner queue */ ErtsMessage *first; ErtsMessage **last; /* point to the last next pointer */ @@ -227,7 +290,7 @@ typedef struct { /* Common for inner and middle queue */ ErtsMessage **saved_last; /* saved last pointer */ - Sint len; /* message queue length (inner+middle) */ + Sint len; /* NOT message queue length (see above) */ } ErtsSignalPrivQueues; typedef struct { @@ -248,8 +311,7 @@ typedef struct erl_trace_message_queue__ { #define ERTS_RECV_MARK_SAVE(P) \ do { \ erts_proc_lock((P), ERTS_PROC_LOCK_MSGQ); \ - if ((P)->sig_inq.first) \ - erts_proc_sig_fetch((P)); \ + erts_proc_sig_fetch((P)); \ erts_proc_unlock((P), ERTS_PROC_LOCK_MSGQ); \ if ((P)->sig_qs.cont) { \ (P)->sig_qs.saved_last = (P)->sig_qs.cont_last; \ @@ -302,23 +364,6 @@ typedef struct erl_trace_message_queue__ { #endif - -/* Add message last in private message queue */ -#define LINK_MESSAGE_PRIVQ(p, first_msg, last_msg, num_msgs) \ - do { \ - ERTS_HDBG_CHECK_SIGNAL_PRIV_QUEUE__((p), "before"); \ - if ((p)->sig_qs.cont || ERTS_MSG_RECV_TRACED((p))) { \ - *(p)->sig_qs.cont_last = (first_msg); \ - (p)->sig_qs.cont_last = (last_msg); \ - } \ - else { \ - *(p)->sig_qs.last = (first_msg); \ - (p)->sig_qs.last = (last_msg); \ - } \ - (p)->sig_qs.len += (num_msgs); \ - ERTS_HDBG_CHECK_SIGNAL_PRIV_QUEUE__((p), "after"); \ - } while (0) - /* Add message last_msg in message queue */ #define LINK_MESSAGE(p, first_msg, last_msg, num_msgs) \ do { \ @@ -333,12 +378,12 @@ typedef struct erl_trace_message_queue__ { #define UNLINK_MESSAGE(p,msgp) \ do { \ ErtsMessage *mp__ = (msgp)->next; \ - ERTS_HDBG_CHECK_SIGNAL_PRIV_QUEUE__((p), "before"); \ + ERTS_HDBG_CHECK_SIGNAL_PRIV_QUEUE__((p), 0, "before"); \ *(p)->sig_qs.save = mp__; \ (p)->sig_qs.len--; \ if (mp__ == NULL) \ (p)->sig_qs.last = (p)->sig_qs.save; \ - ERTS_HDBG_CHECK_SIGNAL_PRIV_QUEUE__((p), "after"); \ + ERTS_HDBG_CHECK_SIGNAL_PRIV_QUEUE__((p), 0, "after"); \ } while(0) /* diff --git a/erts/emulator/beam/erl_proc_sig_queue.c b/erts/emulator/beam/erl_proc_sig_queue.c index 1ba0b789ec..bcc4fc6d9b 100644 --- a/erts/emulator/beam/erl_proc_sig_queue.c +++ b/erts/emulator/beam/erl_proc_sig_queue.c @@ -49,7 +49,7 @@ * Note that not all signal are handled using this functionality! */ -#define ERTS_SIG_Q_OP_MAX 10 +#define ERTS_SIG_Q_OP_MAX 11 #define ERTS_SIG_Q_OP_EXIT 0 #define ERTS_SIG_Q_OP_EXIT_LINKED 1 @@ -61,7 +61,8 @@ #define ERTS_SIG_Q_OP_GROUP_LEADER 7 #define ERTS_SIG_Q_OP_TRACE_CHANGE_STATE 8 #define ERTS_SIG_Q_OP_PERSISTENT_MON_MSG 9 -#define ERTS_SIG_Q_OP_IS_ALIVE ERTS_SIG_Q_OP_MAX +#define ERTS_SIG_Q_OP_IS_ALIVE 10 +#define ERTS_SIG_Q_OP_PROCESS_INFO ERTS_SIG_Q_OP_MAX #define ERTS_SIG_Q_TYPE_MAX (ERTS_MON_LNK_TYPE_MAX + 5) @@ -76,46 +77,6 @@ #define ERTS_SIG_Q_TYPE_ADJUST_TRACE_INFO \ ERTS_SIG_Q_TYPE_MAX - -#define ERTS_SIG_Q_OP_BITS 8 -#define ERTS_SIG_Q_OP_SHIFT 0 -#define ERTS_SIG_Q_OP_MASK ((1 << ERTS_SIG_Q_OP_BITS) - 1) - -#define ERTS_SIG_Q_TYPE_BITS 8 -#define ERTS_SIG_Q_TYPE_SHIFT ERTS_SIG_Q_OP_BITS -#define ERTS_SIG_Q_TYPE_MASK ((1 << ERTS_SIG_Q_TYPE_BITS) - 1) - -#define ERTS_SIG_Q_NON_X_BITS__ (_HEADER_ARITY_OFFS \ - + ERTS_SIG_Q_OP_BITS \ - + ERTS_SIG_Q_TYPE_BITS) - -#define ERTS_SIG_Q_XTRA_BITS (32 - ERTS_SIG_Q_NON_X_BITS__) -#define ERTS_SIG_Q_XTRA_SHIFT (ERTS_SIG_Q_OP_BITS \ - + ERTS_SIG_Q_TYPE_BITS) -#define ERTS_SIG_Q_XTRA_MASK ((1 << ERTS_SIG_Q_XTRA_BITS) - 1) - -#define ERTS_PROC_SIG_OP(Tag) \ - ((int) (_unchecked_thing_arityval((Tag)) \ - >> ERTS_SIG_Q_OP_SHIFT) & ERTS_SIG_Q_OP_MASK) - -#define ERTS_PROC_SIG_TYPE(Tag) \ - ((Uint16) (_unchecked_thing_arityval((Tag)) \ - >> ERTS_SIG_Q_TYPE_SHIFT) & ERTS_SIG_Q_TYPE_MASK) - -#define ERTS_PROC_SIG_XTRA(Tag) \ - ((Uint32) (_unchecked_thing_arityval((Tag)) \ - >> ERTS_SIG_Q_XTRA_SHIFT) & ERTS_SIG_Q_XTRA_MASK) - -#define ERTS_PROC_SIG_MAKE_TAG(Op, Type, Xtra) \ - (ASSERT(0 <= (Xtra) && (Xtra) <= ERTS_SIG_Q_XTRA_MASK), \ - _make_header((((Type) & ERTS_SIG_Q_TYPE_MASK) \ - << ERTS_SIG_Q_TYPE_SHIFT) \ - | (((Op) & ERTS_SIG_Q_OP_MASK) \ - << ERTS_SIG_Q_OP_SHIFT) \ - | (((Xtra) & ERTS_SIG_Q_XTRA_MASK) \ - << ERTS_SIG_Q_XTRA_SHIFT), \ - _TAG_HEADER_EXTERNAL_PID)) - Process *ERTS_WRITE_UNLIKELY(erts_dirty_process_signal_handler); Process *ERTS_WRITE_UNLIKELY(erts_dirty_process_signal_handler_high); Process *ERTS_WRITE_UNLIKELY(erts_dirty_process_signal_handler_max); @@ -123,7 +84,8 @@ Process *ERTS_WRITE_UNLIKELY(erts_dirty_process_signal_handler_max); void erts_proc_sig_queue_init(void) { - ERTS_CT_ASSERT(ERTS_SIG_Q_OP_MASK >= ERTS_SIG_Q_OP_MAX); + ERTS_CT_ASSERT(ERTS_SIG_Q_OP_MASK > ERTS_SIG_Q_OP_MAX); + ERTS_CT_ASSERT(ERTS_SIG_Q_OP_MSGQ_LEN_OFFS_MARK > ERTS_SIG_Q_OP_MAX); ERTS_CT_ASSERT(ERTS_SIG_Q_TYPE_MASK >= ERTS_SIG_Q_TYPE_MAX); } @@ -191,6 +153,29 @@ typedef struct { Eterm requester; } ErtsIsAliveRequest; +typedef struct { + ErtsSignalCommon common; + Sint refc; + Sint delayed_len; + Sint len_offset; +} ErtsProcSigMsgQLenOffsetMarker; + +typedef struct { + ErtsSignalCommon common; + ErtsProcSigMsgQLenOffsetMarker marker; + Sint msgq_len_offset; + Eterm requester; + Eterm ref; + ErtsORefThing oref_thing; + Uint reserve_size; + Uint len; + int flags; + int item_ix[1]; /* of len size in reality... */ +} ErtsProcessInfoSig; + +#define ERTS_PROC_SIG_PI_MSGQ_LEN_IGNORE ((Sint) -1) +#define ERTS_PROC_SIG_PI_MSGQ_LEN_SYNC ((Sint) -2) + static int handle_msg_tracing(Process *c_p, ErtsSigRecvTracing *tracing, ErtsMessage ***next_nm_sig); @@ -523,6 +508,9 @@ ensure_dirty_proc_handled(Eterm pid, } } +static void +check_push_msgq_len_offs_marker(Process *rp, ErtsSignal *sig); + static int proc_queue_signal(Process *c_p, Eterm pid, ErtsSignal *sig, int op) { @@ -559,6 +547,8 @@ proc_queue_signal(Process *c_p, Eterm pid, ErtsSignal *sig, int op) res = 0; else { state = enqueue_signals(rp, first, last, last_next, state); + if (ERTS_UNLIKELY(op == ERTS_SIG_Q_OP_PROCESS_INFO)) + check_push_msgq_len_offs_marker(rp, sig); res = !0; } @@ -620,31 +610,14 @@ maybe_elevate_sig_handling_prio(Process *c_p, Eterm other) } void -erts_proc_sig_fetch(Process *proc) +erts_proc_sig_fetch__(Process *proc) { #ifdef ERTS_PROC_SIG_HARD_DEBUG ErtsSignalPrivQueues sig_qs = proc->sig_qs; ErtsSignalInQueue sig_inq = proc->sig_inq; #endif - ERTS_LC_ASSERT(erts_thr_progress_is_blocking() - || ERTS_PROC_IS_EXITING(proc) - || ((erts_proc_lc_my_proc_locks(proc) - & (ERTS_PROC_LOCK_MAIN - | ERTS_PROC_LOCK_MSGQ)) - == (ERTS_PROC_LOCK_MAIN - | ERTS_PROC_LOCK_MSGQ))); - - if (!proc->sig_inq.first) { - ASSERT(proc->sig_inq.last == &proc->sig_inq.first); - ASSERT(proc->sig_inq.len == 0); - ASSERT(!proc->sig_inq.nmsigs.next); - ASSERT(!proc->sig_inq.nmsigs.last); - return; - } - - ERTS_HDBG_CHECK_SIGNAL_IN_QUEUE(proc); - ERTS_HDBG_CHECK_SIGNAL_PRIV_QUEUE(proc); + ASSERT(proc->sig_inq.first); if (!proc->sig_inq.nmsigs.next) { ASSERT(!(ERTS_PSFLG_SIG_IN_Q @@ -720,10 +693,105 @@ erts_proc_sig_fetch(Process *proc) proc->sig_inq.last = &proc->sig_inq.first; proc->sig_inq.len = 0; - ERTS_HDBG_CHECK_SIGNAL_PRIV_QUEUE(proc); } -void do_seq_trace_output(Eterm to, Eterm token, Eterm msg); +Sint +erts_proc_sig_fetch_msgq_len_offs__(Process *proc) +{ + ErtsProcSigMsgQLenOffsetMarker *marker + = (ErtsProcSigMsgQLenOffsetMarker *) proc->sig_inq.first; + + ASSERT(marker->common.tag == ERTS_PROC_SIG_MSGQ_LEN_OFFS_MARK); + + if (marker->common.next) { + Sint len; + + proc->flags |= F_DELAYED_PSIGQS_LEN; + + /* + * Prevent update of sig_qs.len in fetch. These + * updates are done via process-info signal(s) + * instead... + */ + len = proc->sig_inq.len; + marker->delayed_len += len; + marker->len_offset -= len; + proc->sig_inq.len = 0; + + /* + * Temorarily remove marker during fetch... + */ + + proc->sig_inq.first = marker->common.next; + if (proc->sig_inq.last == &marker->common.next) + proc->sig_inq.last = &proc->sig_inq.first; + if (proc->sig_inq.nmsigs.next == &marker->common.next) + proc->sig_inq.nmsigs.next = &proc->sig_inq.first; + if (proc->sig_inq.nmsigs.last == &marker->common.next) + proc->sig_inq.nmsigs.last = &proc->sig_inq.first; + + erts_proc_sig_fetch__(proc); + + marker->common.next = NULL; + proc->sig_inq.first = (ErtsMessage *) marker; + proc->sig_inq.last = &marker->common.next; + + } + + return marker->delayed_len; +} + +static ERTS_INLINE Sint +proc_sig_privqs_len(Process *c_p, int have_qlock) +{ + Sint res = c_p->sig_qs.len; + + ERTS_LC_ASSERT(!have_qlock + ? (ERTS_PROC_LOCK_MAIN + == erts_proc_lc_my_proc_locks(c_p)) + : ((ERTS_PROC_LOCK_MSGQ|ERTS_PROC_LOCK_MAIN) + == ((ERTS_PROC_LOCK_MSGQ|ERTS_PROC_LOCK_MAIN) + & erts_proc_lc_my_proc_locks(c_p)))); + + if (c_p->flags & F_DELAYED_PSIGQS_LEN) { + ErtsProcSigMsgQLenOffsetMarker *marker; + + if (!have_qlock) + erts_proc_lock(c_p, ERTS_PROC_LOCK_MSGQ); + + marker = (ErtsProcSigMsgQLenOffsetMarker *) c_p->sig_inq.first; + ASSERT(marker); + ASSERT(marker->common.tag == ERTS_PROC_SIG_MSGQ_LEN_OFFS_MARK); + + res += marker->delayed_len; + + if (!have_qlock) + erts_proc_unlock(c_p, ERTS_PROC_LOCK_MSGQ); + } + +#ifdef ERTS_PROC_SIG_HARD_DEBUG_SIGQ_MSG_LEN + { + Sint len = 0; + ERTS_FOREACH_SIG_PRIVQS( + c_p, mp, + { + if (ERTS_SIG_IS_MSG(mp)) + len++; + }); + ERTS_ASSERT(res == len); + } +#endif + + return res; +} + +Sint +erts_proc_sig_privqs_len(Process *c_p) +{ + return proc_sig_privqs_len(c_p, 0); +} + +static void do_seq_trace_output(Eterm to, Eterm token, Eterm msg); static void send_gen_exit_signal(Process *c_p, Eterm from_tag, @@ -869,7 +937,7 @@ send_gen_exit_signal(Process *c_p, Eterm from_tag, } } -void +static void do_seq_trace_output(Eterm to, Eterm token, Eterm msg) { /* @@ -887,15 +955,17 @@ do_seq_trace_output(Eterm to, Eterm token, Eterm msg) else rp = erts_proc_lookup_raw_inc_refc(to); - erts_proc_lock(rp, ERTS_PROC_LOCK_MSGQ); + if (rp) { + erts_proc_lock(rp, ERTS_PROC_LOCK_MSGQ); - if (!ERTS_PROC_IS_EXITING(rp)) - seq_trace_output(token, msg, SEQ_TRACE_SEND, to, rp); + if (!ERTS_PROC_IS_EXITING(rp)) + seq_trace_output(token, msg, SEQ_TRACE_SEND, to, rp); - erts_proc_unlock(rp, ERTS_PROC_LOCK_MSGQ); + erts_proc_unlock(rp, ERTS_PROC_LOCK_MSGQ); - if (!is_normal_sched) - erts_proc_dec_refc(rp); + if (!is_normal_sched) + erts_proc_dec_refc(rp); + } } void @@ -1352,6 +1422,59 @@ erts_proc_sig_send_is_alive_request(Process *c_p, Eterm to, Eterm ref) } } +int +erts_proc_sig_send_process_info_request(Process *c_p, + Eterm to, + int *item_ix, + int len, + int need_msgq_len, + int flags, + Uint reserve_size, + Eterm ref) +{ + Uint size = sizeof(ErtsProcessInfoSig) + (len - 1) * sizeof(int); + ErtsProcessInfoSig *pis = erts_alloc(ERTS_ALC_T_SIG_DATA, size); + int res; + + ASSERT(c_p); + ASSERT(item_ix); + ASSERT(len > 0); + ASSERT(is_internal_ordinary_ref(ref)); + + pis->common.tag = ERTS_PROC_SIG_MAKE_TAG(ERTS_SIG_Q_OP_PROCESS_INFO, + 0, 0); + + if (!need_msgq_len) + pis->msgq_len_offset = ERTS_PROC_SIG_PI_MSGQ_LEN_IGNORE; + else { + pis->msgq_len_offset = ERTS_PROC_SIG_PI_MSGQ_LEN_SYNC; + pis->marker.common.next = NULL; + pis->marker.common.specific.next = NULL; + pis->marker.common.tag = ERTS_PROC_SIG_MSGQ_LEN_OFFS_MARK; + pis->marker.refc = 0; + pis->marker.delayed_len = 0; + pis->marker.len_offset = 0; + } + pis->requester = c_p->common.id; + sys_memcpy((void *) &pis->oref_thing, + (void *) internal_ref_val(ref), + sizeof(ErtsORefThing)); + pis->ref = make_internal_ref((char *) &pis->oref_thing); + pis->reserve_size = reserve_size; + pis->len = len; + pis->flags = flags; + sys_memcpy((void *) &pis->item_ix[0], + (void *) item_ix, + sizeof(int)*len); + res = proc_queue_signal(c_p, to, (ErtsSignal *) pis, + ERTS_SIG_Q_OP_PROCESS_INFO); + if (res) + (void) maybe_elevate_sig_handling_prio(c_p, to); + else + erts_free(ERTS_ALC_T_SIG_DATA, pis); + return res; +} + static void is_alive_response(Process *c_p, ErtsMessage *mp, int is_alive) { @@ -1552,7 +1675,6 @@ remove_mq_m_sig(Process *c_p, ErtsMessage *sig, ErtsMessage **next_sig, ErtsMess { /* Removing message... */ ASSERT(!ERTS_SIG_IS_NON_MSG(sig)); - ASSERT(c_p->sig_qs.len > 0); c_p->sig_qs.len--; remove_mq_sig(c_p, sig, next_sig, next_nm_sig); } @@ -1562,7 +1684,6 @@ remove_iq_m_sig(Process *c_p, ErtsMessage *sig, ErtsMessage **next_sig) { /* Removing message... */ ASSERT(!ERTS_SIG_IS_NON_MSG(sig)); - ASSERT(c_p->sig_qs.len > 0); c_p->sig_qs.len--; remove_iq_sig(c_p, sig, next_sig); } @@ -2138,6 +2259,258 @@ handle_group_leader(Process *c_p, ErtsSigGroupLeader *sgl) destroy_sig_group_leader(sgl); } +static void +check_push_msgq_len_offs_marker(Process *rp, ErtsSignal *sig) +{ + ErtsProcessInfoSig *pisig = (ErtsProcessInfoSig *) sig; + + ASSERT(ERTS_PROC_SIG_OP(sig->common.tag) == ERTS_SIG_Q_OP_PROCESS_INFO); + + if (pisig->msgq_len_offset == ERTS_PROC_SIG_PI_MSGQ_LEN_SYNC) { + ErtsProcSigMsgQLenOffsetMarker *mrkr; + Sint len, msgq_len_offset; + ErtsMessage *first = rp->sig_inq.first; + ASSERT(first); + if (((ErtsSignal *) first)->common.tag == ERTS_PROC_SIG_MSGQ_LEN_OFFS_MARK) + mrkr = (ErtsProcSigMsgQLenOffsetMarker *) first; + else { + mrkr = &pisig->marker; + + ASSERT(mrkr->common.tag == ERTS_PROC_SIG_MSGQ_LEN_OFFS_MARK); + + mrkr->common.next = first; + ASSERT(rp->sig_inq.last != &rp->sig_inq.first); + if (rp->sig_inq.nmsigs.next == &rp->sig_inq.first) + rp->sig_inq.nmsigs.next = &mrkr->common.next; + if (rp->sig_inq.nmsigs.last == &rp->sig_inq.first) + rp->sig_inq.nmsigs.last = &mrkr->common.next; + rp->sig_inq.first = (ErtsMessage *) mrkr; + } + + len = rp->sig_inq.len; + msgq_len_offset = len - mrkr->len_offset; + + mrkr->len_offset = len; + mrkr->refc++; + + pisig->msgq_len_offset = msgq_len_offset; + +#ifdef DEBUG + /* save pointer to used marker... */ + pisig->marker.common.specific.attachment = (void *) mrkr; +#endif + + } +} + +static void +destroy_process_info_request(Process *c_p, ErtsProcessInfoSig *pisig) +{ + int dealloc_pisig = !0; + + if (pisig->msgq_len_offset != ERTS_PROC_SIG_PI_MSGQ_LEN_IGNORE) { + Sint refc; + int dealloc_marker = 0; + ErtsProcSigMsgQLenOffsetMarker *marker; +#ifdef ERTS_PROC_SIG_HARD_DEBUG_SIGQ_MSG_LEN + Sint delayed_len; +#endif + + ASSERT(pisig->msgq_len_offset >= 0); + + erts_proc_lock(c_p, ERTS_PROC_LOCK_MSGQ); + marker = (ErtsProcSigMsgQLenOffsetMarker *) c_p->sig_inq.first; + ASSERT(marker); + ASSERT(marker->refc > 0); + ASSERT(pisig->marker.common.specific.attachment == (void *) marker); + + marker->delayed_len -= pisig->msgq_len_offset; +#ifdef ERTS_PROC_SIG_HARD_DEBUG_SIGQ_MSG_LEN + delayed_len = marker->delayed_len; +#endif + + refc = --marker->refc; + if (refc) { + if (marker == &pisig->marker) { + /* Another signal using our marker... */ + dealloc_pisig = 0; + } + } + else { + /* Marker unused; remove it... */ + ASSERT(marker->delayed_len + marker->len_offset == 0); +#ifdef ERTS_PROC_SIG_HARD_DEBUG_SIGQ_MSG_LEN + delayed_len += marker->len_offset; +#endif + if (marker != &pisig->marker) + dealloc_marker = !0; /* used another signals marker... */ + c_p->sig_inq.first = marker->common.next; + if (c_p->sig_inq.last == &marker->common.next) + c_p->sig_inq.last = &c_p->sig_inq.first; + if (c_p->sig_inq.nmsigs.next == &marker->common.next) + c_p->sig_inq.nmsigs.next = &c_p->sig_inq.first; + if (c_p->sig_inq.nmsigs.last == &marker->common.next) + c_p->sig_inq.nmsigs.last = &c_p->sig_inq.first; + } + erts_proc_unlock(c_p, ERTS_PROC_LOCK_MSGQ); + + if (!refc) { + c_p->flags &= ~F_DELAYED_PSIGQS_LEN; + /* Adjust msg len of inner+middle queue */ + ASSERT(marker->len_offset <= 0); + c_p->sig_qs.len -= marker->len_offset; + + ASSERT(c_p->sig_qs.len >= 0); + } + +#ifdef ERTS_PROC_SIG_HARD_DEBUG_SIGQ_MSG_LEN + { + Sint len = 0; + ERTS_FOREACH_SIG_PRIVQS( + c_p, mp, + { + if (ERTS_SIG_IS_MSG(mp)) + len++; + }); + ERTS_ASSERT(c_p->sig_qs.len + delayed_len == len); + } +#endif + + + if (dealloc_marker) { + ErtsProcessInfoSig *pisig2 + = (ErtsProcessInfoSig *) (((char *) marker) + - offsetof(ErtsProcessInfoSig, + marker)); + erts_free(ERTS_ALC_T_SIG_DATA, pisig2); + } + } + + if (dealloc_pisig) + erts_free(ERTS_ALC_T_SIG_DATA, pisig); +} + +static int +handle_process_info(Process *c_p, ErtsMessage *sig, + ErtsMessage ***next_nm_sig, int is_alive) +{ + ErtsProcessInfoSig *pisig = (ErtsProcessInfoSig *) sig; + Uint reds = 0; + Process *rp; + + if (pisig->msgq_len_offset != ERTS_PROC_SIG_PI_MSGQ_LEN_IGNORE) { + /* + * Request requires message queue data to be updated + * before inspection... + */ + + ASSERT(pisig->msgq_len_offset >= 0); + /* + * Update sig_qs.len to reflect the length + * of the message queue... + */ + c_p->sig_qs.len += pisig->msgq_len_offset; + + if (is_alive) { + /* + * Move messages part of message queue into inner + * signal queue... + */ + if (*next_nm_sig != &c_p->sig_qs.cont) { + *c_p->sig_qs.last = c_p->sig_qs.cont; + c_p->sig_qs.last = *next_nm_sig; + + c_p->sig_qs.cont = **next_nm_sig; + if (c_p->sig_qs.nmsigs.last == *next_nm_sig) + c_p->sig_qs.nmsigs.last = &c_p->sig_qs.cont; + *next_nm_sig = &c_p->sig_qs.cont; + *c_p->sig_qs.last = NULL; + } + + if (!pisig->common.specific.next) { + /* + * No more signals in middle queue... + * + * Process-info 'status' needs sig-q + * process flag to be updated in order + * to show accurate result... + */ + erts_atomic32_read_band_nob(&c_p->state, + ~ERTS_PSFLG_SIG_Q); + } + +#ifdef ERTS_PROC_SIG_HARD_DEBUG_SIGQ_MSG_LEN + { + Sint len; + ErtsMessage *mp; + for (mp = c_p->sig_qs.first, len = 0; mp; mp = mp->next) { + ERTS_ASSERT(ERTS_SIG_IS_MSG(mp)); + len++; + } + ERTS_ASSERT(c_p->sig_qs.len == len); + } +#endif + } + } + if (is_alive) + remove_nm_sig(c_p, sig, next_nm_sig); + + rp = erts_proc_lookup(pisig->requester); + ASSERT(c_p != rp); + if (rp) { + Eterm msg, res, ref, *hp; + ErtsProcLocks locks = 0; + ErtsHeapFactory hfact; + ErtsMessage *mp; + Uint reserve_size = 3 + sizeof(pisig->oref_thing)/sizeof(Eterm); + + if (!is_alive) { + ErlOffHeap *ohp; + mp = erts_alloc_message_heap(rp, &locks, reserve_size, &hp, &ohp); + res = am_undefined; + } + else { + ErlHeapFragment *hfrag; + + reserve_size += pisig->reserve_size; + + mp = erts_alloc_message(0, NULL); + hfrag = new_message_buffer(reserve_size); + mp->data.heap_frag = hfrag; + erts_factory_selfcontained_message_init(&hfact, mp, &hfrag->mem[0]); + + res = erts_process_info(c_p, &hfact, c_p, ERTS_PROC_LOCK_MAIN, + pisig->item_ix, pisig->len, + pisig->flags, reserve_size, &reds); + + hp = erts_produce_heap(&hfact, + 3 + sizeof(pisig->oref_thing)/sizeof(Eterm), + 0); + } + + sys_memcpy((void *) hp, (void *) &pisig->oref_thing, + sizeof(pisig->oref_thing)); + ref = make_internal_ref(hp); + hp += sizeof(pisig->oref_thing)/sizeof(Eterm); + + msg = TUPLE2(hp, ref, res); + + if (is_alive) + erts_factory_trim_and_close(&hfact, &msg, 1); + + erts_queue_message(rp, locks, mp, msg, c_p->common.id); + + if (!is_alive && locks) + erts_proc_unlock(rp, locks); + } + + destroy_process_info_request(c_p, pisig); + + if (reds > INT_MAX/8) + reds = INT_MAX/8; + + return ((int) reds)*4 + 8; +} /* * Called in order to handle incoming signals. @@ -2153,7 +2526,7 @@ erts_proc_sig_handle_incoming(Process *c_p, erts_aint32_t *statep, ErtsMessage *sig, ***next_nm_sig; ErtsSigRecvTracing tracing; - ERTS_HDBG_CHECK_SIGNAL_PRIV_QUEUE(c_p); + ERTS_HDBG_CHECK_SIGNAL_PRIV_QUEUE(c_p, 0); ERTS_LC_ASSERT(ERTS_PROC_LOCK_MAIN == erts_proc_lc_my_proc_locks(c_p)); if (local_only) @@ -2502,6 +2875,12 @@ erts_proc_sig_handle_incoming(Process *c_p, erts_aint32_t *statep, ERTS_PROC_SIG_HDBG_PRIV_CHKQ(c_p, &tracing, next_nm_sig); break; + case ERTS_SIG_Q_OP_PROCESS_INFO: + ERTS_PROC_SIG_HDBG_PRIV_CHKQ(c_p, &tracing, next_nm_sig); + handle_process_info(c_p, sig, next_nm_sig, !0); + ERTS_PROC_SIG_HDBG_PRIV_CHKQ(c_p, &tracing, next_nm_sig); + break; + case ERTS_SIG_Q_OP_TRACE_CHANGE_STATE: { Uint16 type = ERTS_PROC_SIG_TYPE(tag); @@ -2655,7 +3034,7 @@ stop: { c_p->sig_qs.save = c_p->sig_qs.saved_last; } - ERTS_HDBG_CHECK_SIGNAL_PRIV_QUEUE(c_p); + ERTS_HDBG_CHECK_SIGNAL_PRIV_QUEUE(c_p, 0); *redsp = cnt/4 + 1; @@ -2707,8 +3086,8 @@ erts_proc_sig_handle_exit(Process *c_p, int *redsp) int cnt, limit; ErtsMessage *sig, ***next_nm_sig; - ERTS_HDBG_CHECK_SIGNAL_PRIV_QUEUE(c_p); - ERTS_LC_ASSERT(!erts_proc_lc_my_proc_locks(c_p)); + ERTS_HDBG_CHECK_SIGNAL_PRIV_QUEUE(c_p, 0); + ERTS_LC_ASSERT(erts_proc_lc_my_proc_locks(c_p) == ERTS_PROC_LOCK_MAIN); ASSERT(!(ERTS_PSFLG_SIG_IN_Q & erts_atomic32_read_nob(&c_p->state))); @@ -2815,9 +3194,11 @@ erts_proc_sig_handle_exit(Process *c_p, int *redsp) } case ERTS_SIG_Q_OP_IS_ALIVE: - ERTS_PROC_SIG_HDBG_PRIV_CHKQ(c_p, &tracing, next_nm_sig); is_alive_response(c_p, sig, 0); - ERTS_PROC_SIG_HDBG_PRIV_CHKQ(c_p, &tracing, next_nm_sig); + break; + + case ERTS_SIG_Q_OP_PROCESS_INFO: + handle_process_info(c_p, sig, next_nm_sig, 0); break; case ERTS_SIG_Q_OP_TRACE_CHANGE_STATE: @@ -3003,6 +3384,13 @@ erts_proc_sig_signal_size(ErtsSignal *sig) size = sizeof(ErtsSigTraceInfo); break; + case ERTS_SIG_Q_OP_PROCESS_INFO: { + ErtsProcessInfoSig *pisig = (ErtsProcessInfoSig *) sig; + size = sizeof(ErtsProcessInfoSig); + size += (pisig->len - 1) * sizeof(int); + break; + } + default: ERTS_INTERNAL_ERROR("Unknown signal"); break; @@ -3058,8 +3446,7 @@ erts_proc_sig_receive_helper(Process *c_p, consumed_reds += 4; left_reds -= 4; erts_proc_lock(c_p, ERTS_PROC_LOCK_MSGQ); - if (c_p->sig_inq.first) - erts_proc_sig_fetch(c_p); + erts_proc_sig_fetch(c_p); /* * Messages may have been moved directly to * inner queue... @@ -3220,6 +3607,7 @@ handle_message_enqueued_tracing(Process *c_p, Sint tok_label = 0; Sint tok_lastcnt = 0; Sint tok_serial = 0; + Sint len = erts_proc_sig_privqs_len(c_p); Eterm seq_trace_token = ERL_MESSAGE_TOKEN(msg); if (seq_trace_token != NIL && is_tuple(seq_trace_token)) { @@ -3231,7 +3619,7 @@ handle_message_enqueued_tracing(Process *c_p, DTRACE6(message_queued, tracing->messages.receiver_name, size_object(ERL_MESSAGE_TERM(msg)), - c_p->sig_qs.len, + len, /* This is NOT message queue len, but its something... */ tok_label, tok_lastcnt, tok_serial); } #endif @@ -3303,24 +3691,11 @@ handle_msg_tracing(Process *c_p, ErtsSigRecvTracing *tracing, return 0; } -/* - * ERTS_INSPECT_MSGQ_KEEP_OH_MSGS == 0 will move off heap messages - * into the heap of the inspected process if off_heap_message_queue - * is false when process_info(_, messages) is called. That is, the - * following GC will have more data in the rootset compared to the - * scenario when process_info(_, messages) had not been called. - * - * ERTS_INSPECT_MSGQ_KEEP_OH_MSGS != 0 will keep off heap messages - * off heap when process_info(_, messages) is called regardless of - * the off_heap_message_queue setting of the process. That is, it - * will change the following execution of the process as little as - * possible. - */ -#define ERTS_INSPECT_MSGQ_KEEP_OH_MSGS 1 - Uint -erts_proc_sig_prep_msgq_for_inspection(Process *c_p, Process *rp, +erts_proc_sig_prep_msgq_for_inspection(Process *c_p, + Process *rp, ErtsProcLocks rp_locks, + int info_on_self, ErtsMessageInfo *mip) { Uint tot_heap_size; @@ -3329,9 +3704,8 @@ erts_proc_sig_prep_msgq_for_inspection(Process *c_p, Process *rp, int self_on_heap; /* - * Prepare the message queue for inspection - * by process_info(). - * + * Prepare the message queue (inner signal queue) + * for inspection by process_info(). * * - Decode all messages on external format * - Remove all corrupt dist messages from queue @@ -3340,20 +3714,11 @@ erts_proc_sig_prep_msgq_for_inspection(Process *c_p, Process *rp, * - Return total heap size need for all messages * that needs to be copied. * - * If ERTS_INSPECT_MSGQ_KEEP_OH_MSGS == 0: - * - In case off heap messages is disabled and - * we are inspecting our own queue, move all - * off heap data into the heap. */ - /* - * All non-message signals *need* to have been - * handled before calling this functions... - */ - ASSERT(!rp->sig_qs.cont); - ASSERT(!rp->sig_qs.nmsigs.next && !rp->sig_qs.nmsigs.last); + ASSERT(!info_on_self || c_p == rp); - self_on_heap = c_p == rp && !(c_p->flags & F_OFF_HEAP_MSGQ); + self_on_heap = info_on_self && !(c_p->flags & F_OFF_HEAP_MSGQ); tot_heap_size = 0; i = 0; @@ -3367,8 +3732,7 @@ erts_proc_sig_prep_msgq_for_inspection(Process *c_p, Process *rp, if (ERTS_SIG_IS_EXTERNAL_MSG(mp)) { /* decode it... */ if (mp->data.attached) - erts_decode_dist_message(rp, rp_locks, mp, - ERTS_INSPECT_MSGQ_KEEP_OH_MSGS); + erts_decode_dist_message(rp, rp_locks, mp, !0); msg = ERL_MESSAGE_TERM(mp); @@ -3394,44 +3758,11 @@ erts_proc_sig_prep_msgq_for_inspection(Process *c_p, Process *rp, ASSERT(is_value(msg)); -#if ERTS_INSPECT_MSGQ_KEEP_OH_MSGS if (is_not_immed(msg) && (!self_on_heap || mp->data.attached)) { Uint sz = size_object(msg); mip[i].size = sz; tot_heap_size += sz; } -#else - if (self_on_heap) { - if (mp->data.attached) { - ErtsMessage *tmp = NULL; - if (mp->data.attached != ERTS_MSG_COMBINED_HFRAG) { - erts_link_mbuf_to_proc(rp, mp->data.heap_frag); - mp->data.attached = NULL; - } - else { - /* - * Need to replace the message reference since - * we will get references to the message data - * from the heap... - */ - ErtsMessage **mpp; - tmp = erts_alloc_message(0, NULL); - sys_memcpy((void *) tmp->m, (void *) mp->m, - sizeof(Eterm)*ERL_MESSAGE_REF_ARRAY_SZ); - mpp = i == 0 ? &rp->sig_qs.first : &mip[i-1].msgp->next; - erts_msgq_replace_msg_ref(&rp->msg, tmp, mpp); - erts_save_message_in_proc(rp, mp); - mp = tmp; - } - } - } - else if (is_not_immed(msg)) { - Uint sz = size_object(msg); - mip[i].size = sz; - tot_heap_size += sz; - } - -#endif mip[i].msgp = mp; i++; @@ -3439,6 +3770,8 @@ erts_proc_sig_prep_msgq_for_inspection(Process *c_p, Process *rp, mp = mp->next; } + ASSERT(c_p->sig_qs.len == i); + return tot_heap_size; } @@ -3475,11 +3808,11 @@ move_msg_to_heap(Process *c_p, ErtsMessage *mp) void erts_proc_sig_move_msgs_to_heap(Process *c_p) { - ERTS_HDBG_CHECK_SIGNAL_PRIV_QUEUE(c_p); + ERTS_HDBG_CHECK_SIGNAL_PRIV_QUEUE(c_p, 0); ERTS_FOREACH_SIG_PRIVQS(c_p, sig, move_msg_to_heap(c_p, sig)); - ERTS_HDBG_CHECK_SIGNAL_PRIV_QUEUE(c_p); + ERTS_HDBG_CHECK_SIGNAL_PRIV_QUEUE(c_p, 0); } @@ -3670,6 +4003,7 @@ erts_proc_sig_debug_foreach_sig(Process *c_p, case ERTS_SIG_Q_OP_IS_ALIVE: case ERTS_SIG_Q_OP_TRACE_CHANGE_STATE: + case ERTS_SIG_Q_OP_PROCESS_INFO: break; default: @@ -3714,10 +4048,8 @@ chk_eterm(Process *c_p, int privq, ErtsMessage *mp, Eterm term) for (bp = erts_message_to_heap_frag(mp); bp; bp = bp->next) { if (bp->mem <= ptr && ptr < bp->mem + bp->used_size) return; - bp = bp->next; } - ERTS_ASSERT(privq); ASSERT(erts_dbg_within_proc(ptr, c_p, NULL)); } @@ -3740,6 +4072,12 @@ proc_sig_hdbg_check_queue(Process *proc, ErtsMessage **save = proc->sig_qs.save; ErtsMessage **saved_last = proc->sig_qs.saved_last; + if (!privq) { + ErtsSignal *sig = (ErtsSignal *) *sig_next; + if (sig->common.tag == ERTS_PROC_SIG_MSGQ_LEN_OFFS_MARK) { + + } + } nm_next = sig_nm_next; nm_last = sig_nm_last; @@ -3804,21 +4142,29 @@ proc_sig_hdbg_check_queue(Process *proc, if (!sig) break; - nm_sigs++; + nm_sig = (ErtsSignal *) sig; - ERTS_ASSERT(!last_nm_sig_found); - ERTS_ASSERT(ERTS_SIG_IS_NON_MSG(sig)); + if (nm_sig->common.tag == ERTS_PROC_SIG_MSGQ_LEN_OFFS_MARK) { + ERTS_ASSERT(!privq); + ERTS_ASSERT(sig == *sig_next); + } + else { + nm_sigs++; - nm_sig = (ErtsSignal *) sig; + ERTS_ASSERT(!last_nm_sig_found); + ERTS_ASSERT(ERTS_SIG_IS_NON_MSG(sig)); + + ERTS_ASSERT(nm_next == next); + + if (nm_last == next) { + ASSERT(!nm_sig->common.specific.next); + last_nm_sig_found = 1; + } - ERTS_ASSERT(nm_next == next); + nm_next = nm_sig->common.specific.next; - if (nm_last == next) { - ASSERT(!nm_sig->common.specific.next); - last_nm_sig_found = 1; } - nm_next = nm_sig->common.specific.next; next = &nm_sig->common.next; sig = nm_sig->common.next; @@ -3873,10 +4219,10 @@ proc_sig_hdbg_check_queue(Process *proc, } void -erts_proc_sig_hdbg_check_priv_queue(Process *p, char *what, char *file, int line) +erts_proc_sig_hdbg_check_priv_queue(Process *p, int qlock, char *what, char *file, int line) { int found_saved_last = 0; - Sint len1, len2; + Sint len, len1, len2; ERTS_LC_ASSERT(erts_thr_progress_is_blocking() || ERTS_PROC_IS_EXITING(p) || (ERTS_PROC_LOCK_MAIN @@ -3901,7 +4247,8 @@ erts_proc_sig_hdbg_check_priv_queue(Process *p, char *what, char *file, int line ERTS_PSFLG_SIG_Q); if (p->sig_qs.saved_last) ERTS_ASSERT(found_saved_last); - ERTS_ASSERT(p->sig_qs.len == len1 + len2); + len = proc_sig_privqs_len(p, qlock); + ERTS_ASSERT(len == len1 + len2); } void diff --git a/erts/emulator/beam/erl_proc_sig_queue.h b/erts/emulator/beam/erl_proc_sig_queue.h index 56fe3e683e..d250ad820f 100644 --- a/erts/emulator/beam/erl_proc_sig_queue.h +++ b/erts/emulator/beam/erl_proc_sig_queue.h @@ -32,6 +32,7 @@ * - Unlink * - Group leader * - Is process alive + * - Process info request * - Trace change * * The signal queue consists of three parts: @@ -78,6 +79,9 @@ #if 0 # define ERTS_PROC_SIG_HARD_DEBUG #endif +#if 0 +# define ERTS_PROC_SIG_HARD_DEBUG_SIGQ_MSG_LEN +#endif struct erl_mesg; @@ -95,22 +99,22 @@ typedef struct { #ifdef ERTS_PROC_SIG_HARD_DEBUG # define ERTS_HDBG_CHECK_SIGNAL_IN_QUEUE(P) \ ERTS_HDBG_CHECK_SIGNAL_IN_QUEUE__((P), "") -# define ERTS_HDBG_CHECK_SIGNAL_PRIV_QUEUE(P) \ - ERTS_HDBG_CHECK_SIGNAL_PRIV_QUEUE__((P), "") +# define ERTS_HDBG_CHECK_SIGNAL_PRIV_QUEUE(P, QL) \ + ERTS_HDBG_CHECK_SIGNAL_PRIV_QUEUE__((P), (QL), "") # define ERTS_HDBG_CHECK_SIGNAL_IN_QUEUE__(P, What) \ erts_proc_sig_hdbg_check_in_queue((P), (What), __FILE__, __LINE__) -# define ERTS_HDBG_CHECK_SIGNAL_PRIV_QUEUE__(P, What) \ - erts_proc_sig_hdbg_check_priv_queue((P), (What), __FILE__, __LINE__) +# define ERTS_HDBG_CHECK_SIGNAL_PRIV_QUEUE__(P, QL, What) \ + erts_proc_sig_hdbg_check_priv_queue((P), (QL), (What), __FILE__, __LINE__) struct process; -void erts_proc_sig_hdbg_check_priv_queue(struct process *c_p, char *what, - char *file, int line); +void erts_proc_sig_hdbg_check_priv_queue(struct process *c_p, int qlock, + char *what, char *file, int line); void erts_proc_sig_hdbg_check_in_queue(struct process *c_p, char *what, char *file, int line); #else # define ERTS_HDBG_CHECK_SIGNAL_IN_QUEUE(P) -# define ERTS_HDBG_CHECK_SIGNAL_PRIV_QUEUE(P) +# define ERTS_HDBG_CHECK_SIGNAL_PRIV_QUEUE(P, QL) # define ERTS_HDBG_CHECK_SIGNAL_IN_QUEUE__(P, What) -#define ERTS_HDBG_CHECK_SIGNAL_PRIV_QUEUE__(P, What) +#define ERTS_HDBG_CHECK_SIGNAL_PRIV_QUEUE__(P, QL, What) #endif #endif @@ -118,6 +122,57 @@ void erts_proc_sig_hdbg_check_in_queue(struct process *c_p, char *what, #if !defined(ERTS_PROC_SIG_QUEUE_H__) && !defined(ERTS_PROC_SIG_QUEUE_TYPE_ONLY) #define ERTS_PROC_SIG_QUEUE_H__ +#define ERTS_SIG_Q_OP_BITS 8 +#define ERTS_SIG_Q_OP_SHIFT 0 +#define ERTS_SIG_Q_OP_MASK ((1 << ERTS_SIG_Q_OP_BITS) - 1) + +#define ERTS_SIG_Q_TYPE_BITS 8 +#define ERTS_SIG_Q_TYPE_SHIFT ERTS_SIG_Q_OP_BITS +#define ERTS_SIG_Q_TYPE_MASK ((1 << ERTS_SIG_Q_TYPE_BITS) - 1) + +#define ERTS_SIG_Q_NON_X_BITS__ (_HEADER_ARITY_OFFS \ + + ERTS_SIG_Q_OP_BITS \ + + ERTS_SIG_Q_TYPE_BITS) + +#define ERTS_SIG_Q_XTRA_BITS (32 - ERTS_SIG_Q_NON_X_BITS__) +#define ERTS_SIG_Q_XTRA_SHIFT (ERTS_SIG_Q_OP_BITS \ + + ERTS_SIG_Q_TYPE_BITS) +#define ERTS_SIG_Q_XTRA_MASK ((1 << ERTS_SIG_Q_XTRA_BITS) - 1) + + +#define ERTS_PROC_SIG_OP(Tag) \ + ((int) (_unchecked_thing_arityval((Tag)) \ + >> ERTS_SIG_Q_OP_SHIFT) & ERTS_SIG_Q_OP_MASK) + +#define ERTS_PROC_SIG_TYPE(Tag) \ + ((Uint16) (_unchecked_thing_arityval((Tag)) \ + >> ERTS_SIG_Q_TYPE_SHIFT) & ERTS_SIG_Q_TYPE_MASK) + +#define ERTS_PROC_SIG_XTRA(Tag) \ + ((Uint32) (_unchecked_thing_arityval((Tag)) \ + >> ERTS_SIG_Q_XTRA_SHIFT) & ERTS_SIG_Q_XTRA_MASK) + +#define ERTS_PROC_SIG_MAKE_TAG(Op, Type, Xtra) \ + (ASSERT(0 <= (Xtra) && (Xtra) <= ERTS_SIG_Q_XTRA_MASK), \ + _make_header((((Type) & ERTS_SIG_Q_TYPE_MASK) \ + << ERTS_SIG_Q_TYPE_SHIFT) \ + | (((Op) & ERTS_SIG_Q_OP_MASK) \ + << ERTS_SIG_Q_OP_SHIFT) \ + | (((Xtra) & ERTS_SIG_Q_XTRA_MASK) \ + << ERTS_SIG_Q_XTRA_SHIFT), \ + _TAG_HEADER_EXTERNAL_PID)) + + +/* + * ERTS_SIG_Q_OP_MSGQ_LEN_OFFS_MARK is not an actual + * operation. We keep it at the top of the OP range, + * larger than ERTS_SIG_Q_OP_MAX. + */ +#define ERTS_SIG_Q_OP_MSGQ_LEN_OFFS_MARK ERTS_SIG_Q_OP_MASK + +#define ERTS_PROC_SIG_MSGQ_LEN_OFFS_MARK \ + ERTS_PROC_SIG_MAKE_TAG(ERTS_SIG_Q_OP_MSGQ_LEN_OFFS_MARK,0,0) + struct dist_entry_; /* @@ -451,6 +506,58 @@ void erts_proc_sig_send_is_alive_request(Process *c_p, Eterm to, Eterm ref); +/** + * + * @brief Send a 'process info request' signal to a process. + * + * A response message '{Ref, Result}' is sent to the + * sender when performed where Ref is the reference passed + * as 'ref' argument, and Result corresponds to return result + * from erlang:process_info/[1,2]. + * + * @param[in] c_p Pointer to process struct of + * currently executing process. + * NULL if signal arrived via + * distribution. + * + * @param[in] to Identifier of receiver. + * + * @param[in] item_ix Info index array to pass to + * erts_process_info() + * + * @param[in] len Lenght of info index array + * + * @param[in] need_msgq_len Non-zero if message queue + * length is needed; otherwise, + * zero. If non-zero, sig_qs.len + * will be set to correspond + * to the message queue length + * before call to + * erts_process_info() + * + * @param[in] flags Flags to pass to + * erts_process_info() + * + * @param[in] reserve_size Heap size that is known to + * be needed. May not be correct + * though. + * + * @param[in] ref Reference to use in response + * message to the sending + * process (i.e., c_p). + * + */ +int +erts_proc_sig_send_process_info_request(Process *c_p, + Eterm to, + int *item_ix, + int len, + int need_msgq_len, + int flags, + Uint reserve_size, + Eterm ref); + + /* * End of send operations of currently supported process signals. */ @@ -601,9 +708,30 @@ erts_proc_sig_receive_helper(Process *c_p, int fcalls, * * @param[in] c_p Pointer to process struct of * currently executing process. + * @returns Amount of message signals in + * inner plus middle signal + * queues after fetch completed + * (NOT the message queue + * length). + */ +ERTS_GLB_INLINE Sint erts_proc_sig_fetch(Process *p); + +/** + * + * @brief Get amount of messages in private queues + * + * @param[in] c_p Pointer to process struct of + * currently executing process. * + * @returns Amount of message signals in + * inner plus middle signal + * queues after fetch completed + * (NOT the message queue + * length). */ -void erts_proc_sig_fetch(Process *p); +Sint +erts_proc_sig_privqs_len(Process *c_p); + typedef struct { Uint size; @@ -623,17 +751,19 @@ typedef struct { * * @param[in] rp_locks Process locks held on 'rp'. * + * @param[in] info_on_self Integer set to non-zero value + * if caller is inspecting itself; + * otherwise, zero. + * * @param[in] mip Pointer to array of * ErtsMessageInfo structures. - * */ - Uint erts_proc_sig_prep_msgq_for_inspection(Process *c_p, Process *rp, ErtsProcLocks rp_locks, + int info_on_self, ErtsMessageInfo *mip); - /** * * @brief Move message data of messages in private queues to heap @@ -687,4 +817,56 @@ extern Process *erts_dirty_process_signal_handler; extern Process *erts_dirty_process_signal_handler_high; extern Process *erts_dirty_process_signal_handler_max; +void erts_proc_sig_fetch__(Process *proc); +Sint erts_proc_sig_fetch_msgq_len_offs__(Process *proc); + +#if ERTS_GLB_INLINE_INCL_FUNC_DEF + +ERTS_GLB_INLINE Sint +erts_proc_sig_fetch(Process *proc) +{ + Sint res = 0; + ErtsSignal *sig; + + ERTS_LC_ASSERT(erts_thr_progress_is_blocking() + || ERTS_PROC_IS_EXITING(proc) + || ((erts_proc_lc_my_proc_locks(proc) + & (ERTS_PROC_LOCK_MAIN + | ERTS_PROC_LOCK_MSGQ)) + == (ERTS_PROC_LOCK_MAIN + | ERTS_PROC_LOCK_MSGQ))); + + ERTS_HDBG_CHECK_SIGNAL_IN_QUEUE(proc); + ERTS_HDBG_CHECK_SIGNAL_PRIV_QUEUE(proc, !0); + + sig = (ErtsSignal *) proc->sig_inq.first; + if (sig) { + if (ERTS_LIKELY(sig->common.tag != ERTS_PROC_SIG_MSGQ_LEN_OFFS_MARK)) + erts_proc_sig_fetch__(proc); + else + res = erts_proc_sig_fetch_msgq_len_offs__(proc); + } + + res += proc->sig_qs.len; + + ERTS_HDBG_CHECK_SIGNAL_PRIV_QUEUE(proc, !0); + +#ifdef ERTS_PROC_SIG_HARD_DEBUG_SIGQ_MSG_LEN + { + Sint len = 0; + ERTS_FOREACH_SIG_PRIVQS( + proc, mp, + { + if (ERTS_SIG_IS_MSG(mp)) + len++; + }); + ERTS_ASSERT(res == len); + } +#endif + + return res; +} + +#endif /* ERTS_GLB_INLINE_INCL_FUNC_DEF */ + #endif /* ERTS_PROC_SIG_QUEUE_H__ */ diff --git a/erts/emulator/beam/erl_process.c b/erts/emulator/beam/erl_process.c index be1306cd79..71541786d0 100644 --- a/erts/emulator/beam/erl_process.c +++ b/erts/emulator/beam/erl_process.c @@ -10785,7 +10785,6 @@ exit_permanent_prio_elevation(Process *c_p, erts_aint32_t state) while (1) { erts_aint32_t aprio, uprio, n, e; ASSERT(a & ERTS_PSFLG_EXITING); - ASSERT(!(a & ERTS_PSFLG_FREE)); aprio = ERTS_PSFLGS_GET_ACT_PRIO(a); uprio = ERTS_PSFLGS_GET_USR_PRIO(a); if (aprio >= uprio) @@ -10831,8 +10830,7 @@ erts_execute_dirty_system_task(Process *c_p) if (c_p->flags & F_DIRTY_GC_HIBERNATE) { erts_proc_lock(c_p, ERTS_PROC_LOCK_MSGQ|ERTS_PROC_LOCK_STATUS); - erts_proc_sig_fetch(c_p); - if (c_p->sig_qs.len) + if (erts_proc_sig_fetch(c_p)) c_p->flags &= ~F_DIRTY_GC_HIBERNATE; /* operation aborted... */ else { erts_proc_unlock(c_p, ERTS_PROC_LOCK_MSGQ|ERTS_PROC_LOCK_STATUS); @@ -12412,12 +12410,14 @@ erts_proc_exit_handle_monitor(ErtsMonitor *mon, void *vctxt) case ERTS_MON_TYPE_PORT: { Port *prt; ASSERT(is_internal_port(mon->other.item)); + erts_proc_unlock(c_p, ERTS_PROC_LOCK_MAIN); prt = erts_id2port(mon->other.item); if (prt) { erts_fire_port_monitor(prt, mon); erts_port_release(prt); mon = NULL; } + erts_proc_lock(c_p, ERTS_PROC_LOCK_MAIN); break; } case ERTS_MON_TYPE_RESOURCE: @@ -12496,10 +12496,8 @@ erts_proc_exit_handle_monitor(ErtsMonitor *mon, void *vctxt) ASSERT(is_internal_port(mon->other.item)); prt = erts_port_lookup_raw(mon->other.item); if (prt) { - erts_proc_lock(c_p, ERTS_PROC_LOCK_MAIN); if (erts_port_demonitor(c_p, prt, mon) != ERTS_PORT_OP_DROPPED) mon = NULL; - erts_proc_unlock(c_p, ERTS_PROC_LOCK_MAIN); } break; } @@ -12602,7 +12600,6 @@ erts_proc_exit_handle_link(ErtsLink *lnk, void *vctxt) if (!erts_link_dist_delete(dlnk)) ldp = NULL; - erts_proc_lock(c_p, ERTS_PROC_LOCK_MAIN); code = erts_dsig_prepare(&dsd, dep, c_p, 0, ERTS_DSP_NO_LOCK, 0, 0); switch (code) { case ERTS_DSIG_PREP_CONNECTED: @@ -12616,7 +12613,6 @@ erts_proc_exit_handle_link(ErtsLink *lnk, void *vctxt) ASSERT(code == ERTS_DSIG_SEND_OK); } } - erts_proc_unlock(c_p, ERTS_PROC_LOCK_MAIN); break; } default: @@ -12678,8 +12674,6 @@ erts_do_exit_process(Process* p, Eterm reason) cancel_suspend_of_suspendee(p, ERTS_PROC_LOCKS_ALL); - erts_proc_sig_fetch(p); - if (IS_TRACED(p)) { if (IS_TRACED_FL(p, F_TRACE_CALLS)) erts_schedule_time_break(p, ERTS_BP_CALL_TIME_SCHEDULE_EXITING); @@ -12946,6 +12940,12 @@ erts_continue_exit_process(Process *p) pectxt.c_p = p; pectxt.reason = reason; + erts_proc_lock(p, ERTS_PROC_LOCK_MAIN|ERTS_PROC_LOCK_MSGQ); + + erts_proc_sig_fetch(p); + + erts_proc_unlock(p, ERTS_PROC_LOCK_MSGQ); + if (links) { erts_link_tree_foreach_delete(&links, erts_proc_exit_handle_link, @@ -12967,7 +12967,6 @@ erts_continue_exit_process(Process *p) ASSERT(!lt_monitors); } - erts_proc_sig_fetch(p); /* * erts_proc_sig_handle_exit() implements yielding. * However, this function cannot handle it yet... loop @@ -12979,7 +12978,6 @@ erts_continue_exit_process(Process *p) break; } - erts_proc_lock(p, ERTS_PROC_LOCK_MAIN); ERTS_CHK_HAVE_ONLY_MAIN_PROC_LOCK(p); erts_flush_trace_messages(p, ERTS_PROC_LOCK_MAIN); @@ -13016,27 +13014,41 @@ erts_continue_exit_process(Process *p) } Process * -erts_try_lock_sig_free_proc(Eterm pid, ErtsProcLocks locks) +erts_try_lock_sig_free_proc(Eterm pid, ErtsProcLocks locks, + erts_aint32_t *statep) { Process *rp = erts_proc_lookup_raw(pid); erts_aint32_t state; - if (!rp) + if (!rp) { + if (statep) + *statep = ERTS_PSFLG_EXITING|ERTS_PSFLG_FREE; return NULL; + } ERTS_LC_ASSERT(!erts_proc_lc_my_proc_locks(rp)); state = erts_atomic32_read_nob(&rp->state); - if (state & ERTS_PSFLG_EXITING) + if (statep) + *statep = state; + + if (state & ERTS_PSFLG_FREE) return NULL; if (state & (ERTS_PSFLG_SIG_IN_Q|ERTS_PSFLG_SIG_Q)) return ERTS_PROC_LOCK_BUSY; + + if (!locks) + return rp; + if (erts_proc_trylock(rp, locks) == EBUSY) return ERTS_PROC_LOCK_BUSY; state = erts_atomic32_read_nob(&rp->state); - if (state & ERTS_PSFLG_EXITING) { + if (statep) + *statep = state; + + if (state & ERTS_PSFLG_FREE) { erts_proc_unlock(rp, locks); return NULL; } diff --git a/erts/emulator/beam/erl_process.h b/erts/emulator/beam/erl_process.h index f7c6c3435b..e232776016 100644 --- a/erts/emulator/beam/erl_process.h +++ b/erts/emulator/beam/erl_process.h @@ -1391,6 +1391,7 @@ extern int erts_system_profile_ts_type; #define F_LOCAL_SIGS_ONLY (1 << 26) #define F_TRAP_EXIT (1 << 27) /* Trapping exit */ #define F_DEFERRED_SAVED_LAST (1 << 28) +#define F_DELAYED_PSIGQS_LEN (1 << 29) /* * F_DISABLE_GC and F_DELAY_GC are similar. Both will prevent @@ -1817,6 +1818,10 @@ void erts_print_scheduler_info(fmtfn_t to, void *to_arg, ErtsSchedulerData *esdp void erts_print_run_queue_info(fmtfn_t, void *to_arg, ErtsRunQueue*); void erts_dump_extended_process_state(fmtfn_t to, void *to_arg, erts_aint32_t psflg); void erts_dump_process_state(fmtfn_t to, void *to_arg, erts_aint32_t psflg); +Eterm erts_process_info(Process *c_p, ErtsHeapFactory *hfact, + Process *rp, ErtsProcLocks rp_locks, + int *item_ix, int item_ix_len, + int flags, Uint reserve_size, Uint *reds); typedef struct { Process *c_p; @@ -1855,7 +1860,7 @@ Uint erts_debug_nbalance(void); int erts_debug_wait_completed(Process *c_p, int flags); -Uint erts_process_memory(Process *c_p, int incl_msg_inq); +Uint erts_process_memory(Process *c_p, int include_sigs_in_transit); #ifdef ERTS_DO_VERIFY_UNUSED_TEMP_ALLOC # define ERTS_VERIFY_UNUSED_TEMP_ALLOC(P) \ @@ -2595,7 +2600,8 @@ ERTS_TIME2REDS_IMPL__(ErtsMonotonicTime start, ErtsMonotonicTime end) #endif Process *erts_try_lock_sig_free_proc(Eterm pid, - ErtsProcLocks locks); + ErtsProcLocks locks, + erts_aint32_t *statep); Process *erts_pid2proc_not_running(Process *, ErtsProcLocks, diff --git a/erts/emulator/beam/erl_process_dict.c b/erts/emulator/beam/erl_process_dict.c index aee88841ae..38be3938cd 100644 --- a/erts/emulator/beam/erl_process_dict.c +++ b/erts/emulator/beam/erl_process_dict.c @@ -239,39 +239,70 @@ erts_erase_dicts(Process *p) /* * Called from process_info/1,2. */ -Eterm erts_dictionary_copy(Process *p, ProcDict *pd) +Eterm erts_dictionary_copy(ErtsHeapFactory *hfact, ProcDict *pd, Uint reserve_size) { - Eterm* hp; - Eterm* heap_start; - Eterm res = NIL; - Eterm tmp, tmp2; + Eterm res; unsigned int i, num; + Uint *sz; + Uint szi, rsz = reserve_size; - if (pd == NULL) { - return res; - } + if (pd == NULL) + return NIL; PD_CHECK(pd); num = HASH_RANGE(pd); - heap_start = hp = (Eterm *) erts_alloc(ERTS_ALC_T_TMP, - sizeof(Eterm) * pd->numElements * 2); - for (i = 0; i < num; ++i) { - tmp = ARRAY_GET(pd, i); + sz = (Uint *) erts_alloc(ERTS_ALC_T_TMP, sizeof(Uint) * pd->numElements); + + for (i = 0, szi = 0; i < num; ++i) { + Eterm tmp = ARRAY_GET(pd, i); if (is_boxed(tmp)) { + Uint size; ASSERT(is_tuple(tmp)); - res = CONS(hp, tmp, res); - hp += 2; - } else if (is_list(tmp)) { + size = size_object(tmp) + 2; + sz[szi++] = size; + rsz += size; + } + else if (is_list(tmp)) { while (tmp != NIL) { - tmp2 = TCAR(tmp); - res = CONS(hp, tmp2, res); - hp += 2; + Uint size = size_object(TCAR(tmp)) + 2; + sz[szi++] = size; + rsz += size; + tmp = TCDR(tmp); + } + } + } + + res = NIL; + + for (i = 0, szi = 0; i < num; ++i) { + Eterm tmp = ARRAY_GET(pd, i); + if (is_boxed(tmp)) { + Uint size; + Eterm el, *hp; + ASSERT(is_tuple(tmp)); + size = sz[szi++]; + rsz -= size; + hp = erts_produce_heap(hfact, size, rsz); + el = copy_struct(tmp, size-2, &hp, hfact->off_heap); + res = CONS(hp, el, res); + } + else if (is_list(tmp)) { + while (tmp != NIL) { + Uint size = sz[szi++]; + Eterm el, *hp; + rsz -= size; + hp = erts_produce_heap(hfact, size, rsz); + el = copy_struct(TCAR(tmp), size-2, &hp, hfact->off_heap); + res = CONS(hp, el, res); tmp = TCDR(tmp); } } } - res = copy_object(res, p); - erts_free(ERTS_ALC_T_TMP, (void *) heap_start); + + ASSERT(rsz == reserve_size); + + erts_free(ERTS_ALC_T_TMP, sz); + return res; } diff --git a/erts/emulator/beam/erl_process_dict.h b/erts/emulator/beam/erl_process_dict.h index ab58f3c239..b89b387f5a 100644 --- a/erts/emulator/beam/erl_process_dict.h +++ b/erts/emulator/beam/erl_process_dict.h @@ -40,7 +40,7 @@ void erts_erase_dicts(struct process *p); void erts_dictionary_dump(fmtfn_t to, void *to_arg, ProcDict *pd); void erts_deep_dictionary_dump(fmtfn_t to, void *to_arg, ProcDict* pd, void (*cb)(fmtfn_t, void *, Eterm obj)); -Eterm erts_dictionary_copy(struct process *p, ProcDict *pd); +Eterm erts_dictionary_copy(ErtsHeapFactory *hfact, ProcDict *pd, Uint reserve_size); Eterm erts_pd_hash_get(struct process *p, Eterm id); Uint32 erts_pd_make_hx(Eterm key); diff --git a/erts/emulator/beam/erl_process_dump.c b/erts/emulator/beam/erl_process_dump.c index 5db276ec7f..243db4c734 100644 --- a/erts/emulator/beam/erl_process_dump.c +++ b/erts/emulator/beam/erl_process_dump.c @@ -109,56 +109,77 @@ link_size(ErtsMonitor *lnk, void *vsize) *((Uint *) vsize) += erts_link_size(lnk); } -Uint erts_process_memory(Process *p, int incl_msg_inq) { - Uint size = 0; - struct saved_calls *scb; - size += sizeof(Process); - - if (incl_msg_inq) { - erts_proc_lock(p, ERTS_PROC_LOCK_MSGQ); - erts_proc_sig_fetch(p); - erts_proc_unlock(p, ERTS_PROC_LOCK_MSGQ); - } - - erts_link_tree_foreach(ERTS_P_LINKS(p), - link_size, (void *) &size); - erts_monitor_tree_foreach(ERTS_P_MONITORS(p), - monitor_size, (void *) &size); - erts_monitor_list_foreach(ERTS_P_LT_MONITORS(p), - monitor_size, (void *) &size); - size += (p->heap_sz + p->mbuf_sz) * sizeof(Eterm); - if (p->abandoned_heap) - size += (p->hend - p->heap) * sizeof(Eterm); - if (p->old_hend && p->old_heap) - size += (p->old_hend - p->old_heap) * sizeof(Eterm); - - - size += p->sig_qs.len * sizeof(ErtsMessage); - - ERTS_FOREACH_SIG_PRIVQS( - p, mp, - { - if (ERTS_SIG_IS_NON_MSG((ErtsSignal *) mp)) - size += erts_proc_sig_signal_size((ErtsSignal *) mp); - else if (mp->data.attached) - size += erts_msg_attached_data_size(mp) * sizeof(Eterm); - }); - - if (p->arg_reg != p->def_arg_reg) { - size += p->arity * sizeof(p->arg_reg[0]); - } - - if (erts_atomic_read_nob(&p->psd) != (erts_aint_t) NULL) - size += sizeof(ErtsPSD); - - scb = ERTS_PROC_GET_SAVED_CALLS_BUF(p); - if (scb) { - size += (sizeof(struct saved_calls) - + (scb->len-1) * sizeof(scb->ct[0])); - } - - size += erts_dicts_mem_size(p); - return size; +Uint erts_process_memory(Process *p, int include_sigs_in_transit) +{ + Uint size = 0; + struct saved_calls *scb; + + size += sizeof(Process); + + erts_link_tree_foreach(ERTS_P_LINKS(p), + link_size, (void *) &size); + erts_monitor_tree_foreach(ERTS_P_MONITORS(p), + monitor_size, (void *) &size); + erts_monitor_list_foreach(ERTS_P_LT_MONITORS(p), + monitor_size, (void *) &size); + size += (p->heap_sz + p->mbuf_sz) * sizeof(Eterm); + if (p->abandoned_heap) + size += (p->hend - p->heap) * sizeof(Eterm); + if (p->old_hend && p->old_heap) + size += (p->old_hend - p->old_heap) * sizeof(Eterm); + + if (!include_sigs_in_transit) { + /* + * Size of message queue! + * + * Note that this assumes that any part of message + * queue located in middle queue have been moved + * into the inner queue prior to this call. + * process_info() management ensures this is done- + */ + ErtsMessage *mp; + for (mp = p->sig_qs.first; mp; mp = mp->next) { + ASSERT(ERTS_SIG_IS_MSG((ErtsSignal *) mp)); + size += sizeof(ErtsMessage); + if (mp->data.attached) + size += erts_msg_attached_data_size(mp) * sizeof(Eterm); + } + } + else { + /* + * Size of message queue plus size of all signals + * in transit to the process! + */ + erts_proc_lock(p, ERTS_PROC_LOCK_MSGQ); + erts_proc_sig_fetch(p); + erts_proc_unlock(p, ERTS_PROC_LOCK_MSGQ); + + ERTS_FOREACH_SIG_PRIVQS( + p, mp, + { + size += sizeof(ErtsMessage); + if (ERTS_SIG_IS_NON_MSG((ErtsSignal *) mp)) + size += erts_proc_sig_signal_size((ErtsSignal *) mp); + else if (mp->data.attached) + size += erts_msg_attached_data_size(mp) * sizeof(Eterm); + }); + } + + if (p->arg_reg != p->def_arg_reg) { + size += p->arity * sizeof(p->arg_reg[0]); + } + + if (erts_atomic_read_nob(&p->psd) != (erts_aint_t) NULL) + size += sizeof(ErtsPSD); + + scb = ERTS_PROC_GET_SAVED_CALLS_BUF(p); + if (scb) { + size += (sizeof(struct saved_calls) + + (scb->len-1) * sizeof(scb->ct[0])); + } + + size += erts_dicts_mem_size(p); + return size; } static ERTS_INLINE void diff --git a/erts/emulator/beam/erl_time_sup.c b/erts/emulator/beam/erl_time_sup.c index e5bb3cc15f..4f91d9ad07 100644 --- a/erts/emulator/beam/erl_time_sup.c +++ b/erts/emulator/beam/erl_time_sup.c @@ -2204,6 +2204,8 @@ time_unit_conversion(Process *c_p, Eterm term, ErtsMonotonicTime val, ErtsMonoto ERTS_BIF_PREP_RET(ret, make_time_val(c_p, result)); break; #endif + case am_perf_counter: + goto trap_to_erlang_code; default: { Eterm value, native_res; #ifndef ARCH_64 diff --git a/erts/emulator/beam/global.h b/erts/emulator/beam/global.h index 7724231cd5..256670ff22 100644 --- a/erts/emulator/beam/global.h +++ b/erts/emulator/beam/global.h @@ -860,6 +860,8 @@ void erts_emasculate_writable_binary(ProcBin* pb); Eterm erts_new_heap_binary(Process *p, byte *buf, int len, byte** datap); Eterm erts_new_mso_binary(Process*, byte*, Uint); Eterm new_binary(Process*, byte*, Uint); +Eterm erts_heap_factory_new_binary(ErtsHeapFactory *hfact, byte *buf, + Uint len, Uint reserve_size); Eterm erts_realloc_binary(Eterm bin, size_t size); Eterm erts_build_proc_bin(ErlOffHeap*, Eterm*, Binary*); diff --git a/erts/emulator/beam/msg_instrs.tab b/erts/emulator/beam/msg_instrs.tab index 289436da6f..26bea0efc6 100644 --- a/erts/emulator/beam/msg_instrs.tab +++ b/erts/emulator/beam/msg_instrs.tab @@ -225,6 +225,7 @@ remove_message() { Sint tok_label = 0; Sint tok_lastcnt = 0; Sint tok_serial = 0; + Sint len = erts_proc_sig_privqs_len(c_p); dtrace_proc_str(c_p, receiver_name); token2 = SEQ_TRACE_TOKEN(c_p); @@ -235,7 +236,8 @@ remove_message() { } DTRACE6(message_receive, receiver_name, size_object(ERL_MESSAGE_TERM(msgp)), - c_p->sig_qs.len - 1, tok_label, tok_lastcnt, tok_serial); + len, /* This is NOT message queue len, but its something... */ + tok_label, tok_lastcnt, tok_serial); } #endif UNLINK_MESSAGE(c_p, msgp); diff --git a/erts/emulator/beam/utils.c b/erts/emulator/beam/utils.c index 4bf60619ba..188e02eff8 100644 --- a/erts/emulator/beam/utils.c +++ b/erts/emulator/beam/utils.c @@ -59,6 +59,7 @@ #endif #define ERTS_WANT_NFUNC_SCHED_INTERNALS__ #include "erl_nfunc_sched.h" +#include "erl_proc_sig_queue.h" #undef M_TRIM_THRESHOLD #undef M_TOP_PAD diff --git a/erts/emulator/sys/common/erl_poll.c b/erts/emulator/sys/common/erl_poll.c index 7aa53e8f36..ced8a4a2a7 100644 --- a/erts/emulator/sys/common/erl_poll.c +++ b/erts/emulator/sys/common/erl_poll.c @@ -782,10 +782,14 @@ update_pollset(ErtsPollSet *ps, int fd, ErtsPollOp op, ErtsPollEvents events) struct kevent evts[2]; struct timespec ts = {0, 0}; -#ifdef EV_DISPATCH - /* If we have EV_DISPATCH we use it. The kevent descriptions for both - read and write are added on OP_ADD and removed on OP_DEL. And then - after than only EV_ENABLE|EV_DISPATCH are used. +#if defined(EV_DISPATCH) && !defined(__OpenBSD__) + /* If we have EV_DISPATCH we use it, unless we are on OpenBSD as the + behavior of EV_EOF seems to be edge triggered there and we need it + to be level triggered. + + The kevent descriptions for both read and write are added on OP_ADD + and removed on OP_DEL. And then after than only EV_ENABLE|EV_DISPATCH + are used. It could be possible to not modify the pollset when disabling and/or deleting events, but that may cause the poll threads to be awoken diff --git a/erts/emulator/sys/common/erl_sys_common_misc.c b/erts/emulator/sys/common/erl_sys_common_misc.c index 96bdbacb9e..826307c077 100644 --- a/erts/emulator/sys/common/erl_sys_common_misc.c +++ b/erts/emulator/sys/common/erl_sys_common_misc.c @@ -142,7 +142,16 @@ sys_double_to_chars(double fp, char *buffer, size_t buffer_size) return sys_double_to_chars_ext(fp, buffer, buffer_size, SYS_DEFAULT_FLOAT_DECIMALS); } -/* Convert float to string using fixed point notation. + +#if SIZEOF_LONG == 8 +# define round_int64 lround +#elif SIZEOF_LONG_LONG == 8 +# define round_int64 llround +#else +# error "No 64-bit integer type?" +#endif + +/* Convert float to string * decimals must be >= 0 * if compact != 0, the trailing 0's will be truncated */ @@ -154,80 +163,35 @@ sys_double_to_chars_fast(double f, char *buffer, int buffer_size, int decimals, #define FRAC_SIZE 52 #define EXP_SIZE 11 #define EXP_MASK (((Uint64)1 << EXP_SIZE) - 1) - #define MAX_DECIMALS (sizeof(cs_sys_double_pow10) \ - / sizeof(cs_sys_double_pow10[0])) + #define MAX_DECIMALS (sizeof(pow10v) / sizeof(pow10v[0])) #define FRAC_MASK (((Uint64)1 << FRAC_SIZE) - 1) #define FRAC_MASK2 (((Uint64)1 << (FRAC_SIZE + 1)) - 1) #define MAX_FLOAT ((Uint64)1 << (FRAC_SIZE+1)) - static const double cs_sys_double_pow10[] = { - SYS_DOUBLE_RND_CONST / 1e0, - SYS_DOUBLE_RND_CONST / 1e1, - SYS_DOUBLE_RND_CONST / 1e2, - SYS_DOUBLE_RND_CONST / 1e3, - SYS_DOUBLE_RND_CONST / 1e4, - SYS_DOUBLE_RND_CONST / 1e5, - SYS_DOUBLE_RND_CONST / 1e6, - SYS_DOUBLE_RND_CONST / 1e7, - SYS_DOUBLE_RND_CONST / 1e8, - SYS_DOUBLE_RND_CONST / 1e9, - SYS_DOUBLE_RND_CONST / 1e10, - SYS_DOUBLE_RND_CONST / 1e11, - SYS_DOUBLE_RND_CONST / 1e12, - SYS_DOUBLE_RND_CONST / 1e13, - SYS_DOUBLE_RND_CONST / 1e14, - SYS_DOUBLE_RND_CONST / 1e15, - SYS_DOUBLE_RND_CONST / 1e16, - SYS_DOUBLE_RND_CONST / 1e17, - SYS_DOUBLE_RND_CONST / 1e18 + static const double pow10v[] = { + 1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9, + 1e10, 1e11, 1e12, 1e13, 1e14, 1e15, 1e16, 1e17, 1e18 }; - Uint64 mantissa, int_part, frac_part; - int exp; - int fbits; - int max; + double af; + Uint64 int_part, frac_part; int neg; - double fr; - union { Uint64 L; double F; } x; char *p = buffer; if (decimals < 0) return -1; - if (f >= 0) { - neg = 0; - fr = decimals < MAX_DECIMALS ? (f + cs_sys_double_pow10[decimals]) : f; - x.F = fr; - } else { + if (f < 0) { neg = 1; - fr = decimals < MAX_DECIMALS ? (f - cs_sys_double_pow10[decimals]) : f; - x.F = -fr; + af = -f; } - - exp = (x.L >> FRAC_SIZE) & EXP_MASK; - mantissa = x.L & FRAC_MASK; - - if (exp == EXP_MASK) { - if (mantissa == 0) { - if (neg) - *p++ = '-'; - *p++ = 'i'; - *p++ = 'n'; - *p++ = 'f'; - } else { - *p++ = 'n'; - *p++ = 'a'; - *p++ = 'n'; - } - *p = '\0'; - return p - buffer; + else { + neg = 0; + af = f; } - exp -= EXP_MASK >> 1; - mantissa |= ((Uint64)1 << FRAC_SIZE); - /* Don't bother with optimizing too large numbers or too large precision */ - if (x.F > MAX_FLOAT || decimals >= MAX_DECIMALS) { + if (af > MAX_FLOAT || decimals >= MAX_DECIMALS) { int len = erts_snprintf(buffer, buffer_size, "%.*f", decimals, f); char* p = buffer + len; if (len >= buffer_size) @@ -237,77 +201,61 @@ sys_double_to_chars_fast(double f, char *buffer, int buffer_size, int decimals, p = find_first_trailing_zero(p); *p = '\0'; return p - buffer; - } else if (exp >= FRAC_SIZE) { - int_part = mantissa << (exp - FRAC_SIZE); - frac_part = 0; - fbits = FRAC_SIZE; /* not important as frac_part==0 */ - } else if (exp >= 0) { - fbits = FRAC_SIZE - exp; - int_part = mantissa >> fbits; - frac_part = mantissa & (((Uint64)1 << fbits) -1); - } else /* if (exp < 0) */ { - int_part = 0; - frac_part = mantissa; - fbits = FRAC_SIZE - exp; - } - - if (!int_part) { - if (neg) - *p++ = '-'; - *p++ = '0'; - } else { - int ret, i, n; - while (int_part != 0) { - *p++ = (char)((int_part % 10) + '0'); - int_part /= 10; - } - if (neg) - *p++ = '-'; - /* Reverse string */ - ret = p - buffer; - for (i = 0, n = ret/2; i < n; i++) { - int j = ret - i - 1; - char c = buffer[i]; - buffer[i] = buffer[j]; - buffer[j] = c; - } } - if (decimals > 0) { - int i; - *p++ = '.'; + if (decimals) { + double int_f = floor(af); + double frac_f = round((af - int_f) * pow10v[decimals]); - max = buffer_size - (p - buffer) - 1 /* leave room for trailing '\0' */; + int_part = (Uint64)int_f; + frac_part = (Uint64)frac_f; - if (decimals > max) - return -1; /* the number is not large enough to fit in the buffer */ - - max = decimals; + if (frac_f >= pow10v[decimals]) { + /* rounding overflow carry into int_part */ + int_part++; + frac_part = 0; + } - for (i = 0; i < max; i++) { - if (frac_part > (ERTS_UINT64_MAX/5)) { - frac_part >>= 3; - fbits -= 3; + do { + if (!frac_part) { + do { + *p++ = '0'; + } while (--decimals); + break; } + *p++ = (char)((frac_part % 10) + '0'); + frac_part /= 10; + } while (--decimals); - /* Multiply by 10 (5*2) to extract decimal digit as integer part */ - frac_part *= 5; - fbits--; + *p++ = '.'; + } + else + int_part = (Uint64)round_int64(af); - if (fbits >= 64) { - *p++ = '0'; - } - else { - *p++ = (char)((frac_part >> fbits) + '0'); - frac_part &= ((Uint64)1 << fbits) - 1; - } + if (!int_part) { + *p++ = '0'; + } else { + do { + *p++ = (char)((int_part % 10) + '0'); + int_part /= 10; + }while (int_part); + } + if (neg) + *p++ = '-'; + + {/* Reverse string */ + int i = 0; + int j = p - buffer - 1; + for ( ; i < j; i++, j--) { + char tmp = buffer[i]; + buffer[i] = buffer[j]; + buffer[j] = tmp; } - - /* Delete trailing zeroes */ - if (compact) - p = find_first_trailing_zero(p); } + /* Delete trailing zeroes */ + if (compact) + p = find_first_trailing_zero(p); *p = '\0'; return p - buffer; } diff --git a/erts/emulator/test/bif_SUITE.erl b/erts/emulator/test/bif_SUITE.erl index 22706ae8b1..32bfcd5520 100644 --- a/erts/emulator/test/bif_SUITE.erl +++ b/erts/emulator/test/bif_SUITE.erl @@ -35,7 +35,8 @@ is_builtin/1, error_stacktrace/1, error_stacktrace_during_call_trace/1, group_leader_prio/1, group_leader_prio_dirty/1, - is_process_alive/1]). + is_process_alive/1, + process_info_blast/1]). suite() -> [{ct_hooks,[ts_install_cth]}, @@ -50,7 +51,7 @@ all() -> erl_crash_dump_bytes, min_max, erlang_halt, is_builtin, error_stacktrace, error_stacktrace_during_call_trace, group_leader_prio, group_leader_prio_dirty, - is_process_alive]. + is_process_alive, process_info_blast]. %% Uses erlang:display to test that erts_printf does not do deep recursion display(Config) when is_list(Config) -> @@ -1099,6 +1100,76 @@ is_process_alive(Config) when is_list(Config) -> Ps), ok. +process_info_blast(Config) when is_list(Config) -> + Tester = self(), + NoAttackers = 1000, + NoAL = lists:seq(1, NoAttackers), + Consume = make_ref(), + Victim = spawn_link(fun () -> + receive + Consume -> + ok + end, + consume_msgs() + end), + AFun = fun () -> + Victim ! hej, + Res = process_info(Victim, message_queue_len), + Tester ! {self(), Res} + end, + Attackers0 = lists:map(fun (_) -> + spawn_link(AFun) + end, + NoAL), + lists:foreach(fun (A) -> + receive + {A, Res} -> + case Res of + {message_queue_len, Len} when Len > 0, Len =< NoAttackers -> + Len; + Error -> + exit({unexpected, Error}) + end + end + end, + Attackers0), + Attackers1 = lists:map(fun (_) -> + spawn_link(AFun) + end, + NoAL), + Victim ! Consume, + lists:foreach(fun (A) -> + receive + {A, Res} -> + case Res of + {message_queue_len, Len} when Len >= 0, Len =< 2*NoAttackers+1 -> + ok; + undefined -> + ok; + Error -> + exit({unexpected, Error}) + end + end + end, + Attackers1), + KillFun = fun (P) -> + unlink(P), + exit(P, kill), + false = erlang:is_process_alive(P) + end, + lists:foreach(fun (A) -> KillFun(A) end, Attackers0), + lists:foreach(fun (A) -> KillFun(A) end, Attackers1), + KillFun(Victim), + ok. + +consume_msgs() -> + receive + _ -> + consume_msgs() + after 0 -> + ok + end. + %% helpers id(I) -> I. diff --git a/erts/emulator/test/num_bif_SUITE.erl b/erts/emulator/test/num_bif_SUITE.erl index 592542405f..290bb61fc8 100644 --- a/erts/emulator/test/num_bif_SUITE.erl +++ b/erts/emulator/test/num_bif_SUITE.erl @@ -213,6 +213,20 @@ fts_rand_float_decimals(N) -> [begin F0 = rand_float_reasonable(), L0 = float_to_list(F0, [{decimals, D}]), + case conform_with_io_lib_format_os(F0,D) of + false -> ok; + true -> + IOL = lists:flatten(io_lib:format("~.*f", [D, F0])), + true = case L0 =:= IOL of + true -> true; + false -> + io:format("F0 = ~w ~w\n", [F0, <<F0/float>>]), + io:format("decimals = ~w\n", [D]), + io:format("float_to_list = ~s\n", [L0]), + io:format("io_lib:format = ~s\n", [IOL]), + false + end + end, L1 = case D of 0 -> L0 ++ ".0"; _ -> L0 @@ -234,6 +248,26 @@ fts_rand_float_decimals(N) -> fts_rand_float_decimals(N-1). +conform_with_io_lib_format_os(F, D) -> + case os:type() of + {win32,_} -> + %% io_lib:format("~.*f") buggy on windows? OTP-15010 + false; + _ -> + conform_with_io_lib_format(F, D) + end. + +conform_with_io_lib_format(_, 0) -> + %% io_lib:format("~.*f") does not support zero decimals + false; +conform_with_io_lib_format(_, D) when D > 10 -> + %% Seems float_to_list gets it slightly wrong sometimes for many decimals + false; +conform_with_io_lib_format(F, D) -> + %% io_lib:format prints '0' for input bits beyond mantissa precision + %% float_to_list treats those unknown input bits as if they were zeros. + math:log2(abs(F) * math:pow(10,D)) < 54. + max_diff_decimals(F, D) -> IntBits = floor(math:log2(abs(F))) + 1, FracBits = (52 - IntBits), diff --git a/erts/emulator/test/process_SUITE.erl b/erts/emulator/test/process_SUITE.erl index 7eff786e8b..46ece531a8 100644 --- a/erts/emulator/test/process_SUITE.erl +++ b/erts/emulator/test/process_SUITE.erl @@ -42,6 +42,8 @@ process_info_lock_reschedule2/1, process_info_lock_reschedule3/1, process_info_garbage_collection/1, + process_info_smoke_all/1, + process_info_status_handled_signal/1, bump_reductions/1, low_prio/1, binary_owner/1, yield/1, yield2/1, otp_4725/1, bad_register/1, garbage_collect/1, otp_6237/1, process_info_messages/1, process_flag_badarg/1, process_flag_heap_size/1, @@ -79,6 +81,8 @@ all() -> process_info_lock_reschedule2, process_info_lock_reschedule3, process_info_garbage_collection, + process_info_smoke_all, + process_info_status_handled_signal, bump_reductions, low_prio, yield, yield2, otp_4725, bad_register, garbage_collect, process_info_messages, process_flag_badarg, process_flag_heap_size, @@ -510,14 +514,20 @@ pio_current_location(N, Pid, Pi, Looper) -> case Where of {erlang,process_info,2,[]} -> pio_current_location(N-1, Pid, Pi+1, Looper); + {erts_internal,await_result,1, Loc} when is_list(Loc) -> + pio_current_location(N-1, Pid, Pi+1, Looper); {?MODULE,process_info_looper,1,Loc} when is_list(Loc) -> - pio_current_location(N-1, Pid, Pi, Looper+1) + pio_current_location(N-1, Pid, Pi, Looper+1); + _ -> + exit({unexpected_location, Where}) end. pio_current_stacktrace() -> L = [begin - {current_stacktrace,Stk} = process_info(P, current_stacktrace), - {P,Stk} + case process_info(P, current_stacktrace) of + {current_stacktrace, Stk} -> {P,Stk}; + undefined -> {P, []} + end end || P <- processes()], [erlang:garbage_collect(P) || {P,_} <- L], erlang:garbage_collect(), @@ -973,6 +983,106 @@ process_info_garbage_collection(_Config) -> gv(Key,List) -> proplists:get_value(Key,List). +process_info_smoke_all_tester() -> + register(process_info_smoke_all_tester, self()), + put(ets_ref, ets:new(blupp, [])), + put(binary, [list_to_binary(lists:duplicate(1000, 1)), + list_to_binary(lists:duplicate(1000, 2))]), + process_info_smoke_all_tester_loop(). + +process_info_smoke_all_tester_loop() -> + receive + {other_process, Pid} -> + case get(procs) of + undefined -> put(procs, [Pid]); + Procs -> put(procs, [Pid|Procs]) + end, + erlang:monitor(process, Pid), + link(Pid), + process_info_smoke_all_tester_loop() + end. + +process_info_smoke_all(Config) when is_list(Config) -> + AllPIOptions = [registered_name, + current_function, + initial_call, + messages, + message_queue_len, + links, + monitors, + monitored_by, + dictionary, + trap_exit, + error_handler, + heap_size, + stack_size, + memory, + garbage_collection, + group_leader, + reductions, + priority, + trace, + binary, + sequential_trace_token, + catchlevel, + backtrace, + last_calls, + total_heap_size, + suspending, + min_heap_size, + min_bin_vheap_size, + max_heap_size, + current_location, + current_stacktrace, + message_queue_data, + garbage_collection_info, + magic_ref, + fullsweep_after], + + {ok, Node} = start_node(Config, ""), + RP = spawn_link(Node, fun process_info_smoke_all_tester/0), + LP = spawn_link(fun process_info_smoke_all_tester/0), + RP ! {other_process, LP}, + LP ! {other_process, RP}, + LP ! {other_process, self()}, + LP ! ets:new(blapp, []), + LP ! ets:new(blipp, []), + LP ! list_to_binary(lists:duplicate(1000, 3)), + receive after 1000 -> ok end, + _MLP = erlang:monitor(process, LP), + true = is_process_alive(LP), + PI = process_info(LP, AllPIOptions), + io:format("~p~n", [PI]), + garbage_collect(), + unlink(RP), + unlink(LP), + exit(RP, kill), + exit(LP, kill), + false = is_process_alive(LP), + stop_node(Node), + ok. + +process_info_status_handled_signal(Config) when is_list(Config) -> + P = spawn_link(fun () -> + receive after infinity -> ok end + end), + wait_until(fun () -> + process_info(P, status) == {status, waiting} + end), + %% + %% The 'messages' option will force a process-info-request + %% signal to be scheduled on the process. Ensure that status + %% 'waiting' is reported even though it is actually running + %% when handling the request. We want it to report the status + %% it would have had if it had not been handling the + %% process-info-request... + %% + [{status, waiting}, {messages, []}] = process_info(P, [status, messages]), + unlink(P), + exit(P, kill), + false = erlang:is_process_alive(P), + ok. + %% Tests erlang:bump_reductions/1. bump_reductions(Config) when is_list(Config) -> erlang:garbage_collect(), diff --git a/erts/etc/unix/etp-commands.in b/erts/etc/unix/etp-commands.in index bac90cb472..e5ef819444 100644 --- a/erts/etc/unix/etp-commands.in +++ b/erts/etc/unix/etp-commands.in @@ -1997,7 +1997,7 @@ define etp-process-info printf " Msgq len: %d\n", $etp_proc->sig_qs.len end printf " Parent: " - etp-1 $etp_proc->parent + etp-1 ((Eterm)($etp_proc->parent)) printf "\n Pointer: (Process *) %p\n", $etp_proc end end @@ -2017,15 +2017,17 @@ define etp-processes set $proc_ix = 0 set $proc_max_ix = erts_proc.r.o.max set $proc_tab = erts_proc.r.o.tab + set $proc_cnt = erts_proc.vola.tile.count.counter set $invalid_proc = &erts_invalid_process set $proc_decentile = $proc_max_ix / 10 set $proc_printile = $proc_decentile - while $proc_ix < $proc_max_ix + while $proc_ix < $proc_max_ix && $proc_cnt > 0 set $proc = (Process *) *((UWord *) ($proc_tab + $proc_ix)) if ($proc != ((Process *) 0) && $proc != $invalid_proc) printf "---\n" printf " Pix: %d\n", $proc_ix etp-process-info $proc + set $proc_cnt-- end if $proc_ix == $proc_printile printf "--- %d%% (%d / %d) searched\n", $proc_printile / $proc_decentile * 10, $proc_ix, $proc_max_ix @@ -2363,10 +2365,11 @@ define etp-ports set $port_ix = 0 set $port_max_ix = erts_port.r.o.max set $port_tab = erts_port.r.o.tab + set $port_cnt = erts_proc.vola.tile.count.counter set $invalid_port = &erts_invalid_port set $port_decentile = $port_max_ix / 10 set $port_printile = $port_decentile - while $port_ix < $port_max_ix + while $port_ix < $port_max_ix && $port_cnt > 0 set $port = (Port *) *((UWord *) ($port_tab + $port_ix)) if ($port != ((Port *) 0) && $port != $invalid_port) if (*(((Uint32 *) &(((Port *) $port)->state))) & 0x100) == 0 @@ -2374,6 +2377,7 @@ define etp-ports printf "---\n" printf " Pix: %d\n", $port_ix etp-port-info $port + set $port_cnt-- end end if $port_ix == $port_printile diff --git a/erts/preloaded/ebin/init.beam b/erts/preloaded/ebin/init.beam Binary files differindex a2dd41b435..9043ae302e 100644 --- a/erts/preloaded/ebin/init.beam +++ b/erts/preloaded/ebin/init.beam diff --git a/erts/preloaded/src/init.erl b/erts/preloaded/src/init.erl index e0ae6b1656..0c74169e97 100644 --- a/erts/preloaded/src/init.erl +++ b/erts/preloaded/src/init.erl @@ -545,6 +545,8 @@ stop(Reason,State) -> do_stop(Reason,State1). do_stop(restart,#state{start = Start, flags = Flags, args = Args}) -> + %% Make sure we don't have any outstanding messages before doing the restart. + flush(), boot(Start,Flags,Args); do_stop(reboot,_) -> halt(); @@ -560,6 +562,13 @@ clear_system(BootPid,State) -> shutdown_pids(Heart,BootPid,State), unload(Heart). +flush() -> + receive + _M -> flush() + after 0 -> + ok + end. + stop_heart(State) -> case get_heart(State#state.kernel) of false -> diff --git a/lib/.gitignore b/lib/.gitignore index 283393faa9..7cef9d7cf3 100644 --- a/lib/.gitignore +++ b/lib/.gitignore @@ -1,32 +1,3 @@ -# common test - -/common_test/doc/src/ct.xml -/common_test/doc/src/ct_cover.xml -/common_test/doc/src/ct_ftp.xml -/common_test/doc/src/ct_master.xml -/common_test/doc/src/ct_rpc.xml -/common_test/doc/src/ct_snmp.xml -/common_test/doc/src/ct_ssh.xml -/common_test/doc/src/ct_netconfc.xml -/common_test/doc/src/ct_telnet.xml -/common_test/doc/src/unix_telnet.xml - -# edoc - -/edoc/doc/src/chapter.xml -/edoc/doc/src/edoc.xml -/edoc/doc/src/edoc_doclet.xml -/edoc/doc/src/edoc_extract.xml -/edoc/doc/src/edoc_layout.xml -/edoc/doc/src/edoc_lib.xml -/edoc/doc/src/edoc_run.xml - -# eunit - -/eunit/doc/src/chapter.xml -/eunit/doc/src/eunit.xml -/eunit/doc/src/eunit_surefire.xml - # erl_interface /erl_interface/bin @@ -34,15 +5,6 @@ /erl_interface/obj.st /erl_interface/obj -# gs - -/gs/doc/src/gs_chapter2.xml -/gs/doc/src/gs_chapter4.xml -/gs/doc/src/gs_chapter5.xml -/gs/doc/src/gs_chapter6.xml -/gs/doc/src/gs_chapter7.xml -/gs/doc/src/gs_chapter8.xml - # megaco /megaco/src/binary/megaco_ber_bin_drv_media_gateway_control_prev3a.erl @@ -129,19 +91,6 @@ /megaco/src/text/megaco_text_parser_v1.erl /megaco/src/text/megaco_text_parser_v2.erl /megaco/src/text/megaco_text_parser_v3.erl -/megaco/doc/html/mstone1.jpg - -# mnesia - -/mnesia/doc/src/Mnesia_App_A.xml -/mnesia/doc/src/Mnesia_App_B.xml -/mnesia/doc/src/Mnesia_App_C.xml -/mnesia/doc/src/Mnesia_App_D.xml -/mnesia/doc/src/Mnesia_chap2.xml -/mnesia/doc/src/Mnesia_chap3.xml -/mnesia/doc/src/Mnesia_chap4.xml -/mnesia/doc/src/Mnesia_chap5.xml -/mnesia/doc/src/Mnesia_chap7.xml # orber & cos* applications @@ -525,39 +474,3 @@ /orber/src/oe_OrberIFR.hrl /orber/src/oe_erlang.erl /orber/src/oe_erlang.hrl - -# snmp - -snmp/doc/intex.html - -# syntax_tools - -/syntax_tools/doc/src/chapter.xml -/syntax_tools/doc/src/epp_dodger.xml -/syntax_tools/doc/src/erl_comment_scan.xml -/syntax_tools/doc/src/erl_prettypr.xml -/syntax_tools/doc/src/erl_recomment.xml -/syntax_tools/doc/src/erl_syntax.xml -/syntax_tools/doc/src/erl_syntax_lib.xml -/syntax_tools/doc/src/erl_tidy.xml -/syntax_tools/doc/src/merl.xml -/syntax_tools/doc/src/merl_transform.xml -/syntax_tools/doc/src/igor.xml -/syntax_tools/doc/src/prettypr.xml - -# wx - -/wx/doc/src/chapter.xml -/wx/doc/src/gl.xml -/wx/doc/src/glu.xml -/wx/doc/src/ref_man.xml - -# xmerl - -/xmerl/doc/src/xmerl.xml -/xmerl/doc/src/xmerl_eventp.xml -/xmerl/doc/src/xmerl_scan.xml -/xmerl/doc/src/xmerl_ug.xml -/xmerl/doc/src/xmerl_xpath.xml -/xmerl/doc/src/xmerl_xs.xml -/xmerl/doc/src/xmerl_xsd.xml diff --git a/lib/asn1/doc/src/Makefile b/lib/asn1/doc/src/Makefile index 9a388e4e8a..2b5d9467d9 100644 --- a/lib/asn1/doc/src/Makefile +++ b/lib/asn1/doc/src/Makefile @@ -51,13 +51,14 @@ XML_CHAPTER_FILES = \ asn1_introduction.xml \ asn1_getting_started.xml \ asn1_overview.xml \ - asn1_spec.xml \ notes.xml BOOK_FILES = book.xml XML_FILES = $(BOOK_FILES) $(XML_APPLICATION_FILES) $(XML_REF3_FILES) \ - $(GEN_XML) $(XML_PART_FILES) $(XML_CHAPTER_FILES) + $(XML_PART_FILES) $(XML_CHAPTER_FILES) + +XML_GEN_FILES = $(GEN_XML:%=$(XMLDIR)/%) GIF_FILES = \ exclusive_Win_But.gif \ @@ -75,7 +76,8 @@ EXTRA_FILES = \ $(DEFAULT_HTML_FILES) \ $(ASN1_FILES) \ $(XML_REF3_FILES:%.xml=$(HTMLDIR)/%.html) \ - $(XML_CHAPTER_FILES:%.xml=$(HTMLDIR)/%.html) + $(XML_CHAPTER_FILES:%.xml=$(HTMLDIR)/%.html) \ + $(GEN_XML:%.xml=$(HTMLDIR)/%.html) \ MAN3_FILES = $(XML_REF3_FILES:%.xml=$(MAN3DIR)/%.3) diff --git a/lib/edoc/doc/src/Makefile b/lib/edoc/doc/src/Makefile index ca9ea66e3c..71de42795a 100644 --- a/lib/edoc/doc/src/Makefile +++ b/lib/edoc/doc/src/Makefile @@ -54,9 +54,10 @@ XML_NOTES_FILES = notes.xml BOOK_FILES = book.xml XML_FILES=\ - $(BOOK_FILES) $(XML_CHAPTER_FILES) \ - $(XML_PART_FILES) $(XML_REF3_FILES) $(XML_APPLICATION_FILES) \ - $(XML_NOTES_FILES) + $(BOOK_FILES) $(XML_APPLICATION_FILES) \ + $(XML_PART_FILES) $(XML_NOTES_FILES) + +XML_GEN_FILES=$(XML_REF3_FILES:%=$(XMLDIR)/%) $(XML_CHAPTER_FILES:%=$(XMLDIR)/%) # ---------------------------------------------------- INFO_FILE = ../../info @@ -101,11 +102,11 @@ html: gifs $(HTML_REF_MAN_FILE) man: $(MAN3_FILES) -$(XML_REF3_FILES): - escript $(DOCGEN)/priv/bin/xml_from_edoc.escript -def vsn $(EDOC_VSN) -i $(ERL_TOP)/lib/edoc/include $(SRC_DIR)/$(@:%.xml=%.erl) +$(XML_REF3_FILES:%=$(XMLDIR)/%): + $(gen_verbose)escript $(DOCGEN)/priv/bin/xml_from_edoc.escript -def vsn $(EDOC_VSN) -i $(ERL_TOP)/lib/edoc/include -dir $(XMLDIR) $(SRC_DIR)/$(@:$(XMLDIR)/%.xml=%.erl) -$(XML_CHAPTER_FILES): ../overview.edoc - escript $(DOCGEN)/priv/bin/xml_from_edoc.escript -def vsn $(EDOC_VSN) -chapter ../overview.edoc +$(XML_CHAPTER_FILES:%=$(XMLDIR)/%): ../overview.edoc + $(gen_verbose)escript $(DOCGEN)/priv/bin/xml_from_edoc.escript -def vsn $(EDOC_VSN) -chapter -dir $(XMLDIR) $< gifs: $(GIF_FILES:%=$(HTMLDIR)/%) diff --git a/lib/erl_docgen/priv/bin/codeline_preprocessing.escript b/lib/erl_docgen/priv/bin/codeline_preprocessing.escript index 8e1e35bcdd..67966b79e6 100755 --- a/lib/erl_docgen/priv/bin/codeline_preprocessing.escript +++ b/lib/erl_docgen/priv/bin/codeline_preprocessing.escript @@ -30,7 +30,7 @@ %% Function: main/1 %% Description: %%---------------------------------------------------------------------- -main([InFile, OutFile]) -> +main([CPath, InFile, OutFile]) -> InDev = case file:open(InFile, [read]) of {ok,ID} -> @@ -38,7 +38,6 @@ main([InFile, OutFile]) -> _ -> halt(5) end, - CPath=filename:dirname(InFile), OutDev = case file:open(OutFile, [write]) of {ok,OD} -> diff --git a/lib/erl_docgen/priv/bin/github_link.escript b/lib/erl_docgen/priv/bin/github_link.escript new file mode 100755 index 0000000000..1b36fca202 --- /dev/null +++ b/lib/erl_docgen/priv/bin/github_link.escript @@ -0,0 +1,51 @@ +#!/usr/bin/env escript +%% -*- erlang -*- +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2010-2016. All Rights Reserved. +%% +%% Licensed under the Apache License, Version 2.0 (the "License"); +%% you may not use this file except in compliance with the License. +%% You may obtain a copy of the License at +%% +%% http://www.apache.org/licenses/LICENSE-2.0 +%% +%% Unless required by applicable law or agreed to in writing, software +%% distributed under the License is distributed on an "AS IS" BASIS, +%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +%% See the License for the specific language governing permissions and +%% limitations under the License. +%% +%% %CopyrightEnd% +%%---------------------------------------------------------------------- +%% File : github_link.escript +%% +%% Created : 12 Dec 2017 by Lukas Larsson +%%---------------------------------------------------------------------- + +main([In, Filename, Sha, Out]) -> + {ok, Bin} = file:read_file(In), + + TagsToAnnotate = ["description", "func", "datatype", "section"], + + Subs = subs(TagsToAnnotate, Filename, Sha, re:split(Bin,[$\n])), + + file:write_file(Out, Subs). + +subs([], _, _, Bin) -> + lists:join("\n", Bin); +subs([Pat|Pats], Fn, Sha, Bin) -> + subs(Pats, Fn, Sha, sub(Bin, Pat, Fn, Sha)). + +sub(Bin, Pat, Fn, Sha) -> + sub(Bin, Pat, Fn, Sha, 1). +sub([], _Pat, _Fn, _Sha, _Cnt) -> + []; +sub([H|T], Pat, Fn, Sha, Cnt) -> + %% We use the maint branch here, it is not as exact as the tag, + %% but it is the best we can do as github does not allow doing + %% pullrequests on anything but branches. + [re:replace(H,["<",Pat,">"], + ["<",Pat," ghlink=\"maint/",Fn,"#L", + integer_to_list(Cnt),"\">"],[{return,list}]) | + sub(T, Pat, Fn, Sha, Cnt+1)]. diff --git a/lib/erl_docgen/priv/bin/xml_from_edoc.escript b/lib/erl_docgen/priv/bin/xml_from_edoc.escript index b930ae3818..b0e3764fae 100755 --- a/lib/erl_docgen/priv/bin/xml_from_edoc.escript +++ b/lib/erl_docgen/priv/bin/xml_from_edoc.escript @@ -28,6 +28,7 @@ %% Records %%====================================================================== -record(args, {suffix=".xml", + dir=".", layout=docgen_edoc_xml_cb, def=[], includes=[], @@ -85,7 +86,7 @@ module(File, Args) -> {app_default, "OTPROOT"}, {file_suffix, Args#args.suffix}, - {dir, "."}, + {dir, Args#args.dir}, {layout, Args#args.layout}], edoc:file(File, Opts); false -> @@ -118,7 +119,7 @@ users_guide(File, Args) -> Text = edoc_lib:run_layout(F, Opts), OutFile = "chapter" ++ Args#args.suffix, - edoc_lib:write_file(Text, ".", OutFile, Encoding); + edoc_lib:write_file(Text, Args#args.dir, OutFile, Encoding); false -> io:format("~s: not a regular file\n", [File]), usage() @@ -139,6 +140,8 @@ parse(["-def", Key, Val |RawOpts], Type, Args) -> parse(["-i", Dir |RawOpts], Type, Args) -> Args2 = Args#args{includes=Args#args.includes++[Dir]}, parse(RawOpts, Type, Args2); +parse(["-dir", Dir |RawOpts], Type, Args) -> + parse(RawOpts, Type, Args#args{dir=Dir}); parse(["-preprocess", Bool |RawOpts], Type, Args) when Bool == "true"; Bool == "false" -> parse(RawOpts, Type, Args#args{preprocess=list_to_atom(Bool)}); diff --git a/lib/erl_docgen/priv/css/otp_doc.css b/lib/erl_docgen/priv/css/otp_doc.css index 66ea09b53a..34c6befb0e 100644 --- a/lib/erl_docgen/priv/css/otp_doc.css +++ b/lib/erl_docgen/priv/css/otp_doc.css @@ -242,8 +242,25 @@ th { font-size: small; } -h3>a, h4>a{ - color: #1a1a1a !important; +.title_link { + color: #1a1a1a !important; + outline: none; +} + +.ghlink { + margin-left: -2.7em; /* .pencil.font-size + .pencil.padding.left + .pencil.padding.right = 2.7 */ + visibility: hidden; +} + +.pencil:before { + transform: rotateZ(90deg); + content: "\270E"; + color: #1a1a1a !important; + font-weight: bold; + font-size: 1.5em; + padding: .3em .6em .6em; + line-height: 1em; + font-family: mono; } hr{ diff --git a/lib/erl_docgen/priv/dtd/chapter.dtd b/lib/erl_docgen/priv/dtd/chapter.dtd index 8d940b90f7..3e9113d798 100644 --- a/lib/erl_docgen/priv/dtd/chapter.dtd +++ b/lib/erl_docgen/priv/dtd/chapter.dtd @@ -35,3 +35,4 @@ <!ELEMENT section (marker*,title, (%block;|quote|warning|note|dont|do|br|image|marker| table|section)*) > +<!ATTLIST section ghlink CDATA #IMPLIED> diff --git a/lib/erl_docgen/priv/dtd/common.refs.dtd b/lib/erl_docgen/priv/dtd/common.refs.dtd index 172cd16ad4..07c876a17f 100644 --- a/lib/erl_docgen/priv/dtd/common.refs.dtd +++ b/lib/erl_docgen/priv/dtd/common.refs.dtd @@ -26,8 +26,10 @@ %common.header; <!ELEMENT description (%block;|quote|br|marker|warning|note|dont|do)* > +<!ATTLIST description ghlink CDATA #IMPLIED> <!ELEMENT funcs (func)+ > <!ELEMENT func (name+,fsummary,(type|type_desc)*,desc?) > +<!ATTLIST func ghlink CDATA #IMPLIED> <!-- ELEMENT name is defined in each ref dtd --> <!ELEMENT fsummary (#PCDATA|c|i|em|anno)* > <!ELEMENT type (v,d?)* > @@ -42,9 +44,11 @@ <!ELEMENT email (#PCDATA) > <!ELEMENT section (marker*,title,(%block;|quote|br|marker| warning|note|dont|do|section)*) > +<!ATTLIST section ghlink CDATA #IMPLIED> <!ELEMENT datatypes (datatype_title?,datatype)+ > <!ELEMENT datatype_title (#PCDATA) > <!ELEMENT datatype (name+,desc?) > +<!ATTLIST datatype ghlink CDATA #IMPLIED> <!ELEMENT type_desc (#PCDATA|anno|c|seealso)* > <!ATTLIST type_desc variable CDATA #IMPLIED name CDATA #IMPLIED> diff --git a/lib/erl_docgen/priv/xsl/db_html.xsl b/lib/erl_docgen/priv/xsl/db_html.xsl index f9f3a356be..b6ebcc0c67 100644 --- a/lib/erl_docgen/priv/xsl/db_html.xsl +++ b/lib/erl_docgen/priv/xsl/db_html.xsl @@ -54,6 +54,24 @@ <func:result select="$result"/> </func:function> + <func:function name="erl:lower-case"> + <xsl:param name="str"/> + + <xsl:variable name="uppercase" select="'ABCDEFGHIJKLMNOPQRSTUVWXYZ'"/> + <xsl:variable name="lowercase" select="'abcdefghijklmnopqrstuvwxyz'"/> + + <xsl:variable name="result"> + <xsl:value-of select="translate($str, $uppercase, $lowercase)"/> + </xsl:variable> + + <func:result select="$result"/> + </func:function> + + <func:function name="erl:to-link"> + <xsl:param name="text"/> + <func:result select="translate(erl:lower-case($text),': /()" ','-------')"/> + </func:function> + <!-- Used from template menu.funcs to sort a module's functions for the lefthand index list, from the module's .xml file. Returns a value on which to sort the entity in question (a <name> element). @@ -208,6 +226,7 @@ <xsl:variable name="local_types" select="../type[string-length(@name) > 0]"/> <xsl:apply-templates select="$spec/contract/clause/head"> + <xsl:with-param name="ghlink" select="ancestor-or-self::*[@ghlink]/@ghlink"/> <xsl:with-param name="local_types" select="$local_types"/> <xsl:with-param name="global_types" select="$global_types"/> </xsl:apply-templates> @@ -216,9 +235,17 @@ </xsl:template> <xsl:template match="head"> + <xsl:param name="ghlink"/> <xsl:param name="local_types"/> <xsl:param name="global_types"/> - <div class="bold_code func-head"> + <xsl:variable name="id" select="concat(concat(concat(concat(../../../name,'-'),../../../arity),'-'),generate-id(.))"/> + <div class="bold_code func-head" + onMouseOver="document.getElementById('ghlink-{$id}').style.visibility = 'visible';" + onMouseOut="document.getElementById('ghlink-{$id}').style.visibility = 'hidden';"> + <xsl:call-template name="ghlink"> + <xsl:with-param name="ghlink" select="$ghlink"/> + <xsl:with-param name="id" select="$id"/> + </xsl:call-template> <xsl:apply-templates mode="local_type"> <xsl:with-param name="local_types" select="$local_types"/> <xsl:with-param name="global_types" select="$global_types"/> @@ -403,24 +430,35 @@ <!-- Datatypes --> <xsl:template match="datatypes"> - <h3> - <a name="data-types" href="#data-types"><xsl:text>Data Types</xsl:text></a> - </h3> + <xsl:call-template name="h3_title_link"> + <xsl:with-param name="title">Data Types</xsl:with-param> + </xsl:call-template> <xsl:apply-templates/> </xsl:template> - <!-- Datatype Title--> + <!-- Datatype Title, is the really needed? not used by anything --> <xsl:template match="datatype_title"> - <xsl:variable name="title" select="."/> - <h4> - <a name="{$title}" href="#{$title}"><xsl:apply-templates/></a> + <xsl:variable name="title" select="."/> + <h4> + <xsl:call-template name="title_link"> + <xsl:with-param name="title"><xsl:apply-templates/></xsl:with-param> + <xsl:with-param name="link" select="$title"/> + </xsl:call-template> </h4> </xsl:template> <!-- Datatype --> <xsl:template match="datatype"> + <xsl:variable name="id" select="concat('type-',name/@name)"/> <div class="data-types-body"> - <div class="data-type-name"><xsl:apply-templates select="name"/></div> + <div class="data-type-name" + onMouseOver="document.getElementById('ghlink-{$id}').style.visibility = 'visible';" + onMouseOut="document.getElementById('ghlink-{$id}').style.visibility = 'hidden';"> + <xsl:call-template name="ghlink"> + <xsl:with-param name="id" select="$id"/> + </xsl:call-template> + <xsl:apply-templates select="name"/> + </div> <div class="data-type-desc"><xsl:apply-templates select="desc"/></div> </div> </xsl:template> @@ -904,7 +942,7 @@ <!-- Header --> <xsl:template match="header"/> - + <!-- Section/Title --> <xsl:template match="section/title"/> @@ -917,10 +955,12 @@ <xsl:for-each select="marker"> <xsl:call-template name="marker-before-title"/> </xsl:for-each> - <a name="{generate-id(title)}"> - <xsl:value-of select="$chapnum"/>.<xsl:number/>  - <xsl:value-of select="title"/> - </a> + <xsl:call-template name="title_link"> + <xsl:with-param name="title"> + <xsl:value-of select="$chapnum"/>.<xsl:number/>  + <xsl:value-of select="title"/> + </xsl:with-param> + </xsl:call-template> </h3> <xsl:apply-templates> <xsl:with-param name="chapnum" select="$chapnum"/> @@ -937,7 +977,9 @@ <xsl:call-template name="marker-before-title"/> </xsl:for-each> <!-- xsl:value-of select="$partnum"/>.<xsl:value-of select="$chapnum"/>.<xsl:value-of select="$sectnum"/>.<xsl:number/ --> - <xsl:value-of select="title"/> + <xsl:call-template name="title_link"> + <xsl:with-param name="title" select="title"/> + </xsl:call-template> </h4> <xsl:apply-templates> <xsl:with-param name="chapnum" select="$chapnum"/> @@ -967,9 +1009,9 @@ <xsl:for-each select="marker"> <xsl:call-template name="marker-before-title"/> </xsl:for-each> - <a name="{generate-id(title)}"> - <xsl:value-of select="title"/> - </a> + <xsl:call-template name="title_link"> + <xsl:with-param name="title" select="title"/> + </xsl:call-template> </h3> <div class="REFBODY rb-3"> <xsl:apply-templates> @@ -1359,7 +1401,7 @@ <xsl:param name="chapter_file"/> <xsl:for-each select="$entries"> <li title="{title}"> - <a href="{$chapter_file}.html#{generate-id(title)}"> + <a href="{$chapter_file}.html#{erl:to-link(title)}"> <xsl:value-of select="title"/> </a> </li> @@ -1813,7 +1855,9 @@ <!-- Module --> <xsl:template match="module"> <xsl:param name="partnum"/> - <h3><a name="module" href="#module">Module</a></h3> + <xsl:call-template name="h3_title_link"> + <xsl:with-param name="title">Module</xsl:with-param> + </xsl:call-template> <div class="REFBODY module-body"> <xsl:apply-templates> <xsl:with-param name="partnum" select="$partnum"/> @@ -1825,7 +1869,9 @@ <!-- Modulesummary --> <xsl:template match="modulesummary"> <xsl:param name="partnum"/> - <h3><a name="module-summary" href="#module-summary">Module Summary</a></h3> + <xsl:call-template name="h3_title_link"> + <xsl:with-param name="title">Module Summary</xsl:with-param> + </xsl:call-template> <div class="REFBODY module-summary-body"> <xsl:apply-templates> <xsl:with-param name="partnum" select="$partnum"/> @@ -1836,7 +1882,9 @@ <!-- Lib --> <xsl:template match="lib"> <xsl:param name="partnum"/> - <h3><a name="c-library" href="#c-library">C Library</a></h3> + <xsl:call-template name="h3_title_link"> + <xsl:with-param name="title">C Library</xsl:with-param> + </xsl:call-template> <div class="REFBODY c-library-body"> <xsl:apply-templates> <xsl:with-param name="partnum" select="$partnum"/> @@ -1848,7 +1896,9 @@ <!-- Libsummary --> <xsl:template match="libsummary"> <xsl:param name="partnum"/> - <h3><a name="library-summary" href="#library-summary">Library Summary</a></h3> + <xsl:call-template name="h3_title_link"> + <xsl:with-param name="title">Library Summary</xsl:with-param> + </xsl:call-template> <div class="REFBODY library-summary-body"> <xsl:apply-templates> <xsl:with-param name="partnum" select="$partnum"/> @@ -1859,7 +1909,9 @@ <!-- Com --> <xsl:template match="com"> <xsl:param name="partnum"/> - <h3><a name="command" href="#command">Command</a></h3> + <xsl:call-template name="h3_title_link"> + <xsl:with-param name="title">Command</xsl:with-param> + </xsl:call-template> <div class="REFBODY command-body"> <xsl:apply-templates> <xsl:with-param name="partnum" select="$partnum"/> @@ -1871,7 +1923,9 @@ <!-- Comsummary --> <xsl:template match="comsummary"> <xsl:param name="partnum"/> - <h3><a name="command-summary" href="#command-summary">Command Summary</a></h3> + <xsl:call-template name="h3_title_link"> + <xsl:with-param name="title">Command Summary</xsl:with-param> + </xsl:call-template> <div class="REFBODY command-summary-body"> <xsl:apply-templates> <xsl:with-param name="partnum" select="$partnum"/> @@ -1882,7 +1936,9 @@ <!-- File --> <xsl:template match="file"> <xsl:param name="partnum"/> - <h3><a name="file" href="#file">File</a></h3> + <xsl:call-template name="h3_title_link"> + <xsl:with-param name="title">File</xsl:with-param> + </xsl:call-template> <div class="REFBODY file-body"> <xsl:apply-templates> <xsl:with-param name="partnum" select="$partnum"/> @@ -1894,7 +1950,9 @@ <!-- Filesummary --> <xsl:template match="filesummary"> <xsl:param name="partnum"/> - <h3><a name="file-summary" href="#file-summary">File Summary</a></h3> + <xsl:call-template name="h3_title_link"> + <xsl:with-param name="title">File Summary</xsl:with-param> + </xsl:call-template> <div class="REFBODY file-summary-body"> <xsl:apply-templates> <xsl:with-param name="partnum" select="$partnum"/> @@ -1906,7 +1964,9 @@ <!-- App --> <xsl:template match="app"> <xsl:param name="partnum"/> - <h3><a name="application" href="#application">Application</a></h3> + <xsl:call-template name="h3_title_link"> + <xsl:with-param name="title">Application</xsl:with-param> + </xsl:call-template> <div class="REFBODY application-body"> <xsl:apply-templates> <xsl:with-param name="partnum" select="$partnum"/> @@ -1918,7 +1978,9 @@ <!-- Appsummary --> <xsl:template match="appsummary"> <xsl:param name="partnum"/> - <h3><a name="application-summary" href="#application-summary">Application Summary</a></h3> + <xsl:call-template name="h3_title_link"> + <xsl:with-param name="title">Application Summary</xsl:with-param> + </xsl:call-template> <div class="REFBODY application-summary-body"> <xsl:apply-templates> <xsl:with-param name="partnum" select="$partnum"/> @@ -1929,7 +1991,9 @@ <!-- Description --> <xsl:template match="description"> <xsl:param name="partnum"/> - <h3><a name="description" href="#description">Description</a></h3> + <xsl:call-template name="h3_title_link"> + <xsl:with-param name="title">Description</xsl:with-param> + </xsl:call-template> <div class="REFBODY description-body"> <p> <xsl:apply-templates> @@ -1943,7 +2007,9 @@ <xsl:template match="funcs"> <xsl:param name="partnum"/> - <h3><a name="exports" href="#exports"><xsl:text>Exports</xsl:text></a></h3> + <xsl:call-template name="h3_title_link"> + <xsl:with-param name="title">Exports</xsl:with-param> + </xsl:call-template> <div class="exports-body"> <xsl:apply-templates> @@ -1960,7 +2026,8 @@ <p><xsl:apply-templates select="name"/> <xsl:apply-templates select="name[string-length(@arity) > 0 and position()=last()]" - mode="types"/></p> + mode="types"/> + </p> <xsl:apply-templates select="fsummary|type|desc"> <xsl:with-param name="partnum" select="$partnum"/> @@ -2019,14 +2086,19 @@ <xsl:choose> <xsl:when test="ancestor::cref"> - <a name="{substring-before(nametext, '(')}"> - <span class="bold_code bc-7"> - <xsl:value-of select="ret"/> - <xsl:call-template name="maybe-space-after-ret"> - <xsl:with-param name="s" select="ret"/> - </xsl:call-template> - <xsl:value-of select="nametext"/> - </span></a><br/> + <span class="bold_code bc-7"> + <xsl:call-template name="title_link"> + <xsl:with-param name="link" select="substring-before(nametext, '(')"/> + <xsl:with-param name="title"> + <xsl:value-of select="ret"/> + <xsl:call-template name="maybe-space-after-ret"> + <xsl:with-param name="s" select="ret"/> + </xsl:call-template> + <xsl:value-of select="nametext"/> + </xsl:with-param> + </xsl:call-template> + </span> + <br/> </xsl:when> <xsl:when test="ancestor::erlref"> <xsl:variable name="fname"> @@ -2047,15 +2119,29 @@ </xsl:variable> <xsl:choose> <xsl:when test="ancestor::datatype"> - <a name="type-{$fname}"></a><span class="bold_code bc-8"><xsl:apply-templates/></span><br/> + <div class="bold_code bc-8"> + <xsl:call-template name="title_link"> + <xsl:with-param name="link" select="concat('type-',$fname)"/> + <xsl:with-param name="title"> + <xsl:apply-templates/> + </xsl:with-param> + </xsl:call-template> + </div> </xsl:when> <xsl:otherwise> - <a name="{$fname}-{$arity}"></a><span class="bold_code fun-type"><xsl:apply-templates/></span><br/> + <div class="bold_code fun-type"> + <xsl:call-template name="title_link"> + <xsl:with-param name="link" select="concat(concat($fname,'-'),$arity)"/> + <xsl:with-param name="title"> + <xsl:apply-templates/> + </xsl:with-param> + </xsl:call-template> + </div> </xsl:otherwise> </xsl:choose> </xsl:when> <xsl:otherwise> - <span class="bold_code bc-10"><xsl:value-of select="."/></span> + <div class="bold_code bc-10"><xsl:value-of select="."/></div> </xsl:otherwise> </xsl:choose> @@ -2115,6 +2201,49 @@ </div> </xsl:template> + <xsl:template name="h3_title_link"> + <xsl:param name="title"/> + <h3> + <xsl:call-template name="title_link"> + <xsl:with-param name="title" select="$title"/> + <xsl:with-param name="link" select="erl:to-link($title)"/> + </xsl:call-template> + </h3> + </xsl:template> + + <xsl:template name="title_link"> + <xsl:param name="title"/> + <xsl:param name="link" select="erl:to-link(title)"/> + <xsl:param name="ghlink" select="ancestor-or-self::*[@ghlink][position() = 1]/@ghlink"/> + <xsl:variable name="id" select="concat(concat($link,'-'), generate-id(.))"/> + <span onMouseOver="document.getElementById('ghlink-{$id}').style.visibility = 'visible';" + onMouseOut="document.getElementById('ghlink-{$id}').style.visibility = 'hidden';"> + <xsl:call-template name="ghlink"> + <xsl:with-param name="id" select="$id"/> + <xsl:with-param name="ghlink" select="$ghlink"/> + </xsl:call-template> + <a class="title_link" name="{$link}" href="#{$link}"><xsl:value-of select="$title"/></a> + </span> + </xsl:template> + + <xsl:template name="ghlink"> + <xsl:param name="id"/> + <xsl:param name="ghlink" select="ancestor-or-self::*[@ghlink][position() = 1]/@ghlink"/> + <xsl:choose> + <xsl:when test="string-length($ghlink) > 0"> + <span id="ghlink-{$id}" class="ghlink"> + <a href="https://github.com/erlang/otp/edit/{$ghlink}" + title="Found an issue with the documentation? Fix it by clicking here!"> + <span class="pencil"/> + </a> + </span> + </xsl:when> + <xsl:otherwise> + <span id="ghlink-{$id}"/> + </xsl:otherwise> + </xsl:choose> + </xsl:template> + <!-- Desc --> <xsl:template match="desc"> <xsl:param name="partnum"/> diff --git a/lib/et/doc/src/Makefile b/lib/et/doc/src/Makefile index 0257a8f817..162d36e274 100644 --- a/lib/et/doc/src/Makefile +++ b/lib/et/doc/src/Makefile @@ -45,8 +45,11 @@ include files.mk XML_FILES = $(BOOK_FILES) $(XML_APPLICATION_FILES) $(XML_REF3_FILES) \ $(XML_PART_FILES) $(XML_CHAPTER_FILES) +XML_GEN_FILES = $(GEN_XML:%=$(XMLDIR)/%) + HTML_FILES = $(XML_APPLICATION_FILES:%.xml=$(HTMLDIR)/%.html) \ - $(XML_PART_FILES:%.xml=$(HTMLDIR)/%.html) + $(XML_PART_FILES:%.xml=$(HTMLDIR)/%.html) \ + $(GEN_XML:%.xml=$(HTMLDIR)/%.html) INFO_FILE = ../../info diff --git a/lib/et/doc/src/files.mk b/lib/et/doc/src/files.mk index e0ea9b0b76..7437da7ce3 100644 --- a/lib/et/doc/src/files.mk +++ b/lib/et/doc/src/files.mk @@ -31,10 +31,13 @@ XML_PART_FILES = \ XML_CHAPTER_FILES = \ et_intro.xml \ + notes.xml + +GEN_XML = \ et_tutorial.xml \ et_desc.xml \ - et_examples.xml \ - notes.xml + et_examples.xml + BOOK_FILES = book.xml diff --git a/lib/eunit/doc/src/Makefile b/lib/eunit/doc/src/Makefile index 610e575af6..e91d947592 100644 --- a/lib/eunit/doc/src/Makefile +++ b/lib/eunit/doc/src/Makefile @@ -70,9 +70,10 @@ HTML_STYLESHEET_FILES = \ BOOK_FILES = book.xml XML_FILES = \ - $(BOOK_FILES) $(XML_CHAPTER_FILES) $(XML_NOTES_FILES) \ - $(XML_PART_FILES) $(XML_REF3_FILES) $(XML_APPLICATION_FILES) + $(BOOK_FILES) $(XML_NOTES_FILES) \ + $(XML_PART_FILES) $(XML_APPLICATION_FILES) +XML_GEN_FILES = $(XML_REF3_FILES:%=$(XMLDIR)/%) $(XML_CHAPTER_FILES:%=$(XMLDIR)/%) # ---------------------------------------------------- INFO_FILE = ../../info @@ -122,11 +123,11 @@ man: $(MAN3_FILES) gifs: $(GIF_FILES:%=$(HTMLDIR)/%) -$(XML_REF3_FILES): - escript $(DOCGEN)/priv/bin/xml_from_edoc.escript -def vsn $(EUNIT_VSN) -i $(EUNIT_INC_DIR) $(EUNIT_DIR)/$(@:%.xml=%.erl) +$(XML_REF3_FILES:%=$(XMLDIR)/%): + $(gen_verbose)escript $(DOCGEN)/priv/bin/xml_from_edoc.escript -def vsn $(EUNIT_VSN) -i $(EUNIT_INC_DIR) -dir $(XMLDIR) $(EUNIT_DIR)/$(@:$(XMLDIR)/%.xml=%.erl) -$(XML_CHAPTER_FILES): - escript $(DOCGEN)/priv/bin/xml_from_edoc.escript -def vsn $(EUNIT_VSN) -chapter ../overview.edoc +$(XML_CHAPTER_FILES:%=$(XMLDIR)/%): + $(gen_verbose)escript $(DOCGEN)/priv/bin/xml_from_edoc.escript -def vsn $(EUNIT_VSN) -chapter -dir $(XMLDIR) ../overview.edoc info: @echo "XML_PART_FILES: $(XML_PART_FILES)" diff --git a/lib/inets/doc/src/httpc.xml b/lib/inets/doc/src/httpc.xml index 14662f257c..ffc6fec518 100644 --- a/lib/inets/doc/src/httpc.xml +++ b/lib/inets/doc/src/httpc.xml @@ -312,8 +312,7 @@ <v>Body = string() | binary()</v> <v>Profile = profile() | pid()</v> <d>When started <c>stand_alone</c> only the pid can be used.</d> - <v>Reason = {connect_failed, term()} | - {send_failed, term()} | term()</v> + <v>Reason = term()</v> </type> <desc> diff --git a/lib/inets/src/http_client/httpc_handler.erl b/lib/inets/src/http_client/httpc_handler.erl index 9b09832eb8..eeb08ce0ee 100644 --- a/lib/inets/src/http_client/httpc_handler.erl +++ b/lib/inets/src/http_client/httpc_handler.erl @@ -48,19 +48,17 @@ queue_timer :: reference() | 'undefined' }). --type session_failed() :: {'connect_failed',term()} | {'send_failed',term()}. - -record(state, { request :: request() | 'undefined', - session :: session() | session_failed() | 'undefined', + session :: session() | 'undefined', status_line, % {Version, StatusCode, ReasonPharse} headers :: http_response_h() | 'undefined', body :: binary() | 'undefined', mfa, % {Module, Function, Args} pipeline = queue:new() :: queue:queue(), keep_alive = queue:new() :: queue:queue(), - status, % undefined | new | pipeline | keep_alive | close | {ssl_tunnel, Request} + status :: undefined | new | pipeline | keep_alive | close | {ssl_tunnel, request()}, canceled = [], % [RequestId] max_header_size = nolimit :: nolimit | integer(), max_body_size = nolimit :: nolimit | integer(), @@ -255,8 +253,8 @@ handle_call(Request, From, State) -> Result -> Result catch - _:Reason -> - {stop, {shutdown, Reason} , State} + Class:Reason:ST -> + {stop, {shutdown, {{Class, Reason}, ST}}, State} end. @@ -271,8 +269,8 @@ handle_cast(Msg, State) -> Result -> Result catch - _:Reason -> - {stop, {shutdown, Reason} , State} + Class:Reason:ST -> + {stop, {shutdown, {{Class, Reason}, ST}}, State} end. %%-------------------------------------------------------------------- @@ -286,8 +284,8 @@ handle_info(Info, State) -> Result -> Result catch - _:Reason -> - {stop, {shutdown, Reason} , State} + Class:Reason:ST -> + {stop, {shutdown, {{Class, Reason}, ST}}, State} end. %%-------------------------------------------------------------------- @@ -295,23 +293,6 @@ handle_info(Info, State) -> %% Description: Shutdown the httpc_handler %%-------------------------------------------------------------------- -%% Init error there is no socket to be closed. -terminate(normal, - #state{request = Request, - session = {send_failed, _} = Reason} = State) -> - maybe_send_answer(Request, - httpc_response:error(Request, Reason), - State), - ok; - -terminate(normal, - #state{request = Request, - session = {connect_failed, _} = Reason} = State) -> - maybe_send_answer(Request, - httpc_response:error(Request, Reason), - State), - ok; - terminate(normal, #state{session = undefined}) -> ok; @@ -588,11 +569,11 @@ do_handle_info({Proto, _Socket, Data}, activate_once(Session), {noreply, State#state{mfa = NewMFA}} catch - _:Reason -> + Class:Reason:ST -> ClientReason = {could_not_parse_as_http, Data}, ClientErrMsg = httpc_response:error(Request, ClientReason), NewState = answer_request(Request, ClientErrMsg, State), - {stop, {shutdown, Reason}, NewState} + {stop, {shutdown, {{Class, Reason}, ST}}, NewState} end; do_handle_info({Proto, Socket, Data}, @@ -1058,15 +1039,15 @@ handle_response(#state{status = new} = State) -> ?hcrd("handle response - status = new", []), handle_response(try_to_enable_pipeline_or_keep_alive(State)); -handle_response(#state{request = Request, - status = Status, - session = Session, - status_line = StatusLine, - headers = Headers, - body = Body, - options = Options, - profile_name = ProfileName} = State) - when Status =/= new -> +handle_response(#state{status = Status0} = State0) when Status0 =/= new -> + State = handle_server_closing(State0), + #state{request = Request, + session = Session, + status_line = StatusLine, + headers = Headers, + body = Body, + options = Options, + profile_name = ProfileName} = State, handle_cookies(Headers, Request, Options, ProfileName), case httpc_response:result({StatusLine, Headers, Body}, Request) of %% 100-continue @@ -1330,6 +1311,14 @@ try_to_enable_pipeline_or_keep_alive( State#state{status = close} end. +handle_server_closing(State = #state{status = close}) -> State; +handle_server_closing(State = #state{headers = undefined}) -> State; +handle_server_closing(State = #state{headers = Headers}) -> + case httpc_response:is_server_closing(Headers) of + true -> State#state{status = close}; + false -> State + end. + answer_request(#request{id = RequestId, from = From} = Request, Msg, #state{session = Session, timers = Timers, diff --git a/lib/inets/src/http_client/httpc_response.erl b/lib/inets/src/http_client/httpc_response.erl index 58ab9144df..92dc9b0e02 100644 --- a/lib/inets/src/http_client/httpc_response.erl +++ b/lib/inets/src/http_client/httpc_response.erl @@ -83,7 +83,6 @@ whole_body(Body, Length) -> %% result(Response, Request) -> %% Response - {StatusLine, Headers, Body} %% Request - #request{} -%% Session - #tcp_session{} %% %% Description: Checks the status code ... %%------------------------------------------------------------------------- diff --git a/lib/inets/test/httpc_SUITE.erl b/lib/inets/test/httpc_SUITE.erl index 38705372c9..1116fdb1b6 100644 --- a/lib/inets/test/httpc_SUITE.erl +++ b/lib/inets/test/httpc_SUITE.erl @@ -67,7 +67,7 @@ groups() -> %% process_leak_on_keepalive is depending on stream_fun_server_close %% and it shall be the last test case in the suite otherwise cookie %% will fail. - {sim_http, [], only_simulated() ++ [process_leak_on_keepalive]}, + {sim_http, [], only_simulated() ++ server_closing_connection() ++ [process_leak_on_keepalive]}, {http_internal, [], real_requests_esi()}, {http_unix_socket, [], simulated_unix_socket()}, {https, [], real_requests()}, @@ -154,6 +154,12 @@ only_simulated() -> stream_fun_server_close ]. +server_closing_connection() -> + [ + server_closing_connection_on_first_response, + server_closing_connection_on_second_response + ]. + misc() -> [ server_does_not_exist, @@ -233,7 +239,7 @@ init_per_testcase(pipeline, Config) -> init_per_testcase(persistent_connection, Config) -> inets:start(httpc, [{profile, persistent}]), httpc:set_options([{keep_alive_timeout, 50000}, - {max_keep_alive_length, 3}], persistent_connection), + {max_keep_alive_length, 3}], persistent), Config; init_per_testcase(wait_for_whole_response, Config) -> @@ -252,6 +258,24 @@ end_per_testcase(pipeline, _Config) -> inets:stop(httpc, pipeline); end_per_testcase(persistent_connection, _Config) -> inets:stop(httpc, persistent); +end_per_testcase(Case, Config) + when Case == server_closing_connection_on_first_response; + Case == server_closing_connection_on_second_response -> + %% Test case uses at most one session. Ensure no leftover + %% sessions left behind. + {_, Status} = proplists:lookup(tc_status, Config), + ShallCleanup = case Status of + ok -> true; + {failed, _} -> true; + {skipped, _} -> false + end, + if ShallCleanup =:= true -> + httpc:request(url(group_name(Config), "/just_close.html", Config)), + ok; + true -> + ct:pal("Not cleaning up because test case status was ~p", [Status]), + ok + end; end_per_testcase(_Case, _Config) -> ok. @@ -1275,6 +1299,53 @@ stream_fun_server_close(Config) when is_list(Config) -> end. %%-------------------------------------------------------------------- +server_closing_connection_on_first_response() -> + [{doc, "Client receives \"Connection: close\" on first response." + "A client that receives a \"close\" connection option MUST cease sending" + "requests on that connection and close the connection after reading" + "the response message containing the \"close\""}]. +server_closing_connection_on_first_response(Config) when is_list(Config) -> + ReqSrvSendOctFun = + fun(V, U, S) -> + {ok, {{V, S, _}, Headers0, []}} = + httpc:request(get, {U, []}, [{version, V}], []), + {_, SendOctStr} = + proplists:lookup("x-socket-stat-send-oct", Headers0), + list_to_integer(SendOctStr) + end, + V = "HTTP/1.1", + Url0 = url(group_name(Config), "/http_1_1_send_oct.html", Config), + Url1 = url(group_name(Config), "/http_1_1_send_oct_and_connection_close.html", Config), + %% Test case assumes at most one reusable past session. + _ = ReqSrvSendOctFun(V, Url1, 204), + 0 = ReqSrvSendOctFun(V, Url0, 204), + ok. + +%%-------------------------------------------------------------------- +server_closing_connection_on_second_response() -> + [{doc, "Client receives \"Connection: close\" on second response." + "A client that receives a \"close\" connection option MUST cease sending" + "requests on that connection and close the connection after reading" + "the response message containing the \"close\""}]. +server_closing_connection_on_second_response(Config) when is_list(Config) -> + ReqSrvSendOctFun = + fun(V, U, S) -> + {ok, {{V, S, _}, Headers0, []}} = + httpc:request(get, {U, []}, [{version, V}], []), + {_, SendOctStr} = + proplists:lookup("x-socket-stat-send-oct", Headers0), + list_to_integer(SendOctStr) + end, + V = "HTTP/1.1", + Url0 = url(group_name(Config), "/http_1_1_send_oct.html", Config), + Url1 = url(group_name(Config), "/http_1_1_send_oct_and_connection_close.html", Config), + %% Test case assumes no reusable past sessions. + SendOct0 = 0 = ReqSrvSendOctFun(V, Url0, 204), + case ReqSrvSendOctFun(V, Url1, 204) of SendOct1 when SendOct1 > SendOct0 -> ok end, + 0 = ReqSrvSendOctFun(V, Url0, 204), + ok. + +%%-------------------------------------------------------------------- slow_connection() -> [{doc, "Test that a request on a slow keep-alive connection won't crash the httpc_manager"}]. slow_connection(Config) when is_list(Config) -> @@ -2232,10 +2303,32 @@ handle_uri("GET","/v1/kv/foo",_,_,_,_) -> "Content-Length: 24\r\n" ++ "Content-Type: application/json\r\n\r\n" ++ "[{\"Value\": \"aGVsbG8=\"}]\n"; +handle_uri(_,"/http_1_1_send_oct.html",_,_,Socket,_) -> + "HTTP/1.1 204 No Content\r\n" ++ + "X-Socket-Stat-Send-Oct: " ++ integer_to_list(get_stat(Socket, send_oct)) ++ "\r\n" ++ + "\r\n"; +handle_uri(_,"/http_1_1_send_oct_and_connection_close.html",_,_,Socket,_) -> + "HTTP/1.1 204 No Content\r\n" ++ + "X-Socket-Stat-Send-Oct: " ++ integer_to_list(get_stat(Socket, send_oct)) ++ "\r\n" ++ + "Connection: close\r\n" ++ + "\r\n"; handle_uri(_,_,_,_,_,DefaultResponse) -> DefaultResponse. +get_stat(S, Opt) -> + case getstat(S, [Opt]) of + {ok, [{Opt, V}]} when is_integer(V) -> + V; + {error, _} = E -> + E + end. + +getstat(#sslsocket{} = S, Opts) -> + ssl:getstat(S, Opts); +getstat(S, Opts) -> + inet:getstat(S, Opts). + url_start(#sslsocket{}) -> {ok,Host} = inet:gethostname(), ?TLS_URL_START ++ Host ++ ":"; diff --git a/lib/kernel/doc/src/Makefile b/lib/kernel/doc/src/Makefile index 0759f362d4..2413541082 100644 --- a/lib/kernel/doc/src/Makefile +++ b/lib/kernel/doc/src/Makefile @@ -137,16 +137,16 @@ clean clean_docs: rm -f errs core *~ $(SPECDIR)/specs_erl_prim_loader_stub.xml: - escript $(SPECS_EXTRACTOR) $(SPECS_FLAGS) \ + $(gen_verbose)escript $(SPECS_EXTRACTOR) $(SPECS_FLAGS) \ -o$(dir $@) -module erl_prim_loader_stub $(SPECDIR)/specs_erlang_stub.xml: - escript $(SPECS_EXTRACTOR) $(SPECS_FLAGS) \ + $(gen_verbose)escript $(SPECS_EXTRACTOR) $(SPECS_FLAGS) \ -o$(dir $@) -module erlang_stub $(SPECDIR)/specs_init_stub.xml: - escript $(SPECS_EXTRACTOR) $(SPECS_FLAGS) \ + $(gen_verbose)escript $(SPECS_EXTRACTOR) $(SPECS_FLAGS) \ -o$(dir $@) -module init_stub $(SPECDIR)/specs_zlib_stub.xml: - escript $(SPECS_EXTRACTOR) $(SPECS_FLAGS) \ + $(gen_verbose)escript $(SPECS_EXTRACTOR) $(SPECS_FLAGS) \ -o$(dir $@) -module zlib_stub # ---------------------------------------------------- diff --git a/lib/kernel/doc/src/heart.xml b/lib/kernel/doc/src/heart.xml index 5b5b71e521..46c7ce60b6 100644 --- a/lib/kernel/doc/src/heart.xml +++ b/lib/kernel/doc/src/heart.xml @@ -59,8 +59,9 @@ <pre> % <input>erl -heart -env HEART_BEAT_TIMEOUT 30 ...</input></pre> <p>The value (in seconds) must be in the range 10 < X <= 65535.</p> - <p>Notice that if the system clock is adjusted with - more than <c>HEART_BEAT_TIMEOUT</c> seconds, <c>heart</c> + <p>When running on OSs lacking support for monotonic time, + <c>heart</c> is susceptible to system clock adjustments of more than + <c>HEART_BEAT_TIMEOUT</c> seconds. When this happens, <c>heart</c> times out and tries to reboot the system. This can occur, for example, if the system clock is adjusted automatically by use of the Network Time Protocol (NTP).</p> diff --git a/lib/kernel/src/auth.erl b/lib/kernel/src/auth.erl index 40feee6bf0..a2116d8e8a 100644 --- a/lib/kernel/src/auth.erl +++ b/lib/kernel/src/auth.erl @@ -107,7 +107,7 @@ get_cookie() -> get_cookie(_Node) when node() =:= nonode@nohost -> nocookie; get_cookie(Node) -> - gen_server:call(auth, {get_cookie, Node}). + gen_server:call(auth, {get_cookie, Node}, infinity). -spec set_cookie(Cookie :: cookie()) -> 'true'. @@ -119,12 +119,12 @@ set_cookie(Cookie) -> set_cookie(_Node, _Cookie) when node() =:= nonode@nohost -> erlang:error(distribution_not_started); set_cookie(Node, Cookie) -> - gen_server:call(auth, {set_cookie, Node, Cookie}). + gen_server:call(auth, {set_cookie, Node, Cookie}, infinity). -spec sync_cookie() -> any(). sync_cookie() -> - gen_server:call(auth, sync_cookie). + gen_server:call(auth, sync_cookie, infinity). -spec print(Node :: node(), Format :: string(), Args :: [_]) -> 'ok'. diff --git a/lib/mnesia/doc/src/Makefile b/lib/mnesia/doc/src/Makefile index 82fcf66256..aed46d50db 100644 --- a/lib/mnesia/doc/src/Makefile +++ b/lib/mnesia/doc/src/Makefile @@ -49,16 +49,18 @@ XML_PART_FILES = \ XML_CHAPTER_FILES = \ Mnesia_chap1.xml \ Mnesia_overview.xml \ + Mnesia_chap8.xml \ + notes.xml + +XML_CHAPTER_GEN_FILES = \ Mnesia_chap2.xml \ Mnesia_chap3.xml \ Mnesia_chap4.xml \ Mnesia_chap5.xml \ Mnesia_chap7.xml \ - Mnesia_chap8.xml \ Mnesia_App_A.xml \ Mnesia_App_B.xml \ - Mnesia_App_C.xml \ - notes.xml + Mnesia_App_C.xml BOOK_FILES = book.xml @@ -66,6 +68,8 @@ XML_FILES = \ $(BOOK_FILES) $(XML_CHAPTER_FILES) \ $(XML_PART_FILES) $(XML_REF3_FILES) $(XML_APPLICATION_FILES) +XML_GEN_FILES = $(XML_CHAPTER_GEN_FILES:%=$(XMLDIR)/%) + GIF_FILES = \ company.gif diff --git a/lib/runtime_tools/doc/src/Makefile b/lib/runtime_tools/doc/src/Makefile index a9b0056a93..11583406b7 100644 --- a/lib/runtime_tools/doc/src/Makefile +++ b/lib/runtime_tools/doc/src/Makefile @@ -60,8 +60,9 @@ BOOK_FILES = book.xml XML_FILES = \ $(BOOK_FILES) $(XML_CHAPTER_FILES) \ $(XML_PART_FILES) $(XML_REF3_FILES) \ - $(XML_REF6_FILES) $(XML_APPLICATION_FILES) \ - $(GENERATED_XML_FILES) + $(XML_REF6_FILES) $(XML_APPLICATION_FILES) + +XML_GEN_FILES = $(GENERATED_XML_FILES:%=$(XMLDIR)/%) GIF_FILES = @@ -97,7 +98,7 @@ SPECS_FLAGS = -I../../include -I../../../kernel/src # Targets # ---------------------------------------------------- -%.xml: $(ERL_TOP)/HOWTO/%.md $(ERL_TOP)/make/emd2exml +$(XMLDIR)/%.xml: $(ERL_TOP)/HOWTO/%.md $(ERL_TOP)/make/emd2exml $(ERL_TOP)/make/emd2exml $< $@ $(HTMLDIR)/%.gif: %.gif diff --git a/lib/stdlib/doc/src/Makefile b/lib/stdlib/doc/src/Makefile index af27efa6c1..508a4fa2de 100644 --- a/lib/stdlib/doc/src/Makefile +++ b/lib/stdlib/doc/src/Makefile @@ -163,7 +163,7 @@ clean clean_docs: rm -f errs core *~ $(SPECDIR)/specs_erl_id_trans.xml: - escript $(SPECS_EXTRACTOR) $(SPECS_FLAGS) \ + $(gen_verbose)escript $(SPECS_EXTRACTOR) $(SPECS_FLAGS) \ -o$(dir $@) -module erl_id_trans # ---------------------------------------------------- diff --git a/lib/stdlib/doc/src/timer.xml b/lib/stdlib/doc/src/timer.xml index 350847bf7d..53107ade2c 100644 --- a/lib/stdlib/doc/src/timer.xml +++ b/lib/stdlib/doc/src/timer.xml @@ -270,8 +270,8 @@ <item> <p>Evaluates <c>apply(<anno>Module</anno>, <anno>Function</anno>, <anno>Arguments</anno>)</c> and measures the elapsed real time as - reported by <seealso marker="kernel:os#timestamp/0"> - <c>os:timestamp/0</c></seealso>.</p> + reported by <seealso marker="erts:erlang#monotonic_time/0"> + <c>erlang:monotonic_time/0</c></seealso>.</p> <p>Returns <c>{<anno>Time</anno>, <anno>Value</anno>}</c>, where <c><anno>Time</anno></c> is the elapsed real time in <em>microseconds</em>, and <c><anno>Value</anno></c> is what is diff --git a/lib/syntax_tools/doc/src/Makefile b/lib/syntax_tools/doc/src/Makefile index 1ce620b3d6..a346b9a0bd 100644 --- a/lib/syntax_tools/doc/src/Makefile +++ b/lib/syntax_tools/doc/src/Makefile @@ -63,10 +63,11 @@ BOOK_FILES = book.xml XML_FILES=\ - $(BOOK_FILES) $(XML_CHAPTER_FILES) \ - $(XML_PART_FILES) $(XML_REF3_FILES) $(XML_APPLICATION_FILES) \ + $(BOOK_FILES) $(XML_PART_FILES) $(XML_APPLICATION_FILES) \ $(XML_NOTES_FILES) +XML_GEN_FILES = $(XML_REF3_FILES:%=$(XMLDIR)/%) $(XML_CHAPTER_FILES:%=$(XMLDIR)/%) + # ---------------------------------------------------- INFO_FILE = ../../info @@ -108,11 +109,13 @@ html: gifs $(HTML_REF_MAN_FILE) man: $(MAN3_FILES) -$(XML_REF3_FILES): - escript $(DOCGEN)/priv/bin/xml_from_edoc.escript $(SRC_DIR)/$(@:%.xml=%.erl) +$(XML_REF3_FILES:%=$(XMLDIR)/%): + $(gen_verbose)escript $(DOCGEN)/priv/bin/xml_from_edoc.escript \ + -dir $(XMLDIR) $(SRC_DIR)/$(@:$(XMLDIR)/%.xml=%.erl) -$(XML_CHAPTER_FILES): - escript $(DOCGEN)/priv/bin/xml_from_edoc.escript -def vsn $(VSN) -chapter ../overview.edoc +$(XML_CHAPTER_FILES:%=$(XMLDIR)/%): + $(gen_verbose)escript $(DOCGEN)/priv/bin/xml_from_edoc.escript -def vsn $(VSN) \ + -chapter -dir $(XMLDIR) ../overview.edoc gifs: $(GIF_FILES:%=$(HTMLDIR)/%) diff --git a/lib/wx/doc/src/Makefile b/lib/wx/doc/src/Makefile index a76740adf1..c132c628f7 100644 --- a/lib/wx/doc/src/Makefile +++ b/lib/wx/doc/src/Makefile @@ -46,9 +46,13 @@ XML_NOTES_FILES = notes.xml BOOK_FILES = book.xml XML_FILES = \ - $(BOOK_FILES) $(XML_CHAPTER_FILES) \ - $(XML_PART_FILES) $(XML_REF3_FILES) \ - $(XML_NOTES_FILES) $(XML_APPLICATION_FILES) + $(BOOK_FILES) \ + $(XML_PART_FILES) $(XML_NOTES_FILES) + +XML_GEN_FILES = \ + $(XML_CHAPTER_FILES:%=$(XMLDIR)/%) \ + $(XML_REF3_FILES:%=$(XMLDIR)/%) \ + $(XML_APPLICATION_FILES:%=$(XMLDIR)/%) # ---------------------------------------------------- INFO_FILE = ../../info @@ -93,22 +97,26 @@ gifs: $(GIF_FILES:%=$(HTMLDIR)/%) xml: $(XML_REF3_FILES) $(XML_CHAPTER_FILES) ref_man.xml: ref_man.xml.src - @echo Preparing ref_man.xml - @cat ref_man.xml.src > ref_man.xml + @echo Preparing $@ + @cat ref_man.xml.src > $@ @for d in $(ModsNoExt); do \ - echo " <xi:include href=\"$$d.xml\"/>" >> ref_man.xml ; \ + echo " <xi:include href=\"$$d.xml\"/>" >> $@ ; \ done - @echo "</application>" >> ref_man.xml - @echo + @echo "</application>" >> $@ -$(ErlMods:%.erl=%.xml): ../../src/$(@:%.xml=%.erl) - escript $(DOCGEN)/priv/bin/xml_from_edoc.escript -def vsn $(VSN) -preprocess true -sort_functions false ../../src/$(@:%.xml=%.erl) +$(ErlMods:%.erl=$(XMLDIR)/%.xml): + $(gen_verbose)escript $(DOCGEN)/priv/bin/xml_from_edoc.escript \ + -def vsn $(VSN) -preprocess true -sort_functions false -dir $(XMLDIR) \ + ../../src/$(@:$(XMLDIR)/%.xml=%.erl) -$(GenMods:%.erl=%.xml): ../../src/gen/$(@:%.xml=%.erl) - escript $(DOCGEN)/priv/bin/xml_from_edoc.escript -def vsn $(VSN) -i ../../src -preprocess true -sort_functions false ../../src/gen/$(@:%.xml=%.erl) +$(GenMods:%.erl=$(XMLDIR)/%.xml): + $(gen_verbose)escript $(DOCGEN)/priv/bin/xml_from_edoc.escript \ + -def vsn $(VSN) -i ../../src -preprocess true -sort_functions false -dir $(XMLDIR) \ + ../../src/gen/$(@:$(XMLDIR)/%.xml=%.erl) -$(XML_CHAPTER_FILES): ../overview.edoc - escript $(DOCGEN)/priv/bin/xml_from_edoc.escript -def vsn $(VSN) -chapter ../overview.edoc +$(XML_CHAPTER_FILES:%=$(XMLDIR)/%): ../overview.edoc + $(gen_verbose)escript $(DOCGEN)/priv/bin/xml_from_edoc.escript \ + -def vsn $(VSN) -chapter -dir $(XMLDIR) $< debug opt: @@ -118,7 +126,7 @@ clean clean_docs: rm -f $(TOP_PDF_FILE) $(TOP_PDF_FILE:%.pdf=%.fo) rm -f $(SPECDIR)/* rm -f errs core *~ ../html/edoc-info - rm -f $(XML_REF3_FILES) $(XML_CHAPTER_FILES) *.html + rm -f $(XML_GEN_FILES) *.html # ---------------------------------------------------- # Release Target diff --git a/lib/xmerl/doc/src/Makefile b/lib/xmerl/doc/src/Makefile index 7d0b0b2392..94100910ef 100644 --- a/lib/xmerl/doc/src/Makefile +++ b/lib/xmerl/doc/src/Makefile @@ -54,10 +54,9 @@ XMERL_MODULES = \ XML_APPLICATION_FILES = ref_man.xml -XMERL_XML_FILES = $(XMERL_MODULES:=.xml) +XMERL_XML_FILES = $(XMERL_MODULES:%=$(XMLDIR)/%.xml) -XML_REF3_FILES = $(XMERL_XML_FILES) \ - xmerl_sax_parser.xml +XML_REF3_FILES = xmerl_sax_parser.xml XML_PART_FILES = \ part.xml @@ -65,9 +64,10 @@ XML_PART_FILES = \ XML_REF6_FILES = XML_CHAPTER_FILES = \ - xmerl_ug.xml \ notes.xml +XML_CHAPTER_GEN_FILES = \ + $(XMLDIR)/xmerl_ug.xml HTML_EXAMPLE_FILES = \ xmerl_examples.html \ @@ -89,6 +89,8 @@ XML_FILES= \ $(BOOK_FILES) $(XML_CHAPTER_FILES) \ $(XML_PART_FILES) $(XML_REF3_FILES) $(XML_APPLICATION_FILES) +XML_GEN_FILES = $(XMERL_XML_FILES) $(XML_CHAPTER_GEN_FILES) + # ---------------------------------------------------- INFO_FILE = ../../info @@ -97,7 +99,7 @@ HTML_FILES = $(XML_REF_MAN:%.xml=$(HTMLDIR)/%.html) \ $(XML_PART_FILES:%.xml=$(HTMLDIR)/%.html) -MAN3_FILES = $(XML_REF3_FILES:%.xml=$(MAN3DIR)/%.3) +MAN3_FILES = $(XML_REF3_FILES:%.xml=$(MAN3DIR)/%.3) $(XMERL_MODULES:%=$(MAN3DIR)/%.3) MAN6_FILES = $(XML_REF6_FILES:%_app.xml=$(MAN6DIR)/%.6) HTML_REF_MAN_FILE = $(HTMLDIR)/index.html @@ -126,7 +128,7 @@ pdf: $(TOP_PDF_FILE) html: gifs $(HTML_REF_MAN_FILE) $(XMERL_XML_FILES): - escript $(DOCGEN)/priv/bin/xml_from_edoc.escript $(XMERL_DIR)/$(@:%.xml=%.erl) + $(gen_verbose)escript $(DOCGEN)/priv/bin/xml_from_edoc.escript -dir $(XMLDIR) $(XMERL_DIR)/$(@:$(XMLDIR)/%.xml=%.erl) man: $(MAN3_FILES) $(MAN6_FILES) diff --git a/make/emd2exml.in b/make/emd2exml.in index 13bd6700d9..57bcaba24d 100755 --- a/make/emd2exml.in +++ b/make/emd2exml.in @@ -747,7 +747,7 @@ header(#state{ofile = {File, _}} = S0, Title) -> integer_to_list(Day), "</date>", nl(), "<rev>1</rev>", nl(), - "<file>",File,"</file>", nl(), + "<file>",filename:basename(File),"</file>", nl(), "</header>", nl()]), put_delayed(S3, ?DELAYED_TOC_IX). diff --git a/make/otp.mk.in b/make/otp.mk.in index 1d538fa528..c514a150ca 100644 --- a/make/otp.mk.in +++ b/make/otp.mk.in @@ -222,6 +222,7 @@ MAN9DIR = $(DOCDIR)/man9 TEXDIR = . SPECDIR = $(DOCDIR)/specs +XMLDIR = $(DOCDIR)/xml ifeq ($(CSS_FILE),) CSS_FILE = otp_doc.css @@ -276,55 +277,34 @@ endif SPECS_EXTRACTOR=$(DOCGEN)/priv/bin/specs_gen.escript # Extract specifications and types from Erlang source files (-spec, -type) $(SPECDIR)/specs_%.xml: $(SPECS_ESRC)/%.erl - escript $(SPECS_EXTRACTOR) $(SPECS_FLAGS) -o$(dir $@) $< + $(gen_verbose)escript $(SPECS_EXTRACTOR) $(SPECS_FLAGS) -o$(dir $@) $< $(SPECDIR)/specs_%.xml: $(SPECS_ESRC)/gen/%.erl - escript $(SPECS_EXTRACTOR) $(SPECS_FLAGS) -o$(dir $@) $< + $(gen_verbose)escript $(SPECS_EXTRACTOR) $(SPECS_FLAGS) -o$(dir $@) $< +MANXSLTARGS=--stringparam company "Ericsson AB" --stringparam docgen "$(DOCGEN)" --stringparam gendate "$$date" --stringparam appname "$(APPLICATION)" --stringparam appver "$(VSN)" --xinclude -path $(DOCGEN)/priv/dtd -path $(DOCGEN)/priv/dtd_man_entities -path . -$(MAN1DIR)/%.1: %.xml - date=`date +"%B %e, %Y"`; \ - xsltproc --output "$@" --stringparam company "Ericsson AB" --stringparam docgen "$(DOCGEN)" --stringparam gendate "$$date" --stringparam appname "$(APPLICATION)" --stringparam appver "$(VSN)" --xinclude -path $(DOCGEN)/priv/dtd -path $(DOCGEN)/priv/dtd_man_entities $(DOCGEN)/priv/xsl/db_man.xsl $< - -$(MAN2DIR)/%.2: %.xml - date=`date +"%B %e, %Y"`; \ - xsltproc --output "$@" --stringparam company "Ericsson AB" --stringparam docgen "$(DOCGEN)" --stringparam gendate "$$date" --stringparam appname "$(APPLICATION)" --stringparam appver "$(VSN)" --xinclude -path $(DOCGEN)/priv/dtd -path $(DOCGEN)/priv/dtd_man_entities $(DOCGEN)/priv/xsl/db_man.xsl $< +$(MAN1DIR)/%.1 $(MAN2DIR)/%.2 $(MAN4DIR)/%.4 $(MAN4DIR)/%.5 $(MAN9DIR)/%.9: $(XMLDIR)/%.xml + $(gen_verbose)date=`date +"%B %e, %Y"`; \ + xsltproc --output "$@" $(MANXSLTARGS) $(DOCGEN)/priv/xsl/db_man.xsl $< ifneq ($(wildcard $(SPECDIR)),) -$(MAN3DIR)/%.3: %.xml $(SPECDIR)/specs_%.xml - date=`date +"%B %e, %Y"`; \ +$(MAN3DIR)/%.3: $(XMLDIR)/%.xml $(SPECDIR)/specs_%.xml + $(gen_verbose)date=`date +"%B %e, %Y"`; \ specs_file=`pwd`/$(SPECDIR)/specs_$*.xml; \ - xsltproc --output "$@" --stringparam company "Ericsson AB" --stringparam docgen "$(DOCGEN)" --stringparam gendate "$$date" --stringparam appname "$(APPLICATION)" --stringparam appver "$(VSN)" --stringparam specs_file "$$specs_file" --xinclude -path $(DOCGEN)/priv/dtd -path $(DOCGEN)/priv/dtd_man_entities $(DOCGEN)/priv/xsl/db_man.xsl $< + xsltproc --output "$@" $(MANXSLTARGS) --stringparam specs_file "$$specs_file" $(DOCGEN)/priv/xsl/db_man.xsl $< else -$(MAN3DIR)/%.3: %.xml - date=`date +"%B %e, %Y"`; \ - xsltproc --output "$@" --stringparam company "Ericsson AB" --stringparam docgen "$(DOCGEN)" --stringparam gendate "$$date" --stringparam appname "$(APPLICATION)" --stringparam appver "$(VSN)" --xinclude -path $(DOCGEN)/priv/dtd -path $(DOCGEN)/priv/dtd_man_entities $(DOCGEN)/priv/xsl/db_man.xsl $< +$(MAN3DIR)/%.3: $(XMLDIR)/%.xml + $(gen_verbose)date=`date +"%B %e, %Y"`; \ + xsltproc --output "$@" $(MANXSLTARGS) $(DOCGEN)/priv/xsl/db_man.xsl $< endif # left for compatibility -$(MAN4DIR)/%.4: %.xml - date=`date +"%B %e, %Y"`; \ - xsltproc --output "$@" --stringparam company "Ericsson AB" --stringparam docgen "$(DOCGEN)" --stringparam gendate "$$date" --stringparam appname "$(APPLICATION)" --stringparam appver "$(VSN)" --xinclude -path $(DOCGEN)/priv/dtd -path $(DOCGEN)/priv/dtd_man_entities $(DOCGEN)/priv/xsl/db_man.xsl $< - -$(MAN4DIR)/%.5: %.xml - date=`date +"%B %e, %Y"`; \ - xsltproc --output "$@" --stringparam company "Ericsson AB" --stringparam docgen "$(DOCGEN)" --stringparam gendate "$$date" --stringparam appname "$(APPLICATION)" --stringparam appver "$(VSN)" --xinclude -path $(DOCGEN)/priv/dtd -path $(DOCGEN)/priv/dtd_man_entities $(DOCGEN)/priv/xsl/db_man.xsl $< - -# left for compatibility -$(MAN6DIR)/%.6: %_app.xml - date=`date +"%B %e, %Y"`; \ - xsltproc --output "$@" --stringparam company "Ericsson AB" --stringparam docgen "$(DOCGEN)" --stringparam gendate "$$date" --stringparam appname "$(APPLICATION)" --stringparam appver "$(VSN)" --xinclude -path $(DOCGEN)/priv/dtd -path $(DOCGEN)/priv/dtd_man_entities $(DOCGEN)/priv/xsl/db_man.xsl $< - -$(MAN6DIR)/%.7: %_app.xml - date=`date +"%B %e, %Y"`; \ - xsltproc --output "$@" --stringparam company "Ericsson AB" --stringparam docgen "$(DOCGEN)" --stringparam gendate "$$date" --stringparam appname "$(APPLICATION)" --stringparam appver "$(VSN)" --xinclude -path $(DOCGEN)/priv/dtd -path $(DOCGEN)/priv/dtd_man_entities $(DOCGEN)/priv/xsl/db_man.xsl $< - -$(MAN9DIR)/%.9: %.xml - date=`date +"%B %e, %Y"`; \ - xsltproc --output "$@" --stringparam company "Ericsson AB" --stringparam docgen "$(DOCGEN)" --stringparam gendate "$$date" --stringparam appname "$(APPLICATION)" --stringparam appver "$(VSN)" --xinclude -path $(DOCGEN)/priv/dtd -path $(DOCGEN)/priv/dtd_man_entities $(DOCGEN)/priv/xsl/db_man.xsl $< - +$(MAN6DIR)/%.6 $(MAN6DIR)/%.7: $(XMLDIR)/%_app.xml + $(gen_verbose)date=`date +"%B %e, %Y"`; \ + xsltproc --output "$@" $(MANXSLTARGS) $(DOCGEN)/priv/xsl/db_man.xsl $< -.xmlsrc.xml: - escript $(DOCGEN)/priv/bin/codeline_preprocessing.escript $< $@ +$(XMLDIR)/%.xml: $(XMLDIR)/%.xmlsrc + $(gen_verbose)escript $(DOCGEN)/priv/bin/codeline_preprocessing.escript $(shell pwd) $< $@ .fo.pdf: $(FOP) -c $(FOP_CONFIG) -cache $(ERL_TOP)/make/$(TARGET)/fop-fonts.cache -fo $< -pdf $@ diff --git a/make/otp_release_targets.mk b/make/otp_release_targets.mk index 23b4416963..779aaa1a1e 100644 --- a/make/otp_release_targets.mk +++ b/make/otp_release_targets.mk @@ -33,9 +33,24 @@ ifneq ($(wildcard $(MOD2APP)),) MOD2APP_PARAM = --stringparam mod2app_file "$(MOD2APP)" endif +# ------------------------------------------------------- +# Take the XML files and add the github link info to them +# ------------------------------------------------------- +_create_xml_dirs := $(shell mkdir -p $(XMLDIR)) + +XML_GEN_FILES+=$(patsubst %.xml,$(XMLDIR)/%.xml,$(XML_FILES)) +$(XMLDIR)/%.xml: %.xml + $(gen_verbose)escript $(DOCGEN)/priv/bin/github_link.escript $< \ + "$(subst $(ERL_TOP)/,,$(CURDIR)/$^)" "NA" $@ + +$(XMLDIR)/%.xmlsrc: %.xmlsrc + $(gen_verbose)escript $(DOCGEN)/priv/bin/github_link.escript $< \ + "$(subst $(ERL_TOP)/,,$(CURDIR)/$^)" "NA" $@ + ifeq ($(TOPDOC),) -$(HTMLDIR)/index.html: $(XML_FILES) $(SPECS_FILES) - date=`date +"%B %e, %Y"`; \ + +$(HTMLDIR)/index.html: $(XML_GEN_FILES) $(SPECS_FILES) + $(gen_verbose)date=`date +"%B %e, %Y"`; \ $(XSLTPROC) --noout \ --stringparam outdir $(HTMLDIR) \ --stringparam docgen "$(DOCGEN)" \ @@ -50,14 +65,15 @@ $(HTMLDIR)/index.html: $(XML_FILES) $(SPECS_FILES) --stringparam winprefix "$(WINPREFIX)" \ --stringparam logo "$(HTMLLOGO_FILE)" \ --stringparam pdfname "$(PDFNAME)" \ + -path . \ -path $(DOCGEN)/priv/dtd \ -path $(DOCGEN)/priv/dtd_html_entities \ - $(DOCGEN)/priv/xsl/db_html.xsl book.xml + $(DOCGEN)/priv/xsl/db_html.xsl $(XMLDIR)/book.xml endif -$(HTMLDIR)/users_guide.html: $(XML_FILES) - date=`date +"%B %e, %Y"`; \ +$(HTMLDIR)/users_guide.html: $(XML_GEN_FILES) + $(gen_verbose)date=`date +"%B %e, %Y"`; \ $(XSLTPROC) --noout \ --stringparam outdir $(HTMLDIR) \ --stringparam docgen "$(DOCGEN)" \ @@ -72,12 +88,13 @@ $(HTMLDIR)/users_guide.html: $(XML_FILES) --stringparam logo "$(HTMLLOGO_FILE)" \ --stringparam pdfname "$(PDFNAME)" \ --xinclude \ + -path . \ -path $(DOCGEN)/priv/dtd \ -path $(DOCGEN)/priv/dtd_html_entities \ - $(DOCGEN)/priv/xsl/db_html.xsl book.xml + $(DOCGEN)/priv/xsl/db_html.xsl $(XMLDIR)/book.xml -%.fo: $(XML_FILES) $(SPECS_FILES) - date=`date +"%B %e, %Y"`; \ +%.fo: $(XML_GEN_FILES) $(SPECS_FILES) + $(gen_verbose)date=`date +"%B %e, %Y"`; \ $(XSLTPROC) \ --stringparam docgen "$(DOCGEN)" \ --stringparam gendate "$$date" \ @@ -87,9 +104,10 @@ $(HTMLDIR)/users_guide.html: $(XML_FILES) --stringparam logo "$(PDFLOGO_FILE)" \ --stringparam pdfcolor "$(PDFCOLOR)" \ --xinclude $(TOP_SPECS_PARAM) \ + -path . \ -path $(DOCGEN)/priv/dtd \ -path $(DOCGEN)/priv/dtd_html_entities \ - $(DOCGEN)/priv/xsl/db_pdf.xsl book.xml > $@ + $(DOCGEN)/priv/xsl/db_pdf.xsl $(XMLDIR)/book.xml > $@ # ------------------------------------------------------------------------ # The following targets just exist in the documentation directory @@ -101,16 +119,17 @@ ifneq ($(XML_FILES),) # ---------------------------------------------------- # Generation of application index data # ---------------------------------------------------- -$(HTMLDIR)/$(APPLICATION).eix: $(XML_FILES) $(SPECS_FILES) - date=`date +"%B %e, %Y"`; \ +$(HTMLDIR)/$(APPLICATION).eix: $(XML_GEN_FILES) $(SPECS_FILES) + $(gen_verbose)date=`date +"%B %e, %Y"`; \ $(XSLTPROC) --stringparam docgen "$(DOCGEN)" \ --stringparam gendate "$$date" \ --stringparam appname "$(APPLICATION)" \ --stringparam appver "$(VSN)" \ -xinclude $(TOP_SPECS_PARAM) \ + -path . \ -path $(DOCGEN)/priv/dtd \ -path $(DOCGEN)/priv/dtd_html_entities \ - $(DOCGEN)/priv/xsl/db_eix.xsl book.xml > $@ + $(DOCGEN)/priv/xsl/db_eix.xsl $(XMLDIR)/book.xml > $@ docs: $(HTMLDIR)/$(APPLICATION).eix @@ -118,30 +137,37 @@ docs: $(HTMLDIR)/$(APPLICATION).eix ## Then we look into all those files check for xi:includes BOOK_XI_INC_FILES:=$(foreach file,$(BOOK_FILES),$(shell awk -F\" '/xi:include/ {print $$2}' $(file))) $(BOOK_FILES) ALL_XI_INC_FILES:=$(foreach file,$(BOOK_XI_INC_FILES),$(shell awk -F\" '/xi:include/ {if ("$(dir $(file))" != "./") printf "$(dir $(file))"; print $$2}' $(file))) $(BOOK_XI_INC_FILES) +ifeq ($(TOPDOC), true) +ALL_XI_INC_GEN_FILES:=$(filter-out book.xml,$(ALL_XI_INC_FILES)) $(BOOK_FILES:%=$(XMLDIR)/%) +else +ALL_XI_INC_GEN_FILES:=$(ALL_XI_INC_FILES:%=$(XMLDIR)/%) +endif + ## These are the patterns of file names that xmllint cannot currently parse XI_INC_FILES:=%user_man.xml %usersguide.xml %refman.xml %ref_man.xml %part.xml %book.xml ## These are the files that we should run the xmllint on LINT_XI_INC_FILES := $(filter-out $(XI_INC_FILES), $(ALL_XI_INC_FILES)) +LINT_XI_INC_GEN_FILES := $(filter-out $(XI_INC_FILES), $(ALL_XI_INC_GEN_FILES)) EMPTY := SPACE := $(EMPTY) $(EMPTY) XMLLINT_SRCDIRS:=$(subst $(SPACE),:,$(sort $(foreach file,$(XML_FILES),$(dir $(file))))) -xmllint: $(ALL_XI_INC_FILES) -## We verify that the $(XML_FILES) variable in the Makefile have exactly +xmllint: $(ALL_XI_INC_GEN_FILES) +## We verify that the $(XML_GEN_FILES) variable in the Makefile have exactly ## the same files as we found out by following xi:include. -ifneq ($(filter-out $(filter %.xml,$(XML_FILES)),$(ALL_XI_INC_FILES)),) - $(error "$(filter-out $(filter %.xml,$(XML_FILES)),$(ALL_XI_INC_FILES)) in $$ALL_XI_INC_FILES but not in $$XML_FILES"); +ifneq ($(filter-out $(filter %.xml,$(XML_GEN_FILES)),$(ALL_XI_INC_GEN_FILES)),) + $(error "$(filter-out $(filter %.xml,$(XML_GEN_FILES)),$(ALL_XI_INC_GEN_FILES)) in $$ALL_XI_INC_FILES but not in $$XML_GEN_FILES"); endif -ifneq ($(filter-out $(ALL_XI_INC_FILES),$(filter %.xml,$(XML_FILES))),) - $(error "$(filter-out $(ALL_XI_INC_FILES),$(filter %.xml,$(XML_FILES))) in $$XML_FILES but not in $$ALL_XI_INC_FILES"); +ifneq ($(filter-out $(ALL_XI_INC_GEN_FILES),$(filter %.xml,$(XML_GEN_FILES))),) + $(error "$(filter-out $(ALL_XI_INC_GEN_FILES),$(filter %.xml,$(XML_GEN_FILES))) in $$XML_GEN_FILES but not in $$ALL_XI_INC_FILES"); endif - @echo "xmllint $(LINT_XI_INC_FILES)" + @echo "xmllint $(LINT_XI_INC_GEN_FILES)" @xmllint --noout --valid --nodefdtd --loaddtd --path \ $(DOCGEN)/priv/dtd:$(DOCGEN)/priv/dtd_html_entities:$(XMLLINT_SRCDIRS) \ - $(LINT_XI_INC_FILES) + $(LINT_XI_INC_GEN_FILES) # ---------------------------------------------------- # Local documentation target for testing diff --git a/scripts/diffable b/scripts/diffable new file mode 100755 index 0000000000..f22194e99f --- /dev/null +++ b/scripts/diffable @@ -0,0 +1,620 @@ +#!/usr/bin/env escript +%% -*- erlang -*- +-mode(compile). + +main(Args0) -> + {Args,Opts} = opts(Args0, #{format=>asm,no_compile=>false}), + case Args of + [OutDir] -> + do_compile(OutDir, Opts); + _ -> + usage(), + halt(1) + end. + +usage() -> + S = "usage: otp-diffable-asm [OPTION] DIRECTORY\n\n" + "Options:\n" + " --asm Output to .S files (default)\n" + " --dis Output to .dis files\n" + " --no-compile Disassemble from BEAM files (use with --dis)\n" + "\n" + "DESCRIPTION\n" + "\n" + "Compile some applications from OTP (more than 700 modules) to either\n" + ".S files or .dis files. The files are massaged to make them diff-friendly.\n" + "\n" + "EXAMPLES\n" + "\n" + "This example shows how the effectiveness of a compiler \n" + "optimization can be verified (alternatively, that pure code\n" + "refactoring has no effect on the generated code):\n" + "\n" + "$ scripts/diffable old\n" + "# Hack the compiler.\n" + "$ scripts/diffable new\n" + "$ diff -u old new\n" + "\n" + "This example shows how the effectiveness of loader hacks\n" + "can be verified:\n" + "\n" + "$ scripts/diffable --dis --no-compile old\n" + "# Hack ops.tab and/or one of the *instr.tab files.\n" + "$ scripts/diffable --dis --no-compile new\n" + "$ diff -u old new\n", + io:put_chars(S). + +opts(["--asm"|Args], Opts) -> + opts(Args, Opts#{format:=asm}); +opts(["--dis"|Args], Opts) -> + opts(Args, Opts#{format:=dis}); +opts(["--no-compile"|Args], Opts) -> + opts(Args, Opts#{format:=dis,no_compile:=true}); +opts(Args, Opts) -> + {Args,Opts}. + +do_compile(OutDir, Opts0) -> + Opts1 = Opts0#{outdir=>OutDir}, + _ = filelib:ensure_dir(filename:join(OutDir, "dummy")), + Apps = ["preloaded", + "asn1", + "stdlib", + "kernel", + "reltool", + "runtime_tools", + "xmerl", + "common_test", + "compiler", + "diameter", + "mnesia", + "inets", + "syntax_tools", + "parsetools", + "dialyzer", + "ssl", + "wx"], + {Files,Opts} = get_files(Apps, Opts1), + CF = choose_format(Opts), + p_run(fun(File) -> + compile_file(CF, File) + end, Files). + +choose_format(#{format:=Format}=Opts) -> + case Format of + asm -> + compile_to_asm_fun(Opts); + dis -> + compile_to_dis_fun(Opts) + end. + +compile_file(CF, File) -> + try + CF(File) + catch + Class:Error:Stk -> + io:format("~s: ~p ~p\n~p\n", + [File,Class,Error,Stk]), + error + end. + +%%% +%%% Get names of files (either .erl files or BEAM files). +%%% + +get_files(Apps, #{format:=dis,no_compile:=true}=Opts) -> + Files = get_beams(Apps), + {Files,Opts}; +get_files(Apps, #{}=Opts) -> + Inc = make_includes(), + CompilerOpts = [{d,epmd_dist_high,42}, + {d,epmd_dist_low,37}, + {d,'VSN',1}, + {d,'COMPILER_VSN',1}, + {d,erlang_daemon_port,1337}|Inc], + Files0 = get_src(Apps), + Files = add_opts(Files0, CompilerOpts), + {Files,Opts}. + +add_opts([F|Fs], Opts0) -> + Opts = case filename:basename(F) of + "group_history.erl" -> + Opts0 -- [{d,'VSN',1}]; + _ -> + Opts0 + end, + [{F,Opts}|add_opts(Fs, Opts0)]; +add_opts([], _Opts) -> + []. + +get_src(["preloaded"|Apps]) -> + WC = filename:join(code:root_dir(), "erts/preloaded/src/*.erl"), + filelib:wildcard(WC) ++ get_src(Apps); +get_src(["inets"|Apps]) -> + LibDir = code:lib_dir(inets), + WC = filename:join(LibDir, "src/*/*.erl"), + filelib:wildcard(WC) ++ get_src(Apps); +get_src(["syntax_tools"|Apps]) -> + LibDir = code:lib_dir(syntax_tools), + WC = filename:join(LibDir, "src/*.erl"), + Files0 = filelib:wildcard(WC), + Files = [F || F <- Files0, + filename:basename(F) =/= "merl_tests.erl"], + Files ++ get_src(Apps); +get_src(["wx"|Apps]) -> + LibDir = code:lib_dir(wx), + WC1 = filename:join(LibDir, "src/gen/*.erl"), + WC2 = filename:join(LibDir, "src/*.erl"), + filelib:wildcard(WC1) ++ filelib:wildcard(WC2) ++ get_src(Apps); +get_src([App|Apps]) -> + WC = filename:join(code:lib_dir(App), "src/*.erl"), + filelib:wildcard(WC) ++ get_src(Apps); +get_src([]) -> []. + +make_includes() -> + Is = [{common_test,"include"}, + {inets,"include"}, + {inets,"src/http_client"}, + {inets,"src/http_lib"}, + {inets,"src/http_server"}, + {inets,"src/inets_app"}, + {kernel,"include"}, + {kernel,"src"}, + {public_key,"include"}, + {runtime_tools,"include"}, + {ssh,"include"}, + {snmp,"include"}, + {stdlib,"include"}, + {syntax_tools,"include"}, + {wx,"src"}, + {wx,"include"}, + {xmerl,"include"}], + [{i,filename:join(code:lib_dir(App), Path)} || {App,Path} <- Is]. + +get_beams(["preloaded"|Apps]) -> + WC = filename:join(code:root_dir(), "erts/preloaded/ebin/*.beam"), + filelib:wildcard(WC) ++ get_beams(Apps); +get_beams([App|Apps]) -> + WC = filename:join(code:lib_dir(App), "ebin/*.beam"), + filelib:wildcard(WC) ++ get_beams(Apps); +get_beams([]) -> []. + + +%%% +%%% Generate renumbered .S files. +%%% + +compile_to_asm_fun(#{outdir:=OutDir}) -> + fun(File) -> + compile_to_asm(File, OutDir) + end. + +compile_to_asm({File,Opts}, OutDir) -> + case compile:file(File, [to_asm,binary,report_errors|Opts]) of + error -> + error; + {ok,Mod,Asm0} -> + {ok,Asm1} = beam_a:module(Asm0, []), + Asm2 = renumber_asm(Asm1), + {ok,Asm} = beam_z:module(Asm2, []), + print_asm(Mod, OutDir, Asm) + end. + +print_asm(Mod, OutDir, Asm) -> + S = atom_to_list(Mod) ++ ".S", + Name = filename:join(OutDir, S), + {ok,Fd} = file:open(Name, [write,raw,delayed_write]), + ok = beam_listing(Fd, Asm), + ok = file:close(Fd). + +renumber_asm({Mod,Exp,Attr,Fs0,NumLabels}) -> + EntryLabels = maps:from_list(entry_labels(Fs0)), + Fs = [fix_func(F, EntryLabels) || F <- Fs0], + {Mod,Exp,Attr,Fs,NumLabels}. + +entry_labels(Fs) -> + [{Entry,{Name,Arity}} || {function,Name,Arity,Entry,_} <- Fs]. + +fix_func({function,Name,Arity,Entry0,Is0}, LabelMap0) -> + Entry = maps:get(Entry0, LabelMap0), + LabelMap = label_map(Is0, 1, LabelMap0), + Is = replace(Is0, [], LabelMap), + {function,Name,Arity,Entry,Is}. + +label_map([{label,Old}|Is], New, Map) -> + case maps:is_key(Old, Map) of + false -> + label_map(Is, New+1, Map#{Old=>New}); + true -> + label_map(Is, New, Map) + end; +label_map([_|Is], New, Map) -> + label_map(Is, New, Map); +label_map([], _New, Map) -> + Map. + +replace([{label,Lbl}|Is], Acc, D) -> + replace(Is, [{label,label(Lbl, D)}|Acc], D); +replace([{test,Test,{f,Lbl},Ops}|Is], Acc, D) -> + replace(Is, [{test,Test,{f,label(Lbl, D)},Ops}|Acc], D); +replace([{test,Test,{f,Lbl},Live,Ops,Dst}|Is], Acc, D) -> + replace(Is, [{test,Test,{f,label(Lbl, D)},Live,Ops,Dst}|Acc], D); +replace([{select,I,R,{f,Fail0},Vls0}|Is], Acc, D) -> + Vls = lists:map(fun ({f,L}) -> {f,label(L, D)}; + (Other) -> Other + end, Vls0), + Fail = label(Fail0, D), + replace(Is, [{select,I,R,{f,Fail},Vls}|Acc], D); +replace([{'try',R,{f,Lbl}}|Is], Acc, D) -> + replace(Is, [{'try',R,{f,label(Lbl, D)}}|Acc], D); +replace([{'catch',R,{f,Lbl}}|Is], Acc, D) -> + replace(Is, [{'catch',R,{f,label(Lbl, D)}}|Acc], D); +replace([{jump,{f,Lbl}}|Is], Acc, D) -> + replace(Is, [{jump,{f,label(Lbl, D)}}|Acc], D); +replace([{loop_rec,{f,Lbl},R}|Is], Acc, D) -> + replace(Is, [{loop_rec,{f,label(Lbl, D)},R}|Acc], D); +replace([{loop_rec_end,{f,Lbl}}|Is], Acc, D) -> + replace(Is, [{loop_rec_end,{f,label(Lbl, D)}}|Acc], D); +replace([{wait,{f,Lbl}}|Is], Acc, D) -> + replace(Is, [{wait,{f,label(Lbl, D)}}|Acc], D); +replace([{wait_timeout,{f,Lbl},To}|Is], Acc, D) -> + replace(Is, [{wait_timeout,{f,label(Lbl, D)},To}|Acc], D); +replace([{bif,Name,{f,Lbl},As,R}|Is], Acc, D) when Lbl =/= 0 -> + replace(Is, [{bif,Name,{f,label(Lbl, D)},As,R}|Acc], D); +replace([{gc_bif,Name,{f,Lbl},Live,As,R}|Is], Acc, D) when Lbl =/= 0 -> + replace(Is, [{gc_bif,Name,{f,label(Lbl, D)},Live,As,R}|Acc], D); +replace([{call,Ar,{f,Lbl}}|Is], Acc, D) -> + replace(Is, [{call,Ar,{f,label(Lbl,D)}}|Acc], D); +replace([{make_fun2,{f,Lbl},U1,U2,U3}|Is], Acc, D) -> + replace(Is, [{make_fun2,{f,label(Lbl, D)},U1,U2,U3}|Acc], D); +replace([{bs_init,{f,Lbl},Info,Live,Ss,Dst}|Is], Acc, D) when Lbl =/= 0 -> + replace(Is, [{bs_init,{f,label(Lbl, D)},Info,Live,Ss,Dst}|Acc], D); +replace([{bs_put,{f,Lbl},Info,Ss}|Is], Acc, D) when Lbl =/= 0 -> + replace(Is, [{bs_put,{f,label(Lbl, D)},Info,Ss}|Acc], D); +replace([{put_map=I,{f,Lbl},Op,Src,Dst,Live,List}|Is], Acc, D) + when Lbl =/= 0 -> + replace(Is, [{I,{f,label(Lbl, D)},Op,Src,Dst,Live,List}|Acc], D); +replace([{get_map_elements=I,{f,Lbl},Src,List}|Is], Acc, D) when Lbl =/= 0 -> + replace(Is, [{I,{f,label(Lbl, D)},Src,List}|Acc], D); +replace([{recv_mark=I,{f,Lbl}}|Is], Acc, D) -> + replace(Is, [{I,{f,label(Lbl, D)}}|Acc], D); +replace([{recv_set=I,{f,Lbl}}|Is], Acc, D) -> + replace(Is, [{I,{f,label(Lbl, D)}}|Acc], D); +replace([I|Is], Acc, D) -> + replace(Is, [I|Acc], D); +replace([], Acc, _) -> + lists:reverse(Acc). + +label(Old, D) when is_integer(Old) -> + maps:get(Old, D). + +%%% +%%% Compile and disassemble the loaded code. +%%% + +compile_to_dis_fun(#{outdir:=OutDir,no_compile:=false}) -> + fun(File) -> + compile_to_dis(File, OutDir) + end; +compile_to_dis_fun(#{outdir:=OutDir,no_compile:=true}) -> + fun(File) -> + dis_only(File, OutDir) + end. + +compile_to_dis({File,Opts}, OutDir) -> + case compile:file(File, [to_asm,binary,report_errors|Opts]) of + error -> + error; + {ok,Mod,Asm0} -> + NewMod = list_to_atom("--"++atom_to_list(Mod)++"--"), + Asm = rename_mod_in_asm(Asm0, Mod, NewMod), + AsmOpts = [from_asm,report,no_postopt,binary], + {ok,NewMod,Beam} = compile:forms(Asm, AsmOpts), + Dis0 = disasm(NewMod, Beam), + Dis1 = renumber_disasm(Dis0, Mod, NewMod), + Dis = format_disasm(Dis1), + OutFile = filename:join(OutDir, atom_to_list(Mod)++".dis"), + ok = file:write_file(OutFile, Dis) + end. + +dis_only(File, OutDir) -> + Mod0 = filename:rootname(filename:basename(File)), + Mod = list_to_atom(Mod0), + Dis0 = disasm(Mod), + Dis1 = renumber_disasm(Dis0, Mod, Mod), + Dis = format_disasm(Dis1), + OutFile = filename:join(OutDir, atom_to_list(Mod)++".dis"), + ok = file:write_file(OutFile, Dis). + +%%% Loading system modules can cause any number of problems. +%%% Therefore, we rename all modules to a dummy name before +%%% loading and disassembling them. + +rename_mod_in_asm({OldMod,Exp,_Attr,Fs0,NumLabels}, OldMod, NewMod) -> + Fs = [fix_func_info(F, {atom,OldMod}, {atom,NewMod}) || F <- Fs0], + {NewMod,Exp,[],Fs,NumLabels}. + +fix_func_info({function,Name,Arity,Entry,Is0}, OldMod, NewMod) -> + Is1 = [begin + case I of + {func_info,_,F,A} -> + {func_info,NewMod,F,A}; + _ -> + I + end + end || I <- Is0], + Is = case {Name,Arity} of + {module_info,0} -> fix_module_info(Is1, OldMod, NewMod); + {module_info,1} -> fix_module_info(Is1, OldMod, NewMod); + {_,_} -> Is1 + end, + {function,Name,Arity,Entry,Is}. + +fix_module_info([{move,OldMod,Dst}|Is], OldMod, NewMod) -> + [{move,NewMod,Dst}|fix_module_info(Is, OldMod, NewMod)]; +fix_module_info([I|Is], OldMod, NewMod) -> + [I|fix_module_info(Is, OldMod, NewMod)]; +fix_module_info([], _, _) -> + []. + + +%%% Disassemble the module. + +disasm(Mod, Beam) -> + {module,Mod} = code:load_binary(Mod, "", Beam), + disasm(Mod). + +disasm(Mod) -> + disasm_1(Mod:module_info(functions), Mod). + +disasm_1([{Name,Arity}|Fs], Mod) -> + MFA = {Mod,Name,Arity}, + Dis = disasm_func({MFA,<<>>,MFA}, MFA), + [{Name,Arity,Dis}|disasm_1(Fs, Mod)]; +disasm_1([], _) -> + []. + +disasm_func({Next,_,MFA}, MFA) -> + case erts_debug:disassemble(Next) of + {_,Line,MFA}=Cont -> + [Line|disasm_func(Cont, MFA)]; + {_,_,_} -> + []; + false -> + [] + end. + +%%% Renumber the disassembled module to use labels instead of +%%% absolute addresses. Also do other translations so that the +%%% output will be the same each time (for the same BEAM file +%%% runtime system). + +renumber_disasm(Fs0, OldMod, NewMod) -> + Fs1 = split_dis_lines(Fs0), + renumber_disasm_fs(Fs1, OldMod, NewMod). + +renumber_disasm_fs([{Name,Arity,Is0}|Fs], OldMod, NewMod) -> + Labels = find_labels(Is0, Name, Arity), + Is1 = rename_mod(Is0, OldMod, NewMod), + Is = renumber_disasm_func(Is1, Labels), + [{Name,Arity,Is}|renumber_disasm_fs(Fs, OldMod, NewMod)]; +renumber_disasm_fs([], _OldMod, _NewMod) -> + []. + +renumber_disasm_func([[A,OpCode|Ops0]|Is], Labels) -> + Spaces = " ", + Left = case maps:find(A, Labels) of + {ok,Lbl} -> + case byte_size(Lbl) of + LblSize when LblSize < length(Spaces) -> + [$\n,Lbl,":",lists:nth(LblSize, Spaces)]; + _ -> + [Lbl,":\n"|Spaces] + end; + error -> + Spaces + end, + Ops1 = [replace_label(Op, Labels) || Op <- Ops0], + Ops = handle_special_instrs(OpCode, Ops1), + [[Left,OpCode|Ops]|renumber_disasm_func(Is, Labels)]; +renumber_disasm_func([], _) -> + []. + +handle_special_instrs(<<"i_get_hash_cId">>, [Key,_Hash,Dst]) -> + [Key,hash_value(),Dst]; +handle_special_instrs(<<"i_get_map_element_",_/binary>>, + [Fail,Src,Key,_Hash,Dst]) -> + [Fail,Src,Key,hash_value(),Dst]; +handle_special_instrs(<<"i_get_map_elements_",_/binary>>, + [Fail,Src,N,Space|List0]) -> + List1 = rejoin_atoms(List0), + List = fix_hash_value(List1), + [Fail,Src,N,Space|List]; +handle_special_instrs(<<"i_select_val_bins_",_/binary>>, + [Src,Fail,Num|List0]) -> + %% Atoms are sorted in atom-number order, which is + %% different every time the runtime system is restarted. + %% Resort the values in ASCII order. + List1 = rejoin_atoms(List0), + {Values0,Labels0} = lists:split(length(List1) div 2, List1), + Zipped0 = lists:zip(Values0, Labels0), + Zipped = lists:sort(Zipped0), + {Values,Labels} = lists:unzip(Zipped), + [Src,Fail,Num|Values++Labels]; +handle_special_instrs(<<"i_select_val_lins_",_/binary>>, + [Src,Fail,Num|List0]) -> + List1 = rejoin_atoms(List0), + {Values0,Labels0} = lists:split(length(List1) div 2, List1), + Values1 = lists:droplast(Values0), + Labels1 = lists:droplast(Labels0), + Vlast = lists:last(Values0), + Llast = lists:last(Labels0), + Zipped0 = lists:zip(Values1, Labels1), + Zipped = lists:sort(Zipped0), + {Values,Labels} = lists:unzip(Zipped), + [Src,Fail,Num|Values++[Vlast]++Labels++[Llast]]; +handle_special_instrs(_, Ops) -> + Ops. + +fix_hash_value([Val,Dst,_Hash|T]) -> + [Val,Dst,hash_value()|fix_hash_value(T)]; +fix_hash_value([]) -> + []. + +hash_value() -> + <<"--hash-value--">>. + +replace_label(<<"f(",T/binary>>, Labels) -> + replace_label_1("f(", T, Labels); +replace_label(<<"j(",T/binary>>, Labels) -> + replace_label_1("j(", T, Labels); +replace_label(Op, _Labels) -> + Op. + +replace_label_1(Prefix, Lbl0, Labels) -> + Sz = byte_size(Lbl0)-1, + Lbl = case Lbl0 of + <<"0)">> -> + Lbl0; + <<Lbl1:Sz/bytes,")">> -> + [maps:get(Lbl1, Labels),")"]; + _ -> + Lbl0 + end, + iolist_to_binary([Prefix,Lbl]). + +split_dis_lines(Fs) -> + {ok,RE} = re:compile(<<"\\s*\\n$">>), + Colon = binary:compile_pattern(<<": ">>), + Space = binary:compile_pattern(<<" ">>), + [split_dis_func(F, RE, Colon, Space) || F <- Fs]. + +split_dis_func({Name,Arity,Lines0}, RE, Colon, Space) -> + Lines1 = [re:replace(L, RE, <<>>, [{return,binary}]) || L <- Lines0], + Lines2 = [begin + [A,I] = binary:split(L, Colon), + Ops = binary:split(I, Space, [global]), + [A|Ops] + end|| L <- Lines1], + {Name,Arity,Lines2}. + +rejoin_atoms([<<"'",Tail/binary>> = Bin0,Next|Ops]) -> + Sz = byte_size(Tail) - 1, + case Tail of + <<_:Sz/bytes,"'">> -> + [Bin0|rejoin_atoms([Next|Ops])]; + <<>> -> + Bin = <<Bin0/binary,$\s,Next/binary>>, + rejoin_atoms([Bin|Ops]); + _ -> + Bin = <<Bin0/binary,$\s,Next/binary>>, + rejoin_atoms([Bin|Ops]) + end; +rejoin_atoms(Ops) -> + Ops. + +find_labels(Is, Name, Arity) -> + [_,[Entry|_]|_] = Is, + EntryLabel = iolist_to_binary(io_lib:format("~p/~p", [Name,Arity])), + {ok,RE} = re:compile(<<"^[fj]\\(([0-9A-F]{8,16})\\)$">>), + Ls0 = [find_labels_1(Ops, RE) || [_Addr,_OpCode|Ops] <- Is], + Ls1 = lists:flatten(Ls0), + Ls2 = lists:usort(Ls1), + Ls3 = number(Ls2, 1), + Ls = [{Entry,EntryLabel}|Ls3], + maps:from_list(Ls). + +find_labels_1([Op|Ops], RE) -> + case re:run(Op, RE, [{capture,all_but_first,binary}]) of + nomatch -> + find_labels_1(Ops, RE); + {match,[M]} -> + [M|find_labels_1(Ops, RE)] + end; +find_labels_1([], _) -> + []. + +number([H|T], N) -> + S = iolist_to_binary(["L",integer_to_list(N)]), + [{H,S}|number(T, N+1)]; +number([], _) -> + []. + +format_disasm([{_,_,Is}|Fs]) -> + L = [lists:join(" ", I) || I <- Is], + [lists:join("\n", L),"\n\n"|format_disasm(Fs)]; +format_disasm([]) -> + []. + +rename_mod(Is, OldMod0, NewMod) -> + OldMod = atom_to_binary(OldMod0, utf8), + Pattern = <<"'",(atom_to_binary(NewMod, utf8))/binary,"'">>, + [rename_mod_1(I, Pattern, OldMod) || I <- Is]. + +rename_mod_1([A,OpCode|Ops], Pat, Replacement) -> + [A,OpCode|[rename_mod_2(Op, Pat, Replacement) || Op <- Ops]]. + +rename_mod_2(Subject, Pat, Replacement) -> + Sz = byte_size(Pat), + case Subject of + <<Pat:Sz/bytes,Tail/binary>> -> + <<Replacement/binary,Tail/binary>>; + _ -> + Subject + end. + +%%% +%%% Run tasks in parallel. +%%% + +p_run(Test, List) -> + N = erlang:system_info(schedulers) * 2, + p_run_loop(Test, List, N, [], 0). + +p_run_loop(_, [], _, [], Errors) -> + io:put_chars("\r \n"), + case Errors of + 0 -> + ok; + N -> + io:format("~p errors\n", [N]), + halt(1) + end; +p_run_loop(Test, [H|T], N, Refs, Errors) when length(Refs) < N -> + {_,Ref} = erlang:spawn_monitor(fun() -> exit(Test(H)) end), + p_run_loop(Test, T, N, [Ref|Refs], Errors); +p_run_loop(Test, List, N, Refs0, Errors0) -> + io:format("\r~p ", [length(List)+length(Refs0)]), + receive + {'DOWN',Ref,process,_,Res} -> + Errors = case Res of + ok -> Errors0; + error -> Errors0 + 1 + end, + Refs = Refs0 -- [Ref], + p_run_loop(Test, List, N, Refs, Errors) + end. + +%%% +%%% Borrowed from beam_listing and tweaked. +%%% + +beam_listing(Stream, {Mod,Exp,Attr,Code,NumLabels}) -> + Head = ["%% -*- encoding:latin-1 -*-\n", + io_lib:format("{module, ~p}. %% version = ~w\n", + [Mod, beam_opcodes:format_number()]), + io_lib:format("\n{exports, ~p}.\n", [Exp]), + io_lib:format("\n{attributes, ~p}.\n", [Attr]), + io_lib:format("\n{labels, ~p}.\n", [NumLabels])], + ok = file:write(Stream, Head), + lists:foreach( + fun ({function,Name,Arity,Entry,Asm}) -> + S = [io_lib:format("\n\n{function, ~w, ~w, ~w}.\n", + [Name,Arity,Entry])|format_asm(Asm)], + ok = file:write(Stream, S) + end, Code). + +format_asm([{label,_}=I|Is]) -> + [io_lib:format(" ~p", [I]),".\n"|format_asm(Is)]; +format_asm([I|Is]) -> + [io_lib:format(" ~p", [I]),".\n"|format_asm(Is)]; +format_asm([]) -> []. diff --git a/system/doc/design_principles/Makefile b/system/doc/design_principles/Makefile index 5743a50b47..611ab6da99 100644 --- a/system/doc/design_principles/Makefile +++ b/system/doc/design_principles/Makefile @@ -18,6 +18,7 @@ # %CopyrightEnd% # # + include $(ERL_TOP)/make/target.mk include $(ERL_TOP)/make/$(TARGET)/otp.mk @@ -27,6 +28,8 @@ include $(ERL_TOP)/make/$(TARGET)/otp.mk include $(ERL_TOP)/erts/vsn.mk APPLICATION=otp-system-documentation +XMLDIR := $(XMLDIR)/design_principles + # ---------------------------------------------------- # Release directory specification # ---------------------------------------------------- diff --git a/system/doc/efficiency_guide/Makefile b/system/doc/efficiency_guide/Makefile index 36e4cd00df..b1630a36e1 100644 --- a/system/doc/efficiency_guide/Makefile +++ b/system/doc/efficiency_guide/Makefile @@ -28,6 +28,7 @@ include $(ERL_TOP)/erts/vsn.mk #VSN=$(SYSTEM_VSN) APPLICATION=otp-system-documentation +XMLDIR := $(XMLDIR)/efficiency_guide # ---------------------------------------------------- # Release directory specification # ---------------------------------------------------- diff --git a/system/doc/embedded/Makefile b/system/doc/embedded/Makefile index 40a1b1fb23..23d3168e34 100644 --- a/system/doc/embedded/Makefile +++ b/system/doc/embedded/Makefile @@ -28,6 +28,7 @@ include $(ERL_TOP)/erts/vsn.mk #VSN=$(SYSTEM_VSN) APPLICATION=otp-system-documentation +XMLDIR := $(XMLDIR)/embedded # ---------------------------------------------------- # Release directory specification # ---------------------------------------------------- diff --git a/system/doc/getting_started/Makefile b/system/doc/getting_started/Makefile index 1fe3d39e4e..13d767daf5 100644 --- a/system/doc/getting_started/Makefile +++ b/system/doc/getting_started/Makefile @@ -28,6 +28,7 @@ include $(ERL_TOP)/erts/vsn.mk #VSN=$(SYSTEM_VSN) APPLICATION=otp-system-documentation +XMLDIR := $(XMLDIR)/getting_started # ---------------------------------------------------- # Release directory specification # ---------------------------------------------------- diff --git a/system/doc/installation_guide/Makefile b/system/doc/installation_guide/Makefile index 673c203422..002c2a536a 100644 --- a/system/doc/installation_guide/Makefile +++ b/system/doc/installation_guide/Makefile @@ -28,6 +28,8 @@ include $(ERL_TOP)/erts/vsn.mk #VSN=$(SYSTEM_VSN) APPLICATION=otp-system-documentation +XMLDIR := $(XMLDIR)/installation_guide + # ---------------------------------------------------- # Release directory specification # ---------------------------------------------------- @@ -43,6 +45,8 @@ include xmlfiles.mk XML_CHAPTER_FILES=$(INST_GUIDE_CHAPTER_FILES) +# ---------------------------------------------------- + TOPDOCDIR=.. BOOK_FILES = book.xml @@ -55,12 +59,7 @@ XML_FILES = \ $(BOOK_FILES) $(XML_CHAPTER_FILES) \ $(XML_PART_FILES) -# ---------------------------------------------------- -GENERATED_XML_FILES = \ - INSTALL.xml \ - INSTALL-CROSS.xml \ - INSTALL-WIN32.xml \ - OTP-PATCH-APPLY.xml +XML_GEN_FILES = $(INST_GUIDE_CHAPTER_GEN_FILES:%=$(XMLDIR)/%) # ---------------------------------------------------- @@ -88,7 +87,7 @@ DVIPS_FLAGS += # Targets # ---------------------------------------------------- -%.xml: $(ERL_TOP)/HOWTO/%.md $(ERL_TOP)/make/emd2exml +$(XMLDIR)/%.xml: $(ERL_TOP)/HOWTO/%.md $(ERL_TOP)/make/emd2exml $(ERL_TOP)/make/emd2exml $< $@ $(REDIRECT_HTML_DIR)/%.html: Makefile @@ -102,12 +101,12 @@ $(REDIRECT_HTML_DIR)/%.html: Makefile echo "This <a href=\"../"$(notdir $@)"\">link</a> will" >> $@ echo "take you there immediately.</p></body></html>" >> $@ -docs: $(GENERATED_XML_FILES) html +docs: $(XML_GEN_FILES) html local_docs: PDFDIR=../../pdf -local_docs: $(GENERATED_XML_FILES) +local_docs: $(XML_GEN_FILES) -html: $(REDIRECT_HTML_FILES) $(GENERATED_XML_FILES) $(GIF_FILES) $(HTML_UG_FILE) +html: $(REDIRECT_HTML_FILES) $(XML_GEN_FILES) $(GIF_FILES) $(HTML_UG_FILE) debug opt: diff --git a/system/doc/installation_guide/xmlfiles.mk b/system/doc/installation_guide/xmlfiles.mk index 3f720e1ee5..37fbeca96b 100644 --- a/system/doc/installation_guide/xmlfiles.mk +++ b/system/doc/installation_guide/xmlfiles.mk @@ -18,7 +18,9 @@ # %CopyrightEnd% # INST_GUIDE_CHAPTER_FILES = \ - install-binary.xml \ + install-binary.xml + +INST_GUIDE_CHAPTER_GEN_FILES = \ INSTALL.xml \ INSTALL-CROSS.xml \ INSTALL-WIN32.xml \ diff --git a/system/doc/oam/Makefile b/system/doc/oam/Makefile index 9095744423..dfebc6aca0 100644 --- a/system/doc/oam/Makefile +++ b/system/doc/oam/Makefile @@ -27,6 +27,7 @@ include $(ERL_TOP)/erts/vsn.mk #VSN=$(SYSTEM_VSN) APPLICATION=otp-system-documentation +XMLDIR := $(XMLDIR)/oam # ---------------------------------------------------- # Release directory specification # ---------------------------------------------------- diff --git a/system/doc/programming_examples/Makefile b/system/doc/programming_examples/Makefile index 237076d770..af731f85b4 100644 --- a/system/doc/programming_examples/Makefile +++ b/system/doc/programming_examples/Makefile @@ -28,6 +28,7 @@ include $(ERL_TOP)/erts/vsn.mk #VSN=$(SYSTEM_VSN) APPLICATION=otp-system-documentation +XMLDIR := $(XMLDIR)/programming_examples # ---------------------------------------------------- # Release directory specification # ---------------------------------------------------- @@ -52,7 +53,9 @@ PS_FILES = XML_FILES = \ $(BOOK_FILES) $(XML_CHAPTER_FILES) \ - $(XML_PART_FILES) + $(XML_PART_FILES) + +XML_GEN_FILES = $(PROG_EX_CHAPTER_GEN_FILES:%=$(XMLDIR)/%) # ---------------------------------------------------- HTML_FILES = \ diff --git a/system/doc/programming_examples/xmlfiles.mk b/system/doc/programming_examples/xmlfiles.mk index 5129e488f4..20b08d8cd3 100644 --- a/system/doc/programming_examples/xmlfiles.mk +++ b/system/doc/programming_examples/xmlfiles.mk @@ -19,6 +19,8 @@ # PROG_EX_CHAPTER_FILES = \ bit_syntax.xml \ - funs.xml \ list_comprehensions.xml \ records.xml + +PROG_EX_CHAPTER_GEN_FILES = \ + funs.xml diff --git a/system/doc/reference_manual/Makefile b/system/doc/reference_manual/Makefile index e14a056979..75c15e4b5f 100644 --- a/system/doc/reference_manual/Makefile +++ b/system/doc/reference_manual/Makefile @@ -28,6 +28,7 @@ include $(ERL_TOP)/erts/vsn.mk #VSN=$(SYSTEM_VSN) APPLICATION=otp-system-documentation +XMLDIR := $(XMLDIR)/reference_manual # ---------------------------------------------------- # Release directory specification # ---------------------------------------------------- diff --git a/system/doc/system_architecture_intro/Makefile b/system/doc/system_architecture_intro/Makefile index 446e66205c..7a10f305ba 100644 --- a/system/doc/system_architecture_intro/Makefile +++ b/system/doc/system_architecture_intro/Makefile @@ -28,6 +28,7 @@ include $(ERL_TOP)/erts/vsn.mk #VSN=$(SYSTEM_VSN) APPLICATION=otp-system-documentation +XMLDIR := $(XMLDIR)/system_architecture_intro # ---------------------------------------------------- # Release directory specification # ---------------------------------------------------- diff --git a/system/doc/system_principles/Makefile b/system/doc/system_principles/Makefile index 77edea8f58..ec6591ec6b 100644 --- a/system/doc/system_principles/Makefile +++ b/system/doc/system_principles/Makefile @@ -28,6 +28,7 @@ include $(ERL_TOP)/erts/vsn.mk #VSN=$(SYSTEM_VSN) APPLICATION=otp-system-documentation +XMLDIR := $(XMLDIR)/system_principles # ---------------------------------------------------- # Release directory specification # ---------------------------------------------------- @@ -52,6 +53,8 @@ XML_FILES = \ $(BOOK_FILES) $(XML_CHAPTER_FILES) \ $(XML_PART_FILES) +XML_GEN_FILES = $(SYSTEM_PRINCIPLES_CHAPTER_GEN_FILES:%=$(XMLDIR)/%) + # ---------------------------------------------------- HTMLDIR = ../html/system_principles diff --git a/system/doc/system_principles/xmlfiles.mk b/system/doc/system_principles/xmlfiles.mk index c3c3bb4731..f8972b24a7 100644 --- a/system/doc/system_principles/xmlfiles.mk +++ b/system/doc/system_principles/xmlfiles.mk @@ -20,6 +20,8 @@ SYSTEM_PRINCIPLES_CHAPTER_FILES = \ system_principles.xml \ error_logging.xml \ - create_target.xml \ upgrade.xml \ versions.xml + +SYSTEM_PRINCIPLES_CHAPTER_GEN_FILES = \ + create_target.xml diff --git a/system/doc/top/Makefile b/system/doc/top/Makefile index b6a80aadf5..73c943caa1 100644 --- a/system/doc/top/Makefile +++ b/system/doc/top/Makefile @@ -53,30 +53,45 @@ include ../oam/xmlfiles.mk BOOK_FILES = book.xml XML_FILES = \ - $(INST_GUIDE_CHAPTER_FILES:%=../installation_guide/%) \ - $(SYSTEM_PRINCIPLES_CHAPTER_FILES:%=../system_principles/%) \ - $(EMBEDDED_CHAPTER_FILES:%=../embedded/%) \ - $(GETTING_STARTED_CHAPTER_FILES:%=../getting_started/%) \ - $(REF_MAN_CHAPTER_FILES:%=../reference_manual/%) \ - $(PROG_EX_CHAPTER_FILES:%=../programming_examples/%) \ - $(EFF_GUIDE_CHAPTER_FILES:%=../efficiency_guide/%) \ - $(TUTORIAL_CHAPTER_FILES:%=../tutorial/%) \ - $(DESIGN_PRINCIPLES_CHAPTER_FILES:%=../design_principles/%) \ - $(OAM_CHAPTER_FILES:%=../oam/%) \ - ../installation_guide/part.xml \ - ../system_principles/part.xml \ - ../embedded/part.xml \ - ../getting_started/part.xml \ - ../reference_manual/part.xml \ - ../programming_examples/part.xml \ - ../efficiency_guide/part.xml \ - ../tutorial/part.xml \ - ../design_principles/part.xml \ - ../oam/part.xml \ $(BOOK_FILES) - -XMLLINT_SRCDIRS= ../installation_guide:../system_principles:../embedded:../getting_started:../reference_manual:../programming_examples:../efficiency_guide:../tutorial:../design_principles:../oam +XML_GUIDE_FILES = \ + $(INST_GUIDE_CHAPTER_FILES:%=installation_guide/%) \ + $(INST_GUIDE_CHAPTER_GEN_FILES:%=installation_guide/%) \ + $(SYSTEM_PRINCIPLES_CHAPTER_FILES:%=system_principles/%) \ + $(SYSTEM_PRINCIPLES_CHAPTER_GEN_FILES:%=system_principles/%) \ + $(EMBEDDED_CHAPTER_FILES:%=embedded/%) \ + $(EMBEDDED_CHAPTER_GEN_FILES:%=embedded/%) \ + $(GETTING_STARTED_CHAPTER_FILES:%=getting_started/%) \ + $(GETTING_STARTED_CHAPTER_GEN_FILES:%=getting_started/%) \ + $(REF_MAN_CHAPTER_FILES:%=reference_manual/%) \ + $(REF_MAN_CHAPTER_GEN_FILES:%=reference_manual/%) \ + $(PROG_EX_CHAPTER_FILES:%=programming_examples/%) \ + $(PROG_EX_CHAPTER_GEN_FILES:%=programming_examples/%) \ + $(EFF_GUIDE_CHAPTER_FILES:%=efficiency_guide/%) \ + $(EFF_GUIDE_CHAPTER_GEN_FILES:%=efficiency_guide/%) \ + $(TUTORIAL_CHAPTER_FILES:%=tutorial/%) \ + $(TUTORIAL_CHAPTER_GEN_FILES:%=tutorial/%) \ + $(DESIGN_PRINCIPLES_CHAPTER_FILES:%=design_principles/%) \ + $(DESIGN_PRINCIPLES_CHAPTER_GEN_FILES:%=design_principles/%) \ + $(OAM_CHAPTER_FILES:%=oam/%) \ + $(OAM_CHAPTER_GEN_FILES:%=oam/%) + +XML_GEN_FILES = \ + $(XML_GUIDE_FILES:%=$(XMLDIR)/%) \ + $(XMLDIR)/installation_guide/part.xml \ + $(XMLDIR)/system_principles/part.xml \ + $(XMLDIR)/embedded/part.xml \ + $(XMLDIR)/getting_started/part.xml \ + $(XMLDIR)/reference_manual/part.xml \ + $(XMLDIR)/programming_examples/part.xml \ + $(XMLDIR)/efficiency_guide/part.xml \ + $(XMLDIR)/tutorial/part.xml \ + $(XMLDIR)/design_principles/part.xml \ + $(XMLDIR)/oam/part.xml + + +XMLLINT_SRCDIRS= $(XMLDIR)/installation_guide:$(XMLDIR)/system_principles:$(XMLDIR)/embedded:$(XMLDIR)/getting_started:$(XMLDIR)/reference_manual:$(XMLDIR)/programming_examples:$(XMLDIR)/efficiency_guide:$(XMLDIR)/tutorial:$(XMLDIR)/design_principles:$(XMLDIR)/oam HTMLDIR= ../html PDFREFDIR= pdf @@ -240,13 +255,11 @@ clean: rm -f $(INDEX_SCRIPT) $(GLOSSARY_SCRIPT) \ $(JAVASCRIPT_BUILD_SCRIPT) rm -f erl_crash.dump errs core *~ - # ---------------------------------------------------- # Release Target # ---------------------------------------------------- include $(ERL_TOP)/make/otp_release_targets.mk - release_docs_spec: docs $(INSTALL_DIR) "$(RELEASE_PATH)" $(INSTALL_DATA) $(INFO_FILES) "$(RELEASE_PATH)" diff --git a/system/doc/top/book.xml b/system/doc/top/book.xml index c94b0f24d6..540b6bfd24 100644 --- a/system/doc/top/book.xml +++ b/system/doc/top/book.xml @@ -36,16 +36,16 @@ <contents level="2"></contents> </preamble> <parts lift="no"> - <xi:include href="../installation_guide/part.xml"/> - <xi:include href="../system_principles/part.xml"/> - <xi:include href="../embedded/part.xml"/> - <xi:include href="../getting_started/part.xml"/> - <xi:include href="../reference_manual/part.xml"/> - <xi:include href="../programming_examples/part.xml"/> - <xi:include href="../efficiency_guide/part.xml"/> - <xi:include href="../tutorial/part.xml"/> - <xi:include href="../design_principles/part.xml"/> - <xi:include href="../oam/part.xml"/> + <xi:include href="../xml/installation_guide/part.xml"/> + <xi:include href="../xml/system_principles/part.xml"/> + <xi:include href="../xml/embedded/part.xml"/> + <xi:include href="../xml/getting_started/part.xml"/> + <xi:include href="../xml/reference_manual/part.xml"/> + <xi:include href="../xml/programming_examples/part.xml"/> + <xi:include href="../xml/efficiency_guide/part.xml"/> + <xi:include href="../xml/tutorial/part.xml"/> + <xi:include href="../xml/design_principles/part.xml"/> + <xi:include href="../xml/oam/part.xml"/> </parts> <listofterms></listofterms> <index></index> diff --git a/system/doc/tutorial/Makefile b/system/doc/tutorial/Makefile index 5deea41f0a..606064da72 100644 --- a/system/doc/tutorial/Makefile +++ b/system/doc/tutorial/Makefile @@ -28,6 +28,7 @@ include $(ERL_TOP)/erts/vsn.mk #VSN=$(SYSTEM_VSN) APPLICATION=otp-system-documentation +XMLDIR := $(XMLDIR)/tutorial # ---------------------------------------------------- # Release directory specification # ---------------------------------------------------- @@ -53,6 +54,9 @@ XML_FILES = \ $(BOOK_FILES) $(XML_CHAPTER_FILES) \ $(XML_PART_FILES) +XML_GEN_FILES = \ + $(TUTORIAL_CHAPTER_GEN_FILES:%=$(XMLDIR)/%) + # ---------------------------------------------------- C_FILES = \ diff --git a/system/doc/tutorial/xmlfiles.mk b/system/doc/tutorial/xmlfiles.mk index f8ed7be064..53f82c6475 100644 --- a/system/doc/tutorial/xmlfiles.mk +++ b/system/doc/tutorial/xmlfiles.mk @@ -19,13 +19,16 @@ # TUTORIAL_CHAPTER_FILES = \ introduction.xml\ + overview.xml + +TUTORIAL_CHAPTER_GEN_FILES = \ cnode.xml\ c_port.xml\ erl_interface.xml \ c_portdriver.xml \ example.xml\ - overview.xml\ nif.xml + # appendix.xml # distribution.xml (to be part of tutorial later) |